Skip to content

Commit 8d29c4c

Browse files
committed
fix multi transceiver tracking
1 parent 9917c21 commit 8d29c4c

File tree

5 files changed

+55
-107
lines changed

5 files changed

+55
-107
lines changed

evm/ts/src/axelar.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ export async function getAxelarGasFee(
106106
}
107107
}
108108

109-
// If all retries returned 0, just return 0
110-
return lastResult ?? 0n;
109+
// If all retries returned 0, just return 1 wei
110+
return lastResult ?? 1n;
111111
}
112112

113113
export async function getAxelarTransactionStatus(

evm/ts/src/multiTokenNtt.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -270,16 +270,17 @@ export class EvmMultiTokenNtt<N extends Network, C extends EvmChains>
270270
payload: new Uint8Array([1]), // disable standard relayer, use executor route for automatic relay
271271
};
272272
case "axelar": {
273-
// If we fail to fetch the gas fee, then use 0 as a fallback.
274-
// The Axelar relay should fail and the track() method will
275-
// surface a RelayFailedError. We don't want to fail the entire
276-
// transfer just because we couldn't fetch the gas fee quote.
273+
// If we fail to fetch the gas fee, then use 1 wei as a fallback.
274+
// Do *NOT* use 0 wei as the Axelar status API will not return an error.
275+
// The Axelar relay status should return an invalid gas fee error
276+
// and the track() method will surface a RelayFailedError for the user
277+
// to top up the gas fee.
277278
const gasFee = await getAxelarGasFee(
278279
this.network,
279280
this.chain,
280281
dstChain,
281282
gasLimit
282-
).catch(() => 0n);
283+
).catch(() => 1n);
283284
return {
284285
index: transceiver.index,
285286
payload: encoding.bignum.toBytes(gasFee, 32),

sdk/route/src/executor/multiToken.ts

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
signedQuoteLayout,
3838
toChainId,
3939
toUniversal,
40+
AttestedTransferReceipt,
4041
} from "@wormhole-foundation/sdk-connect";
4142
import "@wormhole-foundation/sdk-definitions-ntt";
4243
import { MultiTokenNttRoute, NttRoute } from "../types.js";
@@ -84,6 +85,9 @@ export namespace MultiTokenNttExecutorRoute {
8485
DC extends Chain = Chain
8586
> = _TransferReceipt<MultiTokenNttRoute.ManualAttestationReceipt, SC, DC> & {
8687
params: ValidatedParams;
88+
trackingInfo: {
89+
transceiverAttested: { [type: string]: boolean };
90+
};
8791
};
8892
}
8993

@@ -592,6 +596,7 @@ export class MultiTokenNttExecutorRoute<N extends Network>
592596
state: TransferState.SourceInitiated,
593597
originTxs: txids,
594598
params,
599+
trackingInfo: { transceiverAttested: {} },
595600
};
596601
}
597602

