Skip to content

Commit ee5ca60

Browse files
authored
Typescript SDK changes and bug fixes needed for Connect (#474)
* Typescript SDK changes and bug fixes needed for Connect - Added a WormholeTransferStandardRelayer payload type needed to parse the VAA for an automatic transfer between EVM chains - EVM: getIsExecuted should check if the transfer is inbound queued to determine if the transfer is completed - Solana: getIsExecuted should check if the inboxItem is released - Solana: getIsApproved should not swallow exception - Solana: getInboundQueuedTransfer should return null if the transfer is not queued - Bumped SDK dependencies needed for Connect * Added NTT quote warnings, semver ABI support, fixed queued transfer issues * Added getIsTransferInboundQueued method * bumped sdk deps to ^0.8
1 parent c62c572 commit ee5ca60

19 files changed

+693
-392
lines changed

evm/ts/package.json

+9-9
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,19 @@
4444
"test": "jest --config ./jest.config.ts"
4545
},
4646
"dependencies": {
47-
"@wormhole-foundation/sdk-base": "^0.7",
48-
"@wormhole-foundation/sdk-definitions": "^0.7",
47+
"@wormhole-foundation/sdk-base": "^0.8",
48+
"@wormhole-foundation/sdk-definitions": "^0.8",
4949
"@wormhole-foundation/sdk-definitions-ntt": "0.1.0-beta.0",
50-
"@wormhole-foundation/sdk-evm": "^0.7",
51-
"@wormhole-foundation/sdk-evm-core": "^0.7",
50+
"@wormhole-foundation/sdk-evm": "^0.8",
51+
"@wormhole-foundation/sdk-evm-core": "^0.8",
5252
"ethers": "^6.5.1"
5353
},
5454
"peerDependencies": {
5555
"@wormhole-foundation/sdk-definitions-ntt": "0.1.0-beta.0",
56-
"@wormhole-foundation/sdk-base": "^0.7",
57-
"@wormhole-foundation/sdk-definitions": "^0.7",
58-
"@wormhole-foundation/sdk-evm": "^0.7",
59-
"@wormhole-foundation/sdk-evm-core": "^0.7"
56+
"@wormhole-foundation/sdk-base": "^0.8",
57+
"@wormhole-foundation/sdk-definitions": "^0.8",
58+
"@wormhole-foundation/sdk-evm": "^0.8",
59+
"@wormhole-foundation/sdk-evm-core": "^0.8"
6060
},
6161
"devDependencies": {
6262
"@typechain/ethers-v6": "^0.5.1",
@@ -76,4 +76,4 @@
7676
}
7777
}
7878
}
79-
}
79+
}

evm/ts/src/bindings.ts

+18-12
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import { Provider } from "ethers";
22

33
import { _0_1_0, _1_0_0, _1_1_0 } from "./ethers-contracts/index.js";
4-
5-
export const AbiVersions = {
6-
"0.1.0": _0_1_0,
7-
"1.0.0": _1_0_0,
8-
"1.1.0": _1_1_0,
9-
default: _1_1_0,
10-
} as const;
11-
export type AbiVersion = keyof typeof AbiVersions;
4+
import { Ntt } from "@wormhole-foundation/sdk-definitions-ntt";
5+
6+
// This is a descending list of all ABI versions the SDK is aware of.
7+
// We check for the first match in descending order, allowing for higher minor and patch versions
8+
// being used by the live contract (these are supposed to still be compatible with older ABIs).
9+
export const abiVersions = [
10+
["1.1.0", _1_1_0],
11+
["1.0.0", _1_0_0],
12+
["0.1.0", _0_1_0],
13+
] as const;
14+
export type AbiVersion = (typeof abiVersions)[number][0];
1215

