@aptos-labs/cross-chain-core 5.8.2 → 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 (52) hide show
  1. package/README.md +26 -0
  2. package/dist/CrossChainCore.d.ts +95 -0
  3. package/dist/CrossChainCore.d.ts.map +1 -1
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +908 -404
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +914 -409
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/providers/wormhole/index.d.ts +2 -0
  11. package/dist/providers/wormhole/index.d.ts.map +1 -1
  12. package/dist/providers/wormhole/signers/AptosLocalSigner.d.ts +9 -7
  13. package/dist/providers/wormhole/signers/AptosLocalSigner.d.ts.map +1 -1
  14. package/dist/providers/wormhole/signers/AptosSigner.d.ts +2 -1
  15. package/dist/providers/wormhole/signers/AptosSigner.d.ts.map +1 -1
  16. package/dist/providers/wormhole/signers/EthereumSigner.d.ts +1 -1
  17. package/dist/providers/wormhole/signers/EthereumSigner.d.ts.map +1 -1
  18. package/dist/providers/wormhole/signers/Signer.d.ts +11 -3
  19. package/dist/providers/wormhole/signers/Signer.d.ts.map +1 -1
  20. package/dist/providers/wormhole/signers/SolanaLocalSigner.d.ts +69 -0
  21. package/dist/providers/wormhole/signers/SolanaLocalSigner.d.ts.map +1 -0
  22. package/dist/providers/wormhole/signers/SolanaSigner.d.ts +12 -20
  23. package/dist/providers/wormhole/signers/SolanaSigner.d.ts.map +1 -1
  24. package/dist/providers/wormhole/signers/solanaUtils.d.ts +68 -0
  25. package/dist/providers/wormhole/signers/solanaUtils.d.ts.map +1 -0
  26. package/dist/providers/wormhole/types.d.ts +120 -0
  27. package/dist/providers/wormhole/types.d.ts.map +1 -1
  28. package/dist/providers/wormhole/utils.d.ts +26 -0
  29. package/dist/providers/wormhole/utils.d.ts.map +1 -0
  30. package/dist/providers/wormhole/wormhole.d.ts +62 -6
  31. package/dist/providers/wormhole/wormhole.d.ts.map +1 -1
  32. package/dist/utils/receiptSerialization.d.ts +38 -0
  33. package/dist/utils/receiptSerialization.d.ts.map +1 -0
  34. package/dist/version.d.ts +1 -1
  35. package/package.json +3 -3
  36. package/src/CrossChainCore.ts +110 -3
  37. package/src/config/mainnet/chains.ts +2 -2
  38. package/src/config/testnet/chains.ts +2 -2
  39. package/src/index.ts +1 -0
  40. package/src/providers/wormhole/index.ts +2 -0
  41. package/src/providers/wormhole/signers/AptosLocalSigner.ts +31 -18
  42. package/src/providers/wormhole/signers/AptosSigner.ts +11 -2
  43. package/src/providers/wormhole/signers/EthereumSigner.ts +59 -8
  44. package/src/providers/wormhole/signers/Signer.ts +23 -6
  45. package/src/providers/wormhole/signers/SolanaLocalSigner.ts +250 -0
  46. package/src/providers/wormhole/signers/SolanaSigner.ts +49 -338
  47. package/src/providers/wormhole/signers/solanaUtils.ts +446 -0
  48. package/src/providers/wormhole/types.ts +167 -0
  49. package/src/providers/wormhole/utils.ts +72 -0
  50. package/src/providers/wormhole/wormhole.ts +309 -137
  51. package/src/utils/receiptSerialization.ts +141 -0
  52. package/src/version.ts +1 -1
package/dist/index.js CHANGED
@@ -32,18 +32,26 @@ 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,
42
+ SolanaLocalSigner: () => SolanaLocalSigner,
43
+ TransferError: () => TransferError,
44
+ WithdrawError: () => WithdrawError,
41
45
  WormholeProvider: () => WormholeProvider,
46
+ createCCTPRoute: () => createCCTPRoute,
47
+ deserializeReceipt: () => deserializeReceipt,
42
48
  mainnetChains: () => mainnetChains,
43
49
  mainnetTokens: () => mainnetTokens,
50
+ serializeReceipt: () => serializeReceipt,
44
51
  signAndSendTransaction: () => signAndSendTransaction,
45
52
  testnetChains: () => testnetChains,
46
- testnetTokens: () => testnetTokens
53
+ testnetTokens: () => testnetTokens,
54
+ validateExpireTimestamp: () => validateExpireTimestamp
47
55
  });
48
56
  module.exports = __toCommonJS(index_exports);
49
57
 
@@ -51,7 +59,7 @@ module.exports = __toCommonJS(index_exports);
51
59
  var import_ts_sdk5 = require("@aptos-labs/ts-sdk");
52
60
 
53
61
  // src/providers/wormhole/wormhole.ts
54
- var import_sdk = require("@wormhole-foundation/sdk");
62
+ var import_sdk3 = require("@wormhole-foundation/sdk");
55
63
  var import_ts_sdk3 = require("@aptos-labs/ts-sdk");
56
64
  var import_aptos = __toESM(require("@wormhole-foundation/sdk/aptos"));
57
65
  var import_solana = __toESM(require("@wormhole-foundation/sdk/solana"));
@@ -77,16 +85,129 @@ var logger = {
77
85
  }
78
86
  };
79
87
 
88
+ // src/utils/receiptSerialization.ts
89
+ var import_sdk = require("@wormhole-foundation/sdk");
90
+ function uint8ArrayToBase64(bytes) {
91
+ let binary = "";
92
+ for (let i = 0; i < bytes.length; i++) {
93
+ binary += String.fromCharCode(bytes[i]);
94
+ }
95
+ return btoa(binary);
96
+ }
97
+ function base64ToUint8Array(base64) {
98
+ const binary = atob(base64);
99
+ const bytes = new Uint8Array(binary.length);
100
+ for (let i = 0; i < binary.length; i++) {
101
+ bytes[i] = binary.charCodeAt(i);
102
+ }
103
+ return bytes;
104
+ }
105
+ function serializeReceipt(receipt) {
106
+ return JSON.parse(
107
+ JSON.stringify(receipt, (_key, value) => {
108
+ if (typeof value === "bigint") {
109
+ return { __type: "bigint", value: value.toString() };
110
+ }
111
+ if (value instanceof import_sdk.UniversalAddress) {
112
+ return {
113
+ __type: "UniversalAddress",
114
+ value: uint8ArrayToBase64(value.toUint8Array())
115
+ };
116
+ }
117
+ if (value instanceof Uint8Array) {
118
+ return {
119
+ __type: "Uint8Array",
120
+ value: uint8ArrayToBase64(value)
121
+ };
122
+ }
123
+ return value;
124
+ })
125
+ );
126
+ }
127
+ function deserializeReceipt(obj) {
128
+ function revive(value, key) {
129
+ if (value && typeof value === "object") {
130
+ const objValue = value;
131
+ if ("__type" in objValue) {
132
+ if (objValue.__type === "bigint") {
133
+ return BigInt(objValue.value);
134
+ }
135
+ if (objValue.__type === "UniversalAddress") {
136
+ return new import_sdk.UniversalAddress(
137
+ base64ToUint8Array(objValue.value)
138
+ );
139
+ }
140
+ if (objValue.__type === "Uint8Array") {
141
+ return base64ToUint8Array(objValue.value);
142
+ }
143
+ }
144
+ const addressFields = [
145
+ "sender",
146
+ "recipient",
147
+ "destinationCaller",
148
+ "burnToken",
149
+ "mintRecipient",
150
+ "messageSender"
151
+ ];
152
+ if (key && addressFields.includes(key) && "address" in objValue) {
153
+ const addressBytes = revive(objValue.address);
154
+ if (addressBytes instanceof Uint8Array) {
155
+ return new import_sdk.UniversalAddress(addressBytes);
156
+ }
157
+ }
158
+ if (Array.isArray(value)) {
159
+ return value.map((v, i) => revive(v, String(i)));
160
+ }
161
+ const result = {};
162
+ for (const k in objValue) {
163
+ result[k] = revive(objValue[k], k);
164
+ }
165
+ return result;
166
+ }
167
+ return value;
168
+ }
169
+ return revive(obj);
170
+ }
171
+
80
172
  // src/providers/wormhole/signers/AptosLocalSigner.ts