@@ -716,6 +721,7 @@ export class MultiTokenNttExecutorRoute<N extends Network>
716721
id: msgId,
717722
attestation: vaa,
718723
},
724+
trackingInfo: { transceiverAttested: {} },
719725
params: {
720726
amount: amount.display(amt),
721727
normalizedParams: {
@@ -821,37 +827,42 @@ export class MultiTokenNttExecutorRoute<N extends Network>
821827
yield receipt;
822828
} else {
823829
const { sendTransceivers } = receipt.params.normalizedParams;
824-
const wormholeTransceiver = sendTransceivers.find(
825-
(t) => t.type.toLowerCase() === "wormhole"
826-
);
827-
if (wormholeTransceiver) {
828-
const updatedReceipt = await trackExecutor(
829-
this.wh.network,
830-
receipt,
831-
destinationNtt,
832-
wormholeTransceiver
833-
);
834-
if (updatedReceipt !== receipt) {
835-
receipt = updatedReceipt;
836-
yield receipt;
830+
for (const transceiver of sendTransceivers) {
831+
const transceiverType = transceiver.type.toLowerCase();
832+
if (receipt.trackingInfo.transceiverAttested[transceiverType]) {
833+
continue;
837834
}
838-
}
839835

840-
const axelarTransceiver = sendTransceivers.find(
841-
(t) => t.type.toLowerCase() === "axelar"
842-
);
843-
844-
if (axelarTransceiver) {
845-
const updatedReceipt = await trackAxelar(
846-
this.wh.network,
847-
receipt,
848-
destinationNtt,
849-
axelarTransceiver
836+
const attested = await destinationNtt.transceiverAttestedToMessage(
837+
receipt.from,
838+
receipt.attestation!.attestation.payload.nttManagerPayload,
839+
transceiver.index
850840
);
851-
if (updatedReceipt !== receipt) {
852-
receipt = updatedReceipt;
853-
yield receipt;
841+
if (attested) {
842+
receipt.trackingInfo.transceiverAttested[transceiverType] = true;
843+
if (isFailed(receipt)) {
844+
// Reset the receipt status if the transceiver attested
845+
receipt = {
846+
...receipt,
847+
attestation: receipt.attestation!,
848+
state: TransferState.Attested,
849+
} satisfies AttestedTransferReceipt<MultiTokenNttRoute.ManualAttestationReceipt>;
850+
yield receipt;
851+
}
852+
continue;
853+
}
854+
855+
if (transceiverType === "wormhole") {
856+
receipt = await trackExecutor(this.wh.network, receipt);
857+
} else if (transceiverType === "axelar") {
858+
receipt = await trackAxelar(this.wh.network, receipt);
859+
} else {
860+
throw new Error(
861+
`Unsupported transceiver type: ${transceiver.type}`
862+
);
854863
}
864+
yield receipt;
865+
break;
855866
}
856867
}
857868
}

sdk/route/src/multiTokenManual.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -480,16 +480,14 @@ export class MultiTokenNttManualRoute<N extends Network>
480480
const axelarTransceiver = sendTransceivers.find(
481481
(t) => t.type.toLowerCase() === "axelar"
482482
);
483-
484483
if (axelarTransceiver) {
485-
const updatedReceipt = await trackAxelar(
486-
this.wh.network,
487-
receipt,
488-
destinationNtt,
489-
axelarTransceiver
484+
const attested = await destinationNtt.transceiverAttestedToMessage(
485+
receipt.from,
486+
receipt.attestation!.attestation.payload.nttManagerPayload,
487+
axelarTransceiver.index
490488
);
491-
if (updatedReceipt !== receipt) {
492-
receipt = updatedReceipt;
489+
if (!attested) {
490+
receipt = await trackAxelar(this.wh.network, receipt);
493491
yield receipt;
494492
}
495493
}

sdk/route/src/tracking.ts

Lines changed: 3 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import {
2-
Chain,
32
Network,
43
TransferState,
54
isFailed,
65
routes,
76
isAttested,
87
} from "@wormhole-foundation/sdk-connect";
9-
import { MultiTokenNtt, Ntt } from "@wormhole-foundation/sdk-definitions-ntt";
108
import { MultiTokenNttRoute } from "./types.js";
119
import {
1210
getAxelarTransactionStatus,
@@ -16,55 +14,25 @@ import { fetchStatus, isRelayStatusFailed } from "./executor/utils.js";
1614

1715
export async function trackExecutor<
1816
R extends MultiTokenNttRoute.ManualTransferReceipt
19-
>(
20-
network: Network,
21-
receipt: R,
22-
destinationNtt: MultiTokenNtt<Network, Chain>,
23-
wormholeTransceiver: Ntt.TransceiverMeta
24-
): Promise<R> {
17+
>(network: Network, receipt: R): Promise<R> {
2518
if (!isAttested(receipt) && !isFailed(receipt)) {
2619
return receipt;
2720
}
2821

29-
if (!receipt.attestation) {
30-
throw new Error("No attestation found on the transfer receipt");
31-
}
32-
33-
const wormholeAttested = await destinationNtt.transceiverAttestedToMessage(
34-
receipt.from,
35-
receipt.attestation.attestation.payload.nttManagerPayload,
36-
wormholeTransceiver.index
37-
);
38-
39-
if (wormholeAttested) {
40-
// Clear error state if relay status is not an error
41-
if (isFailed(receipt)) {
42-
return {
43-
...receipt,
44-
state: TransferState.Attested,
45-
// @ts-ignore
46-
error: undefined,
47-
};
48-
}
49-
50-
return receipt;
51-
}
52-
5322
// Check if the relay was successful or failed
5423
const txid = receipt.originTxs.at(-1)!.txid;
5524
const [txStatus] = await fetchStatus(network, txid, receipt.from);
5625
if (!txStatus) throw new Error("No transaction status found");
5726

5827
const relayStatus = txStatus.status;
5928
if (isRelayStatusFailed(relayStatus)) {
60-
receipt = {
29+
return {
6130
...receipt,
6231
state: TransferState.Failed,
6332
error: new routes.RelayFailedError(
6433
`Relay failed with status: ${relayStatus}`
6534
),
6635
};
67-
return receipt;
6836
}
6937

7038
// Clear error state if relay status is not an error
@@ -82,40 +50,11 @@ export async function trackExecutor<
8250

8351
export async function trackAxelar<
8452
R extends MultiTokenNttRoute.ManualTransferReceipt
85-
>(
86-
network: Network,
87-
receipt: R,
88-
destinationNtt: MultiTokenNtt<Network, Chain>,
89-
axelarTransceiver: Ntt.TransceiverMeta
90-
): Promise<R> {
53+
>(network: Network, receipt: R): Promise<R> {
9154
if (!isAttested(receipt) && !isFailed(receipt)) {
9255
return receipt;
9356
}
9457

95-
if (!receipt.attestation) {
96-
throw new Error("No attestation found on the transfer receipt");
97-
}
98-
99-
const axelarAttested = await destinationNtt.transceiverAttestedToMessage(
100-
receipt.from,
101-
receipt.attestation.attestation.payload.nttManagerPayload,
102-
axelarTransceiver.index
103-
);
104-
105-
if (axelarAttested) {
106-
// Clear error state if relay status is not an error
107-
if (isFailed(receipt)) {
108-
return {
109-
...receipt,
110-
state: TransferState.Attested,
111-
// @ts-ignore
112-
error: undefined,
113-
};
114-
}
115-
116-
return receipt;
117-
}
118-
11958
// Check relayer status
12059
const txid = receipt.originTxs.at(-1)!.txid;
12160
const axelarStatus = await getAxelarTransactionStatus(
@@ -130,7 +69,6 @@ export async function trackAxelar<
13069
state: TransferState.Failed,
13170
error: new routes.RelayFailedError(
13271
`Axelar error: ${axelarStatus.error.message}`,
133-
// @ts-ignore
13472
{
13573
url: getAxelarExplorerUrl(network, txid),
13674
name: "Axelarscan",

0 commit comments

Comments
 (0)