@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.
Files changed (35) hide show
  1. package/dist/CrossChainCore.d.ts +75 -0
  2. package/dist/CrossChainCore.d.ts.map +1 -1
  3. package/dist/index.js +360 -161
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +361 -165
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/providers/wormhole/signers/AptosLocalSigner.d.ts +8 -6
  8. package/dist/providers/wormhole/signers/AptosLocalSigner.d.ts.map +1 -1
  9. package/dist/providers/wormhole/signers/AptosSigner.d.ts +2 -1
  10. package/dist/providers/wormhole/signers/AptosSigner.d.ts.map +1 -1
  11. package/dist/providers/wormhole/signers/EthereumSigner.d.ts +1 -1
  12. package/dist/providers/wormhole/signers/EthereumSigner.d.ts.map +1 -1
  13. package/dist/providers/wormhole/signers/Signer.d.ts +10 -2
  14. package/dist/providers/wormhole/signers/Signer.d.ts.map +1 -1
  15. package/dist/providers/wormhole/signers/SolanaLocalSigner.d.ts +4 -0
  16. package/dist/providers/wormhole/signers/SolanaLocalSigner.d.ts.map +1 -1
  17. package/dist/providers/wormhole/signers/SolanaSigner.d.ts.map +1 -1
  18. package/dist/providers/wormhole/signers/solanaUtils.d.ts.map +1 -1
  19. package/dist/providers/wormhole/types.d.ts +78 -1
  20. package/dist/providers/wormhole/types.d.ts.map +1 -1
  21. package/dist/providers/wormhole/wormhole.d.ts +27 -1
  22. package/dist/providers/wormhole/wormhole.d.ts.map +1 -1
  23. package/dist/version.d.ts +1 -1
  24. package/package.json +3 -3
  25. package/src/CrossChainCore.ts +91 -4
  26. package/src/providers/wormhole/signers/AptosLocalSigner.ts +27 -14
  27. package/src/providers/wormhole/signers/AptosSigner.ts +10 -1
  28. package/src/providers/wormhole/signers/EthereumSigner.ts +57 -6
  29. package/src/providers/wormhole/signers/Signer.ts +19 -2
  30. package/src/providers/wormhole/signers/SolanaLocalSigner.ts +7 -0
  31. package/src/providers/wormhole/signers/SolanaSigner.ts +4 -1
  32. package/src/providers/wormhole/signers/solanaUtils.ts +43 -19
  33. package/src/providers/wormhole/types.ts +100 -1
  34. package/src/providers/wormhole/wormhole.ts +138 -28
  35. package/src/version.ts +1 -1
package/dist/index.js CHANGED
@@ -32,13 +32,15 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  AptosLocalSigner: () => AptosLocalSigner,
34
34
  Context: () => Context,
35
- CrossChainCore: () => CrossChainCore,
35
+ CrossChainCore: () => CrossChainCore2,
36
+ EVM_CHAIN_NAMES: () => EVM_CHAIN_NAMES,
36
37
  EthereumChainIdToMainnetChain: () => EthereumChainIdToMainnetChain,
37
38
  EthereumChainIdToTestnetChain: () => EthereumChainIdToTestnetChain,
38
39
  Network: () => import_ts_sdk7.Network,
39
40
  NetworkToChainId: () => import_ts_sdk6.NetworkToChainId,
40
41
  NetworkToNodeAPI: () => import_ts_sdk6.NetworkToNodeAPI,
41
42
  SolanaLocalSigner: () => SolanaLocalSigner,
43
+ TransferError: () => TransferError,
42
44
  WithdrawError: () => WithdrawError,
43
45
  WormholeProvider: () => WormholeProvider,
44
46
  createCCTPRoute: () => createCCTPRoute,
@@ -48,7 +50,8 @@ __export(index_exports, {
48
50
  serializeReceipt: () => serializeReceipt,
49
51
  signAndSendTransaction: () => signAndSendTransaction,
50
52
  testnetChains: () => testnetChains,
51
- testnetTokens: () => testnetTokens
53
+ testnetTokens: () => testnetTokens,
54
+ validateExpireTimestamp: () => validateExpireTimestamp
52
55
  });
53
56
  module.exports = __toCommonJS(index_exports);
54
57
 