1316
export interface NttBindings {
1417
NttManager: NttManagerBindings;
@@ -36,8 +39,11 @@ export interface NttManagerBindings {
3639
connect(address: string, provider: Provider): NttManagerBindings.NttManager;
3740
}
3841

39-
export function loadAbiVersion(version: string) {
40-
if (!(version in AbiVersions))
41-
throw new Error(`Unknown ABI version: ${version}`);
42-
return AbiVersions[version as AbiVersion];
42+
export function loadAbiVersion(targetVersion: string) {
43+
for (const [abiVersion, abi] of abiVersions) {
44+
if (Ntt.abiVersionMatches(targetVersion, abiVersion)) {
45+
return abi;
46+
}
47+
}
48+
throw new Error(`Unknown ABI version: ${targetVersion}`);
4349
}

evm/ts/src/ntt.ts

+42-16
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import {
99
ChainAddress,
1010
ChainsConfig,
1111
Contracts,
12-
TokenAddress,
13-
VAA,
1412
serialize,
1513
universalAddress,
1614
} from "@wormhole-foundation/sdk-definitions";
@@ -100,7 +98,7 @@ export class EvmNtt<N extends Network, C extends EvmChains>
10098
readonly chain: C,
10199
readonly provider: Provider,
102100
readonly contracts: Contracts & { ntt?: Ntt.Contracts },
103-
readonly version: string = "default"
101+
readonly version: string = "1.0.0"
104102
) {
105103
if (!contracts.ntt) throw new Error("No Ntt Contracts provided");
106104

@@ -143,19 +141,41 @@ export class EvmNtt<N extends Network, C extends EvmChains>
143141
return enabled.filter((x) => x).length > 0;
144142
}
145143

146-
getIsExecuted(attestation: Ntt.Attestation): Promise<boolean> {
147-
const { emitterChain: chain, payload } =
148-
attestation as VAA<"Ntt:WormholeTransfer">;
149-
return this.manager.isMessageExecuted(
150-
Ntt.messageDigest(chain, payload["nttManagerPayload"])
144+
async getIsExecuted(attestation: Ntt.Attestation): Promise<boolean> {
145+
const payload =
146+
attestation.payloadName === "WormholeTransfer"
147+
? attestation.payload
148+
: attestation.payload.payload;
149+
const isExecuted = await this.manager.isMessageExecuted(
150+
Ntt.messageDigest(attestation.emitterChain, payload["nttManagerPayload"])
151+
);
152+
if (!isExecuted) return false;
153+
// Also check that the transfer is not queued for it to be considered complete
154+
return !(await this.getIsTransferInboundQueued(attestation));
155+
}
156+
157+
async getIsTransferInboundQueued(
158+
attestation: Ntt.Attestation
159+
): Promise<boolean> {
160+
const payload =
161+
attestation.payloadName === "WormholeTransfer"
162+
? attestation.payload
163+
: attestation.payload.payload;
164+
return (
165+
(await this.getInboundQueuedTransfer(
166+
attestation.emitterChain,
167+
payload["nttManagerPayload"]
168+
)) !== null
151169
);
152170
}
153171

154172
getIsApproved(attestation: Ntt.Attestation): Promise<boolean> {
155-
const { emitterChain: chain, payload } =
156-
attestation as VAA<"Ntt:WormholeTransfer">;
173+
const payload =
174+
attestation.payloadName === "WormholeTransfer"
175+
? attestation.payload
176+
: attestation.payload.payload;
157177
return this.manager.isMessageApproved(
158-
Ntt.messageDigest(chain, payload["nttManagerPayload"])
178+
Ntt.messageDigest(attestation.emitterChain, payload["nttManagerPayload"])
159179
);
160180
}
161181

@@ -311,7 +331,13 @@ export class EvmNtt<N extends Network, C extends EvmChains>
311331

312332
for (const idx in this.xcvrs) {
313333
const xcvr = this.xcvrs[idx]!;
314-
yield* xcvr.receive(attestations[idx]);
334+
const attestation = attestations[idx];
335+
if (attestation?.payloadName !== "WormholeTransfer") {
336+
// TODO: support standard relayer attestations
337+
// which must be submitted to the delivery provider
338+
throw new Error("Invalid attestation type for redeem");
339+
}
340+
yield* xcvr.receive(attestation);
315341
}
316342
}
317343

@@ -349,12 +375,12 @@ export class EvmNtt<N extends Network, C extends EvmChains>
349375
async *completeInboundQueuedTransfer(
350376
fromChain: Chain,
351377
transceiverMessage: Ntt.Message,
352-
token: TokenAddress<C>,
353378
payer?: AccountAddress<C>
354379
) {
355-
const tx = await this.manager.completeInboundQueuedTransfer(
356-
Ntt.messageDigest(fromChain, transceiverMessage)
357-
);
380+
const tx =
381+
await this.manager.completeInboundQueuedTransfer.populateTransaction(
382+
Ntt.messageDigest(fromChain, transceiverMessage)
383+
);
358384
yield this.createUnsignedTx(tx, "Ntt.completeInboundQueuedTransfer");
359385
}
360386

0 commit comments

Comments
 (0)