11import Decimal from "decimal.js"
22import { 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"
57import { timestampToDate } from "@/utils/date.helpers"
68import PriceHelper from "@/utils/price.helpers"
7- import { TokenPriceService } from "./token-price .service"
9+ import { toScaledUsd } from "./volume .service"
810import stringify from "safe-stable-stringify"
911
1012export 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}
0 commit comments