@aptos-labs/cross-chain-core 5.9.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CrossChainCore.d.ts +75 -0
- package/dist/CrossChainCore.d.ts.map +1 -1
- package/dist/index.js +360 -161
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +361 -165
- package/dist/index.mjs.map +1 -1
- package/dist/providers/wormhole/signers/AptosLocalSigner.d.ts +8 -6
- package/dist/providers/wormhole/signers/AptosLocalSigner.d.ts.map +1 -1
- package/dist/providers/wormhole/signers/AptosSigner.d.ts +2 -1
- package/dist/providers/wormhole/signers/AptosSigner.d.ts.map +1 -1
- package/dist/providers/wormhole/signers/EthereumSigner.d.ts +1 -1
- package/dist/providers/wormhole/signers/EthereumSigner.d.ts.map +1 -1
- package/dist/providers/wormhole/signers/Signer.d.ts +10 -2
- package/dist/providers/wormhole/signers/Signer.d.ts.map +1 -1
- package/dist/providers/wormhole/signers/SolanaLocalSigner.d.ts +4 -0
- package/dist/providers/wormhole/signers/SolanaLocalSigner.d.ts.map +1 -1
- package/dist/providers/wormhole/signers/SolanaSigner.d.ts.map +1 -1
- package/dist/providers/wormhole/signers/solanaUtils.d.ts.map +1 -1
- package/dist/providers/wormhole/types.d.ts +78 -1
- package/dist/providers/wormhole/types.d.ts.map +1 -1
- package/dist/providers/wormhole/wormhole.d.ts +27 -1
- package/dist/providers/wormhole/wormhole.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +3 -3
- package/src/CrossChainCore.ts +91 -4
- package/src/providers/wormhole/signers/AptosLocalSigner.ts +27 -14
- package/src/providers/wormhole/signers/AptosSigner.ts +10 -1
- package/src/providers/wormhole/signers/EthereumSigner.ts +57 -6
- package/src/providers/wormhole/signers/Signer.ts +19 -2
- package/src/providers/wormhole/signers/SolanaLocalSigner.ts +7 -0
- package/src/providers/wormhole/signers/SolanaSigner.ts +4 -1
- package/src/providers/wormhole/signers/solanaUtils.ts +43 -19
- package/src/providers/wormhole/types.ts +100 -1
- package/src/providers/wormhole/wormhole.ts +138 -28
- package/src/version.ts +1 -1
|
@@ -15,10 +15,12 @@ import {
|
|
|
15
15
|
Chain,
|
|
16
16
|
CrossChainProvider,
|
|
17
17
|
CrossChainCore,
|
|
18
|
+
EVM_CHAIN_NAMES,
|
|
18
19
|
} from "../../CrossChainCore";
|
|
19
20
|
import { logger } from "../../utils/logger";
|
|
20
21
|
import { serializeReceipt } from "../../utils/receiptSerialization";
|
|
21
22
|
import { AptosLocalSigner } from "./signers/AptosLocalSigner";
|
|
23
|
+
import { isAccount } from "./signers/AptosSigner";
|
|
22
24
|
import { Signer } from "./signers/Signer";
|
|
23
25
|
import { ChainConfig } from "../../config";
|
|
24
26
|
import { createCCTPRoute } from "./utils";
|
|
@@ -38,7 +40,10 @@ import {
|
|
|
38
40
|
WormholeInitiateWithdrawResponse,
|
|
39
41
|
WormholeClaimWithdrawRequest,
|
|
40
42
|
WormholeClaimWithdrawResponse,
|
|
43
|
+
RetryWithdrawClaimRequest,
|
|
44
|
+
RetryWithdrawClaimResponse,
|
|
41
45
|
WithdrawError,
|
|
46
|
+
TransferError,
|
|
42
47
|
} from "./types";
|
|
43
48
|
import { SolanaDerivedWallet } from "@aptos-labs/derived-wallet-solana";
|
|
44
49
|
import { EIP1193DerivedWallet } from "@aptos-labs/derived-wallet-ethereum";
|
|
@@ -80,16 +85,31 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
80
85
|
const isMainnet = dappNetwork === Network.MAINNET;
|
|
81
86
|
const platforms: PlatformLoader<any>[] = [aptos, solana, evm, sui];
|
|
82
87
|
|
|
83
|
-
//
|
|
88
|
+
// RPC resolution order per chain:
|
|
89
|
+
// 1. User-provided config (solanaConfig / suiConfig / evmConfig)
|
|
90
|
+
// 2. Built-in defaultRpc from CHAINS config
|
|
91
|
+
const dappConfig = this.crossChainCore._dappConfig;
|
|
92
|
+
const chains = this.crossChainCore.CHAINS;
|
|
93
|
+
|
|
84
94
|
const solanaRpc =
|
|
85
|
-
|
|
86
|
-
|
|
95
|
+
dappConfig?.solanaConfig?.rpc ?? chains["Solana"]?.defaultRpc;
|
|
96
|
+
|
|
97
|
+
const suiRpc = dappConfig?.suiConfig?.rpc ?? chains["Sui"]?.defaultRpc;
|
|
98
|
+
|
|
99
|
+
const evmChainsConfig: Record<string, { rpc: string }> = {};
|
|
100
|
+
for (const name of EVM_CHAIN_NAMES) {
|
|
101
|
+
const rpc =
|
|
102
|
+
dappConfig?.evmConfig?.[name]?.rpc ?? chains[name]?.defaultRpc;
|
|
103
|
+
if (rpc) {
|
|
104
|
+
evmChainsConfig[name] = { rpc };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
87
107
|
|
|
88
108
|
const wh = await wormhole(isMainnet ? "Mainnet" : "Testnet", platforms, {
|
|
89
109
|
chains: {
|
|
90
|
-
Solana: {
|
|
91
|
-
|
|
92
|
-
|
|
110
|
+
...(solanaRpc ? { Solana: { rpc: solanaRpc } } : {}),
|
|
111
|
+
...(suiRpc ? { Sui: { rpc: suiRpc } } : {}),
|
|
112
|
+
...evmChainsConfig,
|
|
93
113
|
},
|
|
94
114
|
});
|
|
95
115
|
this._wormholeContext = wh;
|
|
@@ -162,7 +182,8 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
162
182
|
async submitCCTPTransfer(
|
|
163
183
|
input: WormholeSubmitTransferRequest,
|
|
164
184
|
): Promise<WormholeStartTransferResponse> {
|
|
165
|
-
const { sourceChain, wallet, destinationAddress } =
|
|
185
|
+
const { sourceChain, wallet, destinationAddress, onTransactionSigned } =
|
|
186
|
+
input;
|
|
166
187
|
|
|
167
188
|
if (!this._wormholeContext) {
|
|
168
189
|
await this.setWormholeContext(sourceChain);
|
|
@@ -201,6 +222,8 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
201
222
|
{},
|
|
202
223
|
wallet,
|
|
203
224
|
this.crossChainCore,
|
|
225
|
+
undefined,
|
|
226
|
+
onTransactionSigned,
|
|
204
227
|
);
|
|
205
228
|
|
|
206
229
|
logger.log("signer", signer);
|
|
@@ -225,10 +248,18 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
225
248
|
async claimCCTPTransfer(
|
|
226
249
|
input: WormholeClaimTransferRequest,
|
|
227
250
|
): Promise<{ destinationChainTxnId: string }> {
|
|
228
|
-
let { receipt, mainSigner, sponsorAccount } = input;
|
|
251
|
+
let { receipt, mainSigner, sponsorAccount, onTransactionSigned } = input;
|
|
229
252
|
if (!this.wormholeRoute) {
|
|
230
253
|
throw new Error("Wormhole route not initialized");
|
|
231
254
|
}
|
|
255
|
+
if (sponsorAccount && !isAccount(sponsorAccount)) {
|
|
256
|
+
throw new Error(
|
|
257
|
+
"AptosLocalSigner does not support GasStationApiKey as a sponsor account. " +
|
|
258
|
+
"Wormhole claim transactions are script-based and cannot be submitted " +
|
|
259
|
+
"via the gas station. Please provide an Account instance as the sponsor, " +
|
|
260
|
+
"or omit the sponsor account.",
|
|
261
|
+
);
|
|
262
|
+
}
|
|
232
263
|
|
|
233
264
|
logger.log("mainSigner", mainSigner.accountAddress.toString());
|
|
234
265
|
|
|
@@ -248,7 +279,8 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
248
279
|
{},
|
|
249
280
|
mainSigner, // the account that signs the "claim" transaction
|
|
250
281
|
sponsorAccount, // the fee payer account
|
|
251
|
-
this.crossChainCore
|
|
282
|
+
this.crossChainCore,
|
|
283
|
+
onTransactionSigned,
|
|
252
284
|
);
|
|
253
285
|
|
|
254
286
|
if (routes.isManual(this.wormholeRoute)) {
|
|
@@ -304,12 +336,21 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
304
336
|
// Submit transfer transaction from origin chain
|
|
305
337
|
let { originChainTxnId, receipt } = await this.submitCCTPTransfer(input);
|
|
306
338
|
// Claim transfer transaction on destination chain
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
339
|
+
try {
|
|
340
|
+
const { destinationChainTxnId } = await this.claimCCTPTransfer({
|
|
341
|
+
receipt,
|
|
342
|
+
mainSigner: input.mainSigner,
|
|
343
|
+
sponsorAccount: input.sponsorAccount,
|
|
344
|
+
onTransactionSigned: input.onTransactionSigned,
|
|
345
|
+
});
|
|
346
|
+
return { originChainTxnId, destinationChainTxnId };
|
|
347
|
+
} catch (error: any) {
|
|
348
|
+
throw new TransferError(
|
|
349
|
+
error?.message ?? "Transfer claim failed after source-chain burn",
|
|
350
|
+
originChainTxnId,
|
|
351
|
+
error,
|
|
352
|
+
);
|
|
353
|
+
}
|
|
313
354
|
}
|
|
314
355
|
|
|
315
356
|
// --- Split withdraw flow: initiateWithdraw + trackWithdraw + claimWithdraw ---
|
|
@@ -322,7 +363,8 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
322
363
|
async initiateWithdraw(
|
|
323
364
|
input: WormholeInitiateWithdrawRequest,
|
|
324
365
|
): Promise<WormholeInitiateWithdrawResponse> {
|
|
325
|
-
const { wallet, destinationAddress, sponsorAccount } =
|
|
366
|
+
const { wallet, destinationAddress, sponsorAccount, onTransactionSigned } =
|
|
367
|
+
input;
|
|
326
368
|
|
|
327
369
|
if (!this._wormholeContext) {
|
|
328
370
|
throw new Error("Wormhole context not initialized");
|
|
@@ -333,13 +375,12 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
333
375
|
|
|
334
376
|
const signer = new Signer(
|
|
335
377
|
this.getChainConfig("Aptos"),
|
|
336
|
-
(
|
|
337
|
-
await wallet.features["aptos:account"].account()
|
|
338
|
-
).address.toString(),
|
|
378
|
+
(await wallet.features["aptos:account"].account()).address.toString(),
|
|
339
379
|
{},
|
|
340
380
|
wallet,
|
|
341
381
|
this.crossChainCore,
|
|
342
382
|
sponsorAccount,
|
|
383
|
+
onTransactionSigned,
|
|
343
384
|
);
|
|
344
385
|
|
|
345
386
|
const wormholeDestAddress = Wormhole.chainAddress(
|
|
@@ -367,9 +408,7 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
367
408
|
* Phase 2: Tracks a withdraw receipt until attestation is ready.
|
|
368
409
|
* This polls Wormhole and returns once the receipt reaches the Attested state.
|
|
369
410
|
*/
|
|
370
|
-
async trackWithdraw(
|
|
371
|
-
receipt: routes.Receipt,
|
|
372
|
-
): Promise<routes.Receipt> {
|
|
411
|
+
async trackWithdraw(receipt: routes.Receipt): Promise<routes.Receipt> {
|
|
373
412
|
if (!this.wormholeRoute) {
|
|
374
413
|
throw new Error("Wormhole route not initialized");
|
|
375
414
|
}
|
|
@@ -412,13 +451,13 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
412
451
|
async claimWithdraw(
|
|
413
452
|
input: WormholeClaimWithdrawRequest,
|
|
414
453
|
): Promise<WormholeClaimWithdrawResponse> {
|
|
415
|
-
const {
|
|
454
|
+
const { claimChain, destinationAddress, receipt } = input;
|
|
416
455
|
|
|
417
456
|
// Server-side claim path: Solana destination with configured serverClaimUrl
|
|
418
457
|
const serverClaimUrl =
|
|
419
458
|
this.crossChainCore._dappConfig?.solanaConfig?.serverClaimUrl;
|
|
420
459
|
|
|
421
|
-
if (
|
|
460
|
+
if (claimChain === "Solana" && serverClaimUrl) {
|
|
422
461
|
logger.log("claimWithdraw: using server-side claim via", serverClaimUrl);
|
|
423
462
|
|
|
424
463
|
const response = await fetch(serverClaimUrl, {
|
|
@@ -427,7 +466,7 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
427
466
|
body: JSON.stringify({
|
|
428
467
|
receipt: serializeReceipt(receipt),
|
|
429
468
|
destinationAddress,
|
|
430
|
-
|
|
469
|
+
claimChain,
|
|
431
470
|
}),
|
|
432
471
|
});
|
|
433
472
|
|
|
@@ -455,11 +494,14 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
455
494
|
}
|
|
456
495
|
|
|
457
496
|
const claimSigner = new Signer(
|
|
458
|
-
this.getChainConfig(
|
|
497
|
+
this.getChainConfig(claimChain),
|
|
459
498
|
destinationAddress,
|
|
460
499
|
{},
|
|
461
500
|
input.wallet,
|
|
462
501
|
this.crossChainCore,
|
|
502
|
+
undefined,
|
|
503
|
+
input.onTransactionSigned,
|
|
504
|
+
false,
|
|
463
505
|
);
|
|
464
506
|
|
|
465
507
|
if (routes.isManual(this.wormholeRoute)) {
|
|
@@ -489,7 +531,14 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
489
531
|
async withdraw(
|
|
490
532
|
input: WormholeWithdrawRequest,
|
|
491
533
|
): Promise<WormholeWithdrawResponse> {
|
|
492
|
-
const {
|
|
534
|
+
const {
|
|
535
|
+
sourceChain,
|
|
536
|
+
wallet,
|
|
537
|
+
destinationAddress,
|
|
538
|
+
sponsorAccount,
|
|
539
|
+
onPhaseChange,
|
|
540
|
+
onTransactionSigned,
|
|
541
|
+
} = input;
|
|
493
542
|
|
|
494
543
|
// Phase 1: Initiate — user signs Aptos burn
|
|
495
544
|
onPhaseChange?.("initiating");
|
|
@@ -497,6 +546,7 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
497
546
|
wallet,
|
|
498
547
|
destinationAddress,
|
|
499
548
|
sponsorAccount,
|
|
549
|
+
onTransactionSigned,
|
|
500
550
|
});
|
|
501
551
|
|
|
502
552
|
// Phases 2 & 3 are wrapped so that, if they fail, the caller still
|
|
@@ -511,10 +561,11 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
511
561
|
currentPhase = "claiming";
|
|
512
562
|
onPhaseChange?.("claiming");
|
|
513
563
|
const { destinationChainTxnId } = await this.claimWithdraw({
|
|
514
|
-
sourceChain,
|
|
564
|
+
claimChain: sourceChain,
|
|
515
565
|
destinationAddress: destinationAddress.toString(),
|
|
516
566
|
receipt: attestedReceipt,
|
|
517
567
|
wallet,
|
|
568
|
+
onTransactionSigned,
|
|
518
569
|
});
|
|
519
570
|
|
|
520
571
|
return { originChainTxnId, destinationChainTxnId };
|
|
@@ -528,6 +579,65 @@ export class WormholeProvider implements CrossChainProvider<
|
|
|
528
579
|
}
|
|
529
580
|
}
|
|
530
581
|
|
|
582
|
+
/**
|
|
583
|
+
* Retries a failed `claimWithdraw` call with configurable exponential backoff.
|
|
584
|
+
*
|
|
585
|
+
* Use this when the claim phase of a withdrawal fails (e.g., RPC instability,
|
|
586
|
+
* network congestion) but the Aptos burn transaction has already been submitted.
|
|
587
|
+
* The attested receipt can be recovered from the `WithdrawError` thrown by
|
|
588
|
+
* `withdraw()` and passed directly to this method.
|
|
589
|
+
*
|
|
590
|
+
* @example
|
|
591
|
+
* ```ts
|
|
592
|
+
* try {
|
|
593
|
+
* await provider.withdraw({ ... });
|
|
594
|
+
* } catch (error) {
|
|
595
|
+
* if (error instanceof WithdrawError && error.phase === "claiming") {
|
|
596
|
+
* const result = await provider.retryWithdrawClaim({
|
|
597
|
+
* sourceChain,
|
|
598
|
+
* destinationAddress,
|
|
599
|
+
* receipt: attestedReceipt,
|
|
600
|
+
* wallet,
|
|
601
|
+
* maxRetries: 5,
|
|
602
|
+
* });
|
|
603
|
+
* }
|
|
604
|
+
* }
|
|
605
|
+
* ```
|
|
606
|
+
*/
|
|
607
|
+
async retryWithdrawClaim(
|
|
608
|
+
input: RetryWithdrawClaimRequest,
|
|
609
|
+
): Promise<RetryWithdrawClaimResponse> {
|
|
610
|
+
const {
|
|
611
|
+
maxRetries = 5,
|
|
612
|
+
initialDelayMs = 2000,
|
|
613
|
+
backoffMultiplier = 2,
|
|
614
|
+
...claimInput
|
|
615
|
+
} = input;
|
|
616
|
+
|
|
617
|
+
let lastError: Error | undefined;
|
|
618
|
+
let delay = initialDelayMs;
|
|
619
|
+
|
|
620
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
621
|
+
try {
|
|
622
|
+
const result = await this.claimWithdraw(claimInput);
|
|
623
|
+
return { ...result, retriesUsed: attempt };
|
|
624
|
+
} catch (error) {
|
|
625
|
+
lastError = error as Error;
|
|
626
|
+
logger.log(
|
|
627
|
+
`retryWithdrawClaim: attempt ${attempt + 1}/${maxRetries + 1} failed: ${lastError.message}`,
|
|
628
|
+
);
|
|
629
|
+
if (attempt < maxRetries) {
|
|
630
|
+
await sleep(delay);
|
|
631
|
+
delay *= backoffMultiplier;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
throw new Error(
|
|
637
|
+
`Claim failed after ${maxRetries + 1} attempts: ${lastError?.message}`,
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
|
|
531
641
|
getChainConfig(chain: Chain): ChainConfig {
|
|
532
642
|
const chainConfig =
|
|
533
643
|
this.crossChainCore.CHAINS[
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CROSS_CHAIN_CORE_VERSION = "
|
|
1
|
+
export const CROSS_CHAIN_CORE_VERSION = "6.0.0";
|