Skip to content

Commit c446947

Browse files
authored
[indexer]: add chain field to DustCollected/DustSwept entities (#972)
1 parent 48acb78 commit c446947

6 files changed

Lines changed: 158 additions & 23 deletions

File tree

sdk/packages/indexer/src/configs/schema.graphql

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,12 +1719,17 @@ type UserActivityV2 @entity {
17191719
"""
17201720
Represents dust collected by the protocol
17211721
"""
1722-
type DustCollected @entity {
1722+
type ProtocolDustCollected @entity {
17231723
"""
1724-
Unique identifier: chainId-tokenAddress
1724+
Unique identifier: chain-tokenAddress
17251725
"""
17261726
id: ID!
17271727

1728+
"""
1729+
Host state machine that emitted the event
1730+
"""
1731+
chain: String! @index
1732+
17281733
"""
17291734
Token symbol
17301735
"""
@@ -1744,12 +1749,17 @@ type DustCollected @entity {
17441749
"""
17451750
Represents dust swept by the protocol
17461751
"""
1747-
type DustSwept @entity {
1752+
type ProtocolDustSwept @entity {
17481753
"""
1749-
Unique identifier: chainId-tokenAddress
1754+
Unique identifier: chain-tokenAddress
17501755
"""
17511756
id: ID!
17521757

1758+
"""
1759+
Host state machine that emitted the event
1760+
"""
1761+
chain: String! @index
1762+
17531763
"""
17541764
Token symbol
17551765
"""
@@ -1766,6 +1776,56 @@ type DustSwept @entity {
17661776
lastUpdated: Date! @index
17671777
}
17681778

1779+
"""
1780+
Cumulative dust collected per chain, denominated in USD
1781+
"""
1782+
type CumulativeDustCollectedPerChain @entity {
1783+
"""
1784+
Unique identifier: chain
1785+
"""
1786+
id: ID!
1787+
1788+
"""
1789+
Host state machine
1790+
"""
1791+
chain: String! @index
1792+
1793+
"""
1794+
Cumulative dust collected in USD, scaled by 1e18 (18-decimal fixed-point integer)
1795+
"""
1796+
amountUSD: BigInt!
1797+
1798+
"""
1799+
Last updated at
1800+
"""
1801+
lastUpdatedAt: BigInt!
1802+
}
1803+
1804+
"""
1805+
Cumulative dust swept per chain, denominated in USD
1806+
"""
1807+
type CumulativeDustSweptPerChain @entity {
1808+
"""
1809+
Unique identifier: chain
1810+
"""
1811+
id: ID!
1812+
1813+
"""
1814+
Host state machine
1815+
"""
1816+
chain: String! @index
1817+
1818+
"""
1819+
Cumulative dust swept in USD, scaled by 1e18 (18-decimal fixed-point integer)
1820+
"""
1821+
amountUSD: BigInt!
1822+
1823+
"""
1824+
Last updated at
1825+
"""
1826+
lastUpdatedAt: BigInt!
1827+
}
1828+
17691829
"""
17701830
Collator rewards indexed from treasury transfers to block authors
17711831
"""

sdk/packages/indexer/src/handlers/events/intentGatewayV3/dustCollected.event.handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ export const handleDustCollectedEventV3 = wrap(async (event: DustCollectedLog):
2424
})}`,
2525
)
2626

27-
await ProtocolRevenueService.recordDustCollected(token, BigInt(amount.toString()), timestamp)
27+
await ProtocolRevenueService.recordDustCollected(chain, token, BigInt(amount.toString()), timestamp)
2828
})

sdk/packages/indexer/src/handlers/events/intentGatewayV3/dustSwept.event.handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ export const handleDustSweptEventV3 = wrap(async (event: DustSweptLog): Promise<
2525
})}`,
2626
)
2727

28-
await ProtocolRevenueService.recordDustSwept(token, BigInt(amount.toString()), timestamp)
28+
await ProtocolRevenueService.recordDustSwept(chain, token, BigInt(amount.toString()), timestamp)
2929
})

sdk/packages/indexer/src/services/protocol-revenue.service.ts

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
11
import Decimal from "decimal.js"
22
import { ERC6160Ext20Abi__factory } from "@/configs/src/types/contracts"
3-
import { DustCollected } from "@/configs/src/types/models/DustCollected"
4-
import { DustSwept } from "@/configs/src/types/models/DustSwept"
3+
import { ProtocolDustCollected } from "@/configs/src/types/models/ProtocolDustCollected"
4+
import { ProtocolDustSwept } from "@/configs/src/types/models/ProtocolDustSwept"
5+
import { CumulativeDustCollectedPerChain } from "@/configs/src/types/models/CumulativeDustCollectedPerChain"
6+
import { CumulativeDustSweptPerChain } from "@/configs/src/types/models/CumulativeDustSweptPerChain"
57
import { timestampToDate } from "@/utils/date.helpers"
68
import PriceHelper from "@/utils/price.helpers"
7-
import { TokenPriceService } from "./token-price.service"
9+
import { toScaledUsd } from "./volume.service"
810
import stringify from "safe-stable-stringify"
911

1012
export class ProtocolRevenueService {
1113
/**
1214
* Get or create a DustCollected record
1315
*/
14-
static async recordDustCollected(tokenAddress: string, amount: bigint, timestamp: bigint): Promise<DustCollected> {
15-
const id = `${chainId}-${tokenAddress.toLowerCase()}`
16+
static async recordDustCollected(
17+
chain: string,
18+
tokenAddress: string,
19+
amount: bigint,
20+
timestamp: bigint,
21+
): Promise<ProtocolDustCollected> {
22+
const id = `${chain}-${tokenAddress.toLowerCase()}`
1623
let symbol = "eth"
24+
let decimals = 18
1725

18-
// Get token symbol if not native token
26+
// Get token symbol and decimals if not native token
1927
if (tokenAddress.toLowerCase() !== "0x0000000000000000000000000000000000000000") {
2028
try {
2129
const tokenContract = ERC6160Ext20Abi__factory.connect(tokenAddress, api)
2230
symbol = await tokenContract.symbol()
31+
decimals = await tokenContract.decimals()
2332
} catch (error) {
2433
logger.warn(
2534
`Failed to get symbol for token ${tokenAddress}: ${stringify({
@@ -30,11 +39,12 @@ export class ProtocolRevenueService {
3039
}
3140
}
3241

33-
let dustCollected = await DustCollected.get(id)
42+
let dustCollected = await ProtocolDustCollected.get(id)
3443

3544
if (!dustCollected) {
36-
dustCollected = await DustCollected.create({
45+
dustCollected = await ProtocolDustCollected.create({
3746
id,
47+
chain,
3848
tokenSymbol: symbol,
3949
amount,
4050
lastUpdated: timestampToDate(timestamp),
@@ -46,6 +56,23 @@ export class ProtocolRevenueService {
4656

4757
await dustCollected.save()
4858

59+
const usdDelta = await this.computeDustUsdDelta(chain, tokenAddress, amount, decimals)
60+
if (usdDelta && usdDelta > 0n) {
61+
let cumulative = await CumulativeDustCollectedPerChain.get(chain)
62+
if (!cumulative) {
63+
cumulative = CumulativeDustCollectedPerChain.create({
64+
id: chain,
65+
chain,
66+
amountUSD: usdDelta,
67+
lastUpdatedAt: timestamp,
68+
})
69+
} else {
70+
cumulative.amountUSD = cumulative.amountUSD + usdDelta
71+
cumulative.lastUpdatedAt = timestamp
72+
}
73+
await cumulative.save()
74+
}
75+
4976
logger.info(
5077
`DustCollected recorded: ${stringify({
5178
id,
@@ -60,15 +87,22 @@ export class ProtocolRevenueService {
6087
/**
6188
* Get or create a DustSwept record
6289
*/
63-
static async recordDustSwept(tokenAddress: string, amount: bigint, timestamp: bigint): Promise<DustSwept> {
64-
const id = `${chainId}-${tokenAddress.toLowerCase()}`
90+
static async recordDustSwept(
91+
chain: string,
92+
tokenAddress: string,
93+
amount: bigint,
94+
timestamp: bigint,
95+
): Promise<ProtocolDustSwept> {
96+
const id = `${chain}-${tokenAddress.toLowerCase()}`
6597
let symbol = "eth"
98+
let decimals = 18
6699

67-
// Get token symbol if not native token
100+
// Get token symbol and decimals if not native token
68101
if (tokenAddress.toLowerCase() !== "0x0000000000000000000000000000000000000000") {
69102
try {
70103
const tokenContract = ERC6160Ext20Abi__factory.connect(tokenAddress, api)
71104
symbol = await tokenContract.symbol()
105+
decimals = await tokenContract.decimals()
72106
} catch (error) {
73107
logger.warn(
74108
`Failed to get symbol for token ${tokenAddress}: ${stringify({
@@ -79,11 +113,12 @@ export class ProtocolRevenueService {
79113
}
80114
}
81115

82-
let dustSwept = await DustSwept.get(id)
116+
let dustSwept = await ProtocolDustSwept.get(id)
83117

84118
if (!dustSwept) {
85-
dustSwept = await DustSwept.create({
119+
dustSwept = await ProtocolDustSwept.create({
86120
id,
121+
chain,
87122
tokenSymbol: symbol,
88123
amount,
89124
lastUpdated: timestampToDate(timestamp),
@@ -95,6 +130,23 @@ export class ProtocolRevenueService {
95130

96131
await dustSwept.save()
97132

133+
const usdDelta = await this.computeDustUsdDelta(chain, tokenAddress, amount, decimals)
134+
if (usdDelta && usdDelta > 0n) {
135+
let cumulative = await CumulativeDustSweptPerChain.get(chain)
136+
if (!cumulative) {
137+
cumulative = CumulativeDustSweptPerChain.create({
138+
id: chain,
139+
chain,
140+
amountUSD: usdDelta,
141+
lastUpdatedAt: timestamp,
142+
})
143+
} else {
144+
cumulative.amountUSD = cumulative.amountUSD + usdDelta
145+
cumulative.lastUpdatedAt = timestamp
146+
}
147+
await cumulative.save()
148+
}
149+
98150
logger.info(
99151
`DustSwept recorded: ${stringify({
100152
id,
@@ -105,4 +157,26 @@ export class ProtocolRevenueService {
105157

106158
return dustSwept
107159
}
160+
161+
/**
162+
* Convert a newly-collected/swept token amount to a scaled-1e18 USD bigint using the
163+
* on-chain DEX price. Returns null when no price is available, in which case the caller
164+
* skips the USD rollup; the raw amount is still retained on the per-token entity.
165+
*/
166+
private static async computeDustUsdDelta(
167+
chain: string,
168+
tokenAddress: string,
169+
amount: bigint,
170+
decimals: number,
171+
): Promise<bigint | null> {
172+
const { amountValueInUSD } = await PriceHelper.getTokenPriceInUSDUniswap(tokenAddress, amount, decimals)
173+
if (!amountValueInUSD || new Decimal(amountValueInUSD).isZero()) {
174+
logger.warn(
175+
`[ProtocolRevenueService] No DEX price for ${tokenAddress} on ${chain}; skipping USD rollup, raw amount retained`,
176+
)
177+
return null
178+
}
179+
180+
return toScaledUsd(amountValueInUSD)
181+
}
108182
}

sdk/packages/indexer/src/services/volume.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const USD_SCALE = 18
99
const USD_SCALE_FACTOR = new Decimal(10).pow(USD_SCALE)
1010

1111
/** Convert a decimal-string USD value (e.g. "1.5") to a scaled BigInt (e.g. 1_500_000_000_000_000_000n). */
12-
function toScaledUsd(volumeUSD: string): bigint {
12+
export function toScaledUsd(volumeUSD: string): bigint {
1313
return BigInt(new Decimal(volumeUSD).mul(USD_SCALE_FACTOR).toFixed(0))
1414
}
1515

sdk/packages/indexer/src/utils/price.helpers.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ENV_CONFIG, ITokenPriceFeedDetails } from "@/constants"
88
import { ChainLinkAggregatorV3Abi__factory } from "@/configs/src/types/contracts"
99
import { ethers } from "ethers"
1010
import { UNISWAP_ADDRESSES } from "@/addresses/uniswap.addresses"
11+
import { getHostStateMachine } from "@/utils/substrate.helpers"
1112
import uniswapV2Abi from "@/configs/abis/UniswapV2.abi.json"
1213
import uniswapV3FactoryAbi from "@/configs/abis/UniswapV3Factory.abi.json"
1314
import uniswapV3PoolAbi from "@/configs/abis/UniswapV3Pool.abi.json"
@@ -113,7 +114,7 @@ export default class PriceHelper {
113114

114115
let priceInUSD: string
115116
if (isNativeToken) {
116-
const nativePrice = await this.getNativeCurrencyPrice(chainId)
117+
const nativePrice = await this.getNativeCurrencyPrice(getHostStateMachine(chainId))
117118
priceInUSD = new Decimal(nativePrice.toString()).dividedBy(new Decimal(10).pow(18)).toFixed(18)
118119
} else {
119120
const uniswapPrice = await this.getUniswapPrice(tokenAddress, decimals)
@@ -187,7 +188,7 @@ export default class PriceHelper {
187188

188189
if (liquidity > BigInt(0)) {
189190
const quoter = new ethers.Contract(V3_QUOTER, uniswapV3QuoterV2Abi, api)
190-
const quoteResult = await quoter.quoteExactInputSingle({
191+
const quoteResult = await quoter.callStatic.quoteExactInputSingle({
191192
tokenIn: tokenAddress,
192193
tokenOut: quoteToken,
193194
fee: fee,
@@ -306,7 +307,7 @@ export default class PriceHelper {
306307
throw new Error(`No Uniswap V2, V3, or V4 pair found for token ${tokenAddress}`)
307308
} catch (error) {
308309
logger.error(`Error getting Uniswap price for ${tokenAddress}: ${error}`)
309-
return new Decimal(1)
310+
return new Decimal(0)
310311
}
311312
}
312313

0 commit comments

Comments
 (0)