81
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
82
202
  var AptosLocalSigner = class {
83
- constructor(chain, options, wallet, feePayerAccount, dappNetwork) {
203
+ constructor(chain, options, wallet, feePayerAccount, crossChainCore, onTransactionSigned) {
204
+ this._claimedTransactionHashes = [];
84
205
  this._chain = chain;
85
206
  this._options = options;
86
207
  this._wallet = wallet;
87
208
  this._sponsorAccount = feePayerAccount;
88
- this._claimedTransactionHashes = "";
89
- this._dappNetwork = dappNetwork;
209
+ this._crossChainCore = crossChainCore;
210
+ this._onTransactionSigned = onTransactionSigned;
90
211
  }
91
212
  chain() {
92
213
  return this._chain;
@@ -95,24 +216,27 @@ var AptosLocalSigner = class {
95
216
  return this._wallet.accountAddress.toString();
96
217
  }
97
218
  claimedTransactionHashes() {
98
- return this._claimedTransactionHashes;
219
+ return this._claimedTransactionHashes.join(",");
99
220
  }
100
221
  async signAndSend(txs) {
101
222
  const txHashes = [];
223
+ this._claimedTransactionHashes = [];
102
224
  for (const tx of txs) {
225
+ this._onTransactionSigned?.(tx.description, null);
103
226
  const txId = await signAndSendTransaction(
104
227
  tx,
105
228
  this._wallet,
106
229
  this._sponsorAccount,
107
- this._dappNetwork
230
+ this._crossChainCore
108
231
  );
232
+ this._onTransactionSigned?.(tx.description, txId);
109
233
  txHashes.push(txId);
110
- this._claimedTransactionHashes = txId;
234
+ this._claimedTransactionHashes.push(txId);
111
235
  }
112
236
  return txHashes;
113
237
  }
114
238
  };
115
- async function signAndSendTransaction(request, wallet, sponsorAccount, dappNetwork) {
239
+ async function signAndSendTransaction(request, wallet, sponsorAccount, crossChainCore) {
116
240
  if (!wallet) {
117
241
  throw new Error("Wallet is undefined");
118
242
  }
@@ -126,14 +250,20 @@ async function signAndSendTransaction(request, wallet, sponsorAccount, dappNetwo
126
250
  return a;
127
251
  }
128
252
  });
253
+ const dappNetwork = crossChainCore._dappConfig.aptosNetwork;
129
254
  const aptosConfig = new import_ts_sdk.AptosConfig({
130
255
  network: dappNetwork
131
256
  });
132
257
  const aptos2 = new import_ts_sdk.Aptos(aptosConfig);
258
+ const expireTimestamp = crossChainCore._dappConfig.getExpireTimestamp?.();
259
+ if (typeof expireTimestamp !== "undefined") {
260
+ validateExpireTimestamp(expireTimestamp);
261
+ }
133
262
  const txnToSign = await aptos2.transaction.build.simple({
134
263
  data: payload,
135
264
  sender: wallet.accountAddress.toString(),
136
- withFeePayer: sponsorAccount ? true : false
265
+ withFeePayer: sponsorAccount ? true : false,
266
+ ...typeof expireTimestamp !== "undefined" ? { options: { expireTimestamp } } : {}
137
267
  });
138
268
  const senderAuthenticator = await aptos2.transaction.sign({
139
269
  signer: wallet,
@@ -157,120 +287,228 @@ async function signAndSendTransaction(request, wallet, sponsorAccount, dappNetwo
157
287
  return tx.hash;
158
288
  }
159
289
 
160
- // src/providers/wormhole/signers/SolanaSigner.ts
161
- var import_web3 = require("@solana/web3.js");
162
- var import_web32 = require("@solana/web3.js");
163
- var import_sdk_solana = require("@wormhole-foundation/sdk-solana");
164
- var import_web33 = require("@solana/web3.js");
165
- var import_derived_wallet_solana = require("@aptos-labs/derived-wallet-solana");
166
- async function signAndSendTransaction2(request, wallet, options, crossChainCore) {
167
- if (!wallet || !(wallet instanceof import_derived_wallet_solana.SolanaDerivedWallet)) {
168
- throw new Error("Invalid wallet type or missing Solana wallet").message;
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");
169
297
  }
170
- const commitment = options?.commitment ?? "finalized";
171
- const connection = new import_web33.Connection(
172
- crossChainCore?._dappConfig?.solanaConfig?.rpc ?? crossChainCore?.CHAINS["Solana"]?.defaultRpc ?? "https://api.devnet.solana.com"
173
- // Last resort fallback
174
- );
175
- const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash(commitment);
176
- const unsignedTx = await setPriorityFeeInstructions(
177
- connection,
178
- blockhash,
179
- lastValidBlockHeight,
180
- request,
181
- crossChainCore
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
182
330
  );
183
- let confirmTransactionPromise = null;
184
- let confirmedTx = null;
185
- let txSendAttempts = 1;
186
- let signature = "";
187
- if (!wallet.solanaWallet.signTransaction) {
188
- throw new Error("Wallet does not support signing transactions").message;
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);
189
339
  }
190
- const tx = await wallet.solanaWallet.signTransaction(unsignedTx);
191
- if (!tx) throw new Error("Failed to sign transaction").message;
192
- if (request.transaction.signers && tx instanceof import_web32.Transaction) {
193
- tx.partialSign(...request.transaction.signers);
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");
194
349
  }
195
- const serializedTx = tx.serialize();
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
+
380
+ // src/providers/wormhole/signers/SolanaSigner.ts
381
+ var import_web32 = require("@solana/web3.js");
382
+ var import_web33 = require("@solana/web3.js");
383
+ var import_derived_wallet_solana = require("@aptos-labs/derived-wallet-solana");
384
+
385
+ // src/providers/wormhole/signers/solanaUtils.ts
386
+ var import_web3 = require("@solana/web3.js");
387
+ var import_sdk_solana = require("@wormhole-foundation/sdk-solana");
388
+ async function sendAndConfirmTransaction(serializedTx, blockhash, lastValidBlockHeight, config) {
389
+ const { connection, commitment, retryIntervalMs = 5e3, verbose = false } = config;
196
390
  const sendOptions = {
197
391
  skipPreflight: true,
198
392
  maxRetries: 0,
199
- preFlightCommitment: commitment
200
- // See PR and linked issue for why setting this matters: https://github.com/anza-xyz/agave/pull/483
393
+ preflightCommitment: commitment
201
394
  };
202
- signature = await connection.sendRawTransaction(serializedTx, sendOptions);
203
- confirmTransactionPromise = connection.confirmTransaction(
204
- {
205
- signature,
206
- blockhash,
207
- lastValidBlockHeight
208
- },
395
+ const signature = await connection.sendRawTransaction(serializedTx, sendOptions);
396
+ const confirmTransactionPromise = connection.confirmTransaction(
397
+ { signature, blockhash, lastValidBlockHeight },
209
398
  commitment
210
399
  );
211
- const txRetryInterval = 5e3;
212
- while (!confirmedTx) {
213
- confirmedTx = await Promise.race([
214
- confirmTransactionPromise,
215
- new Promise(
216
- (resolve) => setTimeout(() => {
217
- resolve(null);
218
- }, txRetryInterval)
219
- )
220
- ]);
221
- if (confirmedTx) {
222
- break;
223
- }
224
- console.log(
225
- `Tx not confirmed after ${txRetryInterval * txSendAttempts++}ms, resending`
226
- );
227
- try {
228
- await connection.sendRawTransaction(serializedTx, sendOptions);
229
- } catch (e) {
230
- console.error("Failed to resend transaction:", e);
231
- }
232
- }
233
- if (confirmedTx.value.err) {
234
- let errorMessage = `Transaction failed: ${confirmedTx.value.err}`;
235
- if (typeof confirmedTx.value.err === "object") {
400
+ let confirmedTx = null;
401
+ let txSendAttempts = 1;
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
+ }
236
416
  try {
237
- errorMessage = `Transaction failed: ${JSON.stringify(
238
- confirmedTx.value.err,
239
- (_key, value) => typeof value === "bigint" ? value.toString() : value
240
- // Handle bigint props
241
- )}`;
417
+ await connection.sendRawTransaction(serializedTx, sendOptions);
242
418
  } catch (e) {
243
- errorMessage = `Transaction failed: Unknown error`;
419
+ if (verbose) {
420
+ console.error("Failed to resend transaction:", e);
421
+ }
422
+ }
423
+ }
424
+ } catch (e) {
425
+ const message = e instanceof Error ? e.message.toLowerCase() : "";
426
+ if (message.includes("block height exceeded") || message.includes("blockheightexceeded")) {
427
+ if (verbose) {
428
+ console.warn(
429
+ "Block height exceeded but tx was already sent, returning signature:",
430
+ signature
431
+ );
244
432
  }
433
+ return signature;
245
434
  }
246
- throw new Error(`Transaction failed: ${errorMessage}`).message;
435
+ throw e;
436
+ }
437
+ if (confirmedTx.value.err) {
438
+ const errorMessage = formatTransactionError(confirmedTx.value.err);
439
+ throw new Error(errorMessage);
247
440
  }
248
441
  return signature;
249
442
  }
250
- async function setPriorityFeeInstructions(connection, blockhash, lastValidBlockHeight, request, crossChainCore) {
251
- const unsignedTx = request.transaction.transaction;
443
+ function formatTransactionError(err) {
444
+ if (typeof err === "object" && err !== null) {
445
+ try {
446
+ return `Transaction failed: ${JSON.stringify(
447
+ err,
448
+ (_key, value) => typeof value === "bigint" ? value.toString() : value
449
+ )}`;
450
+ } catch {
451
+ return "Transaction failed: Unknown error";
452
+ }
453
+ }
454
+ return `Transaction failed: ${err}`;
455
+ }
456
+ async function addPriorityFeeInstructions(connection, transaction, priorityFeeConfig, verbose = false) {
252
457
  const computeBudgetIxFilter = (ix) => ix.programId.toString() !== "ComputeBudget111111111111111111111111111111";
253
- unsignedTx.recentBlockhash = blockhash;
254
- unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
255
- unsignedTx.instructions = unsignedTx.instructions.filter(
256
- computeBudgetIxFilter
458
+ transaction.instructions = transaction.instructions.filter(computeBudgetIxFilter);
459
+ const instructions = await createPriorityFeeInstructions(
460
+ connection,
461
+ transaction,
462
+ priorityFeeConfig,
463
+ verbose
257
464
  );
258
- unsignedTx.add(
259
- ...await createPriorityFeeInstructions(
260
- connection,
261
- unsignedTx,
262
- crossChainCore
263
- )
465
+ transaction.add(...instructions);
466
+ return transaction;
467
+ }
468
+ async function createPriorityFeeInstructions(connection, transaction, priorityFeeConfig, verbose = false) {
469
+ const unitsUsed = await simulateAndGetComputeUnits(connection, transaction);
470
+ const unitBudget = Math.floor(unitsUsed * 1.2);
471
+ const instructions = [];
472
+ instructions.push(
473
+ import_web3.ComputeBudgetProgram.setComputeUnitLimit({
474
+ units: unitBudget
475
+ })
264
476
  );
265
- return unsignedTx;
477
+ const {
478
+ percentile = 0.9,
479
+ percentileMultiple = 1,
480
+ min = 1e5,
481
+ max = 1e8
482
+ } = priorityFeeConfig ?? {};
483
+ const rpcProvider = determineRpcProvider(connection.rpcEndpoint);
484
+ const { fee, methodUsed } = await calculatePriorityFee(
485
+ connection,
486
+ transaction,
487
+ rpcProvider,
488
+ { percentile, percentileMultiple, min, max }
489
+ );
490
+ if (verbose) {
491
+ const maxFeeInSol = fee / 1e6 / import_web3.LAMPORTS_PER_SOL * unitBudget;
492
+ console.table({
493
+ "RPC Provider": rpcProvider,
494
+ "Method used": methodUsed,
495
+ "Percentile used": percentile,
496
+ "Multiple used": percentileMultiple,
497
+ "Compute budget": unitBudget,
498
+ "Priority fee": fee,
499
+ "Max fee in SOL": maxFeeInSol
500
+ });
501
+ }
502
+ instructions.push(
503
+ import_web3.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: fee })
504
+ );
505
+ return instructions;
266
506
  }
267
- async function createPriorityFeeInstructions(connection, transaction, crossChainCore) {
507
+ async function simulateAndGetComputeUnits(connection, transaction) {
268
508
  let unitsUsed = 2e5;
269
509
  let simulationAttempts = 0;
270
510
  simulationLoop: while (true) {
271
- const response = await connection.simulateTransaction(
272
- transaction
273
- );
511
+ const response = await connection.simulateTransaction(transaction);
274
512
  if (response.value.err) {
275
513
  if (checkKnownSimulationError(response.value)) {
276
514
  if (simulationAttempts < 5) {
@@ -287,7 +525,7 @@ async function createPriorityFeeInstructions(connection, transaction, crossChain
287
525
  `Simulation failed: ${JSON.stringify(response.value.err)}
288
526
  Logs:
289
527
  ${(response.value.logs || []).join("\n ")}`
290
- ).message;
528
+ );
291
529
  } else {
292
530
  if (response.value.unitsConsumed) {
293
531
  unitsUsed = response.value.unitsConsumed;
@@ -295,41 +533,13 @@ ${(response.value.logs || []).join("\n ")}`
295
533
  break;
296
534
  }
297
535
  }
298
- const unitBudget = Math.floor(unitsUsed * 1.2);
299
- const instructions = [];
300
- instructions.push(
301
- import_web3.ComputeBudgetProgram.setComputeUnitLimit({
302
- // Set compute budget to 120% of the units used in the simulated transaction
303
- units: unitBudget
304
- })
305
- );
306
- const {
307
- percentile = 0.9,
308
- percentileMultiple = 1,
309
- min = 1e5,
310
- max = 1e8
311
- } = crossChainCore?._dappConfig?.solanaConfig?.priorityFeeConfig ?? {};
312
- const calculateFee = async (rpcProvider2) => {
313
- if (rpcProvider2 === "triton") {
314
- try {
315
- const fee2 = await (0, import_sdk_solana.determinePriorityFeeTritonOne)(
316
- connection,
317
- transaction,
318
- percentile,
319
- percentileMultiple,
320
- min,
321
- max
322
- );
323
- return {
324
- fee: fee2,
325
- methodUsed: "triton"
326
- };
327
- } catch (e) {
328
- console.warn(`Failed to determine priority fee using Triton RPC:`, e);
329
- }
330
- }
536
+ return unitsUsed;
537
+ }
538
+ async function calculatePriorityFee(connection, transaction, rpcProvider, config) {
539
+ const { percentile, percentileMultiple, min, max } = config;
540
+ if (rpcProvider === "triton") {
331
541
  try {
332
- const fee2 = await (0, import_sdk_solana.determinePriorityFee)(
542
+ const fee = await (0, import_sdk_solana.determinePriorityFeeTritonOne)(
333
543
  connection,
334
544
  transaction,
335
545
  percentile,
@@ -337,37 +547,25 @@ ${(response.value.logs || []).join("\n ")}`
337
547
  min,
338
548
  max
339
549
  );
340
- return {
341
- fee: fee2,
342
- methodUsed: "default"
343
- };
550
+ return { fee, methodUsed: "triton" };
344
551
  } catch (e) {
345
552
  console.warn(`Failed to determine priority fee using Triton RPC:`, e);
346
- return {
347
- fee: min,
348
- methodUsed: "minimum"
349
- };
350
553
  }
351
- };
352
- const rpcProvider = determineRpcProvider(connection.rpcEndpoint);
353
- const { fee, methodUsed } = await calculateFee(rpcProvider);
354
- const maxFeeInSol = fee / // convert microlamports to lamports
355
- 1e6 / // convert lamports to SOL
356
- import_web3.LAMPORTS_PER_SOL * // multiply by maximum compute units used
357
- unitBudget;
358
- console.table({
359
- "RPC Provider": rpcProvider,
360
- "Method used": methodUsed,
361
- "Percentile used": percentile,
362
- "Multiple used": percentileMultiple,
363
- "Compute budget": unitBudget,
364
- "Priority fee": fee,
365
- "Max fee in SOL": maxFeeInSol
366
- });
367
- instructions.push(
368
- import_web3.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: fee })
369
- );
370
- return instructions;
554
+ }
555
+ try {
556
+ const fee = await (0, import_sdk_solana.determinePriorityFee)(
557
+ connection,
558
+ transaction,
559
+ percentile,
560
+ percentileMultiple,
561
+ min,
562
+ max
563
+ );
564
+ return { fee, methodUsed: "default" };
565
+ } catch (e) {
566
+ console.warn(`Failed to determine priority fee:`, e);
567
+ return { fee: min, methodUsed: "minimum" };
568
+ }
371
569
  }
372
570
  function checkKnownSimulationError(response) {
373
571
  const errors = {};
@@ -384,154 +582,148 @@ function checkKnownSimulationError(response) {
384
582
  }
385
583
  }
386
584
  }
387
- if (isEmptyObject(errors)) {
585
+ if (Object.keys(errors).length === 0) {
388
586
  return false;
389
587
  }
390
588
  console.table(errors);
391
589
  return true;
392
590
  }
393
- async function sleep(timeout) {
394
- return new Promise((resolve) => setTimeout(resolve, timeout));
591
+ function isHostOrSubdomainOf(hostname, base) {
592
+ return hostname === base || hostname.endsWith(`.${base}`);
395
593
  }
396
- var isEmptyObject = (value) => {
397
- if (value === null || value === void 0) {
398
- return true;
399
- }
400
- for (const key in value) {
401
- if (value.hasOwnProperty.call(value, key)) {
402
- return false;
403
- }
404
- }
405
- return true;
406
- };
407
594
  function determineRpcProvider(endpoint) {
408
595
  try {
409
596
  const url = new URL(endpoint);
410
597
  const hostname = url.hostname;
411
- if (hostname === "rpcpool.com") {
598
+ if (isHostOrSubdomainOf(hostname, "rpcpool.com") || isHostOrSubdomainOf(hostname, "triton.one")) {
412
599
  return "triton";
413
- } else if (hostname === "helius-rpc.com") {
600
+ } else if (isHostOrSubdomainOf(hostname, "helius-rpc.com") || isHostOrSubdomainOf(hostname, "helius.xyz")) {
414
601
  return "helius";
415
- } else if (hostname === "rpc.ankr.com") {
602
+ } else if (isHostOrSubdomainOf(hostname, "ankr.com")) {
416
603
  return "ankr";
417
604
  } else {
418
605
  return "unknown";
419
606
  }
420
- } catch (e) {
607
+ } catch {
421
608
  return "unknown";
422
609
  }
423
610
  }
611
+ async function sleep(timeout) {
612
+ return new Promise((resolve) => setTimeout(resolve, timeout));
613
+ }
614
+
615
+ // src/providers/wormhole/signers/SolanaSigner.ts
616
+ async function signAndSendTransaction3(request, wallet, options, crossChainCore) {
617
+ if (!wallet || !(wallet instanceof import_derived_wallet_solana.SolanaDerivedWallet)) {
618
+ throw new Error("Invalid wallet type or missing Solana wallet");
619
+ }
620
+ const commitment = options?.commitment ?? crossChainCore?._dappConfig?.solanaConfig?.commitment ?? "finalized";
621
+ const connection = new import_web33.Connection(
622
+ crossChainCore?._dappConfig?.solanaConfig?.rpc ?? crossChainCore?.CHAINS["Solana"]?.defaultRpc ?? "https://api.devnet.solana.com"
623
+ // Last resort fallback
624
+ );
625
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash(commitment);
626
+ const unsignedTx = await setPriorityFeeInstructions(
627
+ connection,
628
+ blockhash,
629
+ lastValidBlockHeight,
630
+ request,
631
+ crossChainCore?._dappConfig?.solanaConfig?.priorityFeeConfig
632
+ );
633
+ if (!wallet.solanaWallet.signTransaction) {
634
+ throw new Error("Wallet does not support signing transactions");
635
+ }
636
+ const tx = await wallet.solanaWallet.signTransaction(unsignedTx);
637
+ if (!tx) throw new Error("Failed to sign transaction");
638
+ if (request.transaction.signers && tx instanceof import_web32.Transaction) {
639
+ tx.partialSign(...request.transaction.signers);
640
+ }
641
+ const serializedTx = tx.serialize();
642
+ const signature = await sendAndConfirmTransaction(
643
+ serializedTx,
644
+ blockhash,
645
+ lastValidBlockHeight,
646
+ {
647
+ connection,
648
+ commitment,
649
+ retryIntervalMs: 5e3,
650
+ verbose: false
651
+ }
652
+ );
653
+ return signature;
654
+ }
655
+ async function setPriorityFeeInstructions(connection, blockhash, lastValidBlockHeight, request, priorityFeeConfig) {
656
+ const unsignedTx = request.transaction.transaction;
657
+ unsignedTx.recentBlockhash = blockhash;
658
+ unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
659
+ await addPriorityFeeInstructions(
660
+ connection,
661
+ unsignedTx,
662
+ priorityFeeConfig,
663
+ false
664
+ );
665
+ return unsignedTx;
666
+ }
424
667
 
425
668
  // src/providers/wormhole/signers/EthereumSigner.ts
426
669
  var import_ethers = require("ethers");
427
- async function signAndSendTransaction3(request, wallet, chainName, options) {
670
+ async function signAndSendTransaction4(request, wallet, chainName) {
428
671
  if (!wallet) {
429
- throw new Error("wallet.sendTransaction is undefined").message;
672
+ throw new Error("wallet.sendTransaction is undefined");
430
673
  }
431
674
  const chainId = await wallet.eip1193Provider.request({
432
675
  method: "eth_chainId"
433
676
  });
434
677
  const actualChainId = parseInt(chainId, 16);
435
- if (!actualChainId)
436
- throw new Error("No signer found for chain" + chainName).message;
678
+ if (!actualChainId) throw new Error("No signer found for chain" + chainName);
437
679
  const expectedChainId = request.transaction.chainId ? (0, import_ethers.getBigInt)(request.transaction.chainId) : void 0;
438
680
  if (!actualChainId || !expectedChainId || BigInt(actualChainId) !== expectedChainId) {
439
681
  throw new Error(
440
682
  `Signer is not connected to the right chain. Expected ${expectedChainId}, got ${actualChainId}`
441
- ).message;
683
+ );
442
684
  }
443
685
  const provider = new import_ethers.ethers.BrowserProvider(
444
686
  wallet.eip1193Provider
445
687
  );
446
688
  const signer = await provider.getSigner();
447
- const response = await signer.sendTransaction(request.transaction);
448
- const receipt = await response.wait();
449
- return receipt?.hash || "";
450
- }
451
-
452
- // src/providers/wormhole/signers/AptosSigner.ts
453
- var import_ts_sdk2 = require("@aptos-labs/ts-sdk");
454
- var import_wallet_standard = require("@aptos-labs/wallet-standard");
455
- var import_gas_station_client = require("@aptos-labs/gas-station-client");
456
- async function signAndSendTransaction4(request, wallet, sponsorAccount, dappNetwork) {
457
- if (!wallet) {
458
- throw new Error("wallet.sendTransaction is undefined").message;
459
- }
460
- const payload = request.transaction;
461
- payload.functionArguments = payload.functionArguments.map((a) => {
462
- if (a instanceof Uint8Array) {
463
- return Array.from(a);
464
- } else if (typeof a === "bigint") {
465
- return a.toString();
466
- } else {
467
- 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];
468
698
  }
469
- });
470
- let aptosConfig;
471
- const useGasStation = sponsorAccount && !isAccount(sponsorAccount);
472
- if (useGasStation) {
473
- const gasStationClient = new import_gas_station_client.GasStationClient({
474
- network: dappNetwork,
475
- apiKey: sponsorAccount[dappNetwork]
476
- });
477
- const transactionSubmitter = new import_gas_station_client.GasStationTransactionSubmitter(gasStationClient);
478
- aptosConfig = new import_ts_sdk2.AptosConfig({
479
- network: dappNetwork,
480
- pluginSettings: {
481
- TRANSACTION_SUBMITTER: transactionSubmitter
482
- }
483
- });
484
- } else {
485
- aptosConfig = new import_ts_sdk2.AptosConfig({
486
- network: dappNetwork
487
- });
488
- }
489
- const aptos2 = new import_ts_sdk2.Aptos(aptosConfig);
490
- const functionArguments = extractFunctionArguments(
491
- payload.functionArguments
492
- );
493
- const withdrawFunction = "0x5e2d961f06cd27aa07554a39d55f5ce1e58dff35d803c3529b1cd5c4fa3ab584::withdraw::deposit_for_burn";
494
- const transactionData = {
495
- function: withdrawFunction,
496
- functionArguments
497
- };
498
- const txnToSign = await aptos2.transaction.build.simple({
499
- data: transactionData,
500
- sender: (await wallet.features["aptos:account"]?.account()).address.toString(),
501
- withFeePayer: sponsorAccount ? true : false
502
- });
503
- const response = await wallet.features["aptos:signTransaction"]?.signTransaction(txnToSign);
504
- if (response?.status === import_wallet_standard.UserResponseStatus.REJECTED) {
505
- throw new Error("User has rejected the request");
699
+ throw e;
506
700
  }
507
- const txnToSubmit = {
508
- transaction: txnToSign,
509
- senderAuthenticator: response.args
510
- };
511
- if (sponsorAccount && isAccount(sponsorAccount)) {
512
- const feePayerSignerAuthenticator = aptos2.transaction.signAsFeePayer({
513
- signer: sponsorAccount,
514
- transaction: txnToSign
515
- });
516
- 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;
517
726
  }
518
- const txnSubmitted = await aptos2.transaction.submit.simple(txnToSubmit);
519
- const tx = await aptos2.waitForTransaction({
520
- transactionHash: txnSubmitted.hash
521
- });
522
- return tx.hash;
523
- }
524
- function extractFunctionArguments(functionArguments) {
525
- const deserializer1 = new import_ts_sdk2.Deserializer(functionArguments[0].bcsToBytes());
526
- const amount = deserializer1.deserializeU64();
527
- const deserializer2 = new import_ts_sdk2.Deserializer(functionArguments[1].bcsToBytes());
528
- const destination_domain = deserializer2.deserializeU32();
529
- const mint_recipient = new import_ts_sdk2.AccountAddress(functionArguments[2].bcsToBytes());
530
- const burn_token = new import_ts_sdk2.AccountAddress(functionArguments[3].bcsToBytes());
531
- return [amount, destination_domain, mint_recipient, burn_token];
532
- }
533
- function isAccount(obj) {
534
- return "accountAddress" in obj;
535
727
  }
536
728
 
537
729
  // src/providers/wormhole/signers/SuiSigner.ts
@@ -554,14 +746,16 @@ async function signAndSendTransaction5(request, wallet) {
554
746
 
555
747
  // src/providers/wormhole/signers/Signer.ts
556
748
  var Signer = class {
557
- constructor(chain, address, options, wallet, crossChainCore, sponsorAccount) {
749
+ constructor(chain, address, options, wallet, crossChainCore, sponsorAccount, onTransactionSigned, trackAsSourceChain = true) {
750
+ this._claimedTransactionHashes = [];
558
751
  this._chain = chain;
559
752
  this._address = address;
560
753
  this._options = options;
561
754
  this._wallet = wallet;
562
755
  this._crossChainCore = crossChainCore;
563
756
  this._sponsorAccount = sponsorAccount;
564
- this._claimedTransactionHashes = "";
757
+ this._onTransactionSigned = onTransactionSigned;
758
+ this._trackAsSourceChain = trackAsSourceChain;
565
759
  }
566
760
  chain() {
567
761
  return this._chain.key;
@@ -570,11 +764,13 @@ var Signer = class {
570
764
  return this._address;
571
765
  }
572
766
  claimedTransactionHashes() {
573
- return this._claimedTransactionHashes;
767
+ return this._claimedTransactionHashes.join(",");
574
768
  }
575
769
  async signAndSend(txs) {
576
770
  const txHashes = [];
771
+ this._claimedTransactionHashes = [];
577
772
  for (const tx of txs) {
773
+ this._onTransactionSigned?.(tx.description, null);
578
774
  const txId = await signAndSendTransaction6(
579
775
  this._chain,
580
776
  tx,
@@ -583,8 +779,12 @@ var Signer = class {
583
779
  this._crossChainCore,
584
780
  this._sponsorAccount
585
781
  );
782
+ if (this._trackAsSourceChain) {
783
+ this._crossChainCore._lastSourceChainTxId = txId;
784
+ }
785
+ this._onTransactionSigned?.(tx.description, txId);
586
786
  txHashes.push(txId);
587
- this._claimedTransactionHashes = txId;
787
+ this._claimedTransactionHashes.push(txId);
588
788
  }
589
789
  return txHashes;
590
790
  }
@@ -595,7 +795,7 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
595
795
  }
596
796
  const dappNetwork = crossChainCore._dappConfig.aptosNetwork;
597
797
  if (chain.context === "Solana") {
598
- const signature = await signAndSendTransaction2(
798
+ const signature = await signAndSendTransaction3(
599
799
  request,
600
800
  wallet,
601
801
  options,
@@ -603,11 +803,10 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
603
803
  );
604
804
  return signature;
605
805
  } else if (chain.context === "Ethereum") {
606
- const tx = await signAndSendTransaction3(
806
+ const tx = await signAndSendTransaction4(
607
807
  request,
608
808
  wallet,
609
- chain.displayName,
610
- options
809
+ chain.displayName
611
810
  );
612
811
  return tx;
613
812
  } else if (chain.context === "Sui") {
@@ -617,11 +816,12 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
617
816
  );
618
817
  return tx;
619
818
  } else if (chain.context === "Aptos") {
620
- const tx = await signAndSendTransaction4(
819
+ const tx = await signAndSendTransaction2(
621
820
  request,
622
821
  wallet,
623
822
  sponsorAccount,
624
- dappNetwork
823
+ dappNetwork,
824
+ crossChainCore
625
825
  );
626
826
  return tx;
627
827
  } else {
@@ -629,6 +829,34 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
629
829
  }
630
830
  };
631
831
 
832
+ // src/providers/wormhole/utils.ts
833
+ var import_sdk2 = require("@wormhole-foundation/sdk");
834
+ async function createCCTPRoute(wh, sourceChain, destChain, tokens) {
835
+ const sourceToken = import_sdk2.Wormhole.tokenId(
836
+ sourceChain,
837
+ tokens[sourceChain].tokenId.address
838
+ );
839
+ const destToken = import_sdk2.Wormhole.tokenId(
840
+ destChain,
841
+ tokens[destChain].tokenId.address
842
+ );
843
+ const destContext = wh.getPlatform((0, import_sdk2.chainToPlatform)(destChain)).getChain(destChain);
844
+ const sourceContext = wh.getPlatform((0, import_sdk2.chainToPlatform)(sourceChain)).getChain(sourceChain);
845
+ const request = await import_sdk2.routes.RouteTransferRequest.create(
846
+ wh,
847
+ { source: sourceToken, destination: destToken },
848
+ sourceContext,
849
+ destContext
850
+ );
851
+ const resolver = wh.resolver([import_sdk2.routes.CCTPRoute]);
852
+ const foundRoutes = await resolver.findRoutes(request);
853
+ const cctpRoute = foundRoutes[0];
854
+ if (!cctpRoute || !import_sdk2.routes.isManual(cctpRoute)) {
855
+ throw new Error("Expected manual CCTP route");
856
+ }
857
+ return { route: cctpRoute, request };
858
+ }
859
+
632
860
  // src/providers/wormhole/wormhole.ts
633
861
  var WormholeProvider = class {
634
862
  constructor(core) {
@@ -647,12 +875,22 @@ var WormholeProvider = class {
647
875
  }
648
876
  const isMainnet = dappNetwork === import_ts_sdk3.Network.MAINNET;
649
877
  const platforms = [import_aptos.default, import_solana.default, import_evm.default, import_sui.default];
650
- const solanaRpc = this.crossChainCore._dappConfig?.solanaConfig?.rpc ?? this.crossChainCore.CHAINS["Solana"]?.defaultRpc;
651
- const wh = await (0, import_sdk.wormhole)(isMainnet ? "Mainnet" : "Testnet", platforms, {
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
+ }
889
+ const wh = await (0, import_sdk3.wormhole)(isMainnet ? "Mainnet" : "Testnet", platforms, {
652
890
  chains: {
653
- Solana: {
654
- rpc: solanaRpc
655
- }
891
+ ...solanaRpc ? { Solana: { rpc: solanaRpc } } : {},
892
+ ...suiRpc ? { Sui: { rpc: suiRpc } } : {},
893
+ ...evmChainsConfig
656
894
  }
657
895
  });
658
896
  this._wormholeContext = wh;
@@ -661,33 +899,15 @@ var WormholeProvider = class {
661
899
  if (!this._wormholeContext) {
662
900
  throw new Error("Wormhole context not initialized");
663
901
  }
664
- const { sourceToken, destToken } = this.getTokenInfo(
665
- sourceChain,
666
- destinationChain
667
- );
668
- const destContext = this._wormholeContext.getPlatform((0, import_sdk.chainToPlatform)(destinationChain)).getChain(destinationChain);
669
- const sourceContext = this._wormholeContext.getPlatform((0, import_sdk.chainToPlatform)(sourceChain)).getChain(sourceChain);
670
- logger.log("sourceContext", sourceContext);
671
- logger.log("sourceToken", sourceToken);
672
- logger.log("destContext", destContext);
673
- logger.log("destToken", destToken);
674
- const request = await import_sdk.routes.RouteTransferRequest.create(
902
+ const { route: cctpRoute, request } = await createCCTPRoute(
675
903
  this._wormholeContext,
676
- {
677
- source: sourceToken,
678
- destination: destToken
679
- },
680
- sourceContext,
681
- destContext
904
+ sourceChain,
905
+ destinationChain,
906
+ this.crossChainCore.TOKENS
682
907
  );
683
- const resolver = this._wormholeContext.resolver([
684
- import_sdk.routes.CCTPRoute
685
- // manual CCTP
686
- ]);
687
- const route = await resolver.findRoutes(request);
688
- const cctpRoute = route[0];
689
908
  this.wormholeRoute = cctpRoute;
690
909
  this.wormholeRequest = request;
910
+ this.destinationChain = destinationChain;
691
911
  return { route: cctpRoute, request };
692
912
  }
693
913
  async getQuote(input) {
@@ -709,19 +929,19 @@ var WormholeProvider = class {
709
929
  const validated = await route.validate(request, transferParams);
710
930
  if (!validated.valid) {
711
931
  logger.log("invalid", validated.valid);
712
- throw new Error(`Invalid quote: ${validated.error}`).message;
932
+ throw new Error(`Invalid quote: ${validated.error}`);
713
933
  }
714
934
  const quote = await route.quote(request, validated.params);
715
935
  if (!quote.success) {
716
936
  logger.log("quote failed", quote.success);
717
- throw new Error(`Invalid quote: ${quote.error}`).message;
937
+ throw new Error(`Invalid quote: ${quote.error}`);
718
938
  }
719
939
  this.wormholeQuote = quote;
720
940
  logger.log("quote", quote);
721
941
  return quote;
722
942
  }
723
943
  async submitCCTPTransfer(input) {
724
- const { sourceChain, wallet, destinationAddress } = input;
944
+ const { sourceChain, wallet, destinationAddress, onTransactionSigned } = input;
725
945
  if (!this._wormholeContext) {
726
946
  await this.setWormholeContext(sourceChain);
727
947
  }
@@ -747,7 +967,9 @@ var WormholeProvider = class {
747
967
  signerAddress,
748
968
  {},
749
969
  wallet,
750
- this.crossChainCore
970
+ this.crossChainCore,
971
+ void 0,
972
+ onTransactionSigned
751
973
  );
752
974
  logger.log("signer", signer);
753
975
  logger.log("wormholeRequest", this.wormholeRequest);
@@ -756,16 +978,21 @@ var WormholeProvider = class {
756
978
  this.wormholeRequest,
757
979
  signer,
758
980
  this.wormholeQuote,
759
- import_sdk.Wormhole.chainAddress("Aptos", destinationAddress.toString())
981
+ import_sdk3.Wormhole.chainAddress("Aptos", destinationAddress.toString())
760
982
  );
761
983
  const originChainTxnId = "originTxs" in receipt ? receipt.originTxs[receipt.originTxs.length - 1].txid : void 0;
762
984
  return { originChainTxnId: originChainTxnId || "", receipt };
763
985
  }
764
986
  async claimCCTPTransfer(input) {
765
- let { receipt, mainSigner, sponsorAccount } = input;
987
+ let { receipt, mainSigner, sponsorAccount, onTransactionSigned } = input;
766
988
  if (!this.wormholeRoute) {
767
989
  throw new Error("Wormhole route not initialized");
768
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
+ }
769
996
  logger.log("mainSigner", mainSigner.accountAddress.toString());
770
997
  let retries = 0;
771
998
  const maxRetries = 5;
@@ -773,7 +1000,7 @@ var WormholeProvider = class {
773
1000
  while (retries < maxRetries) {
774
1001
  try {
775
1002
  for await (receipt of this.wormholeRoute.track(receipt, 120 * 1e3)) {
776
- if (receipt.state >= import_sdk.TransferState.SourceInitiated) {
1003
+ if (receipt.state >= import_sdk3.TransferState.SourceInitiated) {
777
1004
  logger.log("Receipt is on track ", receipt);
778
1005
  try {
779
1006
  const signer = new AptosLocalSigner(
@@ -783,9 +1010,10 @@ var WormholeProvider = class {
783
1010
  // the account that signs the "claim" transaction
784
1011
  sponsorAccount,
785
1012
  // the fee payer account
786
- this.crossChainCore._dappConfig?.aptosNetwork
1013
+ this.crossChainCore,
1014
+ onTransactionSigned
787
1015
  );
788
- if (import_sdk.routes.isManual(this.wormholeRoute)) {
1016
+ if (import_sdk3.routes.isManual(this.wormholeRoute)) {
789
1017
  const circleAttestationReceipt = await this.wormholeRoute.complete(signer, receipt);
790
1018
  logger.log("Claim receipt: ", circleAttestationReceipt);
791
1019
  const destinationChainTxnId = signer.claimedTransactionHashes();
@@ -828,22 +1056,30 @@ var WormholeProvider = class {
828
1056
  });
829
1057
  }
830
1058
  let { originChainTxnId, receipt } = await this.submitCCTPTransfer(input);
831
- const { destinationChainTxnId } = await this.claimCCTPTransfer({
832
- receipt,
833
- mainSigner: input.mainSigner,
834
- sponsorAccount: input.sponsorAccount
835
- });
836
- return { originChainTxnId, destinationChainTxnId };
837
- }
838
- async withdraw(input) {
839
- const { sourceChain, wallet, destinationAddress, sponsorAccount } = input;
840
- logger.log("sourceChain", sourceChain);
841
- logger.log("wallet", wallet);
842
- logger.log("destinationAddress", destinationAddress);
843
- logger.log("sponsorAccount", sponsorAccount);
844
- if (!this._wormholeContext) {
845
- await this.setWormholeContext(sourceChain);
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
+ );
846
1073
  }
1074
+ }
1075
+ // --- Split withdraw flow: initiateWithdraw + trackWithdraw + claimWithdraw ---
1076
+ /**
1077
+ * Phase 1: Initiates a withdraw by burning USDC on Aptos.
1078
+ * The user signs the Aptos burn transaction via their wallet.
1079
+ * Returns a receipt that can be tracked and later claimed.
1080
+ */
1081
+ async initiateWithdraw(input) {
1082
+ const { wallet, destinationAddress, sponsorAccount, onTransactionSigned } = input;
847
1083
  if (!this._wormholeContext) {
848
1084
  throw new Error("Wormhole context not initialized");
849
1085
  }
@@ -852,69 +1088,49 @@ var WormholeProvider = class {
852
1088
  }
853
1089
  const signer = new Signer(
854
1090
  this.getChainConfig("Aptos"),
855
- (await input.wallet.features["aptos:account"].account()).address.toString(),
1091
+ (await wallet.features["aptos:account"].account()).address.toString(),
856
1092
  {},
857
- input.wallet,
1093
+ wallet,
858
1094
  this.crossChainCore,
859
- sponsorAccount
1095
+ sponsorAccount,
1096
+ onTransactionSigned
860
1097
  );
861
- logger.log("signer", signer);
862
- logger.log("wormholeRequest", this.wormholeRequest);
863
- logger.log("wormholeQuote", this.wormholeQuote);
864
- logger.log(
865
- "Wormhole.chainAddress",
866
- import_sdk.Wormhole.chainAddress(sourceChain, input.destinationAddress.toString())
1098
+ const wormholeDestAddress = import_sdk3.Wormhole.chainAddress(
1099
+ this.destinationChain,
1100
+ destinationAddress.toString()
867
1101
  );
868
- let receipt = await this.wormholeRoute.initiate(
1102
+ const receipt = await this.wormholeRoute.initiate(
869
1103
  this.wormholeRequest,
870
1104
  signer,
871
1105
  this.wormholeQuote,
872
- import_sdk.Wormhole.chainAddress(sourceChain, input.destinationAddress.toString())
1106
+ wormholeDestAddress
873
1107
  );
874
- logger.log("receipt", receipt);
1108
+ logger.log("initiateWithdraw receipt", receipt);
875
1109
  const originChainTxnId = "originTxs" in receipt ? receipt.originTxs[receipt.originTxs.length - 1].txid : void 0;
1110
+ return { originChainTxnId: originChainTxnId || "", receipt };
1111
+ }
1112
+ /**
1113
+ * Phase 2: Tracks a withdraw receipt until attestation is ready.
1114
+ * This polls Wormhole and returns once the receipt reaches the Attested state.
1115
+ */
1116
+ async trackWithdraw(receipt) {
1117
+ if (!this.wormholeRoute) {
1118
+ throw new Error("Wormhole route not initialized");
1119
+ }
876
1120
  let retries = 0;
877
1121
  const maxRetries = 5;
878
1122
  const baseDelay = 1e3;
879
1123
  while (retries < maxRetries) {
880
1124
  try {
881
1125
  for await (receipt of this.wormholeRoute.track(receipt, 120 * 1e3)) {
882
- if (receipt.state >= import_sdk.TransferState.SourceInitiated) {
883
- logger.log("Receipt is on track ", receipt);
884
- try {
885
- const signer2 = new Signer(
886
- this.getChainConfig(sourceChain),
887
- destinationAddress.toString(),
888
- {},
889
- wallet,
890
- this.crossChainCore
891
- );
892
- if (import_sdk.routes.isManual(this.wormholeRoute)) {
893
- const circleAttestationReceipt = await this.wormholeRoute.complete(signer2, receipt);
894
- logger.log("Claim receipt: ", circleAttestationReceipt);
895
- const destinationChainTxnId = signer2.claimedTransactionHashes();
896
- return {
897
- originChainTxnId: originChainTxnId || "",
898
- destinationChainTxnId
899
- };
900
- } else {
901
- return {
902
- originChainTxnId: originChainTxnId || "",
903
- destinationChainTxnId: ""
904
- };
905
- }
906
- } catch (e) {
907
- console.error("Failed to claim", e);
908
- return {
909
- originChainTxnId: originChainTxnId || "",
910
- destinationChainTxnId: ""
911
- };
912
- }
1126
+ if (receipt.state >= import_sdk3.TransferState.Attested) {
1127
+ logger.log("trackWithdraw: receipt attested", receipt);
1128
+ return receipt;
913
1129
  }
914
1130
  }
915
1131
  } catch (e) {
916
1132
  console.error(
917
- `Error tracking transfer (attempt ${retries + 1} / ${maxRetries}):`,
1133
+ `Error tracking withdraw (attempt ${retries + 1} / ${maxRetries}):`,
918
1134
  e
919
1135
  );
920
1136
  const delay = baseDelay * Math.pow(2, retries);
@@ -922,10 +1138,173 @@ var WormholeProvider = class {
922
1138
  retries++;
923
1139
  }
924
1140
  }
925
- return {
926
- originChainTxnId: originChainTxnId || "",
927
- destinationChainTxnId: ""
928
- };
1141
+ throw new Error("Failed to track withdraw to attested state");
1142
+ }
1143
+ /**
1144
+ * Phase 3: Claims the withdraw on the destination chain.
1145
+ *
1146
+ * If the destination is Solana and `solanaConfig.serverClaimUrl` is configured
1147
+ * in the dapp config, the SDK automatically POSTs the attested receipt to that
1148
+ * URL — no wallet popup required. The dapp's server endpoint handles signing
1149
+ * and submitting the claim transaction.
1150
+ *
1151
+ * Otherwise falls back to the wallet-based Signer (triggers wallet popup).
1152
+ */
1153
+ async claimWithdraw(input) {
1154
+ const { claimChain, destinationAddress, receipt } = input;
1155
+ const serverClaimUrl = this.crossChainCore._dappConfig?.solanaConfig?.serverClaimUrl;
1156
+ if (claimChain === "Solana" && serverClaimUrl) {
1157
+ logger.log("claimWithdraw: using server-side claim via", serverClaimUrl);
1158
+ const response = await fetch(serverClaimUrl, {
1159
+ method: "POST",
1160
+ headers: { "Content-Type": "application/json" },
1161
+ body: JSON.stringify({
1162
+ receipt: serializeReceipt(receipt),
1163
+ destinationAddress,
1164
+ claimChain
1165
+ })
1166
+ });
1167
+ if (!response.ok) {
1168
+ const errorData = await response.json().catch(() => ({}));
1169
+ throw new Error(
1170
+ errorData.error || `Server-side claim failed with status ${response.status}`
1171
+ );
1172
+ }
1173
+ const result = await response.json();
1174
+ return { destinationChainTxnId: result.destinationChainTxnId };
1175
+ }
1176
+ if (!this.wormholeRoute) {
1177
+ throw new Error("Wormhole route not initialized");
1178
+ }
1179
+ if (!input.wallet) {
1180
+ throw new Error(
1181
+ "Wallet is required for claim when serverClaimUrl is not configured"
1182
+ );
1183
+ }
1184
+ const claimSigner = new Signer(
1185
+ this.getChainConfig(claimChain),
1186
+ destinationAddress,
1187
+ {},
1188
+ input.wallet,
1189
+ this.crossChainCore,
1190
+ void 0,
1191
+ input.onTransactionSigned,
1192
+ false
1193
+ );
1194
+ if (import_sdk3.routes.isManual(this.wormholeRoute)) {
1195
+ const circleAttestationReceipt = await this.wormholeRoute.complete(
1196
+ claimSigner,
1197
+ receipt
1198
+ );
1199
+ logger.log("claimWithdraw receipt:", circleAttestationReceipt);
1200
+ const destinationChainTxnId = claimSigner.claimedTransactionHashes();
1201
+ return { destinationChainTxnId };
1202
+ } else {
1203
+ throw new Error("Automatic route not supported for manual claim");
1204
+ }
1205
+ }
1206
+ /**
1207
+ * Withdraws USDC from Aptos to a destination chain.
1208
+ * Orchestrates all three phases internally:
1209
+ * 1. Initiate — user signs the Aptos burn transaction
1210
+ * 2. Track — wait for Wormhole attestation
1211
+ * 3. Claim — if serverClaimUrl is configured for Solana, delegates to
1212
+ * the server; otherwise uses the wallet-based signer.
1213
+ *
1214
+ * The optional `onPhaseChange` callback lets the dapp update its UI
1215
+ * as the flow progresses.
1216
+ */
1217
+ async withdraw(input) {
1218
+ const {
1219
+ sourceChain,
1220
+ wallet,
1221
+ destinationAddress,
1222
+ sponsorAccount,
1223
+ onPhaseChange,
1224
+ onTransactionSigned
1225
+ } = input;
1226
+ onPhaseChange?.("initiating");
1227
+ const { originChainTxnId, receipt } = await this.initiateWithdraw({
1228
+ wallet,
1229
+ destinationAddress,
1230
+ sponsorAccount,
1231
+ onTransactionSigned
1232
+ });
1233
+ let currentPhase = "tracking";
1234
+ try {
1235
+ onPhaseChange?.("tracking");
1236
+ const attestedReceipt = await this.trackWithdraw(receipt);
1237
+ currentPhase = "claiming";
1238
+ onPhaseChange?.("claiming");
1239
+ const { destinationChainTxnId } = await this.claimWithdraw({
1240
+ claimChain: sourceChain,
1241
+ destinationAddress: destinationAddress.toString(),
1242
+ receipt: attestedReceipt,
1243
+ wallet,
1244
+ onTransactionSigned
1245
+ });
1246
+ return { originChainTxnId, destinationChainTxnId };
1247
+ } catch (error) {
1248
+ throw new WithdrawError(
1249
+ error?.message ?? "Withdraw failed after Aptos burn",
1250
+ originChainTxnId,
1251
+ currentPhase,
1252
+ error
1253
+ );
1254
+ }
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
+ );
929
1308
  }
930
1309
  getChainConfig(chain) {
931
1310
  const chainConfig = this.crossChainCore.CHAINS[chain];
@@ -934,16 +1313,122 @@ var WormholeProvider = class {
934
1313
  }
935
1314
  return chainConfig;
936
1315
  }
937
- getTokenInfo(sourceChain, destinationChain) {
938
- const sourceToken = import_sdk.Wormhole.tokenId(
939
- this.crossChainCore.TOKENS[sourceChain].tokenId.chain,
940
- this.crossChainCore.TOKENS[sourceChain].tokenId.address
941
- );
942
- const destToken = import_sdk.Wormhole.tokenId(
943
- this.crossChainCore.TOKENS[destinationChain].tokenId.chain,
944
- this.crossChainCore.TOKENS[destinationChain].tokenId.address
1316
+ };
1317
+
1318
+ // src/providers/wormhole/signers/SolanaLocalSigner.ts
1319
+ var import_web34 = require("@solana/web3.js");
1320
+ var SolanaLocalSigner = class {
1321
+ constructor(config) {
1322
+ this._claimedTransactionHashes = [];
1323
+ this.keypair = config.keypair;
1324
+ this.connection = config.connection;
1325
+ this.commitment = config.commitment ?? "finalized";
1326
+ this.retryIntervalMs = config.retryIntervalMs ?? 5e3;
1327
+ this.priorityFeeConfig = config.priorityFeeConfig;
1328
+ this.verbose = config.verbose ?? false;
1329
+ this._onTransactionSigned = config.onTransactionSigned;
1330
+ }
1331
+ chain() {
1332
+ return "Solana";
1333
+ }
1334
+ address() {
1335
+ return this.keypair.publicKey.toBase58();
1336
+ }
1337
+ /**
1338
+ * Returns all transaction hashes from the most recent signAndSend call,
1339
+ * joined by comma. If only one transaction was signed, returns a single hash string.
1340
+ */
1341
+ claimedTransactionHashes() {
1342
+ return this._claimedTransactionHashes.join(",");
1343
+ }
1344
+ async signAndSend(txs) {
1345
+ const txHashes = [];
1346
+ this._claimedTransactionHashes = [];
1347
+ for (const tx of txs) {
1348
+ this._onTransactionSigned?.(tx.description, null);
1349
+ const txId = await this.signAndSendTransaction(tx);
1350
+ this._onTransactionSigned?.(tx.description, txId);
1351
+ txHashes.push(txId);
1352
+ this._claimedTransactionHashes.push(txId);
1353
+ }
1354
+ return txHashes;
1355
+ }
1356
+ async signAndSendTransaction(request) {
1357
+ const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash(this.commitment);
1358
+ let unsignedTx = request.transaction ?? request;
1359
+ const additionalSigners = request.transaction?.signers;
1360
+ const MAX_UNWRAP_DEPTH = 10;
1361
+ let unwrapDepth = 0;
1362
+ while (unsignedTx && typeof unsignedTx === "object" && "transaction" in unsignedTx && !(unsignedTx instanceof import_web34.Transaction) && !("signatures" in unsignedTx && "message" in unsignedTx)) {
1363
+ if (++unwrapDepth > MAX_UNWRAP_DEPTH) {
1364
+ throw new Error(
1365
+ "Transaction unwrapping exceeded maximum depth \u2014 possible circular nesting"
1366
+ );
1367
+ }
1368
+ unsignedTx = unsignedTx.transaction;
1369
+ }
1370
+ const isVersioned = unsignedTx.message !== void 0 && unsignedTx.signatures !== void 0 && typeof unsignedTx.message.recentBlockhash !== "undefined";
1371
+ if (isVersioned) {
1372
+ unsignedTx.message.recentBlockhash = blockhash;
1373
+ if (this.verbose || this.priorityFeeConfig) {
1374
+ console.warn(
1375
+ "SolanaLocalSigner: Versioned transaction detected \u2014 priority fees are not applied. Consider using legacy transactions if priority fees are required."
1376
+ );
1377
+ }
1378
+ unsignedTx.sign([this.keypair]);
1379
+ if (additionalSigners && additionalSigners.length > 0) {
1380
+ unsignedTx.sign(additionalSigners);
1381
+ }
1382
+ } else if (unsignedTx instanceof import_web34.Transaction) {
1383
+ unsignedTx.recentBlockhash = blockhash;
1384
+ unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
1385
+ if (this.priorityFeeConfig) {
1386
+ await addPriorityFeeInstructions(
1387
+ this.connection,
1388
+ unsignedTx,
1389
+ this.priorityFeeConfig,
1390
+ this.verbose
1391
+ );
1392
+ }
1393
+ if (additionalSigners && additionalSigners.length > 0) {
1394
+ unsignedTx.sign(this.keypair, ...additionalSigners);
1395
+ } else {
1396
+ unsignedTx.sign(this.keypair);
1397
+ }
1398
+ } else if (unsignedTx.recentBlockhash !== void 0 || unsignedTx.feePayer !== void 0) {
1399
+ unsignedTx.recentBlockhash = blockhash;
1400
+ unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
1401
+ if (this.priorityFeeConfig) {
1402
+ await addPriorityFeeInstructions(
1403
+ this.connection,
1404
+ unsignedTx,
1405
+ this.priorityFeeConfig,
1406
+ this.verbose
1407
+ );
1408
+ }
1409
+ if (additionalSigners && additionalSigners.length > 0) {
1410
+ unsignedTx.sign(this.keypair, ...additionalSigners);
1411
+ } else {
1412
+ unsignedTx.sign(this.keypair);
1413
+ }
1414
+ } else {
1415
+ throw new Error(
1416
+ `Unsupported transaction type: ${unsignedTx?.constructor?.name}`
1417
+ );
1418
+ }
1419
+ const serializedTx = unsignedTx.serialize();
1420
+ const signature = await sendAndConfirmTransaction(
1421
+ serializedTx,
1422
+ blockhash,
1423
+ lastValidBlockHeight,
1424
+ {
1425
+ connection: this.connection,
1426
+ commitment: this.commitment,
1427
+ retryIntervalMs: this.retryIntervalMs,
1428
+ verbose: this.verbose
1429
+ }
945
1430
  );
946
- return { sourceToken, destToken };
1431
+ return signature;
947
1432
  }
948
1433
  };
949
1434
 
@@ -1017,8 +1502,8 @@ var testnetChains = {
1017
1502
  key: "Solana",
1018
1503
  context: "Solana" /* SOLANA */,
1019
1504
  displayName: "Solana",
1020
- explorerUrl: "https://explorer.solana.com/",
1021
- explorerName: "Solana Explorer",
1505
+ explorerUrl: "https://solscan.io",
1506
+ explorerName: "Solscan",
1022
1507
  chainId: 0,
1023
1508
  icon: "Solana",
1024
1509
  symbol: "SOL",
@@ -1141,8 +1626,8 @@ var mainnetChains = {
1141
1626
  key: "Solana",
1142
1627
  context: "Solana" /* SOLANA */,
1143
1628
  displayName: "Solana",
1144
- explorerUrl: "https://explorer.solana.com/",
1145
- explorerName: "Solana Explorer",
1629
+ explorerUrl: "https://solscan.io",
1630
+ explorerName: "Solscan",
1146
1631
  chainId: 0,
1147
1632
  icon: "Solana",
1148
1633
  symbol: "SOL",
@@ -1294,15 +1779,15 @@ var mainnetTokens = {
1294
1779
 
1295
1780
  // src/utils/getUsdcBalance.ts
1296
1781
  var import_ts_sdk4 = require("@aptos-labs/ts-sdk");
1297
- var import_web34 = require("@solana/web3.js");
1782
+ var import_web35 = require("@solana/web3.js");
1298
1783
  var import_ethers2 = require("ethers");
1299
1784
  var import_client = require("@mysten/sui/client");
1300
1785
  var getSolanaWalletUSDCBalance = async (walletAddress, aptosNetwork, rpc) => {
1301
- const address = new import_web34.PublicKey(walletAddress);
1786
+ const address = new import_web35.PublicKey(walletAddress);
1302
1787
  const tokenAddress = aptosNetwork === import_ts_sdk4.Network.MAINNET ? mainnetTokens["Solana"].tokenId.address : testnetTokens["Solana"].tokenId.address;
1303
- const connection = new import_web34.Connection(rpc);
1788
+ const connection = new import_web35.Connection(rpc);
1304
1789
  const splToken = await connection.getTokenAccountsByOwner(address, {
1305
- mint: new import_web34.PublicKey(tokenAddress)
1790
+ mint: new import_web35.PublicKey(tokenAddress)
1306
1791
  });
1307
1792
  if (splToken.value.length === 0) {
1308
1793
  return "0";
@@ -1353,6 +1838,18 @@ var getSuiWalletUSDCBalance = async (walletAddress, aptosNetwork, rpc) => {
1353
1838
 
1354
1839
  // src/CrossChainCore.ts
1355
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);
1356
1853
  var EthereumChainIdToTestnetChain = {
1357
1854
  11155111: testnetChains.Sepolia,
1358
1855
  84532: testnetChains.BaseSepolia,
@@ -1367,7 +1864,7 @@ var EthereumChainIdToMainnetChain = {
1367
1864
  43114: mainnetChains.Avalanche,
1368
1865
  137: mainnetChains.Polygon
1369
1866
  };
1370
- var CrossChainCore = class {
1867
+ var CrossChainCore2 = class {
1371
1868
  constructor(args) {
1372
1869
  this._dappConfig = {
1373
1870
  aptosNetwork: import_ts_sdk5.Network.TESTNET
@@ -1421,14 +1918,13 @@ var CrossChainCore = class {
1421
1918
  walletAddress,
1422
1919
  this._dappConfig.aptosNetwork,
1423
1920
  sourceChain,
1424
- // TODO: maybe let the user config it
1425
- this.CHAINS[sourceChain].defaultRpc
1921
+ this._dappConfig?.evmConfig?.[sourceChain]?.rpc ?? this.CHAINS[sourceChain].defaultRpc
1426
1922
  );
1427
1923
  case "Sui":
1428
1924
  return await getSuiWalletUSDCBalance(
1429
1925
  walletAddress,
1430
1926
  this._dappConfig.aptosNetwork,
1431
- this.CHAINS[sourceChain].defaultRpc
1927
+ this._dappConfig?.suiConfig?.rpc ?? this.CHAINS[sourceChain].defaultRpc
1432
1928
  );
1433
1929
  default:
1434
1930
  throw new Error(`Unsupported chain: ${sourceChain}`);
@@ -1443,16 +1939,24 @@ var import_ts_sdk7 = require("@aptos-labs/ts-sdk");
1443
1939
  AptosLocalSigner,
1444
1940
  Context,
1445
1941
  CrossChainCore,
1942
+ EVM_CHAIN_NAMES,
1446
1943
  EthereumChainIdToMainnetChain,
1447
1944
  EthereumChainIdToTestnetChain,
1448
1945
  Network,
1449
1946
  NetworkToChainId,
1450
1947
  NetworkToNodeAPI,
1948
+ SolanaLocalSigner,
1949
+ TransferError,
1950
+ WithdrawError,
1451
1951
  WormholeProvider,
1952
+ createCCTPRoute,
1953
+ deserializeReceipt,
1452
1954
  mainnetChains,
1453
1955
  mainnetTokens,
1956
+ serializeReceipt,
1454
1957
  signAndSendTransaction,
1455
1958
  testnetChains,
1456
- testnetTokens
1959
+ testnetTokens,
1960
+ validateExpireTimestamp
1457
1961
  });
1458
1962
  //# sourceMappingURL=index.js.map