Skip to content

Commit ead475a

Browse files
authored
Merge branch 'main' into fix/symlink-spaces-in-path
2 parents 0940774 + 4f43691 commit ead475a

11 files changed

Lines changed: 327 additions & 95 deletions

File tree

cli/src/commands/token-transfer.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@ import type {
3939
Ntt,
4040
NttWithExecutor,
4141
} from "@wormhole-foundation/sdk-definitions-ntt";
42-
import "@wormhole-foundation/sdk-evm-ntt";
43-
import "@wormhole-foundation/sdk-solana-ntt";
44-
import "@wormhole-foundation/sdk-sui-ntt";
42+
import { register as registerEvm } from "@wormhole-foundation/sdk-evm-ntt";
43+
import { register as registerSolana } from "@wormhole-foundation/sdk-solana-ntt";
44+
import { register as registerSui } from "@wormhole-foundation/sdk-sui-ntt";
45+
46+
registerEvm();
47+
registerSolana();
48+
registerSui();
4549
import { loadConfig, type ChainConfig, type Config } from "../deployments";
4650
import fs from "fs";
4751
import readline from "readline";

cli/src/index.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ import type { Network } from "@wormhole-foundation/sdk-connect";
44
import type { WormholeConfigOverrides } from "@wormhole-foundation/sdk-connect";
55
import yargs from "yargs";
66
import { hideBin } from "yargs/helpers";
7-
import "@wormhole-foundation/sdk-evm-ntt";
8-
import "@wormhole-foundation/sdk-solana-ntt";
9-
import "@wormhole-foundation/sdk-sui-ntt";
10-
import "@wormhole-foundation/sdk-definitions-ntt";
7+
import { register as registerEvm } from "@wormhole-foundation/sdk-evm-ntt";
8+
import { register as registerSolana } from "@wormhole-foundation/sdk-solana-ntt";
9+
import { register as registerSui } from "@wormhole-foundation/sdk-sui-ntt";
10+
11+
registerEvm();
12+
registerSolana();
13+
registerSui();
1114