@@ -168,14 +171,43 @@ function deserializeReceipt(obj) {
168
171
 
169
172
  // src/providers/wormhole/signers/AptosLocalSigner.ts
170
173
  var import_ts_sdk = require("@aptos-labs/ts-sdk");
174
+
175
+ // src/providers/wormhole/types.ts
176
+ function validateExpireTimestamp(value) {
177
+ if (!Number.isInteger(value) || value < 0) {
178
+ throw new Error(
179
+ `getExpireTimestamp returned an invalid value (${value}). Expected a non-negative integer (epoch seconds).`
180
+ );
181
+ }
182
+ }
183
+ var TransferError = class extends Error {
184
+ constructor(message, originChainTxnId, cause) {
185
+ super(message);
186
+ this.name = "TransferError";
187
+ this.originChainTxnId = originChainTxnId;
188
+ this.cause = cause;
189
+ }
190
+ };
191
+ var WithdrawError = class extends Error {
192
+ constructor(message, originChainTxnId, phase, cause) {
193
+ super(message);
194
+ this.name = "WithdrawError";
195
+ this.originChainTxnId = originChainTxnId;
196
+ this.phase = phase;
197
+ this.cause = cause;
198
+ }
199
+ };
200
+
201
+ // src/providers/wormhole/signers/AptosLocalSigner.ts
171
202
  var AptosLocalSigner = class {
172
- constructor(chain, options, wallet, feePayerAccount, dappNetwork) {
203
+ constructor(chain, options, wallet, feePayerAccount, crossChainCore, onTransactionSigned) {
173
204
  this._claimedTransactionHashes = [];
174
205
  this._chain = chain;
175
206
  this._options = options;
176
207
  this._wallet = wallet;
177
208
  this._sponsorAccount = feePayerAccount;
178
- this._dappNetwork = dappNetwork;
209
+ this._crossChainCore = crossChainCore;
210
+ this._onTransactionSigned = onTransactionSigned;
179
211
  }
180
212
  chain() {
181
213
  return this._chain;
@@ -190,19 +222,21 @@ var AptosLocalSigner = class {
190
222
  const txHashes = [];
191
223
  this._claimedTransactionHashes = [];
192
224
  for (const tx of txs) {
225
+ this._onTransactionSigned?.(tx.description, null);
193
226
  const txId = await signAndSendTransaction(
194
227
  tx,
195
228
  this._wallet,
196
229
  this._sponsorAccount,
197
- this._dappNetwork
230
+ this._crossChainCore
198
231
  );
232
+ this._onTransactionSigned?.(tx.description, txId);
199
233
  txHashes.push(txId);
200
234
  this._claimedTransactionHashes.push(txId);
201
235
  }
202
236
  return txHashes;
203
237
  }
204
238
  };
205
- async function signAndSendTransaction(request, wallet, sponsorAccount, dappNetwork) {
239
+ async function signAndSendTransaction(request, wallet, sponsorAccount, crossChainCore) {
206
240
  if (!wallet) {
207
241
  throw new Error("Wallet is undefined");
208
242
  }
@@ -216,14 +250,20 @@ async function signAndSendTransaction(request, wallet, sponsorAccount, dappNetwo
216
250
  return a;
217
251
  }
218
252
  });
253
+ const dappNetwork = crossChainCore._dappConfig.aptosNetwork;
219
254
  const aptosConfig = new import_ts_sdk.AptosConfig({
220
255
  network: dappNetwork
221
256
  });
222
257
  const aptos2 = new import_ts_sdk.Aptos(aptosConfig);
258
+ const expireTimestamp = crossChainCore._dappConfig.getExpireTimestamp?.();
259
+ if (typeof expireTimestamp !== "undefined") {
260
+ validateExpireTimestamp(expireTimestamp);
261
+ }
223
262
  const txnToSign = await aptos2.transaction.build.simple({
224
263
  data: payload,
225
264
  sender: wallet.accountAddress.toString(),
226
- withFeePayer: sponsorAccount ? true : false
265
+ withFeePayer: sponsorAccount ? true : false,
266
+ ...typeof expireTimestamp !== "undefined" ? { options: { expireTimestamp } } : {}
227
267
  });
228
268
  const senderAuthenticator = await aptos2.transaction.sign({
229
269
  signer: wallet,
@@ -247,6 +287,96 @@ async function signAndSendTransaction(request, wallet, sponsorAccount, dappNetwo
247
287
  return tx.hash;
248
288
  }
249
289
 
290
+ // src/providers/wormhole/signers/AptosSigner.ts
291
+ var import_ts_sdk2 = require("@aptos-labs/ts-sdk");
292
+ var import_wallet_standard = require("@aptos-labs/wallet-standard");
293
+ var import_gas_station_client = require("@aptos-labs/gas-station-client");
294
+ async function signAndSendTransaction2(request, wallet, sponsorAccount, dappNetwork, crossChainCore) {
295
+ if (!wallet) {
296
+ throw new Error("wallet.sendTransaction is undefined");
297
+ }
298
+ const payload = request.transaction;
299
+ payload.functionArguments = payload.functionArguments.map((a) => {
300
+ if (a instanceof Uint8Array) {
301
+ return Array.from(a);
302
+ } else if (typeof a === "bigint") {
303
+ return a.toString();
304
+ } else {
305
+ return a;
306
+ }
307
+ });
308
+ let aptosConfig;
309
+ const useGasStation = sponsorAccount && !isAccount(sponsorAccount);
310
+ if (useGasStation) {
311
+ const gasStationClient = new import_gas_station_client.GasStationClient({
312
+ network: dappNetwork,
313
+ apiKey: sponsorAccount[dappNetwork]
314
+ });
315
+ const transactionSubmitter = new import_gas_station_client.GasStationTransactionSubmitter(gasStationClient);
316
+ aptosConfig = new import_ts_sdk2.AptosConfig({
317
+ network: dappNetwork,
318
+ pluginSettings: {
319
+ TRANSACTION_SUBMITTER: transactionSubmitter
320
+ }
321
+ });
322
+ } else {
323
+ aptosConfig = new import_ts_sdk2.AptosConfig({
324
+ network: dappNetwork
325
+ });
326
+ }
327
+ const aptos2 = new import_ts_sdk2.Aptos(aptosConfig);
328
+ const functionArguments = extractFunctionArguments(
329
+ payload.functionArguments
330
+ );
331
+ const withdrawFunction = "0x5e2d961f06cd27aa07554a39d55f5ce1e58dff35d803c3529b1cd5c4fa3ab584::withdraw::deposit_for_burn";
332
+ const transactionData = {
333
+ function: withdrawFunction,
334
+ functionArguments
335
+ };
336
+ const expireTimestamp = crossChainCore?._dappConfig?.getExpireTimestamp?.();
337
+ if (typeof expireTimestamp !== "undefined") {
338
+ validateExpireTimestamp(expireTimestamp);
339
+ }
340
+ const txnToSign = await aptos2.transaction.build.simple({
341
+ data: transactionData,
342
+ sender: (await wallet.features["aptos:account"]?.account()).address.toString(),
343
+ withFeePayer: sponsorAccount ? true : false,
344
+ ...typeof expireTimestamp !== "undefined" ? { options: { expireTimestamp } } : {}
345
+ });
346
+ const response = await wallet.features["aptos:signTransaction"]?.signTransaction(txnToSign);
347
+ if (response?.status === import_wallet_standard.UserResponseStatus.REJECTED) {
348
+ throw new Error("User has rejected the request");
349
+ }
350
+ const txnToSubmit = {
351
+ transaction: txnToSign,
352
+ senderAuthenticator: response.args
353
+ };
354
+ if (sponsorAccount && isAccount(sponsorAccount)) {
355
+ const feePayerSignerAuthenticator = aptos2.transaction.signAsFeePayer({
356
+ signer: sponsorAccount,
357
+ transaction: txnToSign
358
+ });
359
+ txnToSubmit.feePayerAuthenticator = feePayerSignerAuthenticator;
360
+ }
361
+ const txnSubmitted = await aptos2.transaction.submit.simple(txnToSubmit);
362
+ const tx = await aptos2.waitForTransaction({
363
+ transactionHash: txnSubmitted.hash
364
+ });
365
+ return tx.hash;
366
+ }
367
+ function extractFunctionArguments(functionArguments) {
368
+ const deserializer1 = new import_ts_sdk2.Deserializer(functionArguments[0].bcsToBytes());
369
+ const amount = deserializer1.deserializeU64();
370
+ const deserializer2 = new import_ts_sdk2.Deserializer(functionArguments[1].bcsToBytes());
371
+ const destination_domain = deserializer2.deserializeU32();
372
+ const mint_recipient = new import_ts_sdk2.AccountAddress(functionArguments[2].bcsToBytes());
373
+ const burn_token = new import_ts_sdk2.AccountAddress(functionArguments[3].bcsToBytes());
374
+ return [amount, destination_domain, mint_recipient, burn_token];
375
+ }
376
+ function isAccount(obj) {
377
+ return "accountAddress" in obj;
378
+ }
379
+
250
380
  // src/providers/wormhole/signers/SolanaSigner.ts
251
381
  var import_web32 = require("@solana/web3.js");
252
382
  var import_web33 = require("@solana/web3.js");
@@ -269,26 +399,40 @@ async function sendAndConfirmTransaction(serializedTx, blockhash, lastValidBlock
269
399
  );
270
400
  let confirmedTx = null;
271
401
  let txSendAttempts = 1;
272
- while (!confirmedTx) {
273
- confirmedTx = await Promise.race([
274
- confirmTransactionPromise,
275
- new Promise(
276
- (resolve) => setTimeout(() => resolve(null), retryIntervalMs)
277
- )
278
- ]);
279
- if (confirmedTx) break;
280
- if (verbose) {
281
- console.log(
282
- `Tx not confirmed after ${retryIntervalMs * txSendAttempts++}ms, resending`
283
- );
402
+ try {
403
+ while (!confirmedTx) {
404
+ confirmedTx = await Promise.race([
405
+ confirmTransactionPromise,
406
+ new Promise(
407
+ (resolve) => setTimeout(() => resolve(null), retryIntervalMs)
408
+ )
409
+ ]);
410
+ if (confirmedTx) break;
411
+ if (verbose) {
412
+ console.log(
413
+ `Tx not confirmed after ${retryIntervalMs * txSendAttempts++}ms, resending`
414
+ );
415
+ }
416
+ try {
417
+ await connection.sendRawTransaction(serializedTx, sendOptions);
418
+ } catch (e) {
419
+ if (verbose) {
420
+ console.error("Failed to resend transaction:", e);
421
+ }
422
+ }
284
423
  }
285
- try {
286
- await connection.sendRawTransaction(serializedTx, sendOptions);
287
- } catch (e) {
424
+ } catch (e) {
425
+ const message = e instanceof Error ? e.message.toLowerCase() : "";
426
+ if (message.includes("block height exceeded") || message.includes("blockheightexceeded")) {
288
427
  if (verbose) {
289
- console.error("Failed to resend transaction:", e);
428
+ console.warn(
429
+ "Block height exceeded but tx was already sent, returning signature:",
430
+ signature
431
+ );
290
432
  }
433
+ return signature;
291
434
  }
435
+ throw e;
292
436
  }
293
437
  if (confirmedTx.value.err) {
294
438
  const errorMessage = formatTransactionError(confirmedTx.value.err);
@@ -469,11 +613,11 @@ async function sleep(timeout) {
469
613
  }
470
614
 
471
615
  // src/providers/wormhole/signers/SolanaSigner.ts
472
- async function signAndSendTransaction2(request, wallet, options, crossChainCore) {
616
+ async function signAndSendTransaction3(request, wallet, options, crossChainCore) {
473
617
  if (!wallet || !(wallet instanceof import_derived_wallet_solana.SolanaDerivedWallet)) {
474
618
  throw new Error("Invalid wallet type or missing Solana wallet");
475
619
  }
476
- const commitment = options?.commitment ?? "finalized";
620
+ const commitment = options?.commitment ?? crossChainCore?._dappConfig?.solanaConfig?.commitment ?? "finalized";
477
621
  const connection = new import_web33.Connection(
478
622
  crossChainCore?._dappConfig?.solanaConfig?.rpc ?? crossChainCore?.CHAINS["Solana"]?.defaultRpc ?? "https://api.devnet.solana.com"
479
623
  // Last resort fallback
@@ -523,7 +667,7 @@ async function setPriorityFeeInstructions(connection, blockhash, lastValidBlockH
523
667
 
524
668
  // src/providers/wormhole/signers/EthereumSigner.ts
525
669
  var import_ethers = require("ethers");
526
- async function signAndSendTransaction3(request, wallet, chainName, options) {
670
+ async function signAndSendTransaction4(request, wallet, chainName) {
527
671
  if (!wallet) {
528
672
  throw new Error("wallet.sendTransaction is undefined");
529
673
  }
@@ -531,8 +675,7 @@ async function signAndSendTransaction3(request, wallet, chainName, options) {
531
675
  method: "eth_chainId"
532
676
  });
533
677
  const actualChainId = parseInt(chainId, 16);
534
- if (!actualChainId)
535
- throw new Error("No signer found for chain" + chainName);
678
+ if (!actualChainId) throw new Error("No signer found for chain" + chainName);
536
679
  const expectedChainId = request.transaction.chainId ? (0, import_ethers.getBigInt)(request.transaction.chainId) : void 0;
537
680
  if (!actualChainId || !expectedChainId || BigInt(actualChainId) !== expectedChainId) {
538
681
  throw new Error(
@@ -543,94 +686,44 @@ async function signAndSendTransaction3(request, wallet, chainName, options) {
543
686
  wallet.eip1193Provider
544
687
  );
545
688
  const signer = await provider.getSigner();
546
- const response = await signer.sendTransaction(request.transaction);
547
- const receipt = await response.wait();
548
- return receipt?.hash || "";
549
- }
550
-
551
- // src/providers/wormhole/signers/AptosSigner.ts
552
- var import_ts_sdk2 = require("@aptos-labs/ts-sdk");
553
- var import_wallet_standard = require("@aptos-labs/wallet-standard");
554
- var import_gas_station_client = require("@aptos-labs/gas-station-client");
555
- async function signAndSendTransaction4(request, wallet, sponsorAccount, dappNetwork) {
556
- if (!wallet) {
557
- throw new Error("wallet.sendTransaction is undefined");
558
- }
559
- const payload = request.transaction;
560
- payload.functionArguments = payload.functionArguments.map((a) => {
561
- if (a instanceof Uint8Array) {
562
- return Array.from(a);
563
- } else if (typeof a === "bigint") {
564
- return a.toString();
565
- } else {
566
- return a;
689
+ let response;
690
+ try {
691
+ response = await signer.sendTransaction(request.transaction);
692
+ } catch (e) {
693
+ const message = e instanceof Error ? e.message : String(e);
694
+ const hashMatch = message.match(/"hash":\s*"(0x[a-fA-F0-9]{64})"/);
695
+ if (hashMatch) {
696
+ console.warn("Extracted EVM tx hash from error:", hashMatch[1]);
697
+ return hashMatch[1];
567
698
  }
568
- });
569
- let aptosConfig;
570
- const useGasStation = sponsorAccount && !isAccount(sponsorAccount);
571
- if (useGasStation) {
572
- const gasStationClient = new import_gas_station_client.GasStationClient({
573
- network: dappNetwork,
574
- apiKey: sponsorAccount[dappNetwork]
575
- });
576
- const transactionSubmitter = new import_gas_station_client.GasStationTransactionSubmitter(gasStationClient);
577
- aptosConfig = new import_ts_sdk2.AptosConfig({
578
- network: dappNetwork,
579
- pluginSettings: {
580
- TRANSACTION_SUBMITTER: transactionSubmitter
581
- }
582
- });
583
- } else {
584
- aptosConfig = new import_ts_sdk2.AptosConfig({
585
- network: dappNetwork
586
- });
587
- }
588
- const aptos2 = new import_ts_sdk2.Aptos(aptosConfig);
589
- const functionArguments = extractFunctionArguments(
590
- payload.functionArguments
591
- );
592
- const withdrawFunction = "0x5e2d961f06cd27aa07554a39d55f5ce1e58dff35d803c3529b1cd5c4fa3ab584::withdraw::deposit_for_burn";
593
- const transactionData = {
594
- function: withdrawFunction,
595
- functionArguments
596
- };
597
- const txnToSign = await aptos2.transaction.build.simple({
598
- data: transactionData,
599
- sender: (await wallet.features["aptos:account"]?.account()).address.toString(),
600
- withFeePayer: sponsorAccount ? true : false
601
- });
602
- const response = await wallet.features["aptos:signTransaction"]?.signTransaction(txnToSign);
603
- if (response?.status === import_wallet_standard.UserResponseStatus.REJECTED) {
604
- throw new Error("User has rejected the request");
699
+ throw e;
605
700
  }
606
- const txnToSubmit = {
607
- transaction: txnToSign,
608
- senderAuthenticator: response.args
609
- };
610
- if (sponsorAccount && isAccount(sponsorAccount)) {
611
- const feePayerSignerAuthenticator = aptos2.transaction.signAsFeePayer({
612
- signer: sponsorAccount,
613
- transaction: txnToSign
614
- });
615
- txnToSubmit.feePayerAuthenticator = feePayerSignerAuthenticator;
701
+ try {
702
+ const receipt = await response.wait();
703
+ return receipt?.hash || response.hash || "";
704
+ } catch (e) {
705
+ if (e?.code === "TRANSACTION_REPLACED") {
706
+ if (e.reason === "repriced") {
707
+ const replacementHash = e.receipt?.hash || e.replacement?.hash;
708
+ if (replacementHash) {
709
+ console.warn(
710
+ "EVM transaction was repriced. Using replacement hash:",
711
+ replacementHash
712
+ );
713
+ return replacementHash;
714
+ }
715
+ }
716
+ throw e;
717
+ }
718
+ if (response.hash) {
719
+ console.warn(
720
+ "EVM transaction wait failed but tx was submitted:",
721
+ response.hash
722
+ );
723
+ return response.hash;
724
+ }
725
+ throw e;
616
726
  }
617
- const txnSubmitted = await aptos2.transaction.submit.simple(txnToSubmit);
618
- const tx = await aptos2.waitForTransaction({
619
- transactionHash: txnSubmitted.hash
620
- });
621
- return tx.hash;
622
- }
623
- function extractFunctionArguments(functionArguments) {
624
- const deserializer1 = new import_ts_sdk2.Deserializer(functionArguments[0].bcsToBytes());
625
- const amount = deserializer1.deserializeU64();
626
- const deserializer2 = new import_ts_sdk2.Deserializer(functionArguments[1].bcsToBytes());
627
- const destination_domain = deserializer2.deserializeU32();
628
- const mint_recipient = new import_ts_sdk2.AccountAddress(functionArguments[2].bcsToBytes());
629
- const burn_token = new import_ts_sdk2.AccountAddress(functionArguments[3].bcsToBytes());
630
- return [amount, destination_domain, mint_recipient, burn_token];
631
- }
632
- function isAccount(obj) {
633
- return "accountAddress" in obj;
634
727
  }
635
728
 
636
729
  // src/providers/wormhole/signers/SuiSigner.ts
@@ -653,7 +746,7 @@ async function signAndSendTransaction5(request, wallet) {
653
746
 
654
747
  // src/providers/wormhole/signers/Signer.ts
655
748
  var Signer = class {
656
- constructor(chain, address, options, wallet, crossChainCore, sponsorAccount) {
749
+ constructor(chain, address, options, wallet, crossChainCore, sponsorAccount, onTransactionSigned, trackAsSourceChain = true) {
657
750
  this._claimedTransactionHashes = [];
658
751
  this._chain = chain;
659
752
  this._address = address;
@@ -661,6 +754,8 @@ var Signer = class {
661
754
  this._wallet = wallet;
662
755
  this._crossChainCore = crossChainCore;
663
756
  this._sponsorAccount = sponsorAccount;
757
+ this._onTransactionSigned = onTransactionSigned;
758
+ this._trackAsSourceChain = trackAsSourceChain;
664
759
  }
665
760
  chain() {
666
761
  return this._chain.key;
@@ -675,6 +770,7 @@ var Signer = class {
675
770
  const txHashes = [];
676
771
  this._claimedTransactionHashes = [];
677
772
  for (const tx of txs) {
773
+ this._onTransactionSigned?.(tx.description, null);
678
774
  const txId = await signAndSendTransaction6(
679
775
  this._chain,
680
776
  tx,
@@ -683,6 +779,10 @@ var Signer = class {
683
779
  this._crossChainCore,
684
780
  this._sponsorAccount
685
781
  );
782
+ if (this._trackAsSourceChain) {
783
+ this._crossChainCore._lastSourceChainTxId = txId;
784
+ }
785
+ this._onTransactionSigned?.(tx.description, txId);
686
786
  txHashes.push(txId);
687
787
  this._claimedTransactionHashes.push(txId);
688
788
  }
@@ -695,7 +795,7 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
695
795
  }
696
796
  const dappNetwork = crossChainCore._dappConfig.aptosNetwork;
697
797
  if (chain.context === "Solana") {
698
- const signature = await signAndSendTransaction2(
798
+ const signature = await signAndSendTransaction3(
699
799
  request,
700
800
  wallet,
701
801
  options,
@@ -703,11 +803,10 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
703
803
  );
704
804
  return signature;
705
805
  } else if (chain.context === "Ethereum") {
706
- const tx = await signAndSendTransaction3(
806
+ const tx = await signAndSendTransaction4(
707
807
  request,
708
808
  wallet,
709
- chain.displayName,
710
- options
809
+ chain.displayName
711
810
  );
712
811
  return tx;
713
812
  } else if (chain.context === "Sui") {
@@ -717,11 +816,12 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
717
816
  );
718
817
  return tx;
719
818
  } else if (chain.context === "Aptos") {
720
- const tx = await signAndSendTransaction4(
819
+ const tx = await signAndSendTransaction2(
721
820
  request,
722
821
  wallet,
723
822
  sponsorAccount,
724
- dappNetwork
823
+ dappNetwork,
824
+ crossChainCore
725
825
  );
726
826
  return tx;
727
827
  } else {
@@ -757,17 +857,6 @@ async function createCCTPRoute(wh, sourceChain, destChain, tokens) {
757
857
  return { route: cctpRoute, request };
758
858
  }
759
859
 
760
- // src/providers/wormhole/types.ts
761
- var WithdrawError = class extends Error {
762
- constructor(message, originChainTxnId, phase, cause) {
763
- super(message);
764
- this.name = "WithdrawError";
765
- this.originChainTxnId = originChainTxnId;
766
- this.phase = phase;
767
- this.cause = cause;
768
- }
769
- };
770
-
771
860
  // src/providers/wormhole/wormhole.ts
772
861
  var WormholeProvider = class {
773
862
  constructor(core) {
@@ -786,12 +875,22 @@ var WormholeProvider = class {
786
875
  }
787
876
  const isMainnet = dappNetwork === import_ts_sdk3.Network.MAINNET;
788
877
  const platforms = [import_aptos.default, import_solana.default, import_evm.default, import_sui.default];
789
- const solanaRpc = this.crossChainCore._dappConfig?.solanaConfig?.rpc ?? this.crossChainCore.CHAINS["Solana"]?.defaultRpc;
878
+ const dappConfig = this.crossChainCore._dappConfig;
879
+ const chains = this.crossChainCore.CHAINS;
880
+ const solanaRpc = dappConfig?.solanaConfig?.rpc ?? chains["Solana"]?.defaultRpc;
881
+ const suiRpc = dappConfig?.suiConfig?.rpc ?? chains["Sui"]?.defaultRpc;
882
+ const evmChainsConfig = {};
883
+ for (const name of EVM_CHAIN_NAMES) {
884
+ const rpc = dappConfig?.evmConfig?.[name]?.rpc ?? chains[name]?.defaultRpc;
885
+ if (rpc) {
886
+ evmChainsConfig[name] = { rpc };
887
+ }
888
+ }
790
889
  const wh = await (0, import_sdk3.wormhole)(isMainnet ? "Mainnet" : "Testnet", platforms, {
791
890
  chains: {
792
- Solana: {
793
- rpc: solanaRpc
794
- }
891
+ ...solanaRpc ? { Solana: { rpc: solanaRpc } } : {},
892
+ ...suiRpc ? { Sui: { rpc: suiRpc } } : {},
893
+ ...evmChainsConfig
795
894
  }
796
895
  });
797
896
  this._wormholeContext = wh;
@@ -842,7 +941,7 @@ var WormholeProvider = class {
842
941
  return quote;
843
942
  }
844
943
  async submitCCTPTransfer(input) {
845
- const { sourceChain, wallet, destinationAddress } = input;
944
+ const { sourceChain, wallet, destinationAddress, onTransactionSigned } = input;
846
945
  if (!this._wormholeContext) {
847
946
  await this.setWormholeContext(sourceChain);
848
947
  }
@@ -868,7 +967,9 @@ var WormholeProvider = class {
868
967
  signerAddress,
869
968
  {},
870
969
  wallet,
871
- this.crossChainCore
970
+ this.crossChainCore,
971
+ void 0,
972
+ onTransactionSigned
872
973
  );
873
974
  logger.log("signer", signer);
874
975
  logger.log("wormholeRequest", this.wormholeRequest);
@@ -883,10 +984,15 @@ var WormholeProvider = class {
883
984
  return { originChainTxnId: originChainTxnId || "", receipt };
884
985
  }
885
986
  async claimCCTPTransfer(input) {
886
- let { receipt, mainSigner, sponsorAccount } = input;
987
+ let { receipt, mainSigner, sponsorAccount, onTransactionSigned } = input;
887
988
  if (!this.wormholeRoute) {
888
989
  throw new Error("Wormhole route not initialized");
889
990
  }
991
+ if (sponsorAccount && !isAccount(sponsorAccount)) {
992
+ throw new Error(
993
+ "AptosLocalSigner does not support GasStationApiKey as a sponsor account. Wormhole claim transactions are script-based and cannot be submitted via the gas station. Please provide an Account instance as the sponsor, or omit the sponsor account."
994
+ );
995
+ }
890
996
  logger.log("mainSigner", mainSigner.accountAddress.toString());
891
997
  let retries = 0;
892
998
  const maxRetries = 5;
@@ -904,7 +1010,8 @@ var WormholeProvider = class {
904
1010
  // the account that signs the "claim" transaction
905
1011
  sponsorAccount,
906
1012
  // the fee payer account
907
- this.crossChainCore._dappConfig?.aptosNetwork
1013
+ this.crossChainCore,
1014
+ onTransactionSigned
908
1015
  );
909
1016
  if (import_sdk3.routes.isManual(this.wormholeRoute)) {
910
1017
  const circleAttestationReceipt = await this.wormholeRoute.complete(signer, receipt);
@@ -949,12 +1056,21 @@ var WormholeProvider = class {
949
1056
  });
950
1057
  }
951
1058
  let { originChainTxnId, receipt } = await this.submitCCTPTransfer(input);
952
- const { destinationChainTxnId } = await this.claimCCTPTransfer({
953
- receipt,
954
- mainSigner: input.mainSigner,
955
- sponsorAccount: input.sponsorAccount
956
- });
957
- return { originChainTxnId, destinationChainTxnId };
1059
+ try {
1060
+ const { destinationChainTxnId } = await this.claimCCTPTransfer({
1061
+ receipt,
1062
+ mainSigner: input.mainSigner,
1063
+ sponsorAccount: input.sponsorAccount,
1064
+ onTransactionSigned: input.onTransactionSigned
1065
+ });
1066
+ return { originChainTxnId, destinationChainTxnId };
1067
+ } catch (error) {
1068
+ throw new TransferError(
1069
+ error?.message ?? "Transfer claim failed after source-chain burn",
1070
+ originChainTxnId,
1071
+ error
1072
+ );
1073
+ }
958
1074
  }
959
1075
  // --- Split withdraw flow: initiateWithdraw + trackWithdraw + claimWithdraw ---
960
1076
  /**
@@ -963,7 +1079,7 @@ var WormholeProvider = class {
963
1079
  * Returns a receipt that can be tracked and later claimed.
964
1080
  */
965
1081
  async initiateWithdraw(input) {
966
- const { wallet, destinationAddress, sponsorAccount } = input;
1082
+ const { wallet, destinationAddress, sponsorAccount, onTransactionSigned } = input;
967
1083
  if (!this._wormholeContext) {
968
1084
  throw new Error("Wormhole context not initialized");
969
1085
  }
@@ -976,7 +1092,8 @@ var WormholeProvider = class {
976
1092
  {},
977
1093
  wallet,
978
1094
  this.crossChainCore,
979
- sponsorAccount
1095
+ sponsorAccount,
1096
+ onTransactionSigned
980
1097
  );
981
1098
  const wormholeDestAddress = import_sdk3.Wormhole.chainAddress(
982
1099
  this.destinationChain,
@@ -1034,9 +1151,9 @@ var WormholeProvider = class {
1034
1151
  * Otherwise falls back to the wallet-based Signer (triggers wallet popup).
1035
1152
  */
1036
1153
  async claimWithdraw(input) {
1037
- const { sourceChain, destinationAddress, receipt } = input;
1154
+ const { claimChain, destinationAddress, receipt } = input;
1038
1155
  const serverClaimUrl = this.crossChainCore._dappConfig?.solanaConfig?.serverClaimUrl;
1039
- if (sourceChain === "Solana" && serverClaimUrl) {
1156
+ if (claimChain === "Solana" && serverClaimUrl) {
1040
1157
  logger.log("claimWithdraw: using server-side claim via", serverClaimUrl);
1041
1158
  const response = await fetch(serverClaimUrl, {
1042
1159
  method: "POST",
@@ -1044,7 +1161,7 @@ var WormholeProvider = class {
1044
1161
  body: JSON.stringify({
1045
1162
  receipt: serializeReceipt(receipt),
1046
1163
  destinationAddress,
1047
- sourceChain
1164
+ claimChain
1048
1165
  })
1049
1166
  });
1050
1167
  if (!response.ok) {
@@ -1065,11 +1182,14 @@ var WormholeProvider = class {
1065
1182
  );
1066
1183
  }
1067
1184
  const claimSigner = new Signer(
1068
- this.getChainConfig(sourceChain),
1185
+ this.getChainConfig(claimChain),
1069
1186
  destinationAddress,
1070
1187
  {},
1071
1188
  input.wallet,
1072
- this.crossChainCore
1189
+ this.crossChainCore,
1190
+ void 0,
1191
+ input.onTransactionSigned,
1192
+ false
1073
1193
  );
1074
1194
  if (import_sdk3.routes.isManual(this.wormholeRoute)) {
1075
1195
  const circleAttestationReceipt = await this.wormholeRoute.complete(
@@ -1095,12 +1215,20 @@ var WormholeProvider = class {
1095
1215
  * as the flow progresses.
1096
1216
  */
1097
1217
  async withdraw(input) {
1098
- const { sourceChain, wallet, destinationAddress, sponsorAccount, onPhaseChange } = input;
1218
+ const {
1219
+ sourceChain,
1220
+ wallet,
1221
+ destinationAddress,
1222
+ sponsorAccount,
1223
+ onPhaseChange,
1224
+ onTransactionSigned
1225
+ } = input;
1099
1226
  onPhaseChange?.("initiating");
1100
1227
  const { originChainTxnId, receipt } = await this.initiateWithdraw({
1101
1228
  wallet,
1102
1229
  destinationAddress,
1103
- sponsorAccount
1230
+ sponsorAccount,
1231
+ onTransactionSigned
1104
1232
  });
1105
1233
  let currentPhase = "tracking";
1106
1234
  try {
@@ -1109,10 +1237,11 @@ var WormholeProvider = class {
1109
1237
  currentPhase = "claiming";
1110
1238
  onPhaseChange?.("claiming");
1111
1239
  const { destinationChainTxnId } = await this.claimWithdraw({
1112
- sourceChain,
1240
+ claimChain: sourceChain,
1113
1241
  destinationAddress: destinationAddress.toString(),
1114
1242
  receipt: attestedReceipt,
1115
- wallet
1243
+ wallet,
1244
+ onTransactionSigned
1116
1245
  });
1117
1246
  return { originChainTxnId, destinationChainTxnId };
1118
1247
  } catch (error) {
@@ -1124,6 +1253,59 @@ var WormholeProvider = class {
1124
1253
  );
1125
1254
  }
1126
1255
  }
1256
+ /**
1257
+ * Retries a failed `claimWithdraw` call with configurable exponential backoff.
1258
+ *
1259
+ * Use this when the claim phase of a withdrawal fails (e.g., RPC instability,
1260
+ * network congestion) but the Aptos burn transaction has already been submitted.
1261
+ * The attested receipt can be recovered from the `WithdrawError` thrown by
1262
+ * `withdraw()` and passed directly to this method.
1263
+ *
1264
+ * @example
1265
+ * ```ts
1266
+ * try {
1267
+ * await provider.withdraw({ ... });
1268
+ * } catch (error) {
1269
+ * if (error instanceof WithdrawError && error.phase === "claiming") {
1270
+ * const result = await provider.retryWithdrawClaim({
1271
+ * sourceChain,
1272
+ * destinationAddress,
1273
+ * receipt: attestedReceipt,
1274
+ * wallet,
1275
+ * maxRetries: 5,
1276
+ * });
1277
+ * }
1278
+ * }
1279
+ * ```
1280
+ */
1281
+ async retryWithdrawClaim(input) {
1282
+ const {
1283
+ maxRetries = 5,
1284
+ initialDelayMs = 2e3,
1285
+ backoffMultiplier = 2,
1286
+ ...claimInput
1287
+ } = input;
1288
+ let lastError;
1289
+ let delay = initialDelayMs;
1290
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
1291
+ try {
1292
+ const result = await this.claimWithdraw(claimInput);
1293
+ return { ...result, retriesUsed: attempt };
1294
+ } catch (error) {
1295
+ lastError = error;
1296
+ logger.log(
1297
+ `retryWithdrawClaim: attempt ${attempt + 1}/${maxRetries + 1} failed: ${lastError.message}`
1298
+ );
1299
+ if (attempt < maxRetries) {
1300
+ await (0, import_ts_sdk3.sleep)(delay);
1301
+ delay *= backoffMultiplier;
1302
+ }
1303
+ }
1304
+ }
1305
+ throw new Error(
1306
+ `Claim failed after ${maxRetries + 1} attempts: ${lastError?.message}`
1307
+ );
1308
+ }
1127
1309
  getChainConfig(chain) {
1128
1310
  const chainConfig = this.crossChainCore.CHAINS[chain];
1129
1311
  if (!chainConfig) {
@@ -1144,6 +1326,7 @@ var SolanaLocalSigner = class {
1144
1326
  this.retryIntervalMs = config.retryIntervalMs ?? 5e3;
1145
1327
  this.priorityFeeConfig = config.priorityFeeConfig;
1146
1328
  this.verbose = config.verbose ?? false;
1329
+ this._onTransactionSigned = config.onTransactionSigned;
1147
1330
  }
1148
1331
  chain() {
1149
1332
  return "Solana";
@@ -1162,7 +1345,9 @@ var SolanaLocalSigner = class {
1162
1345
  const txHashes = [];
1163
1346
  this._claimedTransactionHashes = [];
1164
1347
  for (const tx of txs) {
1348
+ this._onTransactionSigned?.(tx.description, null);
1165
1349
  const txId = await this.signAndSendTransaction(tx);
1350
+ this._onTransactionSigned?.(tx.description, txId);
1166
1351
  txHashes.push(txId);
1167
1352
  this._claimedTransactionHashes.push(txId);
1168
1353
  }
@@ -1653,6 +1838,18 @@ var getSuiWalletUSDCBalance = async (walletAddress, aptosNetwork, rpc) => {
1653
1838
 
1654
1839
  // src/CrossChainCore.ts
1655
1840
  var import_ts_sdk6 = require("@aptos-labs/ts-sdk");
1841
+ var _evmChainRecord = {
1842
+ Ethereum: true,
1843
+ Sepolia: true,
1844
+ BaseSepolia: true,
1845
+ ArbitrumSepolia: true,
1846
+ Avalanche: true,
1847
+ Base: true,
1848
+ Arbitrum: true,
1849
+ PolygonSepolia: true,
1850
+ Polygon: true
1851
+ };
1852
+ var EVM_CHAIN_NAMES = Object.keys(_evmChainRecord);
1656
1853
  var EthereumChainIdToTestnetChain = {
1657
1854
  11155111: testnetChains.Sepolia,
1658
1855
  84532: testnetChains.BaseSepolia,
@@ -1667,7 +1864,7 @@ var EthereumChainIdToMainnetChain = {
1667
1864
  43114: mainnetChains.Avalanche,
1668
1865
  137: mainnetChains.Polygon
1669
1866
  };
1670
- var CrossChainCore = class {
1867
+ var CrossChainCore2 = class {
1671
1868
  constructor(args) {
1672
1869
  this._dappConfig = {
1673
1870
  aptosNetwork: import_ts_sdk5.Network.TESTNET
@@ -1721,14 +1918,13 @@ var CrossChainCore = class {
1721
1918
  walletAddress,
1722
1919
  this._dappConfig.aptosNetwork,
1723
1920
  sourceChain,
1724
- // TODO: maybe let the user config it
1725
- this.CHAINS[sourceChain].defaultRpc
1921
+ this._dappConfig?.evmConfig?.[sourceChain]?.rpc ?? this.CHAINS[sourceChain].defaultRpc
1726
1922
  );
1727
1923
  case "Sui":
1728
1924
  return await getSuiWalletUSDCBalance(
1729
1925
  walletAddress,
1730
1926
  this._dappConfig.aptosNetwork,
1731
- this.CHAINS[sourceChain].defaultRpc
1927
+ this._dappConfig?.suiConfig?.rpc ?? this.CHAINS[sourceChain].defaultRpc
1732
1928
  );
1733
1929
  default:
1734
1930
  throw new Error(`Unsupported chain: ${sourceChain}`);
@@ -1743,12 +1939,14 @@ var import_ts_sdk7 = require("@aptos-labs/ts-sdk");
1743
1939
  AptosLocalSigner,
1744
1940
  Context,
1745
1941
  CrossChainCore,
1942
+ EVM_CHAIN_NAMES,
1746
1943
  EthereumChainIdToMainnetChain,
1747
1944
  EthereumChainIdToTestnetChain,
1748
1945
  Network,
1749
1946
  NetworkToChainId,
1750
1947
  NetworkToNodeAPI,
1751
1948
  SolanaLocalSigner,
1949
+ TransferError,
1752
1950
  WithdrawError,
1753
1951
  WormholeProvider,
1754
1952
  createCCTPRoute,
@@ -1758,6 +1956,7 @@ var import_ts_sdk7 = require("@aptos-labs/ts-sdk");
1758
1956
  serializeReceipt,
1759
1957
  signAndSendTransaction,
1760
1958
  testnetChains,
1761
- testnetTokens
1959
+ testnetTokens,
1960
+ validateExpireTimestamp
1762
1961
  });
1763
1962
  //# sourceMappingURL=index.js.map