Skip to content

Commit 6261b5c

Browse files
committed
executor working
1 parent 0eae9cf commit 6261b5c

File tree

5 files changed

+192
-46
lines changed

5 files changed

+192
-46
lines changed

sdk/route/src/executor/executor.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,13 @@ import {
3737
} from "@wormhole-foundation/sdk-connect";
3838
import "@wormhole-foundation/sdk-definitions-ntt";
3939
import { NttRoute } from "../types.js";
40-
import { calculateReferrerFee } from "./utils.js";
40+
import {
41+
calculateReferrerFee,
42+
fetchCapabilities,
43+
fetchSignedQuote,
44+
fetchStatus,
45+
isRelayStatusFailed,
46+
} from "./utils.js";
4147
import { Ntt, NttWithExecutor } from "@wormhole-foundation/sdk-definitions-ntt";
4248
import {
4349
isNative,
@@ -705,12 +711,7 @@ export class NttExecutorRoute<N extends Network>
705711
if (!txStatus) throw new Error("No transaction status found");
706712

707713
const relayStatus = txStatus.status;
708-
if (
709-
relayStatus === RelayStatus.Failed || // this could happen if simulation fails
710-
relayStatus === RelayStatus.Underpaid || // only happens if you don't pay at least the costEstimate
711-
relayStatus === RelayStatus.Unsupported || // capabilities check didn't pass
712-
relayStatus === RelayStatus.Aborted // An unrecoverable error indicating the attempt should stop (bad data, pre-flight checks failed, or chain-specific conditions)
713-
) {
714+
if (isRelayStatusFailed(relayStatus)) {
714715
receipt = {
715716
...receipt,
716717
state: TransferState.Failed,

sdk/route/src/executor/multiToken.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,6 @@ import {
3737
signedQuoteLayout,
3838
toChainId,
3939
toUniversal,
40-
fetchStatus,
41-
fetchQuote,
42-
Capabilities,
43-
fetchCapabilities,
4440
} from "@wormhole-foundation/sdk-connect";
4541
import "@wormhole-foundation/sdk-definitions-ntt";
4642
import { MultiTokenNttRoute, NttRoute } from "../types.js";
@@ -50,7 +46,13 @@ import {
5046
Ntt,
5147
NttWithExecutor,
5248
} from "@wormhole-foundation/sdk-definitions-ntt";
53-
import { calculateReferrerFee } from "./utils.js";
49+
import {
50+
calculateReferrerFee,
51+
Capabilities,
52+
fetchCapabilities,
53+
fetchSignedQuote,
54+
fetchStatus,
55+
} from "./utils.js";
5456
import { getDefaultReferrerAddress } from "./consts.js";
5557
import { NttExecutorRoute } from "./executor.js";
5658
import { trackAxelar, trackExecutor } from "../tracking.js";
@@ -206,19 +208,16 @@ export class MultiTokenNttExecutorRoute<N extends Network>
206208
request.toChain.chain
207209
);
208210

209-
const destinationNttWithExecutor = await request.fromChain.getProtocol(
211+
const destinationNttWithExecutor = await request.toChain.getProtocol(
210212
"MultiTokenNttWithExecutor",
211213
{
212214
multiTokenNtt: destinationContracts,
213215
}
214216
);
215217

216-
const destinationNtt = await request.fromChain.getProtocol(
217-
"MultiTokenNtt",
218-
{
219-
multiTokenNtt: destinationContracts,
220-
}
221-
);
218+
const destinationNtt = await request.toChain.getProtocol("MultiTokenNtt", {
219+
multiTokenNtt: destinationContracts,
220+
});
222221

223222
const referrerFeeDbps = this.getReferrerFeeDbps(request);
224223

@@ -499,7 +498,7 @@ export class MultiTokenNttExecutorRoute<N extends Network>
499498
requests: relayRequests,
500499
});
501500

502-
const quote = await fetchQuote(
501+
const quote = await fetchSignedQuote(
503502
fromChain.network,
504503
fromChain.chain,
505504
toChain.chain,

sdk/route/src/executor/utils.ts

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,145 @@
1-
import { amount as sdkAmount } from "@wormhole-foundation/sdk-base";
1+
import {
2+
Chain,
3+
Network,
4+
toChainId,
5+
amount as sdkAmount,
6+
} from "@wormhole-foundation/sdk-base";
7+
import { SignedQuote } from "@wormhole-foundation/sdk-definitions";
8+
import axios from "axios";
9+
import { apiBaseUrl } from "./consts.js";
210
import { NttRoute } from "../types.js";
311

12+
export enum RelayStatus {
13+
Pending = "pending",
14+
Failed = "failed",
15+
Unsupported = "unsupported",
16+
Submitted = "submitted",
17+
Underpaid = "underpaid",
18+
Aborted = "aborted",
19+
}
20+
21+
export type RequestForExecution = {
22+
quoterAddress: `0x${string}`;
23+
amtPaid: string;
24+
dstChain: number;
25+
dstAddr: `0x${string}`;
26+
refundAddr: `0x${string}`;
27+
signedQuoteBytes: `0x${string}`;
28+
requestBytes: `0x${string}`;
29+
relayInstructionsBytes: `0x${string}`;
30+
timestamp: Date;
31+
};
32+
33+
export type TxInfo = {
34+
txHash: string;
35+
chainId: number;
36+
blockNumber: string;
37+
blockTime: Date | null;
38+
cost: string;
39+
};
40+
41+
export type RelayData = {
42+
id: `0x${string}`;
43+
txHash: string;
44+
chainId: number;
45+
status: string;
46+
estimatedCost: string;
47+
requestForExecution: RequestForExecution;
48+
instruction?: Request;
49+
txs?: TxInfo[];
50+
indexed_at: Date;
51+
};
52+
53+
export enum RequestPrefix {
54+
ERM1 = "ERM1", // MM
55+
ERV1 = "ERV1", // VAA_V1
56+
ERN1 = "ERN1", // NTT_V1
57+
ERC1 = "ERC1", // CCTP_V1
58+
ERC2 = "ERC2", // CCTP_V2
59+
}
60+
61+
export type Capabilities = {
62+
requestPrefixes: Array<keyof typeof RequestPrefix>;
63+
gasDropOffLimit: string;
64+
maxGasLimit: string;
65+
maxMsgValue: string; // the maximum msgValue, inclusive of the gasDropOffLimit
66+
};
67+
68+
export interface CapabilitiesResponse {
69+
[chainId: string]: Capabilities;
70+
}
71+
72+
export async function fetchCapabilities(
73+
network: Network
74+
): Promise<CapabilitiesResponse> {
75+
const url = `${apiBaseUrl[network]}/v0/capabilities`;
76+
77+
try {
78+
const response = await axios.get<CapabilitiesResponse>(url);
79+
return response.data;
80+
} catch (error) {
81+
throw new Error(`Failed to fetch capabilities for network: ${network}.`);
82+
}
83+
}
84+
85+
export interface QuoteResponse {
86+
signedQuote: `0x${string}`;
87+
estimatedCost?: string;
88+
}
89+
90+
export async function fetchSignedQuote(
91+
network: Network,
92+
srcChain: Chain,
93+
dstChain: Chain,
94+
relayInstructions: string // TODO: `0x:${string}`
95+
): Promise<QuoteResponse> {
96+
const url = `${apiBaseUrl[network]}/v0/quote`;
97+
98+
try {
99+
const response = await axios.post<QuoteResponse>(url, {
100+
srcChain: toChainId(srcChain),
101+
dstChain: toChainId(dstChain),
102+
relayInstructions,
103+
});
104+
return response.data;
105+
} catch (error) {
106+
throw new Error(`Failed to fetch signed quote.`);
107+
}
108+
}
109+
110+
export interface StatusResponse extends RelayData {
111+
signedQuote: SignedQuote;
112+
estimatedCost: string;
113+
}
114+
115+
// Fetch Status
116+
export async function fetchStatus(
117+
network: Network,
118+
txHash: string,
119+
chain: Chain
120+
): Promise<StatusResponse[]> {
121+
const url = `${apiBaseUrl[network]}/v0/status/tx`;
122+
123+
try {
124+
const response = await axios.post<StatusResponse[]>(url, {
125+
txHash,
126+
chainId: toChainId(chain),
127+
});
128+
return response.data;
129+
} catch (error) {
130+
throw new Error(`Failed to fetch status for txHash: ${txHash}.`);
131+
}
132+
}
133+
134+
export function isRelayStatusFailed(status: string): boolean {
135+
return (
136+
status === RelayStatus.Failed || // this could happen if simulation fails
137+
status === RelayStatus.Underpaid || // only happens if you don't pay at least the costEstimate
138+
status === RelayStatus.Unsupported || // capabilities check didn't pass
139+
status === RelayStatus.Aborted
140+
);
141+
}
142+
4143
const MAX_U16 = 65_535n;
5144
export function calculateReferrerFee(
6145
_amount: sdkAmount.Amount,

sdk/route/src/multiTokenManual.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,18 +491,20 @@ export class MultiTokenNttManualRoute<N extends Network>
491491
);
492492

493493
if (queuedTransfer !== null) {
494-
return {
494+
receipt = {
495495
...receipt,
496496
state: TransferState.DestinationQueued,
497497
queueReleaseTime: new Date(
498498
queuedTransfer.rateLimitExpiryTimestamp * 1000
499499
),
500500
} satisfies DestinationQueuedTransferReceipt<MultiTokenNttRoute.ManualAttestationReceipt>;
501+
yield receipt;
501502
} else if (await destinationNtt.getIsExecuted(vaa)) {
502-
return {
503+
receipt = {
503504
...receipt,
504505
state: TransferState.DestinationFinalized,
505506
} satisfies CompletedTransferReceipt<MultiTokenNttRoute.ManualAttestationReceipt>;
507+
yield receipt;
506508
}
507509
}
508510

sdk/route/src/tracking.ts

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
getAxelarTransactionStatus,
1313
getAxelarExplorerUrl,
1414
} from "@wormhole-foundation/sdk-evm-ntt";
15+
import { fetchStatus, isRelayStatusFailed } from "./executor/utils.js";
1516

1617
export async function trackExecutor<
1718
R extends MultiTokenNttRoute.ManualTransferReceipt
@@ -36,15 +37,17 @@ export async function trackExecutor<
3637
);
3738

3839
if (wormholeAttested) {
39-
return isFailed(receipt)
40-
? {
41-
...receipt,
42-
state: TransferState.Attested,
43-
// reset the error if we were previously failed
44-
// @ts-ignore
45-
error: undefined,
46-
}
47-
: receipt;
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;
4851
}
4952

5053
// Check if the relay was successful or failed
@@ -53,12 +56,7 @@ export async function trackExecutor<
5356
if (!txStatus) throw new Error("No transaction status found");
5457

5558
const relayStatus = txStatus.status;
56-
if (
57-
relayStatus === RelayStatus.Failed || // this could happen if simulation fails
58-
relayStatus === RelayStatus.Underpaid || // only happens if you don't pay at least the costEstimate
59-
relayStatus === RelayStatus.Unsupported || // capabilities check didn't pass
60-
relayStatus === RelayStatus.Aborted // An unrecoverable error indicating the attempt should stop (bad data, pre-flight checks failed, or chain-specific conditions)
61-
) {
59+
if (isRelayStatusFailed(relayStatus)) {
6260
receipt = {
6361
...receipt,
6462
state: TransferState.Failed,
@@ -104,15 +102,20 @@ export async function trackAxelar<
104102
axelarTransceiver.index
105103
);
106104

105+
console.log("Axelar attested:", axelarAttested);
106+
107107
if (axelarAttested) {
108-
return isFailed(receipt)
109-
? {
110-
...receipt,
111-
state: TransferState.Attested,
112-
// reset the error if we were previously failed
113-
error: undefined,
114-
}
115-
: receipt;
108+
// Clear error state if relay status is not an error
109+
if (isFailed(receipt)) {
110+
return {
111+
...receipt,
112+
state: TransferState.Attested,
113+
// @ts-ignore
114+
error: undefined,
115+
};
116+
}
117+
118+
return receipt;
116119
}
117120

118121
// Check relayer status
@@ -123,6 +126,8 @@ export async function trackAxelar<
123126
txid
124127
);
125128

129+
console.log("Axelar status:", axelarStatus);
130+
126131
if (axelarStatus.error) {
127132
return {
128133
...receipt,

0 commit comments

Comments
 (0)