1215
import { createTokenTransferCommand } from "./commands/token-transfer";
1316
import {

evm/ts/src/index.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,11 @@ import { EvmMultiTokenNtt } from "./multiTokenNtt.js";
99
import { EvmMultiTokenNttWithExecutor } from "./multiTokenNttWithExecutor.js";
1010
import { register as registerDefinitions } from "@wormhole-foundation/sdk-definitions-ntt";
1111

12+
let _explicitlyRegistered = false;
13+
1214
/** Explicitly register EVM NTT protocols. Idempotent — safe to call multiple times. */
13-
export function register(topLevel = false): void {
14-
if (topLevel) {
15-
console.warn(
16-
"@wormhole-foundation/sdk-evm-ntt: auto-registration on import is deprecated. Import { register } and call it explicitly."
17-
);
18-
}
15+
export function register(_deprecatedTopLevel?: boolean): void {
16+
_explicitlyRegistered = true;
1917
registerDefinitions();
2018
if (!protocolIsRegistered(_platform, "Ntt")) {
2119
registerProtocol(_platform, "Ntt", EvmNtt);
@@ -35,9 +33,17 @@ export function register(topLevel = false): void {
3533
}
3634
}
3735

38-
// Backward-compatible: auto-register on import
36+
// Backward-compatible: auto-register on import.
37+
// Deferred so that consumers who call register() explicitly don't see the warning.
3938
// TODO: remove this next time we are cool with a major version bump and are OK requiring integrators to make code changes
40-
register(true);
39+
setTimeout(() => {
40+
if (!_explicitlyRegistered) {
41+
console.warn(
42+
"@wormhole-foundation/sdk-evm-ntt: auto-registration on import is deprecated. Import { register } and call it explicitly."
43+
);
44+
}
45+
register();
46+
}, 0);
4147

4248
export * as ethers_contracts from "./ethers-contracts/index.js";
4349
export * from "./ntt.js";
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
describe("definitions register warning behavior", () => {
2+
let warnSpy: jest.SpyInstance;
3+
4+
beforeEach(() => {
5+
jest.resetModules();
6+
jest.useFakeTimers();
7+
warnSpy = jest.spyOn(console, "warn").mockImplementation(() => {});
8+
});
9+
10+
afterEach(() => {
11+
jest.runOnlyPendingTimers();
12+
jest.useRealTimers();
13+
warnSpy.mockRestore();
14+
});
15+
16+
test("does not warn when register() is called explicitly", async () => {
17+
await jest.isolateModulesAsync(async () => {
18+
const mod = await import("../src/index.js");
19+
mod.register();
20+
});
21+
22+
jest.runOnlyPendingTimers();
23+
expect(warnSpy).not.toHaveBeenCalled();
24+
});
25+
26+
test("warns when relying on side-effect import auto-registration", async () => {
27+
await jest.isolateModulesAsync(async () => {
28+
await import("../src/index.js");
29+
});
30+
31+
jest.runOnlyPendingTimers();
32+
expect(warnSpy).toHaveBeenCalledWith(
33+
expect.stringContaining(
34+
"@wormhole-foundation/sdk-definitions-ntt: auto-registration on import is deprecated."
35+
)
36+
);
37+
});
38+
});

sdk/definitions/src/index.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ import {
88
nttNamedPayloads,
99
} from "./layouts/index.js";
1010

11+
let _explicitlyRegistered = false;
12+
1113
/** Explicitly register NTT payload types. Idempotent — safe to call multiple times. */
12-
export function register(topLevel = false): void {
13-
if (topLevel) {
14-
console.warn(
15-
"@wormhole-foundation/sdk-definitions-ntt: auto-registration on import is deprecated. Import { register } and call it explicitly."
16-
);
17-
}
14+
export function register(_deprecatedTopLevel?: boolean): void {
15+
_explicitlyRegistered = true;
1816
if (!payloadFactory.has(composeLiteral("Ntt", nttNamedPayloads[0]![0]))) {
1917
registerPayloadTypes("Ntt", nttNamedPayloads);
2018
}
@@ -27,9 +25,17 @@ export function register(topLevel = false): void {
2725
}
2826
}
2927

30-
// Backward-compatible: auto-register on import
28+
// Backward-compatible: auto-register on import.
29+
// Deferred so that consumers who call register() explicitly don't see the warning.
3130
// TODO: remove this next time we are cool with a major version bump and are OK requiring integrators to make code changes
32-
register(true);
31+
setTimeout(() => {
32+
if (!_explicitlyRegistered) {
33+
console.warn(
34+
"@wormhole-foundation/sdk-definitions-ntt: auto-registration on import is deprecated. Import { register } and call it explicitly."
35+
);
36+
}
37+
register();
38+
}, 0);
3339

3440
export * from "./ntt.js";
3541
export * from "./nttWithExecutor.js";

sdk/route/src/executor/executor.ts

Lines changed: 95 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
TransferReceipt as _TransferReceipt,
1414
TransferState,
1515
UniversalAddress,
16+
UnsignedTransaction,
1617
Wormhole,
1718
WormholeMessageId,
1819
amount,
@@ -39,6 +40,7 @@ import "@wormhole-foundation/sdk-definitions-ntt";
3940
import { NttRoute } from "../types.js";
4041
import {
4142
calculateReferrerFee,
43+
collectTransactions,
4244
fetchCapabilities,
4345
fetchSignedQuote,
4446
fetchStatus,
@@ -449,12 +451,12 @@ export class NttExecutorRoute<N extends Network>
449451
};
450452
}
451453

452-
async initiate(
454+
async _buildInitiateXfer(
453455
request: routes.RouteTransferRequest<N>,
454-
signer: Signer,
455-
quote: Q,
456-
to: ChainAddress
457-
): Promise<R> {
456+
sender: ChainAddress,
457+
to: ChainAddress,
458+
quote: Q
459+
) {
458460
if (!quote.details) {
459461
throw new Error("Missing quote details");
460462
}
@@ -477,7 +479,10 @@ export class NttExecutorRoute<N extends Network>
477479
});
478480

479481
const { fromChain } = request;
480-
const sender = Wormhole.parseAddress(signer.chain(), signer.address());
482+
const senderAddress = Wormhole.parseAddress(
483+
sender.chain,
484+
sender.address.toString()
485+
);
481486

482487
const nttWithExec = await fromChain.getProtocol("NttWithExecutor", {
483488
ntt: params.normalizedParams.sourceContracts,
@@ -489,15 +494,43 @@ export class NttExecutorRoute<N extends Network>
489494

490495
const wrapNative = isNative(request.source.id.address);
491496

492-
const initXfer = nttWithExec.transfer(
493-
sender,
497+
return nttWithExec.transfer(
498+
senderAddress,
494499
to,
495500
amount.units(params.normalizedParams.amount),
496501
details,
497502
ntt,
498503
wrapNative
499504
);
500-
const txids = await signSendWait(fromChain, initXfer, signer);
505+
}
506+
507+
async buildInitiateTransactions(
508+
request: routes.RouteTransferRequest<N>,
509+
sender: ChainAddress,
510+
recipient: ChainAddress,
511+
quote: Q
512+
): Promise<UnsignedTransaction<N, Chain>[]> {
513+
const xfer = await this._buildInitiateXfer(
514+
request,
515+
sender,
516+
recipient,
517+
quote
518+
);
519+
const txs = await collectTransactions(xfer);
520+
return txs as UnsignedTransaction<N, Chain>[];
521+
}
522+
523+
async initiate(
524+
request: routes.RouteTransferRequest<N>,
525+
signer: Signer,
526+
quote: Q,
527+
to: ChainAddress
528+
): Promise<R> {
529+
const sender = Wormhole.chainAddress(signer.chain(), signer.address());
530+
const xfer = await this._buildInitiateXfer(request, sender, to, quote);
531+
532+
const { fromChain } = request;
533+
const txids = await signSendWait(fromChain, xfer, signer);
501534

502535
// Status the transfer immediately before returning
503536
let statusAttempts = 0;
@@ -532,13 +565,13 @@ export class NttExecutorRoute<N extends Network>
532565
to: to.chain,
533566
state: TransferState.SourceInitiated,
534567
originTxs: txids,
535-
params,
568+
params: quote.params,
536569
};
537570
}
538571

539-
async complete(signer: Signer, receipt: R): Promise<R> {
572+
async _buildCompleteXfer(sender: ChainAddress, receipt: R) {
540573
if (!isAttested(receipt) && !isFailed(receipt)) {
541-
if (isRedeemed(receipt)) return receipt;
574+
if (isRedeemed(receipt)) return null;
542575
throw new Error(
543576
"The source must be finalized in order to complete the transfer"
544577
);
@@ -552,16 +585,36 @@ export class NttExecutorRoute<N extends Network>
552585
const ntt = await toChain.getProtocol("Ntt", {
553586
ntt: receipt.params.normalizedParams.destinationContracts,
554587
});
555-
const sender = Wormhole.parseAddress(signer.chain(), signer.address());
556-
const completeXfer = ntt.redeem([receipt.attestation.attestation], sender);
588+
const senderAddress = Wormhole.parseAddress(
589+
sender.chain,
590+
sender.address.toString()
591+
);
592+
return ntt.redeem([receipt.attestation.attestation], senderAddress);
593+
}
594+
595+
async buildCompleteTransactions(
596+
sender: ChainAddress,
597+
receipt: R
598+
): Promise<UnsignedTransaction<N, Chain>[]> {
599+
const xfer = await this._buildCompleteXfer(sender, receipt);
600+
if (xfer === null) return [];
601+
602+
const txs = await collectTransactions(xfer);
603+
return txs as UnsignedTransaction<N, Chain>[];
604+
}
605+
606+
async complete(signer: Signer, receipt: R): Promise<R> {
607+
const sender = Wormhole.chainAddress(signer.chain(), signer.address());
608+
const xfer = await this._buildCompleteXfer(sender, receipt);
609+
if (xfer === null) return receipt;
557610

558-
const txids = await signSendWait(toChain, completeXfer, signer);
611+
const toChain = this.wh.getChain(receipt.to);
612+
const txids = await signSendWait(toChain, xfer, signer);
559613
return {
560614
...receipt,
561615
state: TransferState.DestinationInitiated,
562-
attestation: receipt.attestation,
563616
destinationTxs: txids,
564-
};
617+
} as R;
565618
}
566619

567620
async resume(tx: TransactionId): Promise<R> {
@@ -643,7 +696,7 @@ export class NttExecutorRoute<N extends Network>
643696

644697
// Even though this is an automatic route, the transfer may need to be
645698
// manually finalized if it was queued
646-
async finalize(signer: Signer, receipt: R): Promise<R> {
699+
async _buildFinalizeXfer(sender: ChainAddress, receipt: R) {
647700
if (!isDestinationQueued(receipt)) {
648701
throw new Error(
649702
"The transfer must be destination queued in order to finalize"
@@ -658,13 +711,34 @@ export class NttExecutorRoute<N extends Network>
658711
const ntt = await toChain.getProtocol("Ntt", {
659712
ntt: receipt.params.normalizedParams.destinationContracts,
660713
});
661-
const sender = Wormhole.chainAddress(signer.chain(), signer.address());
662-
const completeTransfer = ntt.completeInboundQueuedTransfer(
714+
return ntt.completeInboundQueuedTransfer(
663715
receipt.from,
664716
vaa.payload["nttManagerPayload"],
665717
sender.address
666718
);
667-
const finalizeTxids = await signSendWait(toChain, completeTransfer, signer);
719+
}
720+
721+
async buildFinalizeTransactions(
722+
sender: ChainAddress,
723+
receipt: R
724+
): Promise<UnsignedTransaction<N, Chain>[]> {
725+
const txs = await collectTransactions(
726+
await this._buildFinalizeXfer(sender, receipt)
727+
);
728+
return txs as UnsignedTransaction<N, Chain>[];
729+
}
730+
731+
async finalize(signer: Signer, receipt: R): Promise<R> {
732+
if (!isDestinationQueued(receipt)) {
733+
throw new Error(
734+
"The transfer must be destination queued in order to finalize"
735+
);
736+
}
737+
738+
const sender = Wormhole.chainAddress(signer.chain(), signer.address());
739+
const xfer = await this._buildFinalizeXfer(sender, receipt);
740+
const toChain = this.wh.getChain(receipt.to);
741+
const finalizeTxids = await signSendWait(toChain, xfer, signer);
668742
return {
669743
...receipt,
670744
state: TransferState.DestinationFinalized,

0 commit comments

Comments
 (0)