@@ -173,9 +173,9 @@ function getTransactionCoinsGrouped(
173173 perpsBaseDenom ?: string ,
174174) {
175175 const transactionCoins : TransactionCoin [ ] = [ ]
176- // Event types that include coins are wasm, token_swapped, pool_joined, and message (for Duality swaps)
176+ // Event types that include coins are wasm, token_swapped, pool_joined, message (for Duality swaps), and TickUpdate (for MultihopSwap )
177177 // This should be streamlined by SC one day
178- const eventTypes = [ 'wasm' , 'token_swapped' , 'pool_joined' , 'message' ]
178+ const eventTypes = [ 'wasm' , 'token_swapped' , 'pool_joined' , 'message' , 'TickUpdate' ]
179179
180180 const coinRules = getRules ( )
181181
@@ -192,6 +192,63 @@ function getTransactionCoinsGrouped(
192192 return action === 'swap'
193193 } )
194194
195+ // Also collect MultihopSwap events (new pattern)
196+ const multihopSwapEvents = filteredEvents . filter ( ( event : TransactionEvent ) => {
197+ if ( ! Array . isArray ( event . attributes ) ) return false
198+ const action = event . attributes . find (
199+ ( a : TransactionEventAttribute ) => a . key === 'action' ,
200+ ) ?. value
201+ return action === 'MultihopSwap'
202+ } )
203+
204+ // Process MultihopSwap events by looking for WASM events with coin_in/denom_out
205+ if ( multihopSwapEvents . length > 0 ) {
206+ const wasmSwapEvents = filteredEvents . filter ( ( event : TransactionEvent ) => {
207+ if ( event . type !== 'wasm' ) return false
208+ if ( ! Array . isArray ( event . attributes ) ) return false
209+
210+ const hasCoinIn = event . attributes . some ( a => a . key === 'coin_in' )
211+ const hasDenomOut = event . attributes . some ( a => a . key === 'denom_out' )
212+
213+ return hasCoinIn && hasDenomOut
214+ } )
215+
216+ wasmSwapEvents . forEach ( ( event : TransactionEvent ) => {
217+ const coinInAttr = event . attributes . find ( a => a . key === 'coin_in' ) ?. value
218+ const denomOut = event . attributes . find ( a => a . key === 'denom_out' ) ?. value
219+
220+ if ( coinInAttr && denomOut ) {
221+ // Parse coin_in format: "amount+denom"
222+ const coinInMatch = coinInAttr . match ( / ^ ( \d + ) ( .+ ) $ / )
223+ if ( coinInMatch ) {
224+ const [ , amount , denom ] = coinInMatch
225+
226+ // Add input coin
227+ transactionCoins . push ( {
228+ type : 'swap' ,
229+ coin : BNCoin . fromDenomAndBigNumber ( denom , BN ( amount ) ) ,
230+ } )
231+
232+ // For output, we need to find the actual output amount
233+ // Look for SwapAmountOut in TickUpdate events
234+ const tickUpdateEvent = filteredEvents . find ( ( tickEvent : TransactionEvent ) => {
235+ if ( tickEvent . type !== 'TickUpdate' ) return false
236+ return tickEvent . attributes ?. some ( ( a : TransactionEventAttribute ) => a . key === 'SwapAmountOut' && parseInt ( a . value || '0' ) > 1000 )
237+ } )
238+
239+ const outputAmount = tickUpdateEvent ?. attributes ?. find ( ( a : TransactionEventAttribute ) => a . key === 'SwapAmountOut' ) ?. value
240+
241+ if ( outputAmount ) {
242+ transactionCoins . push ( {
243+ type : 'swap' ,
244+ coin : BNCoin . fromDenomAndBigNumber ( denomOut , BN ( outputAmount ) ) ,
245+ } )
246+ }
247+ }
248+ }
249+ } )
250+ }
251+
195252 // Process swap events to show complete multi-hop route
196253 if ( swapEvents . length > 1 ) {
197254 // For multi-hop swaps, show the complete route: input -> output -> input -> output -> etc.
0 commit comments