Skip to content

Commit d8e17c6

Browse files
committed
Add Doma Protocol TVL adapter
Doma is a DomainFi protocol enabling fractionalization of web3 domains on the Doma L2 (Chain ID: 97477). TVL tracks USDC.e balances in protocol contracts: - DomaFractionalization (diamond proxy) - DomaLaunchpad contracts - Associated Uniswap V3 pools Addresses discovered dynamically via Blockscout explorer API.
1 parent efacee7 commit d8e17c6

File tree

3 files changed

+168
-0
lines changed

3 files changed

+168
-0
lines changed

projects/doma/index.js

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
const { get } = require('../helper/http')
2+
const { sumTokens2 } = require('../helper/unwrapLPs')
3+
4+
// VERIFIED ADDRESSES - 2024-11-27 via explorer.doma.xyz
5+
// USDC.e (Bridged USDC via Stargate) - 6 decimals
6+
// https://explorer.doma.xyz/token/0x31EEf89D5215C305304a2fA5376a1f1b6C5dc477
7+
const USDC_E_ADDRESS = '0x31EEf89D5215C305304a2fA5376a1f1b6C5dc477'
8+
9+
// DomaFractionalization Diamond Proxy - verified via explorer.doma.xyz
10+
// https://explorer.doma.xyz/address/0xd00000000004f450f1438cfA436587d8f8A55A29
11+
const DOMA_FRACTIONALIZATION = '0xd00000000004f450f1438cfA436587d8f8A55A29'
12+
13+
// Blockscout explorer API (public, no auth required)
14+
const EXPLORER_API = 'https://explorer.doma.xyz/api/v2'
15+
16+
// NameTokenFractionalized event topic (from explorer logs)
17+
// Event: NameTokenFractionalized(address indexed tokenAddress, uint256 indexed tokenId,
18+
// address tokenOwner, address fractionalTokenAddress, address launchpadAddress,
19+
// address vestingWallet, uint256 fractionalizationVersion, tuple params)
20+
const FRACTIONALIZED_EVENT_TOPIC = '0x033884feaa2ca8a3d4414e2f3b49f102e4eeaf1b0baf49466e0407c4770de3e5'
21+
22+
/**
23+
* Fetches all NameTokenFractionalized events from the DomaFractionalization contract
24+
* to discover deployed launchpad and vesting wallet addresses
25+
*/
26+
async function fetchFractionalizedTokens() {
27+
const tokens = []
28+
let nextPageParams = null
29+
30+
do {
31+
let url = `${EXPLORER_API}/addresses/${DOMA_FRACTIONALIZATION}/logs`
32+
if (nextPageParams) {
33+
const params = new URLSearchParams(nextPageParams)
34+
url += `?${params.toString()}`
35+
}
36+
37+
const response = await get(url)
38+
39+
if (!response?.items) {
40+
throw new Error(`Invalid explorer response: ${JSON.stringify(response)}`)
41+
}
42+
43+
for (const log of response.items) {
44+
// Filter for NameTokenFractionalized events
45+
const topics = log.topics || []
46+
if (topics[0]?.toLowerCase() !== FRACTIONALIZED_EVENT_TOPIC.toLowerCase()) {
47+
continue
48+
}
49+
50+
// Extract addresses from decoded event data
51+
const decoded = log.decoded?.parameters
52+
if (!decoded) continue
53+
54+
const fractionalToken = decoded.find(p => p.name === 'fractionalTokenAddress')?.value
55+
const launchpad = decoded.find(p => p.name === 'launchpadAddress')?.value
56+
const vestingWallet = decoded.find(p => p.name === 'vestingWallet')?.value
57+
58+
if (fractionalToken && launchpad) {
59+
tokens.push({
60+
fractionalToken,
61+
launchpad,
62+
vestingWallet,
63+
})
64+
}
65+
}
66+
67+
nextPageParams = response.next_page_params
68+
} while (nextPageParams)
69+
70+
return tokens
71+
}
72+
73+
/**
74+
* Fetches UniswapV3 pools that hold USDC.e (for graduated tokens)
75+
* These are pools where fractionalized domain tokens trade against USDC.e
76+
*/
77+
async function fetchUniswapV3Pools() {
78+
const pools = []
79+
let nextPageParams = null
80+
81+
do {
82+
let url = `${EXPLORER_API}/tokens/${USDC_E_ADDRESS}/holders`
83+
if (nextPageParams) {
84+
const params = new URLSearchParams(nextPageParams)
85+
url += `?${params.toString()}`
86+
}
87+
88+
const response = await get(url)
89+
if (!response?.items) break
90+
91+
for (const holder of response.items) {
92+
const address = holder?.address
93+
if (!address?.is_contract || !address?.is_verified) continue
94+
95+
// Only include UniswapV3Pool contracts
96+
if (address.name === 'UniswapV3Pool') {
97+
pools.push(address.hash)
98+
}
99+
}
100+
101+
nextPageParams = response.next_page_params
102+
} while (nextPageParams)
103+
104+
return pools
105+
}
106+
107+
async function tvl(api) {
108+
// Get all fractionalized tokens (includes launchpads and vesting wallets)
109+
const fractionalizedTokens = await fetchFractionalizedTokens()
110+
111+
// Get UniswapV3 pools holding USDC.e (for graduated tokens)
112+
const uniV3Pools = await fetchUniswapV3Pools()
113+
114+
// Collect all protocol-owned addresses
115+
const protocolAddresses = new Set()
116+
117+
// Add main fractionalization contract
118+
protocolAddresses.add(DOMA_FRACTIONALIZATION)
119+
120+
// Add launchpads and vesting wallets from fractionalization events
121+
for (const token of fractionalizedTokens) {
122+
if (token.launchpad) protocolAddresses.add(token.launchpad)
123+
if (token.vestingWallet) protocolAddresses.add(token.vestingWallet)
124+
}
125+
126+
// Add UniswapV3 pools
127+
for (const pool of uniV3Pools) {
128+
protocolAddresses.add(pool)
129+
}
130+
131+
const addressList = Array.from(protocolAddresses)
132+
133+
console.log(`Found ${fractionalizedTokens.length} fractionalized tokens`)
134+
console.log(`Found ${uniV3Pools.length} UniswapV3 pools`)
135+
console.log(`Total protocol addresses: ${addressList.length}`)
136+
137+
if (addressList.length === 0) {
138+
console.warn('No protocol addresses found - TVL will be empty')
139+
return {}
140+
}
141+
142+
// Build token-owner pairs for on-chain balance queries
143+
const tokensAndOwners = addressList.map(owner => [USDC_E_ADDRESS, owner])
144+
145+
return sumTokens2({
146+
api,
147+
tokensAndOwners,
148+
resolveLP: false,
149+
})
150+
}
151+
152+
module.exports = {
153+
timetravel: false,
154+
misrepresentedTokens: true,
155+
methodology:
156+
'TVL is calculated by summing USDC.e balances held in Doma protocol contracts. ' +
157+
'Protocol addresses are discovered by querying NameTokenFractionalized events from the ' +
158+
'DomaFractionalization contract (0xd00000000004f450f1438cfA436587d8f8A55A29) to enumerate ' +
159+
'all deployed launchpads and vesting wallets. UniswapV3 pools holding USDC.e liquidity ' +
160+
'for graduated fractional tokens are also included. Balances are fetched via on-chain ' +
161+
'ERC-20 balanceOf() calls on the Doma network (Chain ID: 97477).',
162+
doma: { tvl },
163+
}

projects/helper/chains.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
"dfk",
112112
"dfs",
113113
"doge",
114+
"doma",
114115
"dogechain",
115116
"dsc",
116117
"duckchain",

projects/helper/tokenMapping.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ const fixBalancesTokens = {
6666
YLDS: { coingeckoId: 'usd-coin', decimals: 0 },
6767
'pm.sale.pool.3dxq3fk9llvhrqqwhodiap': { coingeckoId: 'usd-coin', decimals: 0 },
6868
},
69+
doma: {
70+
// USDC.e (Bridged USDC via Stargate) - Verified 2024-11-27 via explorer.doma.xyz/token/0x31EEf89D5215C305304a2fA5376a1f1b6C5dc477
71+
'0x31eef89d5215c305304a2fa5376a1f1b6c5dc477': { coingeckoId: 'usd-coin', decimals: 6 },
72+
},
6973
}
7074

7175
ibcChains.forEach(chain => fixBalancesTokens[chain] = { ...ibcMappings, ...(fixBalancesTokens[chain] || {}) })

0 commit comments

Comments
 (0)