Skip to content

Commit e04e6f9

Browse files
committed
feat: track manages its own timeout
1 parent 8045873 commit e04e6f9

File tree

2 files changed

+131
-121
lines changed

2 files changed

+131
-121
lines changed

evm/ts/src/multiTokenNtt.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,6 @@ export class EvmMultiTokenNtt<N extends Network, C extends EvmChains>
679679
return 1_000_000n;
680680
}
681681

682-
return 500_000n;
682+
return 300_000n;
683683
}
684684
}

sdk/route/src/types.ts

Lines changed: 130 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
amount,
1717
canonicalAddress,
1818
isAttested,
19+
isCompleted,
1920
isDestinationQueued,
2021
isFailed,
2122
isNative,
@@ -710,143 +711,152 @@ export namespace MultiTokenNttRoute {
710711
isManual?: boolean,
711712
timeout?: number
712713
) {
713-
if (isSourceInitiated(receipt) || isSourceFinalized(receipt)) {
714-
const txid = receipt.originTxs.at(-1)!;
715-
716-
// TODO: can pass txid when this is published: https://github.com/wormhole-foundation/wormhole-sdk-ts/pull/909
717-
const fromChain = wh.getChain(receipt.from);
718-
const [msg] = await fromChain.parseTransaction(txid.txid);
719-
if (!msg) throw new Error("No Wormhole messages found");
720-
721-
const vaa = await wh.getVaa(
722-
msg,
723-
"MultiTokenNtt:WormholeTransfer",
724-
timeout
725-
);
726-
if (!vaa) throw new Error("No VAA found for transaction: " + txid.txid);
727-
728-
const msgId: WormholeMessageId = {
729-
chain: vaa.emitterChain,
730-
emitter: vaa.emitterAddress,
731-
sequence: vaa.sequence,
732-
};
733-
734-
receipt = {
735-
...receipt,
736-
state: TransferState.Attested,
737-
attestation: {
738-
id: msgId,
739-
attestation: vaa,
740-
},
741-
};
742-
yield receipt;
743-
}
744-
745-
const toChain = wh.getChain(receipt.to);
746-
const destinationNtt = await toChain.getProtocol("MultiTokenNtt", {
747-
multiTokenNtt: receipt.params.normalizedParams.destinationContracts,
748-
});
749-
750-
// Check if the transfer was redeemed
751-
if (isAttested(receipt) || isFailed(receipt)) {
752-
if (!receipt.attestation) {
753-
throw new Error("No attestation found");
754-
}
714+
let leftover = timeout ? timeout : 60 * 60 * 1000;
715+
while (leftover > 0 && !isCompleted(receipt)) {
716+
const start = Date.now();
717+
718+
if (isSourceInitiated(receipt) || isSourceFinalized(receipt)) {
719+
const txid = receipt.originTxs.at(-1)!;
720+
721+
// TODO: can pass txid when this is published: https://github.com/wormhole-foundation/wormhole-sdk-ts/pull/909
722+
const fromChain: ChainContext<N> = wh.getChain(receipt.from);
723+
const [msg] = await fromChain.parseTransaction(txid.txid);
724+
if (!msg) throw new Error("No Wormhole messages found");
725+
726+
const vaa = await wh.getVaa(
727+
msg,
728+
"MultiTokenNtt:WormholeTransfer",
729+
timeout
730+
);
731+
if (!vaa) throw new Error("No VAA found for transaction: " + txid.txid);
755732

756-
const vaa = receipt.attestation.attestation;
733+
const msgId: WormholeMessageId = {
734+
chain: vaa.emitterChain,
735+
emitter: vaa.emitterAddress,
736+
sequence: vaa.sequence,
737+
};
757738

758-
if (await destinationNtt.getIsApproved(vaa)) {
759-
// All transceivers have approved the transfer
760739
receipt = {
761740
...receipt,
762-
state: TransferState.DestinationInitiated,
763-
attestation: receipt.attestation,
741+
state: TransferState.Attested,
742+
attestation: {
743+
id: msgId,
744+
attestation: vaa,
745+
},
764746
};
765747
yield receipt;
766-
} else {
767-
const { sendTransceivers } = receipt.params.normalizedParams;
768-
769-
// The Wormhole transceiver may wait to attest until all other transceivers have attested
770-
// so we want to check it last
771-
const sortedTransceivers = [...sendTransceivers].sort((a, b) => {
772-
const aType = a.type.toLowerCase();
773-
const bType = b.type.toLowerCase();
774-
if (aType === "wormhole" && bType !== "wormhole") return 1;
775-
if (aType !== "wormhole" && bType === "wormhole") return -1;
776-
return 0;
777-
});
778-
779-
for (const transceiver of sortedTransceivers) {
780-
const transceiverType = transceiver.type.toLowerCase();
781-
if (receipt.trackingInfo.transceiverAttested[transceiverType]) {
782-
continue;
783-
}
748+
}
784749

785-
const attested = await destinationNtt.transceiverAttestedToMessage(
786-
receipt.from,
787-
vaa.payload.nttManagerPayload,
788-
transceiver.index
789-
);
790-
if (attested) {
791-
receipt.trackingInfo.transceiverAttested[transceiverType] = true;
792-
if (isFailed(receipt)) {
793-
// Reset the receipt status if the transceiver attested
794-
receipt = {
795-
...receipt,
796-
attestation: receipt.attestation!,
797-
state: TransferState.Attested,
798-
};
799-
yield receipt;
800-
}
801-
continue;
802-
}
750+
const toChain = wh.getChain(receipt.to);
751+
const destinationNtt = await toChain.getProtocol("MultiTokenNtt", {
752+
multiTokenNtt: receipt.params.normalizedParams.destinationContracts,
753+
});
803754

804-
if (transceiverType === "wormhole") {
805-
// Manual transfers don't use executor
806-
if (!isManual) {
807-
receipt = await trackExecutor(wh.network, receipt);
755+
// Check if the transfer was redeemed
756+
if (isAttested(receipt) || isFailed(receipt)) {
757+
if (!receipt.attestation) {
758+
throw new Error("No attestation found");
759+
}
760+
761+
const vaa = receipt.attestation.attestation;
762+
763+
if (await destinationNtt.getIsApproved(vaa)) {
764+
// All transceivers have approved the transfer
765+
receipt = {
766+
...receipt,
767+
state: TransferState.DestinationInitiated,
768+
attestation: receipt.attestation,
769+
};
770+
yield receipt;
771+
} else {
772+
const { sendTransceivers } = receipt.params.normalizedParams;
773+
774+
// The Wormhole transceiver may wait to attest until all other transceivers have attested
775+
// so we want to check it last
776+
const sortedTransceivers = [...sendTransceivers].sort((a, b) => {
777+
const aType = a.type.toLowerCase();
778+
const bType = b.type.toLowerCase();
779+
if (aType === "wormhole" && bType !== "wormhole") return 1;
780+
if (aType !== "wormhole" && bType === "wormhole") return -1;
781+
return 0;
782+
});
783+
784+
for (const transceiver of sortedTransceivers) {
785+
const transceiverType = transceiver.type.toLowerCase();
786+
if (receipt.trackingInfo.transceiverAttested[transceiverType]) {
787+
continue;
808788
}
809-
} else if (transceiverType === "axelar") {
810-
receipt = await trackAxelar(wh.network, receipt);
811-
} else {
812-
throw new Error(
813-
`Unsupported transceiver type: ${transceiver.type}`
789+
790+
const attested = await destinationNtt.transceiverAttestedToMessage(
791+
receipt.from,
792+
vaa.payload.nttManagerPayload,
793+
transceiver.index
814794
);
795+
if (attested) {
796+
receipt.trackingInfo.transceiverAttested[transceiverType] = true;
797+
if (isFailed(receipt)) {
798+
// Reset the receipt status if the transceiver attested
799+
receipt = {
800+
...receipt,
801+
attestation: receipt.attestation!,
802+
state: TransferState.Attested,
803+
};
804+
yield receipt;
805+
}
806+
continue;
807+
}
808+
809+
if (transceiverType === "wormhole") {
810+
// Manual transfers don't use executor
811+
if (!isManual) {
812+
receipt = await trackExecutor(wh.network, receipt);
813+
}
814+
} else if (transceiverType === "axelar") {
815+
receipt = await trackAxelar(wh.network, receipt);
816+
} else {
817+
throw new Error(
818+
`Unsupported transceiver type: ${transceiver.type}`
819+
);
820+
}
821+
yield receipt;
822+
// We are breaking here so we only track one transceiver at a time
823+
// until all transceivers have attested. Otherwise the receipt state
824+
// may jump around too much resulting in a glitchy UI.
825+
break;
815826
}
816-
yield receipt;
817-
// We are breaking here so we only track one transceiver at a time
818-
// until all transceivers have attested. Otherwise the receipt state
819-
// may jump around too much resulting in a glitchy UI.
820-
break;
821827
}
822828
}
823-
}
824829

825-
if (isRedeemed(receipt) || isDestinationQueued(receipt)) {
826-
const vaa = receipt.attestation.attestation;
830+
if (isRedeemed(receipt) || isDestinationQueued(receipt)) {
831+
const vaa = receipt.attestation.attestation;
827832

828-
const queuedTransfer = await destinationNtt.getInboundQueuedTransfer(
829-
vaa.emitterChain,
830-
vaa.payload.nttManagerPayload
831-
);
832-
if (queuedTransfer !== null) {
833-
receipt = {
834-
...receipt,
835-
state: TransferState.DestinationQueued,
836-
queueReleaseTime: new Date(
837-
queuedTransfer.rateLimitExpiryTimestamp * 1000
838-
),
839-
};
840-
yield receipt;
841-
} else if (await destinationNtt.getIsExecuted(vaa)) {
842-
receipt = {
843-
...receipt,
844-
state: TransferState.DestinationFinalized,
845-
};
846-
yield receipt;
833+
const queuedTransfer = await destinationNtt.getInboundQueuedTransfer(
834+
vaa.emitterChain,
835+
vaa.payload.nttManagerPayload
836+
);
837+
if (queuedTransfer !== null) {
838+
receipt = {
839+
...receipt,
840+
state: TransferState.DestinationQueued,
841+
queueReleaseTime: new Date(
842+
queuedTransfer.rateLimitExpiryTimestamp * 1000
843+
),
844+
};
845+
} else if (await destinationNtt.getIsExecuted(vaa)) {
846+
receipt = {
847+
...receipt,
848+
state: TransferState.DestinationFinalized,
849+
};
850+
}
847851
}
852+
853+
yield receipt;
854+
855+
// sleep for a few seconds so we don't spam the endpoints
856+
await new Promise((resolve) => setTimeout(resolve, 3000));
857+
leftover -= Date.now() - start;
848858
}
849859

850-
yield receipt;
860+
return receipt;
851861
}
852862
}

0 commit comments

Comments
 (0)