@@ -55,6 +55,156 @@ export const formatTvlsByChain = ({ historicalChainTvls, extraTvlsEnabled }) =>
5555 return result
5656}
5757
58+ function buildInflows ( { chainTvls, extraTvlsEnabled, tokensUnique, datesToDelete } ) {
59+ const usdInflows : Record < string , number > = { }
60+ const tokenInflows : Record < string , any > = { }
61+ const tokensUniqueSet = new Set ( tokensUnique )
62+
63+ let zeroUsdInfows = 0
64+ let zeroTokenInfows = 0
65+
66+ for ( const section in chainTvls ) {
67+ const name = section . toLowerCase ( )
68+
69+ // skip sum of keys like ethereum-staking, arbitrum-vesting
70+ if ( name . includes ( '-' ) ) continue
71+
72+ const isEnabled = name in extraTvlsEnabled ? extraTvlsEnabled [ name ] : true
73+ if ( ! isEnabled ) continue
74+
75+ // Index per-date maps
76+ const tokensInUsdByDate : Record < string , Record < string , number > > = { }
77+ const tokensByDate : Record < string , Record < string , number > > = { }
78+ const dateSet = new Set < string > ( )
79+
80+ for ( const { date, tokens } of chainTvls [ section ] ?. tokensInUsd ?? [ ] ) {
81+ tokensInUsdByDate [ date ] = tokens
82+ dateSet . add ( String ( date ) )
83+ }
84+ for ( const { date, tokens } of chainTvls [ section ] ?. tokens ?? [ ] ) {
85+ tokensByDate [ date ] = tokens
86+ dateSet . add ( String ( date ) )
87+ }
88+
89+ const dates : string [ ] = Array . from ( dateSet ) . sort ( ( a , b ) => Number ( a ) - Number ( b ) )
90+
91+ for ( let i = 1 ; i < dates . length ; i ++ ) {
92+ const currentDate = dates [ i ]
93+ const prevDate = dates [ i - 1 ]
94+
95+ const currentTokens = tokensByDate [ currentDate ] || { }
96+ const oldTokens = tokensByDate [ prevDate ] || { }
97+ const currentUsdTokens = tokensInUsdByDate [ currentDate ] || { }
98+ const oldUsdTokens = tokensInUsdByDate [ prevDate ] || { }
99+
100+ // Build price map using larger totalUSD preference
101+ const priceMap : Record < string , { value : number ; totalUSD : number } > = { }
102+ for ( const token in currentUsdTokens ) {
103+ const amount = currentTokens [ token ]
104+ const usd = currentUsdTokens [ token ]
105+ if ( amount && amount > 0 ) {
106+ priceMap [ token ] = { value : usd / amount , totalUSD : usd }
107+ }
108+ }
109+ for ( const token in oldUsdTokens ) {
110+ const amount = oldTokens [ token ]
111+ const usd = oldUsdTokens [ token ]
112+ if ( amount && amount > 0 ) {
113+ if ( ! priceMap [ token ] || priceMap [ token ] . totalUSD < usd ) {
114+ priceMap [ token ] = { value : usd / amount , totalUSD : usd }
115+ }
116+ }
117+ }
118+
119+ let dayDifference = 0
120+ let tokenDayDifference : Record < string , number > = { }
121+
122+ // Iterate all tokens that changed
123+ const allTokens = new Set ( [ ...Object . keys ( currentTokens ) , ...Object . keys ( oldTokens ) ] )
124+
125+ for ( const token of allTokens ) {
126+ const currentAmount = currentTokens [ token ] || 0
127+ const prevAmount = oldTokens [ token ] || 0
128+ const diff = currentAmount - prevAmount
129+ if ( diff === 0 ) continue
130+
131+ let priceInfo = priceMap [ token ]
132+ if ( ! priceInfo ) {
133+ // Fallback price from whichever side has info
134+ if ( currentAmount > 0 && currentUsdTokens [ token ] != null ) {
135+ priceInfo = { value : currentUsdTokens [ token ] / currentAmount , totalUSD : currentUsdTokens [ token ] }
136+ } else if ( prevAmount > 0 && oldUsdTokens [ token ] != null ) {
137+ priceInfo = { value : oldUsdTokens [ token ] / prevAmount , totalUSD : oldUsdTokens [ token ] }
138+ }
139+ }
140+
141+ if ( ! priceInfo || ! isFinite ( priceInfo . value ) ) continue
142+
143+ const diffUsd = diff * priceInfo . value
144+ // Ignore outliers similar to computeInflowsData
145+ if ( Math . abs ( diffUsd ) > 2 * ( priceInfo . totalUSD || 0 ) ) continue
146+
147+ dayDifference += diffUsd
148+
149+ // Track token inflows only for tokens in tokensUnique
150+ if ( tokensUniqueSet . has ( token ) ) {
151+ tokenDayDifference [ token ] = ( tokenDayDifference [ token ] || 0 ) + diffUsd
152+ }
153+ }
154+
155+ if ( dayDifference === 0 ) {
156+ zeroUsdInfows ++
157+ }
158+
159+ let hasTokenDifference = false
160+ for ( const _ in tokenDayDifference ) {
161+ hasTokenDifference = true
162+ break
163+ }
164+ if ( ! hasTokenDifference ) {
165+ zeroTokenInfows ++
166+ }
167+
168+ usdInflows [ currentDate ] = ( usdInflows [ currentDate ] || 0 ) + dayDifference
169+
170+ if ( ! tokenInflows [ currentDate ] ) {
171+ tokenInflows [ currentDate ] = { date : Number ( currentDate ) }
172+ }
173+ // Merge existing values accumulated from other chains before writing
174+ for ( const token in tokenInflows [ currentDate ] ) {
175+ if ( token !== 'date' ) {
176+ tokenDayDifference [ token ] = ( tokenDayDifference [ token ] || 0 ) + tokenInflows [ currentDate ] [ token ]
177+ }
178+ }
179+ for ( const token in tokenDayDifference ) {
180+ tokenInflows [ currentDate ] [ token ] = tokenDayDifference [ token ]
181+ }
182+ }
183+ }
184+
185+ for ( const date of datesToDelete ) {
186+ delete usdInflows [ date ]
187+ delete tokenInflows [ date ]
188+ }
189+
190+ const usdFlows : Array < [ string , number ] > = [ ]
191+ for ( const date in usdInflows ) {
192+ usdFlows . push ( [ date , usdInflows [ date ] ] )
193+ }
194+ usdFlows . sort ( ( a , b ) => Number ( a [ 0 ] ) - Number ( b [ 0 ] ) )
195+
196+ const tokenFlows = [ ]
197+ for ( const date in tokenInflows ) {
198+ tokenFlows . push ( tokenInflows [ date ] )
199+ }
200+ tokenFlows . sort ( ( a , b ) => a . date - b . date )
201+
202+ return {
203+ usdInflows : ( zeroUsdInfows === usdFlows . length ? null : usdFlows ) as Array < [ string , number ] > | null ,
204+ tokenInflows : zeroTokenInfows === tokenFlows . length ? null : tokenFlows
205+ }
206+ }
207+
58208// build unique tokens based on top 10 tokens in usd value on each day
59209// also includes tokens with significant flows (outflows/inflows > $100M)
60210function getUniqueTokens ( { chainTvls, extraTvlsEnabled } ) {
@@ -219,127 +369,6 @@ function getUniqueTokens({ chainTvls, extraTvlsEnabled }) {
219369 return Array . from ( tokenSet )
220370}
221371
222- function buildInflows ( { chainTvls, extraTvlsEnabled, tokensUnique, datesToDelete } ) {
223- const usdInflows = { }
224- const tokenInflows = { }
225-
226- const tokensUniqueSet = new Set ( tokensUnique )
227-
228- let zeroUsdInfows = 0
229- let zeroTokenInfows = 0
230-
231- for ( const section in chainTvls ) {
232- const name = section . toLowerCase ( )
233-
234- // skip sum of keys like ethereum-staking, arbitrum-vesting
235- if ( ! name . includes ( '-' ) ) {
236- // sum key with staking, ethereum, arbitrum etc
237- const isEnabled = name in extraTvlsEnabled ? extraTvlsEnabled [ name ] : true
238- if ( isEnabled ) {
239- const tokensInUsd : Record < string , Record < string , number > > = { }
240- const tokensData : Record < string , Record < string , number > > = { }
241-
242- const tokensInUsdArray = chainTvls [ section ] ?. tokensInUsd ?? [ ]
243- for ( const { date, tokens } of tokensInUsdArray ) {
244- tokensInUsd [ date ] = tokens
245- }
246-
247- const tokensArray = chainTvls [ section ] ?. tokens ?? [ ]
248- for ( const { date, tokens } of tokensArray ) {
249- tokensData [ date ] = tokens
250- }
251-
252- const tokens = tokensData
253-
254- let prevDate = null
255-
256- for ( const date in tokensInUsd ) {
257- let dayDifference = 0
258- let tokenDayDifference = { }
259-
260- for ( const token in tokensInUsd [ date ] ) {
261- const price = tokens [ date ] ?. [ token ]
262- ? Number ( ( tokensInUsd [ date ] [ token ] / tokens [ date ] [ token ] ) . toFixed ( 4 ) )
263- : null
264-
265- const diff =
266- tokens [ date ] ?. [ token ] && prevDate && tokens [ prevDate ] ?. [ token ]
267- ? tokens [ date ] [ token ] - tokens [ prevDate ] [ token ]
268- : null
269-
270- const diffUsd = price && diff ? price * diff : null
271-
272- if ( diffUsd && ! Number . isNaN ( diffUsd ) && isFinite ( price ) ) {
273- // Show only top 10 inflow tokens of the day, add remaining inlfows under "Others" category
274- if ( tokensUniqueSet . has ( token ) ) {
275- tokenDayDifference [ token ] = ( tokenDayDifference [ token ] || 0 ) + diffUsd
276- } else {
277- tokenDayDifference [ 'Others' ] = ( tokenDayDifference [ 'Others' ] || 0 ) + diffUsd
278- }
279-
280- dayDifference += diffUsd
281- }
282- }
283-
284- if ( dayDifference === 0 ) {
285- zeroUsdInfows ++
286- }
287-
288- let hasTokenDifference = false
289- // eslint-disable-next-line @typescript-eslint/no-unused-vars
290- for ( const _ in tokenDayDifference ) {
291- hasTokenDifference = true
292- break
293- }
294- if ( ! hasTokenDifference ) {
295- zeroTokenInfows ++
296- }
297-
298- usdInflows [ date ] = ( usdInflows [ date ] || 0 ) + dayDifference
299-
300- if ( ! tokenInflows [ date ] ) {
301- tokenInflows [ date ] = { date }
302- }
303-
304- for ( const token in tokenInflows [ date ] ) {
305- if ( token !== 'date' ) {
306- tokenDayDifference [ token ] = ( tokenDayDifference [ token ] || 0 ) + tokenInflows [ date ] [ token ]
307- }
308- }
309-
310- for ( const token in tokenDayDifference ) {
311- tokenInflows [ date ] [ token ] = tokenDayDifference [ token ]
312- }
313-
314- prevDate = date
315- }
316- }
317- }
318- }
319-
320- for ( const date of datesToDelete ) {
321- delete usdInflows [ date ]
322- delete tokenInflows [ date ]
323- }
324-
325- const usdFlows : Array < [ string , number ] > = [ ]
326- for ( const date in usdInflows ) {
327- usdFlows . push ( [ date , usdInflows [ date ] ] )
328- }
329- usdFlows . sort ( ( a , b ) => Number ( a [ 0 ] ) - Number ( b [ 0 ] ) )
330-
331- const tokenFlows = [ ]
332- for ( const date in tokenInflows ) {
333- tokenFlows . push ( tokenInflows [ date ] )
334- }
335- tokenFlows . sort ( ( a , b ) => a . date - b . date )
336-
337- return {
338- usdInflows : ( zeroUsdInfows === usdFlows . length ? null : usdFlows ) as Array < [ string , number ] > | null ,
339- tokenInflows : zeroTokenInfows === tokenFlows . length ? null : tokenFlows
340- }
341- }
342-
343372function storeTokensBreakdown ( { date, tokens, tokensUnique, directory } ) {
344373 const tokensOfTheDay = { }
345374 // filters tokens that have no name or their value is near zero
0 commit comments