@@ -31,7 +31,7 @@ import {
3131} from "@wormhole-foundation/sdk-connect" ;
3232import "@wormhole-foundation/sdk-definitions-ntt" ;
3333import { MultiTokenNttRoute , NttRoute } from "./types.js" ;
34- import { MultiTokenNtt } from "@wormhole-foundation/sdk-definitions-ntt" ;
34+ import { MultiTokenNtt , Ntt } from "@wormhole-foundation/sdk-definitions-ntt" ;
3535import {
3636 getAxelarTransactionStatus ,
3737 getAxelarExplorerUrl ,
@@ -131,7 +131,7 @@ export class MultiTokenNttManualRoute<N extends Network>
131131 ? await sourceNtt . getWrappedNativeToken ( )
132132 : request . source . id ;
133133
134- const originalToken = await sourceNtt . getOriginalToken ( sourceToken ) ;
134+ const originalTokenId = await sourceNtt . getOriginalToken ( sourceToken ) ;
135135
136136 const sendTransceivers = await sourceNtt . getSendTransceivers (
137137 request . toChain . chain
@@ -145,7 +145,7 @@ export class MultiTokenNttManualRoute<N extends Network>
145145 destinationContracts,
146146 sourceTokenId : request . source . id ,
147147 destinationTokenId : request . destination . id ,
148- originalTokenId : originalToken ,
148+ originalTokenId,
149149 sendTransceivers,
150150 } ,
151151 options,
@@ -413,31 +413,145 @@ export class MultiTokenNttManualRoute<N extends Network>
413413 } ;
414414 }
415415
416- public override async * track ( receipt : R , timeout ?: number ) {
417- if ( isSourceInitiated ( receipt ) || isSourceFinalized ( receipt ) ) {
418- const { txid } = receipt . originTxs . at ( - 1 ) ! ;
419- const vaa = await this . wh . getVaa (
420- txid ,
421- "MultiTokenNtt:WormholeTransfer" ,
422- timeout
416+ async trackWormholeAttestation ( receipt : R , timeout ?: number ) : Promise < R > {
417+ if ( ! isSourceInitiated ( receipt ) && ! isSourceFinalized ( receipt ) ) {
418+ return receipt ;
419+ }
420+
421+ const { txid } = receipt . originTxs . at ( - 1 ) ! ;
422+ const vaa = await this . wh . getVaa (
423+ txid ,
424+ "MultiTokenNtt:WormholeTransfer" ,
425+ timeout
426+ ) ;
427+ if ( ! vaa ) throw new Error ( "No VAA found for transaction: " + txid ) ;
428+
429+ const msgId : WormholeMessageId = {
430+ chain : vaa . emitterChain ,
431+ emitter : vaa . emitterAddress ,
432+ sequence : vaa . sequence ,
433+ } ;
434+
435+ return {
436+ ...receipt ,
437+ state : TransferState . Attested ,
438+ attestation : {
439+ id : msgId ,
440+ attestation : vaa ,
441+ } ,
442+ } satisfies AttestedTransferReceipt < MultiTokenNttRoute . ManualAttestationReceipt > as R ;
443+ }
444+
445+ async trackAxelarTransceiver (
446+ receipt : R ,
447+ destinationNtt : MultiTokenNtt < N , Chain > ,
448+ axelarTransceiver : Ntt . TransceiverMeta
449+ ) : Promise < R > {
450+ if ( ! isAttested ( receipt ) && ! isFailed ( receipt ) ) {
451+ return receipt ;
452+ }
453+
454+ if ( ! receipt . attestation ) {
455+ throw new Error ( "No attestation found on the transfer receipt" ) ;
456+ }
457+
458+ const axelarAttested = await destinationNtt . transceiverAttestedToMessage (
459+ receipt . from ,
460+ receipt . attestation ! . attestation . payload . nttManagerPayload ,
461+ axelarTransceiver . index
462+ ) ;
463+
464+ if ( axelarAttested ) {
465+ // Axelar has attested - if we were in failed state, reset to attested
466+ if ( isFailed ( receipt ) ) {
467+ return {
468+ ...receipt ,
469+ state : TransferState . Attested ,
470+ attestation : receipt . attestation ,
471+ // @ts -ignore
472+ error : undefined ,
473+ } satisfies AttestedTransferReceipt < MultiTokenNttRoute . ManualAttestationReceipt > as R ;
474+ }
475+ return receipt ;
476+ }
477+
478+ // Axelar hasn't attested yet - check status via API
479+ try {
480+ const txid = receipt . originTxs . at ( - 1 ) ! . txid ;
481+ const axelarStatus = await getAxelarTransactionStatus (
482+ this . wh . network ,
483+ txid
423484 ) ;
424- if ( ! vaa ) throw new Error ( "No VAA found for transaction: " + txid ) ;
425485
426- const msgId : WormholeMessageId = {
427- chain : vaa . emitterChain ,
428- emitter : vaa . emitterAddress ,
429- sequence : vaa . sequence ,
430- } ;
486+ if ( axelarStatus . error ) {
487+ return {
488+ ...receipt ,
489+ state : TransferState . Failed ,
490+ error : new routes . RelayFailedError (
491+ `Axelar transceiver error: ${ axelarStatus . error . message } ` ,
492+ // @ts -ignore
493+ {
494+ url : getAxelarExplorerUrl ( this . wh . network , txid ) ,
495+ explorerName : "Axelarscan" ,
496+ }
497+ ) ,
498+ } ;
499+ } else if ( isFailed ( receipt ) ) {
500+ // if we previously marked it as failed, but now it's not an error, clear the error
501+ return {
502+ ...receipt ,
503+ state : TransferState . Attested ,
504+ attestation : receipt . attestation ,
505+ // @ts -ignore
506+ error : undefined ,
507+ } satisfies AttestedTransferReceipt < MultiTokenNttRoute . ManualAttestationReceipt > as R ;
508+ }
509+
510+ console . log ( "Axelar transceiver status:" , axelarStatus ) ;
511+ } catch ( error ) {
512+ // Log but don't fail - continue with standard tracking
513+ console . warn ( "Failed to query Axelar transceiver status:" , error ) ;
514+ }
515+
516+ return receipt ;
517+ }
518+
519+ async checkDestinationQueue (
520+ receipt : R ,
521+ destinationNtt : MultiTokenNtt < N , Chain >
522+ ) : Promise < R > {
523+ if ( ! isRedeemed ( receipt ) ) {
524+ return receipt ;
525+ }
526+
527+ const vaa = receipt . attestation ! . attestation ;
528+
529+ const queuedTransfer = await destinationNtt . getInboundQueuedTransfer (
530+ vaa . emitterChain ,
531+ vaa . payload . nttManagerPayload
532+ ) ;
431533
432- receipt = {
534+ if ( queuedTransfer !== null ) {
535+ return {
433536 ...receipt ,
434- state : TransferState . Attested ,
435- attestation : {
436- id : msgId ,
437- attestation : vaa ,
438- } ,
439- } satisfies AttestedTransferReceipt < MultiTokenNttRoute . ManualAttestationReceipt > as R ;
537+ state : TransferState . DestinationQueued ,
538+ queueReleaseTime : new Date (
539+ queuedTransfer . rateLimitExpiryTimestamp * 1000
540+ ) ,
541+ } satisfies DestinationQueuedTransferReceipt < MultiTokenNttRoute . ManualAttestationReceipt > as R ;
542+ } else if ( await destinationNtt . getIsExecuted ( vaa ) ) {
543+ return {
544+ ...receipt ,
545+ state : TransferState . DestinationFinalized ,
546+ } satisfies CompletedTransferReceipt < MultiTokenNttRoute . ManualAttestationReceipt > as R ;
547+ }
440548
549+ return receipt ;
550+ }
551+
552+ public override async * track ( receipt : R , timeout ?: number ) {
553+ if ( isSourceInitiated ( receipt ) || isSourceFinalized ( receipt ) ) {
554+ receipt = await this . trackWormholeAttestation ( receipt , timeout ) ;
441555 yield receipt ;
442556 }
443557
@@ -451,9 +565,7 @@ export class MultiTokenNttManualRoute<N extends Network>
451565 throw new Error ( "No attestation found on the transfer receipt" ) ;
452566 }
453567
454- const {
455- attestation : { attestation : vaa } ,
456- } = receipt ;
568+ const vaa = receipt . attestation . attestation ;
457569
458570 if ( await destinationNtt . getIsApproved ( vaa ) ) {
459571 // All transceivers have approved the transfer
@@ -464,85 +576,33 @@ export class MultiTokenNttManualRoute<N extends Network>
464576 } satisfies RedeemedTransferReceipt < MultiTokenNttRoute . ManualAttestationReceipt > ;
465577 yield receipt ;
466578 } else {
467- // At this point the wormhole message has been emitted, but we need to check
468- // the status of the axelar transceiver if configured
579+ // Wormhole transceiver has attested, check Axelar transceiver (if enabled)
469580 const { sendTransceivers } = receipt . params . normalizedParams ;
470581 const axelarTransceiver = sendTransceivers . find (
471582 ( t ) => t . type . toLowerCase ( ) === "axelar"
472583 ) ;
584+
473585 if ( axelarTransceiver ) {
474- const axelarAttested =
475- await destinationNtt . transceiverAttestedToMessage (
476- receipt . from ,
477- receipt . attestation . attestation . payload . nttManagerPayload ,
478- axelarTransceiver . index
479- ) ;
480-
481- if ( ! axelarAttested ) {
482- try {
483- const txid = receipt . originTxs . at ( - 1 ) ! . txid ;
484- const axelarStatus = await getAxelarTransactionStatus (
485- this . wh . network ,
486- txid
487- ) ;
488- if ( axelarStatus . error ) {
489- receipt = {
490- ...receipt ,
491- state : TransferState . Failed ,
492- error : new routes . RelayFailedError (
493- `Axelar transceiver error: ${ axelarStatus . error . message } ` ,
494- {
495- url : getAxelarExplorerUrl ( this . wh . network , txid ) ,
496- explorerName : "Axelarscan" ,
497- }
498- ) ,
499- } ;
500- yield receipt ;
501- } else if ( isFailed ( receipt ) ) {
502- // if we previously marked it as failed, but now it's not an error, clear the error
503- receipt = {
504- ...receipt ,
505- state : TransferState . Attested ,
506- attestation : receipt . attestation ,
507- // @ts -ignore
508- error : undefined ,
509- } satisfies AttestedTransferReceipt < MultiTokenNttRoute . ManualAttestationReceipt > as R ;
510- yield receipt ;
511- }
512-
513- console . log ( "Axelar transceiver status:" , axelarStatus ) ;
514- } catch ( error ) {
515- // Log but don't fail - continue with standard tracking
516- console . warn ( "Failed to query Axelar transceiver status:" , error ) ;
517- }
586+ const updatedReceipt = await this . trackAxelarTransceiver (
587+ receipt ,
588+ destinationNtt ,
589+ axelarTransceiver
590+ ) ;
591+ if ( updatedReceipt !== receipt ) {
592+ receipt = updatedReceipt ;
593+ yield receipt ;
518594 }
519595 }
520596 }
521597 }
522598
523599 if ( isRedeemed ( receipt ) || isDestinationQueued ( receipt ) ) {
524- const {
525- attestation : { attestation : vaa } ,
526- } = receipt ;
527-
528- const queuedTransfer = await destinationNtt . getInboundQueuedTransfer (
529- vaa . emitterChain ,
530- vaa . payload . nttManagerPayload
600+ const updatedReceipt = await this . checkDestinationQueue (
601+ receipt ,
602+ destinationNtt
531603 ) ;
532- if ( queuedTransfer !== null ) {
533- receipt = {
534- ...receipt ,
535- state : TransferState . DestinationQueued ,
536- queueReleaseTime : new Date (
537- queuedTransfer . rateLimitExpiryTimestamp * 1000
538- ) ,
539- } satisfies DestinationQueuedTransferReceipt < MultiTokenNttRoute . ManualAttestationReceipt > ;
540- yield receipt ;
541- } else if ( await destinationNtt . getIsExecuted ( vaa ) ) {
542- receipt = {
543- ...receipt ,
544- state : TransferState . DestinationFinalized ,
545- } satisfies CompletedTransferReceipt < MultiTokenNttRoute . ManualAttestationReceipt > ;
604+ if ( updatedReceipt !== receipt ) {
605+ receipt = updatedReceipt ;
546606 yield receipt ;
547607 }
548608 }
0 commit comments