@@ -16,7 +16,14 @@ import { arbitrum, base, blast, bsc, linea, mainnet, optimism, polygon, scroll,
1616import { monad , plasma } from 'components/Web3Provider'
1717import { NETWORKS_INFO } from 'hooks/useChainsConfig'
1818
19- import { AcrossClient , createAcrossClient } from '@across-protocol/app-sdk'
19+ import {
20+ AcrossClient ,
21+ createAcrossClient ,
22+ parseDepositLogs ,
23+ parseFillLogs ,
24+ waitForDepositTx ,
25+ waitForFillTx ,
26+ } from '@across-protocol/app-sdk'
2027import { Quote } from '../registry'
2128import {
2229 BaseSwapAdapter ,
@@ -58,6 +65,22 @@ const chainIdToSpokePoolPeriphery: Record<number, Address> = {
5865 [ ChainId . BLAST ] : '0x924a9f036260DdD5808007E1AA95f08eD08aA569' ,
5966}
6067
68+ // Chain ID to SpokePool address mapping (Across protocol)
69+ // These are the official Across SpokePool contract addresses for destination chains
70+ const chainIdToSpokePool : Record < number , Address > = {
71+ [ ChainId . MAINNET ] : '0x5c7BCd6E7De5423a257D81B442095A1a6ced35C5' ,
72+ [ ChainId . ARBITRUM ] : '0xe35e9842fceaCA96570B734083f4a58e8F7C5f2A' ,
73+ [ ChainId . OPTIMISM ] : '0x6f26Bf09B1C792e3228e5467807a900A503c0281' ,
74+ [ ChainId . MATIC ] : '0x9295ee1d8C5b022Be115A2AD3c30C72E34e7F096' ,
75+ [ ChainId . BASE ] : '0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64' ,
76+ [ ChainId . LINEA ] : '0x7E63A5f1a8F0B4d0934B2f2327DAED3F6bb2ee75' ,
77+ [ ChainId . ZKSYNC ] : '0xE0B015E54d54fc84a6cB9B666099c46adE9335FF' ,
78+ [ ChainId . SCROLL ] : '0x3baD7AD0728f9917d1Bf08af5782dCbD516cDd96' ,
79+ [ ChainId . BLAST ] : '0x2D509190Ed0172ba588407D4c2df918F955Cc6E1' ,
80+ [ ChainId . BSCMAINNET ] : '0x4e8E101924eDE233C13e2D8622DC8aED2872d505' ,
81+ [ ChainId . UNICHAIN ] : '0xeF684C38F94F48775959ECf2012D7E864ffb9dd4' ,
82+ }
83+
6184// TransferType enum
6285export enum TransferType {
6386 Approval = 0 ,
@@ -182,32 +205,6 @@ export const spokePoolPeripheryAbi = [
182205 } ,
183206] as const
184207
185- // V3FundsDeposited event ABI for parsing deposit ID from logs
186- const V3FundsDepositedAbi = [
187- {
188- anonymous : false ,
189- inputs : [
190- { indexed : false , internalType : 'address' , name : 'inputToken' , type : 'address' } ,
191- { indexed : false , internalType : 'address' , name : 'outputToken' , type : 'address' } ,
192- { indexed : false , internalType : 'uint256' , name : 'inputAmount' , type : 'uint256' } ,
193- { indexed : false , internalType : 'uint256' , name : 'outputAmount' , type : 'uint256' } ,
194- { indexed : true , internalType : 'uint256' , name : 'destinationChainId' , type : 'uint256' } ,
195- { indexed : true , internalType : 'uint32' , name : 'depositId' , type : 'uint32' } ,
196- { indexed : false , internalType : 'uint32' , name : 'quoteTimestamp' , type : 'uint32' } ,
197- { indexed : false , internalType : 'uint32' , name : 'fillDeadline' , type : 'uint32' } ,
198- { indexed : false , internalType : 'uint32' , name : 'exclusivityDeadline' , type : 'uint32' } ,
199- { indexed : true , internalType : 'address' , name : 'depositor' , type : 'address' } ,
200- { indexed : false , internalType : 'address' , name : 'recipient' , type : 'address' } ,
201- { indexed : false , internalType : 'address' , name : 'exclusiveRelayer' , type : 'address' } ,
202- { indexed : false , internalType : 'bytes' , name : 'message' , type : 'bytes' } ,
203- ] ,
204- name : 'V3FundsDeposited' ,
205- type : 'event' ,
206- } ,
207- ] as const
208-
209- // V3FundsDeposited event signature
210- const V3_FUNDS_DEPOSITED_EVENT_SIGNATURE = '0xa123dc29aebf7d0c3322c8eeb5b999e859f39937950ed31056532713d0de396f'
211208
212209// Progress tracking types
213210type ProgressMeta = ApproveMeta | SwapAndBridgeMeta | FillMeta | undefined
@@ -253,13 +250,23 @@ export type SwapAndBridgeProgress =
253250 status : 'txSuccess'
254251 txReceipt : TransactionReceipt
255252 depositId : bigint
253+ depositLog : ReturnType < typeof parseDepositLogs >
256254 meta : SwapAndBridgeMeta
257255 }
258256 | {
259257 step : 'fill'
260258 status : 'pending'
261259 meta : FillMeta
262260 }
261+ | {
262+ step : 'fill'
263+ status : 'txSuccess'
264+ txReceipt : TransactionReceipt
265+ fillTxTimestamp : bigint
266+ actionSuccess : boolean | undefined
267+ fillLog : ReturnType < typeof parseFillLogs >
268+ meta : FillMeta
269+ }
263270 | {
264271 step : 'approve' | 'swapAndBridge' | 'fill'
265272 status : 'error'
@@ -271,12 +278,14 @@ export interface ExecuteSwapAndBridgeParams {
271278 // Wallet and clients
272279 walletClient : WalletClient
273280 originChain : ViemChain
281+ destinationChain : ViemChain
274282 // User address
275283 userAddress : Address
276284 // Swap and bridge data
277285 swapAndDepositData : SwapAndDepositData
278286 // Contract addresses
279287 spokePoolPeripheryAddress : Address
288+ destinationSpokePoolAddress : Address
280289 // Options
281290 isNative ?: boolean
282291 infiniteApproval ?: boolean
@@ -289,25 +298,10 @@ export interface ExecuteSwapAndBridgeParams {
289298export interface ExecuteSwapAndBridgeResponse {
290299 depositId ?: bigint
291300 swapAndBridgeTxReceipt ?: TransactionReceipt
301+ fillTxReceipt ?: TransactionReceipt
292302 error ?: Error
293303}
294304
295- /**
296- * Gets deposit info from transaction logs
297- */
298- function getDepositFromLogs ( receipt : TransactionReceipt ) : { depositId : bigint } {
299- const depositLog = receipt . logs . find ( log => log . topics [ 0 ] === V3_FUNDS_DEPOSITED_EVENT_SIGNATURE )
300-
301- if ( ! depositLog ) {
302- throw new Error ( 'V3FundsDeposited event not found in transaction logs' )
303- }
304-
305- // depositId is the second indexed parameter (topics[2])
306- const depositId = BigInt ( depositLog . topics [ 2 ] || '0' )
307-
308- return { depositId }
309- }
310-
311305/**
312306 * Transforms raw API quote data (with string values) to properly typed SwapAndDepositData (with bigint values)
313307 * The API returns numeric values as strings, but the contract expects bigint types
@@ -435,6 +429,14 @@ export class KyberAcrossAdapter extends BaseSwapAdapter {
435429 throw new Error ( `Unsupported chain: ${ originChainId } ` )
436430 }
437431
432+ // Get destination chain from quoteParams
433+ const destinationChainId = quote . quote . quoteParams . toChain as ChainId
434+ const destinationChain = chainIdToViemChain [ destinationChainId ]
435+
436+ if ( ! destinationChain ) {
437+ throw new Error ( `Unsupported destination chain: ${ destinationChainId } ` )
438+ }
439+
438440 // Get spokePoolPeripheryAddress from rawQuote or use fallback mapping
439441 const spokePoolPeripheryAddress : Address =
440442 rawQuote . spokePoolPeripheryAddress || chainIdToSpokePoolPeriphery [ originChainId ]
@@ -443,6 +445,14 @@ export class KyberAcrossAdapter extends BaseSwapAdapter {
443445 throw new Error ( `No SpokePoolPeriphery address found for chain: ${ originChainId } ` )
444446 }
445447
448+ // Get destinationSpokePoolAddress from rawQuote or use fallback mapping
449+ const destinationSpokePoolAddress : Address =
450+ rawQuote . destinationSpokePoolAddress || chainIdToSpokePool [ destinationChainId ]
451+
452+ if ( ! destinationSpokePoolAddress ) {
453+ throw new Error ( `No SpokePool address found for destination chain: ${ destinationChainId } ` )
454+ }
455+
446456 // Get user address from quote params
447457 const userAddress = quote . quote . quoteParams . sender as Address
448458
@@ -457,16 +467,17 @@ export class KyberAcrossAdapter extends BaseSwapAdapter {
457467 this . executeSwapAndBridge ( {
458468 walletClient,
459469 originChain,
470+ destinationChain,
460471 userAddress,
461472 swapAndDepositData,
462473 spokePoolPeripheryAddress,
474+ destinationSpokePoolAddress,
463475 isNative,
464476 infiniteApproval : false ,
465477 skipAllowanceCheck : false ,
466478 throwOnError : true ,
467- onProgress : ( progress : SwapAndBridgeProgress ) => {
468- // Resolve when swapAndBridge transaction is pending (similar to Across SDK behavior)
469- if ( progress . step === 'swapAndBridge' && progress . status === 'txPending' ) {
479+ onProgress : progress => {
480+ if ( progress . step === 'swapAndBridge' && 'txHash' in progress ) {
470481 resolve ( {
471482 sender : quote . quote . quoteParams . sender ,
472483 sourceTxHash : progress . txHash ,
@@ -485,10 +496,6 @@ export class KyberAcrossAdapter extends BaseSwapAdapter {
485496 recipient : quote . quote . quoteParams . recipient ,
486497 } )
487498 }
488-
489- if ( progress . status === 'error' ) {
490- reject ( progress . error )
491- }
492499 } ,
493500 } ) . catch ( reject )
494501 } )
@@ -504,9 +511,11 @@ export class KyberAcrossAdapter extends BaseSwapAdapter {
504511 const {
505512 walletClient,
506513 originChain,
514+ destinationChain,
507515 userAddress,
508516 swapAndDepositData,
509517 spokePoolPeripheryAddress,
518+ destinationSpokePoolAddress,
510519 isNative = false ,
511520 infiniteApproval = false ,
512521 skipAllowanceCheck = false ,
@@ -523,8 +532,9 @@ export class KyberAcrossAdapter extends BaseSwapAdapter {
523532 let currentProgressMeta : ProgressMeta
524533
525534 try {
526- // Create public client for reading blockchain state
535+ // Create public clients for reading blockchain state
527536 const originClient = this . acrossClient . getPublicClient ( originChain . id )
537+ const destinationClient = this . acrossClient . getPublicClient ( destinationChain . id )
528538
529539 // Step 1: Check and handle approval if necessary (skip for native ETH)
530540 if ( ! skipAllowanceCheck && ! isNative ) {
@@ -631,39 +641,67 @@ export class KyberAcrossAdapter extends BaseSwapAdapter {
631641 }
632642 onProgressHandler ( currentProgress )
633643
634- // Wait for transaction confirmation
635- const swapAndBridgeTxReceipt = await originClient . waitForTransactionReceipt ( {
636- hash : swapAndBridgeTxHash ,
644+ // Wait for deposit transaction and parse logs using SDK
645+ const { depositId, depositTxReceipt } = await waitForDepositTx ( {
646+ originChainId : originChain . id ,
647+ transactionHash : swapAndBridgeTxHash ,
648+ publicClient : originClient ,
637649 } )
638-
639- // Parse deposit ID from logs
640- const deposit = getDepositFromLogs ( swapAndBridgeTxReceipt )
641- const depositId = deposit . depositId
650+ const depositLog = parseDepositLogs ( depositTxReceipt . logs )
642651
643652 currentProgress = {
644653 step : 'swapAndBridge' ,
645654 status : 'txSuccess' ,
646- txReceipt : swapAndBridgeTxReceipt ,
655+ txReceipt : depositTxReceipt ,
647656 depositId,
657+ depositLog,
648658 meta : currentProgressMeta ,
649659 }
650660 onProgressHandler ( currentProgress )
651661
652- // Step 3: Notify about fill pending
662+ // Step 3: Wait for fill on destination chain
653663 currentProgressMeta = {
654664 depositId,
655665 }
656-
657666 currentProgress = {
658667 step : 'fill' ,
659668 status : 'pending' ,
660669 meta : currentProgressMeta ,
661670 }
662671 onProgressHandler ( currentProgress )
663672
673+ const destinationBlock = await destinationClient . getBlockNumber ( )
674+
675+ const { fillTxReceipt, fillTxTimestamp, actionSuccess } = await waitForFillTx ( {
676+ deposit : {
677+ originChainId : originChain . id ,
678+ destinationChainId : destinationChain . id ,
679+ destinationSpokePoolAddress,
680+ message : swapAndDepositData . depositData . message ,
681+ } ,
682+ depositId,
683+ depositTxHash : depositTxReceipt . transactionHash ,
684+ destinationChainClient : destinationClient ,
685+ fromBlock : destinationBlock - 100n ,
686+ } )
687+
688+ const fillLog = parseFillLogs ( fillTxReceipt . logs )
689+
690+ currentProgress = {
691+ step : 'fill' ,
692+ status : 'txSuccess' ,
693+ txReceipt : fillTxReceipt ,
694+ fillTxTimestamp,
695+ actionSuccess,
696+ fillLog,
697+ meta : currentProgressMeta ,
698+ }
699+ onProgressHandler ( currentProgress )
700+
664701 return {
665702 depositId,
666- swapAndBridgeTxReceipt,
703+ swapAndBridgeTxReceipt : depositTxReceipt ,
704+ fillTxReceipt,
667705 }
668706 } catch ( error ) {
669707 currentProgress = {
@@ -683,11 +721,21 @@ export class KyberAcrossAdapter extends BaseSwapAdapter {
683721 }
684722
685723 // getTransactionStatus is empty for now - will be added later
686- async getTransactionStatus ( _params : NormalizedTxResponse ) : Promise < SwapStatus > {
687- // TODO: Implement transaction status tracking
688- return {
689- txHash : '' ,
690- status : 'Processing' ,
724+ async getTransactionStatus ( params : NormalizedTxResponse ) : Promise < SwapStatus > {
725+ try {
726+ const res = await fetch ( `https://app.across.to/api/deposit/status?depositTxHash=${ params . sourceTxHash } ` ) . then (
727+ res => res . json ( ) ,
728+ )
729+ return {
730+ txHash : res . fillTx || '' ,
731+ status : res . status === 'refunded' ? 'Refunded' : res . status === 'filled' ? 'Success' : 'Processing' ,
732+ }
733+ } catch ( error ) {
734+ console . error ( 'Error fetching transaction status:' , error )
735+ return {
736+ txHash : '' ,
737+ status : 'Processing' ,
738+ }
691739 }
692740 }
693741}
0 commit comments