@@ -421,6 +421,21 @@ export const createOriginARMProcessors = ({
421421 }
422422 const calculateTotalYield = ( state : ArmState ) =>
423423 state . totalAssets - state . totalDeposits + state . totalWithdrawals
424+ // A base asset's rate in asset0 (liquidity) terms, 1e18-scaled (token0 per base).
425+ // Mirrors the assetRates logic: pegged base assets and the liquidity asset are 1:1;
426+ // appreciating assets use their adapter (post-upgrade) or getRate1 (pre-upgrade single base).
427+ const getBaseAssetRate = async ( block : Block , assetIdx : number ) : Promise < bigint > => {
428+ if ( assetIdx === 0 || armEntity . assetPegged [ assetIdx ] ) return 10n ** 18n
429+ const upgraded = armEntity . upgradeBlock != null && block . header . height >= armEntity . upgradeBlock
430+ if ( upgraded ) {
431+ return new originMultibaseArmAbi . Contract (
432+ ctx ,
433+ block . header ,
434+ armEntity . assetAdapters [ assetIdx ] ,
435+ ) . convertToAssets ( 10n ** 18n )
436+ }
437+ return getRate1 ? await getRate1 ( ctx , block ) : 10n ** 18n
438+ }
424439 const checkpoint = (
425440 account : string ,
426441 block : Block ,
@@ -607,66 +622,104 @@ export const createOriginARMProcessors = ({
607622 const transfers0 = transfers
608623 . filter ( ( log ) => log . address === armEntity . token0 )
609624 . map ( ( log ) => erc20Abi . events . Transfer . decode ( log ) )
610- const transfers1 = transfers
611- . filter ( ( log ) => log . address === armEntity . token1 )
612- . map ( ( log ) => erc20Abi . events . Transfer . decode ( log ) )
613625
614- const pairs : { assets0 : bigint ; assets1 : bigint } [ ] = [ ]
626+ const ONE = 10n ** 18n
627+ const swapMeta = {
628+ chainId : ctx . chain . id ,
629+ txHash : transactionHash ,
630+ txFrom : trace . transaction ?. from ?? '' ,
631+ txTo : trace . transaction ?. to ?? '' ,
632+ timestamp : new Date ( block . header . timestamp ) ,
633+ blockNumber : block . header . height ,
634+ address : armAddress ,
635+ from : trace . action . from ,
636+ }
615637
616- const transfersOut0 = transfers0 . filter ( ( t ) => t . from . toLowerCase ( ) === armAddress )
617- const transfersIn1 = transfers1 . filter ( ( t ) => t . to . toLowerCase ( ) === armAddress )
638+ // Every swap is liquidityAsset(token0) <-> one base asset (the contract forbids
639+ // base<->base). Pair token0 transfers against each base asset and emit one ArmSwap
640+ // per (tx, baseAsset, direction) with raw amounts and each side's asset0 rate.
641+ for ( let assetIdx = 1 ; assetIdx < armEntity . assets . length ; assetIdx ++ ) {
642+ const baseAsset = armEntity . assets [ assetIdx ]
643+ const transfersB = transfers
644+ . filter ( ( log ) => log . address === baseAsset )
645+ . map ( ( log ) => erc20Abi . events . Transfer . decode ( log ) )
646+ if ( transfersB . length === 0 ) continue
618647
619- const rate1 = getRate1 ? await getRate1 ( ctx , block ) : 10n ** 18n
620- const rate1Number = + formatEther ( rate1 )
648+ const rateB = await getBaseAssetRate ( block , assetIdx ) // token0 per base
649+ const rateBNumber = + formatEther ( rateB )
621650
622- for ( let i = 0 ; i < transfersOut0 . length ; i ++ ) {
623- for ( let j = 0 ; j < transfersIn1 . length ; j ++ ) {
624- const out0 = transfersOut0 [ i ]
625- const in1 = transfersIn1 [ j ]
626- if ( out0 . value === 0n || in1 . value === 0n ) continue
627- const rate = + formatEther ( ( out0 . value * 10n ** 18n ) / in1 . value )
628- if ( Math . abs ( rate - rate1Number ) <= 0.01 ) {
629- pairs . push ( { assets0 : - out0 . value , assets1 : ( in1 . value * rate1 ) / 10n ** 18n } )
630- transfersIn1 . splice ( j , 1 )
631- break
651+ // Trader sells base for token0: ARM receives base, sends token0.
652+ const transfersOut0 = transfers0 . filter ( ( t ) => t . from . toLowerCase ( ) === armAddress )
653+ const transfersInB = transfersB . filter ( ( t ) => t . to . toLowerCase ( ) === armAddress )
654+ let sellBaseIn = 0n
655+ let sellToken0Out = 0n
656+ for ( let i = 0 ; i < transfersOut0 . length ; i ++ ) {
657+ for ( let j = 0 ; j < transfersInB . length ; j ++ ) {
658+ const out0 = transfersOut0 [ i ]
659+ const inB = transfersInB [ j ]
660+ if ( out0 . value === 0n || inB . value === 0n ) continue
661+ const rate = + formatEther ( ( out0 . value * ONE ) / inB . value ) // token0 per base
662+ if ( Math . abs ( rate - rateBNumber ) <= 0.01 ) {
663+ sellBaseIn += inB . value
664+ sellToken0Out += out0 . value
665+ transfersInB . splice ( j , 1 )
666+ break
667+ }
632668 }
633669 }
634- }
670+ if ( sellBaseIn > 0n ) {
671+ swaps . push (
672+ new ArmSwap ( {
673+ ...swapMeta ,
674+ id : `${ ctx . chain . id } ::${ transactionHash } :${ baseAsset } :sell` ,
675+ tokenIn : baseAsset ,
676+ amountIn : sellBaseIn ,
677+ rateIn : rateB ,
678+ tokenOut : armEntity . token0 ,
679+ amountOut : sellToken0Out ,
680+ rateOut : ONE ,
681+ assets0 : - sellToken0Out ,
682+ assets1 : ( sellBaseIn * rateB ) / ONE ,
683+ } ) ,
684+ )
685+ }
635686
636- const transfersOut1 = transfers1 . filter ( ( t ) => t . from . toLowerCase ( ) === armAddress )
637- const transfersIn0 = transfers0 . filter ( ( t ) => t . to . toLowerCase ( ) === armAddress )
638- for ( let i = 0 ; i < transfersOut1 . length ; i ++ ) {
639- for ( let j = 0 ; j < transfersIn0 . length ; j ++ ) {
640- const out1 = transfersOut1 [ i ]
641- const in0 = transfersIn0 [ j ]
642- if ( out1 . value === 0n || in0 . value === 0n ) continue
643- const rate = + formatEther ( ( out1 . value * 10n ** 18n ) / in0 . value )
644- if ( Math . abs ( rate - rate1Number ) <= 0.01 ) {
645- pairs . push ( { assets0 : in0 . value , assets1 : ( - out1 . value * rate1 ) / 10n ** 18n } )
646- transfersIn0 . splice ( j , 1 )
647- break
687+ // Trader buys base with token0: ARM receives token0, sends base.
688+ const transfersOutB = transfersB . filter ( ( t ) => t . from . toLowerCase ( ) === armAddress )
689+ const transfersIn0 = transfers0 . filter ( ( t ) => t . to . toLowerCase ( ) === armAddress )
690+ let buyBaseOut = 0n
691+ let buyToken0In = 0n
692+ for ( let i = 0 ; i < transfersOutB . length ; i ++ ) {
693+ for ( let j = 0 ; j < transfersIn0 . length ; j ++ ) {
694+ const outB = transfersOutB [ i ]
695+ const in0 = transfersIn0 [ j ]
696+ if ( outB . value === 0n || in0 . value === 0n ) continue
697+ const rate = + formatEther ( ( in0 . value * ONE ) / outB . value ) // token0 per base
698+ if ( Math . abs ( rate - rateBNumber ) <= 0.01 ) {
699+ buyBaseOut += outB . value
700+ buyToken0In += in0 . value
701+ transfersIn0 . splice ( j , 1 )
702+ break
703+ }
648704 }
649705 }
706+ if ( buyBaseOut > 0n ) {
707+ swaps . push (
708+ new ArmSwap ( {
709+ ...swapMeta ,
710+ id : `${ ctx . chain . id } ::${ transactionHash } :${ baseAsset } :buy` ,
711+ tokenIn : armEntity . token0 ,
712+ amountIn : buyToken0In ,
713+ rateIn : ONE ,
714+ tokenOut : baseAsset ,
715+ amountOut : buyBaseOut ,
716+ rateOut : rateB ,
717+ assets0 : buyToken0In ,
718+ assets1 : - ( buyBaseOut * rateB ) / ONE ,
719+ } ) ,
720+ )
721+ }
650722 }
651-
652- const assets0 = pairs . reduce ( ( acc , pair ) => acc + pair . assets0 , 0n )
653- const assets1 = pairs . reduce ( ( acc , pair ) => acc + pair . assets1 , 0n )
654-
655- swaps . push (
656- new ArmSwap ( {
657- id : `${ ctx . chain . id } ::${ transactionHash } :${ trace . traceAddress . join ( ':' ) } ` ,
658- chainId : ctx . chain . id ,
659- txHash : transactionHash ,
660- txFrom : trace . transaction ?. from ?? '' ,
661- txTo : trace . transaction ?. to ?? '' ,
662- timestamp : new Date ( block . header . timestamp ) ,
663- blockNumber : block . header . height ,
664- address : armAddress ,
665- from : trace . action . from ,
666- assets0,
667- assets1,
668- } ) ,
669- )
670723 }
671724 }
672725 }
0 commit comments