@aptos-labs/cross-chain-core 5.8.1 → 5.9.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 (48) hide show
  1. package/README.md +26 -0
  2. package/dist/CrossChainCore.d.ts +20 -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 +580 -275
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +583 -274
  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 +1 -1
  13. package/dist/providers/wormhole/signers/AptosLocalSigner.d.ts.map +1 -1
  14. package/dist/providers/wormhole/signers/Signer.d.ts +1 -1
  15. package/dist/providers/wormhole/signers/Signer.d.ts.map +1 -1
  16. package/dist/providers/wormhole/signers/SolanaLocalSigner.d.ts +65 -0
  17. package/dist/providers/wormhole/signers/SolanaLocalSigner.d.ts.map +1 -0
  18. package/dist/providers/wormhole/signers/SolanaSigner.d.ts +12 -20
  19. package/dist/providers/wormhole/signers/SolanaSigner.d.ts.map +1 -1
  20. package/dist/providers/wormhole/signers/solanaUtils.d.ts +68 -0
  21. package/dist/providers/wormhole/signers/solanaUtils.d.ts.map +1 -0
  22. package/dist/providers/wormhole/types.d.ts +43 -0
  23. package/dist/providers/wormhole/types.d.ts.map +1 -1
  24. package/dist/providers/wormhole/utils.d.ts +26 -0
  25. package/dist/providers/wormhole/utils.d.ts.map +1 -0
  26. package/dist/providers/wormhole/wormhole.d.ts +36 -6
  27. package/dist/providers/wormhole/wormhole.d.ts.map +1 -1
  28. package/dist/utils/receiptSerialization.d.ts +38 -0
  29. package/dist/utils/receiptSerialization.d.ts.map +1 -0
  30. package/dist/version.d.ts +1 -1
  31. package/package.json +3 -3
  32. package/src/CrossChainCore.ts +20 -0
  33. package/src/config/mainnet/chains.ts +2 -2
  34. package/src/config/testnet/chains.ts +2 -2
  35. package/src/index.ts +1 -0
  36. package/src/providers/wormhole/index.ts +2 -0
  37. package/src/providers/wormhole/signers/AptosLocalSigner.ts +4 -4
  38. package/src/providers/wormhole/signers/AptosSigner.ts +1 -1
  39. package/src/providers/wormhole/signers/EthereumSigner.ts +3 -3
  40. package/src/providers/wormhole/signers/Signer.ts +4 -4
  41. package/src/providers/wormhole/signers/SolanaLocalSigner.ts +243 -0
  42. package/src/providers/wormhole/signers/SolanaSigner.ts +45 -337
  43. package/src/providers/wormhole/signers/solanaUtils.ts +422 -0
  44. package/src/providers/wormhole/types.ts +68 -0
  45. package/src/providers/wormhole/utils.ts +72 -0
  46. package/src/providers/wormhole/wormhole.ts +182 -120
  47. package/src/utils/receiptSerialization.ts +141 -0
  48. package/src/version.ts +1 -1
package/dist/index.js CHANGED
@@ -38,9 +38,14 @@ __export(index_exports, {
38
38
  Network: () => import_ts_sdk7.Network,
39
39
  NetworkToChainId: () => import_ts_sdk6.NetworkToChainId,
40
40
  NetworkToNodeAPI: () => import_ts_sdk6.NetworkToNodeAPI,
41
+ SolanaLocalSigner: () => SolanaLocalSigner,
42
+ WithdrawError: () => WithdrawError,
41
43
  WormholeProvider: () => WormholeProvider,
44
+ createCCTPRoute: () => createCCTPRoute,
45
+ deserializeReceipt: () => deserializeReceipt,
42
46
  mainnetChains: () => mainnetChains,
43
47
  mainnetTokens: () => mainnetTokens,
48
+ serializeReceipt: () => serializeReceipt,
44
49
  signAndSendTransaction: () => signAndSendTransaction,
45
50
  testnetChains: () => testnetChains,
46
51
  testnetTokens: () => testnetTokens
@@ -51,7 +56,7 @@ module.exports = __toCommonJS(index_exports);
51
56
  var import_ts_sdk5 = require("@aptos-labs/ts-sdk");
52
57
 
53
58
  // src/providers/wormhole/wormhole.ts
54
- var import_sdk = require("@wormhole-foundation/sdk");
59
+ var import_sdk3 = require("@wormhole-foundation/sdk");
55
60
  var import_ts_sdk3 = require("@aptos-labs/ts-sdk");
56
61
  var import_aptos = __toESM(require("@wormhole-foundation/sdk/aptos"));
57
62
  var import_solana = __toESM(require("@wormhole-foundation/sdk/solana"));
@@ -77,15 +82,99 @@ var logger = {
77
82
  }
78
83
  };
79
84
 
85
+ // src/utils/receiptSerialization.ts
86
+ var import_sdk = require("@wormhole-foundation/sdk");
87
+ function uint8ArrayToBase64(bytes) {
88
+ let binary = "";
89
+ for (let i = 0; i < bytes.length; i++) {
90
+ binary += String.fromCharCode(bytes[i]);
91
+ }
92
+ return btoa(binary);
93
+ }
94
+ function base64ToUint8Array(base64) {
95
+ const binary = atob(base64);
96
+ const bytes = new Uint8Array(binary.length);
97
+ for (let i = 0; i < binary.length; i++) {
98
+ bytes[i] = binary.charCodeAt(i);
99
+ }
100
+ return bytes;
101
+ }
102
+ function serializeReceipt(receipt) {
103
+ return JSON.parse(
104
+ JSON.stringify(receipt, (_key, value) => {
105
+ if (typeof value === "bigint") {
106
+ return { __type: "bigint", value: value.toString() };
107
+ }
108
+ if (value instanceof import_sdk.UniversalAddress) {
109
+ return {
110
+ __type: "UniversalAddress",
111
+ value: uint8ArrayToBase64(value.toUint8Array())
112
+ };
113
+ }
114
+ if (value instanceof Uint8Array) {
115
+ return {
116
+ __type: "Uint8Array",
117
+ value: uint8ArrayToBase64(value)
118
+ };
119
+ }
120
+ return value;
121
+ })
122
+ );
123
+ }
124
+ function deserializeReceipt(obj) {
125
+ function revive(value, key) {
126
+ if (value && typeof value === "object") {
127
+ const objValue = value;
128
+ if ("__type" in objValue) {
129
+ if (objValue.__type === "bigint") {
130
+ return BigInt(objValue.value);
131
+ }
132
+ if (objValue.__type === "UniversalAddress") {
133
+ return new import_sdk.UniversalAddress(
134
+ base64ToUint8Array(objValue.value)
135
+ );
136
+ }
137
+ if (objValue.__type === "Uint8Array") {
138
+ return base64ToUint8Array(objValue.value);
139
+ }
140
+ }
141
+ const addressFields = [
142
+ "sender",
143
+ "recipient",
144
+ "destinationCaller",
145
+ "burnToken",
146
+ "mintRecipient",
147
+ "messageSender"
148
+ ];
149
+ if (key && addressFields.includes(key) && "address" in objValue) {
150
+ const addressBytes = revive(objValue.address);
151
+ if (addressBytes instanceof Uint8Array) {
152
+ return new import_sdk.UniversalAddress(addressBytes);
153
+ }
154
+ }
155
+ if (Array.isArray(value)) {
156
+ return value.map((v, i) => revive(v, String(i)));
157
+ }
158
+ const result = {};
159
+ for (const k in objValue) {
160
+ result[k] = revive(objValue[k], k);
161
+ }
162
+ return result;
163
+ }
164
+ return value;
165
+ }
166
+ return revive(obj);
167
+ }
168
+
80
169
  // src/providers/wormhole/signers/AptosLocalSigner.ts
81
170
  var import_ts_sdk = require("@aptos-labs/ts-sdk");
82
171
  var AptosLocalSigner = class {
83
172
  constructor(chain, options, wallet, feePayerAccount, dappNetwork) {
173
+ this._claimedTransactionHashes = [];
84
174
  this._chain = chain;
85
175
  this._options = options;
86
176
  this._wallet = wallet;
87
177
  this._sponsorAccount = feePayerAccount;
88
- this._claimedTransactionHashes = "";
89
178
  this._dappNetwork = dappNetwork;
90
179
  }
91
180
  chain() {
@@ -95,10 +184,11 @@ var AptosLocalSigner = class {
95
184
  return this._wallet.accountAddress.toString();
96
185
  }
97
186
  claimedTransactionHashes() {
98
- return this._claimedTransactionHashes;
187
+ return this._claimedTransactionHashes.join(",");
99
188
  }
100
189
  async signAndSend(txs) {
101
190
  const txHashes = [];
191
+ this._claimedTransactionHashes = [];
102
192
  for (const tx of txs) {
103
193
  const txId = await signAndSendTransaction(
104
194
  tx,
@@ -107,7 +197,7 @@ var AptosLocalSigner = class {
107
197
  this._dappNetwork
108
198
  );
109
199
  txHashes.push(txId);
110
- this._claimedTransactionHashes = txId;
200
+ this._claimedTransactionHashes.push(txId);
111
201
  }
112
202
  return txHashes;
113
203
  }
@@ -158,119 +248,123 @@ async function signAndSendTransaction(request, wallet, sponsorAccount, dappNetwo
158
248
  }
159
249
 
160
250
  // src/providers/wormhole/signers/SolanaSigner.ts
161
- var import_web3 = require("@solana/web3.js");
162
251
  var import_web32 = require("@solana/web3.js");
163
- var import_sdk_solana = require("@wormhole-foundation/sdk-solana");
164
252
  var import_web33 = require("@solana/web3.js");
165
253
  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;
169
- }
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
182
- );
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;
189
- }
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);
194
- }
195
- const serializedTx = tx.serialize();
254
+
255
+ // src/providers/wormhole/signers/solanaUtils.ts
256
+ var import_web3 = require("@solana/web3.js");
257
+ var import_sdk_solana = require("@wormhole-foundation/sdk-solana");
258
+ async function sendAndConfirmTransaction(serializedTx, blockhash, lastValidBlockHeight, config) {
259
+ const { connection, commitment, retryIntervalMs = 5e3, verbose = false } = config;
196
260
  const sendOptions = {
197
261
  skipPreflight: true,
198
262
  maxRetries: 0,
199
- preFlightCommitment: commitment
200
- // See PR and linked issue for why setting this matters: https://github.com/anza-xyz/agave/pull/483
263
+ preflightCommitment: commitment
201
264
  };
202
- signature = await connection.sendRawTransaction(serializedTx, sendOptions);
203
- confirmTransactionPromise = connection.confirmTransaction(
204
- {
205
- signature,
206
- blockhash,
207
- lastValidBlockHeight
208
- },
265
+ const signature = await connection.sendRawTransaction(serializedTx, sendOptions);
266
+ const confirmTransactionPromise = connection.confirmTransaction(
267
+ { signature, blockhash, lastValidBlockHeight },
209
268
  commitment
210
269
  );
211
- const txRetryInterval = 5e3;
270
+ let confirmedTx = null;
271
+ let txSendAttempts = 1;
212
272
  while (!confirmedTx) {
213
273
  confirmedTx = await Promise.race([
214
274
  confirmTransactionPromise,
215
275
  new Promise(
216
- (resolve) => setTimeout(() => {
217
- resolve(null);
218
- }, txRetryInterval)
276
+ (resolve) => setTimeout(() => resolve(null), retryIntervalMs)
219
277
  )
220
278
  ]);
221
- if (confirmedTx) {
222
- break;
279
+ if (confirmedTx) break;
280
+ if (verbose) {
281
+ console.log(
282
+ `Tx not confirmed after ${retryIntervalMs * txSendAttempts++}ms, resending`
283
+ );
223
284
  }
224
- console.log(
225
- `Tx not confirmed after ${txRetryInterval * txSendAttempts++}ms, resending`
226
- );
227
285
  try {
228
286
  await connection.sendRawTransaction(serializedTx, sendOptions);
229
287
  } catch (e) {
230
- console.error("Failed to resend transaction:", e);
288
+ if (verbose) {
289
+ console.error("Failed to resend transaction:", e);
290
+ }
231
291
  }
232
292
  }
233
293
  if (confirmedTx.value.err) {
234
- let errorMessage = `Transaction failed: ${confirmedTx.value.err}`;
235
- if (typeof confirmedTx.value.err === "object") {
236
- 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
- )}`;
242
- } catch (e) {
243
- errorMessage = `Transaction failed: Unknown error`;
244
- }
245
- }
246
- throw new Error(`Transaction failed: ${errorMessage}`).message;
294
+ const errorMessage = formatTransactionError(confirmedTx.value.err);
295
+ throw new Error(errorMessage);
247
296
  }
248
297
  return signature;
249
298
  }
250
- async function setPriorityFeeInstructions(connection, blockhash, lastValidBlockHeight, request, crossChainCore) {
251
- const unsignedTx = request.transaction.transaction;
299
+ function formatTransactionError(err) {
300
+ if (typeof err === "object" && err !== null) {
301
+ try {
302
+ return `Transaction failed: ${JSON.stringify(
303
+ err,
304
+ (_key, value) => typeof value === "bigint" ? value.toString() : value
305
+ )}`;
306
+ } catch {
307
+ return "Transaction failed: Unknown error";
308
+ }
309
+ }
310
+ return `Transaction failed: ${err}`;
311
+ }
312
+ async function addPriorityFeeInstructions(connection, transaction, priorityFeeConfig, verbose = false) {
252
313
  const computeBudgetIxFilter = (ix) => ix.programId.toString() !== "ComputeBudget111111111111111111111111111111";
253
- unsignedTx.recentBlockhash = blockhash;
254
- unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
255
- unsignedTx.instructions = unsignedTx.instructions.filter(
256
- computeBudgetIxFilter
314
+ transaction.instructions = transaction.instructions.filter(computeBudgetIxFilter);
315
+ const instructions = await createPriorityFeeInstructions(
316
+ connection,
317
+ transaction,
318
+ priorityFeeConfig,
319
+ verbose
257
320
  );
258
- unsignedTx.add(
259
- ...await createPriorityFeeInstructions(
260
- connection,
261
- unsignedTx,
262
- crossChainCore
263
- )
321
+ transaction.add(...instructions);
322
+ return transaction;
323
+ }
324
+ async function createPriorityFeeInstructions(connection, transaction, priorityFeeConfig, verbose = false) {
325
+ const unitsUsed = await simulateAndGetComputeUnits(connection, transaction);
326
+ const unitBudget = Math.floor(unitsUsed * 1.2);
327
+ const instructions = [];
328
+ instructions.push(
329
+ import_web3.ComputeBudgetProgram.setComputeUnitLimit({
330
+ units: unitBudget
331
+ })
264
332
  );
265
- return unsignedTx;
333
+ const {
334
+ percentile = 0.9,
335
+ percentileMultiple = 1,
336
+ min = 1e5,
337
+ max = 1e8
338
+ } = priorityFeeConfig ?? {};
339
+ const rpcProvider = determineRpcProvider(connection.rpcEndpoint);
340
+ const { fee, methodUsed } = await calculatePriorityFee(
341
+ connection,
342
+ transaction,
343
+ rpcProvider,
344
+ { percentile, percentileMultiple, min, max }
345
+ );
346
+ if (verbose) {
347
+ const maxFeeInSol = fee / 1e6 / import_web3.LAMPORTS_PER_SOL * unitBudget;
348
+ console.table({
349
+ "RPC Provider": rpcProvider,
350
+ "Method used": methodUsed,
351
+ "Percentile used": percentile,
352
+ "Multiple used": percentileMultiple,
353
+ "Compute budget": unitBudget,
354
+ "Priority fee": fee,
355
+ "Max fee in SOL": maxFeeInSol
356
+ });
357
+ }
358
+ instructions.push(
359
+ import_web3.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: fee })
360
+ );
361
+ return instructions;
266
362
  }
267
- async function createPriorityFeeInstructions(connection, transaction, crossChainCore) {
363
+ async function simulateAndGetComputeUnits(connection, transaction) {
268
364
  let unitsUsed = 2e5;
269
365
  let simulationAttempts = 0;
270
366
  simulationLoop: while (true) {
271
- const response = await connection.simulateTransaction(
272
- transaction
273
- );
367
+ const response = await connection.simulateTransaction(transaction);
274
368
  if (response.value.err) {
275
369
  if (checkKnownSimulationError(response.value)) {
276
370
  if (simulationAttempts < 5) {
@@ -287,7 +381,7 @@ async function createPriorityFeeInstructions(connection, transaction, crossChain
287
381
  `Simulation failed: ${JSON.stringify(response.value.err)}
288
382
  Logs:
289
383
  ${(response.value.logs || []).join("\n ")}`
290
- ).message;
384
+ );
291
385
  } else {
292
386
  if (response.value.unitsConsumed) {
293
387
  unitsUsed = response.value.unitsConsumed;
@@ -295,41 +389,13 @@ ${(response.value.logs || []).join("\n ")}`
295
389
  break;
296
390
  }
297
391
  }
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
- }
392
+ return unitsUsed;
393
+ }
394
+ async function calculatePriorityFee(connection, transaction, rpcProvider, config) {
395
+ const { percentile, percentileMultiple, min, max } = config;
396
+ if (rpcProvider === "triton") {
331
397
  try {
332
- const fee2 = await (0, import_sdk_solana.determinePriorityFee)(
398
+ const fee = await (0, import_sdk_solana.determinePriorityFeeTritonOne)(
333
399
  connection,
334
400
  transaction,
335
401
  percentile,
@@ -337,37 +403,25 @@ ${(response.value.logs || []).join("\n ")}`
337
403
  min,
338
404
  max
339
405
  );
340
- return {
341
- fee: fee2,
342
- methodUsed: "default"
343
- };
406
+ return { fee, methodUsed: "triton" };
344
407
  } catch (e) {
345
408
  console.warn(`Failed to determine priority fee using Triton RPC:`, e);
346
- return {
347
- fee: min,
348
- methodUsed: "minimum"
349
- };
350
409
  }
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;
410
+ }
411
+ try {
412
+ const fee = await (0, import_sdk_solana.determinePriorityFee)(
413
+ connection,
414
+ transaction,
415
+ percentile,
416
+ percentileMultiple,
417
+ min,
418
+ max
419
+ );
420
+ return { fee, methodUsed: "default" };
421
+ } catch (e) {
422
+ console.warn(`Failed to determine priority fee:`, e);
423
+ return { fee: min, methodUsed: "minimum" };
424
+ }
371
425
  }
372
426
  function checkKnownSimulationError(response) {
373
427
  const errors = {};
@@ -384,61 +438,106 @@ function checkKnownSimulationError(response) {
384
438
  }
385
439
  }
386
440
  }
387
- if (isEmptyObject(errors)) {
441
+ if (Object.keys(errors).length === 0) {
388
442
  return false;
389
443
  }
390
444
  console.table(errors);
391
445
  return true;
392
446
  }
393
- async function sleep(timeout) {
394
- return new Promise((resolve) => setTimeout(resolve, timeout));
447
+ function isHostOrSubdomainOf(hostname, base) {
448
+ return hostname === base || hostname.endsWith(`.${base}`);
395
449
  }
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
450
  function determineRpcProvider(endpoint) {
408
451
  try {
409
452
  const url = new URL(endpoint);
410
453
  const hostname = url.hostname;
411
- if (hostname === "rpcpool.com") {
454
+ if (isHostOrSubdomainOf(hostname, "rpcpool.com") || isHostOrSubdomainOf(hostname, "triton.one")) {
412
455
  return "triton";
413
- } else if (hostname === "helius-rpc.com") {
456
+ } else if (isHostOrSubdomainOf(hostname, "helius-rpc.com") || isHostOrSubdomainOf(hostname, "helius.xyz")) {
414
457
  return "helius";
415
- } else if (hostname === "rpc.ankr.com") {
458
+ } else if (isHostOrSubdomainOf(hostname, "ankr.com")) {
416
459
  return "ankr";
417
460
  } else {
418
461
  return "unknown";
419
462
  }
420
- } catch (e) {
463
+ } catch {
421
464
  return "unknown";
422
465
  }
423
466
  }
467
+ async function sleep(timeout) {
468
+ return new Promise((resolve) => setTimeout(resolve, timeout));
469
+ }
470
+
471
+ // src/providers/wormhole/signers/SolanaSigner.ts
472
+ async function signAndSendTransaction2(request, wallet, options, crossChainCore) {
473
+ if (!wallet || !(wallet instanceof import_derived_wallet_solana.SolanaDerivedWallet)) {
474
+ throw new Error("Invalid wallet type or missing Solana wallet");
475
+ }
476
+ const commitment = options?.commitment ?? "finalized";
477
+ const connection = new import_web33.Connection(
478
+ crossChainCore?._dappConfig?.solanaConfig?.rpc ?? crossChainCore?.CHAINS["Solana"]?.defaultRpc ?? "https://api.devnet.solana.com"
479
+ // Last resort fallback
480
+ );
481
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash(commitment);
482
+ const unsignedTx = await setPriorityFeeInstructions(
483
+ connection,
484
+ blockhash,
485
+ lastValidBlockHeight,
486
+ request,
487
+ crossChainCore?._dappConfig?.solanaConfig?.priorityFeeConfig
488
+ );
489
+ if (!wallet.solanaWallet.signTransaction) {
490
+ throw new Error("Wallet does not support signing transactions");
491
+ }
492
+ const tx = await wallet.solanaWallet.signTransaction(unsignedTx);
493
+ if (!tx) throw new Error("Failed to sign transaction");
494
+ if (request.transaction.signers && tx instanceof import_web32.Transaction) {
495
+ tx.partialSign(...request.transaction.signers);
496
+ }
497
+ const serializedTx = tx.serialize();
498
+ const signature = await sendAndConfirmTransaction(
499
+ serializedTx,
500
+ blockhash,
501
+ lastValidBlockHeight,
502
+ {
503
+ connection,
504
+ commitment,
505
+ retryIntervalMs: 5e3,
506
+ verbose: false
507
+ }
508
+ );
509
+ return signature;
510
+ }
511
+ async function setPriorityFeeInstructions(connection, blockhash, lastValidBlockHeight, request, priorityFeeConfig) {
512
+ const unsignedTx = request.transaction.transaction;
513
+ unsignedTx.recentBlockhash = blockhash;
514
+ unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
515
+ await addPriorityFeeInstructions(
516
+ connection,
517
+ unsignedTx,
518
+ priorityFeeConfig,
519
+ false
520
+ );
521
+ return unsignedTx;
522
+ }
424
523
 
425
524
  // src/providers/wormhole/signers/EthereumSigner.ts
426
525
  var import_ethers = require("ethers");
427
526
  async function signAndSendTransaction3(request, wallet, chainName, options) {
428
527
  if (!wallet) {
429
- throw new Error("wallet.sendTransaction is undefined").message;
528
+ throw new Error("wallet.sendTransaction is undefined");
430
529
  }
431
530
  const chainId = await wallet.eip1193Provider.request({
432
531
  method: "eth_chainId"
433
532
  });
434
533
  const actualChainId = parseInt(chainId, 16);
435
534
  if (!actualChainId)
436
- throw new Error("No signer found for chain" + chainName).message;
535
+ throw new Error("No signer found for chain" + chainName);
437
536
  const expectedChainId = request.transaction.chainId ? (0, import_ethers.getBigInt)(request.transaction.chainId) : void 0;
438
537
  if (!actualChainId || !expectedChainId || BigInt(actualChainId) !== expectedChainId) {
439
538
  throw new Error(
440
539
  `Signer is not connected to the right chain. Expected ${expectedChainId}, got ${actualChainId}`
441
- ).message;
540
+ );
442
541
  }
443
542
  const provider = new import_ethers.ethers.BrowserProvider(
444
543
  wallet.eip1193Provider
@@ -455,7 +554,7 @@ var import_wallet_standard = require("@aptos-labs/wallet-standard");
455
554
  var import_gas_station_client = require("@aptos-labs/gas-station-client");
456
555
  async function signAndSendTransaction4(request, wallet, sponsorAccount, dappNetwork) {
457
556
  if (!wallet) {
458
- throw new Error("wallet.sendTransaction is undefined").message;
557
+ throw new Error("wallet.sendTransaction is undefined");
459
558
  }
460
559
  const payload = request.transaction;
461
560
  payload.functionArguments = payload.functionArguments.map((a) => {
@@ -555,13 +654,13 @@ async function signAndSendTransaction5(request, wallet) {
555
654
  // src/providers/wormhole/signers/Signer.ts
556
655
  var Signer = class {
557
656
  constructor(chain, address, options, wallet, crossChainCore, sponsorAccount) {
657
+ this._claimedTransactionHashes = [];
558
658
  this._chain = chain;
559
659
  this._address = address;
560
660
  this._options = options;
561
661
  this._wallet = wallet;
562
662
  this._crossChainCore = crossChainCore;
563
663
  this._sponsorAccount = sponsorAccount;
564
- this._claimedTransactionHashes = "";
565
664
  }
566
665
  chain() {
567
666
  return this._chain.key;
@@ -570,10 +669,11 @@ var Signer = class {
570
669
  return this._address;
571
670
  }
572
671
  claimedTransactionHashes() {
573
- return this._claimedTransactionHashes;
672
+ return this._claimedTransactionHashes.join(",");
574
673
  }
575
674
  async signAndSend(txs) {
576
675
  const txHashes = [];
676
+ this._claimedTransactionHashes = [];
577
677
  for (const tx of txs) {
578
678
  const txId = await signAndSendTransaction6(
579
679
  this._chain,
@@ -584,7 +684,7 @@ var Signer = class {
584
684
  this._sponsorAccount
585
685
  );
586
686
  txHashes.push(txId);
587
- this._claimedTransactionHashes = txId;
687
+ this._claimedTransactionHashes.push(txId);
588
688
  }
589
689
  return txHashes;
590
690
  }
@@ -629,6 +729,45 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
629
729
  }
630
730
  };
631
731
 
732
+ // src/providers/wormhole/utils.ts
733
+ var import_sdk2 = require("@wormhole-foundation/sdk");
734
+ async function createCCTPRoute(wh, sourceChain, destChain, tokens) {
735
+ const sourceToken = import_sdk2.Wormhole.tokenId(
736
+ sourceChain,
737
+ tokens[sourceChain].tokenId.address
738
+ );
739
+ const destToken = import_sdk2.Wormhole.tokenId(
740
+ destChain,
741
+ tokens[destChain].tokenId.address
742
+ );
743
+ const destContext = wh.getPlatform((0, import_sdk2.chainToPlatform)(destChain)).getChain(destChain);
744
+ const sourceContext = wh.getPlatform((0, import_sdk2.chainToPlatform)(sourceChain)).getChain(sourceChain);
745
+ const request = await import_sdk2.routes.RouteTransferRequest.create(
746
+ wh,
747
+ { source: sourceToken, destination: destToken },
748
+ sourceContext,
749
+ destContext
750
+ );
751
+ const resolver = wh.resolver([import_sdk2.routes.CCTPRoute]);
752
+ const foundRoutes = await resolver.findRoutes(request);
753
+ const cctpRoute = foundRoutes[0];
754
+ if (!cctpRoute || !import_sdk2.routes.isManual(cctpRoute)) {
755
+ throw new Error("Expected manual CCTP route");
756
+ }
757
+ return { route: cctpRoute, request };
758
+ }
759
+
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
+
632
771
  // src/providers/wormhole/wormhole.ts
633
772
  var WormholeProvider = class {
634
773
  constructor(core) {
@@ -648,7 +787,7 @@ var WormholeProvider = class {
648
787
  const isMainnet = dappNetwork === import_ts_sdk3.Network.MAINNET;
649
788
  const platforms = [import_aptos.default, import_solana.default, import_evm.default, import_sui.default];
650
789
  const solanaRpc = this.crossChainCore._dappConfig?.solanaConfig?.rpc ?? this.crossChainCore.CHAINS["Solana"]?.defaultRpc;
651
- const wh = await (0, import_sdk.wormhole)(isMainnet ? "Mainnet" : "Testnet", platforms, {
790
+ const wh = await (0, import_sdk3.wormhole)(isMainnet ? "Mainnet" : "Testnet", platforms, {
652
791
  chains: {
653
792
  Solana: {
654
793
  rpc: solanaRpc
@@ -661,33 +800,15 @@ var WormholeProvider = class {
661
800
  if (!this._wormholeContext) {
662
801
  throw new Error("Wormhole context not initialized");
663
802
  }
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(
803
+ const { route: cctpRoute, request } = await createCCTPRoute(
675
804
  this._wormholeContext,
676
- {
677
- source: sourceToken,
678
- destination: destToken
679
- },
680
- sourceContext,
681
- destContext
805
+ sourceChain,
806
+ destinationChain,
807
+ this.crossChainCore.TOKENS
682
808
  );
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
809
  this.wormholeRoute = cctpRoute;
690
810
  this.wormholeRequest = request;
811
+ this.destinationChain = destinationChain;
691
812
  return { route: cctpRoute, request };
692
813
  }
693
814
  async getQuote(input) {
@@ -709,12 +830,12 @@ var WormholeProvider = class {
709
830
  const validated = await route.validate(request, transferParams);
710
831
  if (!validated.valid) {
711
832
  logger.log("invalid", validated.valid);
712
- throw new Error(`Invalid quote: ${validated.error}`).message;
833
+ throw new Error(`Invalid quote: ${validated.error}`);
713
834
  }
714
835
  const quote = await route.quote(request, validated.params);
715
836
  if (!quote.success) {
716
837
  logger.log("quote failed", quote.success);
717
- throw new Error(`Invalid quote: ${quote.error}`).message;
838
+ throw new Error(`Invalid quote: ${quote.error}`);
718
839
  }
719
840
  this.wormholeQuote = quote;
720
841
  logger.log("quote", quote);
@@ -756,7 +877,7 @@ var WormholeProvider = class {
756
877
  this.wormholeRequest,
757
878
  signer,
758
879
  this.wormholeQuote,
759
- import_sdk.Wormhole.chainAddress("Aptos", destinationAddress.toString())
880
+ import_sdk3.Wormhole.chainAddress("Aptos", destinationAddress.toString())
760
881
  );
761
882
  const originChainTxnId = "originTxs" in receipt ? receipt.originTxs[receipt.originTxs.length - 1].txid : void 0;
762
883
  return { originChainTxnId: originChainTxnId || "", receipt };
@@ -773,7 +894,7 @@ var WormholeProvider = class {
773
894
  while (retries < maxRetries) {
774
895
  try {
775
896
  for await (receipt of this.wormholeRoute.track(receipt, 120 * 1e3)) {
776
- if (receipt.state >= import_sdk.TransferState.SourceInitiated) {
897
+ if (receipt.state >= import_sdk3.TransferState.SourceInitiated) {
777
898
  logger.log("Receipt is on track ", receipt);
778
899
  try {
779
900
  const signer = new AptosLocalSigner(
@@ -785,7 +906,7 @@ var WormholeProvider = class {
785
906
  // the fee payer account
786
907
  this.crossChainCore._dappConfig?.aptosNetwork
787
908
  );
788
- if (import_sdk.routes.isManual(this.wormholeRoute)) {
909
+ if (import_sdk3.routes.isManual(this.wormholeRoute)) {
789
910
  const circleAttestationReceipt = await this.wormholeRoute.complete(signer, receipt);
790
911
  logger.log("Claim receipt: ", circleAttestationReceipt);
791
912
  const destinationChainTxnId = signer.claimedTransactionHashes();
@@ -835,15 +956,14 @@ var WormholeProvider = class {
835
956
  });
836
957
  return { originChainTxnId, destinationChainTxnId };
837
958
  }
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);
846
- }
959
+ // --- Split withdraw flow: initiateWithdraw + trackWithdraw + claimWithdraw ---
960
+ /**
961
+ * Phase 1: Initiates a withdraw by burning USDC on Aptos.
962
+ * The user signs the Aptos burn transaction via their wallet.
963
+ * Returns a receipt that can be tracked and later claimed.
964
+ */
965
+ async initiateWithdraw(input) {
966
+ const { wallet, destinationAddress, sponsorAccount } = input;
847
967
  if (!this._wormholeContext) {
848
968
  throw new Error("Wormhole context not initialized");
849
969
  }
@@ -852,69 +972,48 @@ var WormholeProvider = class {
852
972
  }
853
973
  const signer = new Signer(
854
974
  this.getChainConfig("Aptos"),
855
- (await input.wallet.features["aptos:account"].account()).address.toString(),
975
+ (await wallet.features["aptos:account"].account()).address.toString(),
856
976
  {},
857
- input.wallet,
977
+ wallet,
858
978
  this.crossChainCore,
859
979
  sponsorAccount
860
980
  );
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())
981
+ const wormholeDestAddress = import_sdk3.Wormhole.chainAddress(
982
+ this.destinationChain,
983
+ destinationAddress.toString()
867
984
  );
868
- let receipt = await this.wormholeRoute.initiate(
985
+ const receipt = await this.wormholeRoute.initiate(
869
986
  this.wormholeRequest,
870
987
  signer,
871
988
  this.wormholeQuote,
872
- import_sdk.Wormhole.chainAddress(sourceChain, input.destinationAddress.toString())
989
+ wormholeDestAddress
873
990
  );
874
- logger.log("receipt", receipt);
991
+ logger.log("initiateWithdraw receipt", receipt);
875
992
  const originChainTxnId = "originTxs" in receipt ? receipt.originTxs[receipt.originTxs.length - 1].txid : void 0;
993
+ return { originChainTxnId: originChainTxnId || "", receipt };
994
+ }
995
+ /**
996
+ * Phase 2: Tracks a withdraw receipt until attestation is ready.
997
+ * This polls Wormhole and returns once the receipt reaches the Attested state.
998
+ */
999
+ async trackWithdraw(receipt) {
1000
+ if (!this.wormholeRoute) {
1001
+ throw new Error("Wormhole route not initialized");
1002
+ }
876
1003
  let retries = 0;
877
1004
  const maxRetries = 5;
878
1005
  const baseDelay = 1e3;
879
1006
  while (retries < maxRetries) {
880
1007
  try {
881
1008
  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
- }
1009
+ if (receipt.state >= import_sdk3.TransferState.Attested) {
1010
+ logger.log("trackWithdraw: receipt attested", receipt);
1011
+ return receipt;
913
1012
  }
914
1013
  }
915
1014
  } catch (e) {
916
1015
  console.error(
917
- `Error tracking transfer (attempt ${retries + 1} / ${maxRetries}):`,
1016
+ `Error tracking withdraw (attempt ${retries + 1} / ${maxRetries}):`,
918
1017
  e
919
1018
  );
920
1019
  const delay = baseDelay * Math.pow(2, retries);
@@ -922,10 +1021,108 @@ var WormholeProvider = class {
922
1021
  retries++;
923
1022
  }
924
1023
  }
925
- return {
926
- originChainTxnId: originChainTxnId || "",
927
- destinationChainTxnId: ""
928
- };
1024
+ throw new Error("Failed to track withdraw to attested state");
1025
+ }
1026
+ /**
1027
+ * Phase 3: Claims the withdraw on the destination chain.
1028
+ *
1029
+ * If the destination is Solana and `solanaConfig.serverClaimUrl` is configured
1030
+ * in the dapp config, the SDK automatically POSTs the attested receipt to that
1031
+ * URL — no wallet popup required. The dapp's server endpoint handles signing
1032
+ * and submitting the claim transaction.
1033
+ *
1034
+ * Otherwise falls back to the wallet-based Signer (triggers wallet popup).
1035
+ */
1036
+ async claimWithdraw(input) {
1037
+ const { sourceChain, destinationAddress, receipt } = input;
1038
+ const serverClaimUrl = this.crossChainCore._dappConfig?.solanaConfig?.serverClaimUrl;
1039
+ if (sourceChain === "Solana" && serverClaimUrl) {
1040
+ logger.log("claimWithdraw: using server-side claim via", serverClaimUrl);
1041
+ const response = await fetch(serverClaimUrl, {
1042
+ method: "POST",
1043
+ headers: { "Content-Type": "application/json" },
1044
+ body: JSON.stringify({
1045
+ receipt: serializeReceipt(receipt),
1046
+ destinationAddress,
1047
+ sourceChain
1048
+ })
1049
+ });
1050
+ if (!response.ok) {
1051
+ const errorData = await response.json().catch(() => ({}));
1052
+ throw new Error(
1053
+ errorData.error || `Server-side claim failed with status ${response.status}`
1054
+ );
1055
+ }
1056
+ const result = await response.json();
1057
+ return { destinationChainTxnId: result.destinationChainTxnId };
1058
+ }
1059
+ if (!this.wormholeRoute) {
1060
+ throw new Error("Wormhole route not initialized");
1061
+ }
1062
+ if (!input.wallet) {
1063
+ throw new Error(
1064
+ "Wallet is required for claim when serverClaimUrl is not configured"
1065
+ );
1066
+ }
1067
+ const claimSigner = new Signer(
1068
+ this.getChainConfig(sourceChain),
1069
+ destinationAddress,
1070
+ {},
1071
+ input.wallet,
1072
+ this.crossChainCore
1073
+ );
1074
+ if (import_sdk3.routes.isManual(this.wormholeRoute)) {
1075
+ const circleAttestationReceipt = await this.wormholeRoute.complete(
1076
+ claimSigner,
1077
+ receipt
1078
+ );
1079
+ logger.log("claimWithdraw receipt:", circleAttestationReceipt);
1080
+ const destinationChainTxnId = claimSigner.claimedTransactionHashes();
1081
+ return { destinationChainTxnId };
1082
+ } else {
1083
+ throw new Error("Automatic route not supported for manual claim");
1084
+ }
1085
+ }
1086
+ /**
1087
+ * Withdraws USDC from Aptos to a destination chain.
1088
+ * Orchestrates all three phases internally:
1089
+ * 1. Initiate — user signs the Aptos burn transaction
1090
+ * 2. Track — wait for Wormhole attestation
1091
+ * 3. Claim — if serverClaimUrl is configured for Solana, delegates to
1092
+ * the server; otherwise uses the wallet-based signer.
1093
+ *
1094
+ * The optional `onPhaseChange` callback lets the dapp update its UI
1095
+ * as the flow progresses.
1096
+ */
1097
+ async withdraw(input) {
1098
+ const { sourceChain, wallet, destinationAddress, sponsorAccount, onPhaseChange } = input;
1099
+ onPhaseChange?.("initiating");
1100
+ const { originChainTxnId, receipt } = await this.initiateWithdraw({
1101
+ wallet,
1102
+ destinationAddress,
1103
+ sponsorAccount
1104
+ });
1105
+ let currentPhase = "tracking";
1106
+ try {
1107
+ onPhaseChange?.("tracking");
1108
+ const attestedReceipt = await this.trackWithdraw(receipt);
1109
+ currentPhase = "claiming";
1110
+ onPhaseChange?.("claiming");
1111
+ const { destinationChainTxnId } = await this.claimWithdraw({
1112
+ sourceChain,
1113
+ destinationAddress: destinationAddress.toString(),
1114
+ receipt: attestedReceipt,
1115
+ wallet
1116
+ });
1117
+ return { originChainTxnId, destinationChainTxnId };
1118
+ } catch (error) {
1119
+ throw new WithdrawError(
1120
+ error?.message ?? "Withdraw failed after Aptos burn",
1121
+ originChainTxnId,
1122
+ currentPhase,
1123
+ error
1124
+ );
1125
+ }
929
1126
  }
930
1127
  getChainConfig(chain) {
931
1128
  const chainConfig = this.crossChainCore.CHAINS[chain];
@@ -934,16 +1131,119 @@ var WormholeProvider = class {
934
1131
  }
935
1132
  return chainConfig;
936
1133
  }
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
1134
+ };
1135
+
1136
+ // src/providers/wormhole/signers/SolanaLocalSigner.ts
1137
+ var import_web34 = require("@solana/web3.js");
1138
+ var SolanaLocalSigner = class {
1139
+ constructor(config) {
1140
+ this._claimedTransactionHashes = [];
1141
+ this.keypair = config.keypair;
1142
+ this.connection = config.connection;
1143
+ this.commitment = config.commitment ?? "finalized";
1144
+ this.retryIntervalMs = config.retryIntervalMs ?? 5e3;
1145
+ this.priorityFeeConfig = config.priorityFeeConfig;
1146
+ this.verbose = config.verbose ?? false;
1147
+ }
1148
+ chain() {
1149
+ return "Solana";
1150
+ }
1151
+ address() {
1152
+ return this.keypair.publicKey.toBase58();
1153
+ }
1154
+ /**
1155
+ * Returns all transaction hashes from the most recent signAndSend call,
1156
+ * joined by comma. If only one transaction was signed, returns a single hash string.
1157
+ */
1158
+ claimedTransactionHashes() {
1159
+ return this._claimedTransactionHashes.join(",");
1160
+ }
1161
+ async signAndSend(txs) {
1162
+ const txHashes = [];
1163
+ this._claimedTransactionHashes = [];
1164
+ for (const tx of txs) {
1165
+ const txId = await this.signAndSendTransaction(tx);
1166
+ txHashes.push(txId);
1167
+ this._claimedTransactionHashes.push(txId);
1168
+ }
1169
+ return txHashes;
1170
+ }
1171
+ async signAndSendTransaction(request) {
1172
+ const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash(this.commitment);
1173
+ let unsignedTx = request.transaction ?? request;
1174
+ const additionalSigners = request.transaction?.signers;
1175
+ const MAX_UNWRAP_DEPTH = 10;
1176
+ let unwrapDepth = 0;
1177
+ while (unsignedTx && typeof unsignedTx === "object" && "transaction" in unsignedTx && !(unsignedTx instanceof import_web34.Transaction) && !("signatures" in unsignedTx && "message" in unsignedTx)) {
1178
+ if (++unwrapDepth > MAX_UNWRAP_DEPTH) {
1179
+ throw new Error(
1180
+ "Transaction unwrapping exceeded maximum depth \u2014 possible circular nesting"
1181
+ );
1182
+ }
1183
+ unsignedTx = unsignedTx.transaction;
1184
+ }
1185
+ const isVersioned = unsignedTx.message !== void 0 && unsignedTx.signatures !== void 0 && typeof unsignedTx.message.recentBlockhash !== "undefined";
1186
+ if (isVersioned) {
1187
+ unsignedTx.message.recentBlockhash = blockhash;
1188
+ if (this.verbose || this.priorityFeeConfig) {
1189
+ console.warn(
1190
+ "SolanaLocalSigner: Versioned transaction detected \u2014 priority fees are not applied. Consider using legacy transactions if priority fees are required."
1191
+ );
1192
+ }
1193
+ unsignedTx.sign([this.keypair]);
1194
+ if (additionalSigners && additionalSigners.length > 0) {
1195
+ unsignedTx.sign(additionalSigners);
1196
+ }
1197
+ } else if (unsignedTx instanceof import_web34.Transaction) {
1198
+ unsignedTx.recentBlockhash = blockhash;
1199
+ unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
1200
+ if (this.priorityFeeConfig) {
1201
+ await addPriorityFeeInstructions(
1202
+ this.connection,
1203
+ unsignedTx,
1204
+ this.priorityFeeConfig,
1205
+ this.verbose
1206
+ );
1207
+ }
1208
+ if (additionalSigners && additionalSigners.length > 0) {
1209
+ unsignedTx.sign(this.keypair, ...additionalSigners);
1210
+ } else {
1211
+ unsignedTx.sign(this.keypair);
1212
+ }
1213
+ } else if (unsignedTx.recentBlockhash !== void 0 || unsignedTx.feePayer !== void 0) {
1214
+ unsignedTx.recentBlockhash = blockhash;
1215
+ unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
1216
+ if (this.priorityFeeConfig) {
1217
+ await addPriorityFeeInstructions(
1218
+ this.connection,
1219
+ unsignedTx,
1220
+ this.priorityFeeConfig,
1221
+ this.verbose
1222
+ );
1223
+ }
1224
+ if (additionalSigners && additionalSigners.length > 0) {
1225
+ unsignedTx.sign(this.keypair, ...additionalSigners);
1226
+ } else {
1227
+ unsignedTx.sign(this.keypair);
1228
+ }
1229
+ } else {
1230
+ throw new Error(
1231
+ `Unsupported transaction type: ${unsignedTx?.constructor?.name}`
1232
+ );
1233
+ }
1234
+ const serializedTx = unsignedTx.serialize();
1235
+ const signature = await sendAndConfirmTransaction(
1236
+ serializedTx,
1237
+ blockhash,
1238
+ lastValidBlockHeight,
1239
+ {
1240
+ connection: this.connection,
1241
+ commitment: this.commitment,
1242
+ retryIntervalMs: this.retryIntervalMs,
1243
+ verbose: this.verbose
1244
+ }
945
1245
  );
946
- return { sourceToken, destToken };
1246
+ return signature;
947
1247
  }
948
1248
  };
949
1249
 
@@ -1017,8 +1317,8 @@ var testnetChains = {
1017
1317
  key: "Solana",
1018
1318
  context: "Solana" /* SOLANA */,
1019
1319
  displayName: "Solana",
1020
- explorerUrl: "https://explorer.solana.com/",
1021
- explorerName: "Solana Explorer",
1320
+ explorerUrl: "https://solscan.io",
1321
+ explorerName: "Solscan",
1022
1322
  chainId: 0,
1023
1323
  icon: "Solana",
1024
1324
  symbol: "SOL",
@@ -1141,8 +1441,8 @@ var mainnetChains = {
1141
1441
  key: "Solana",
1142
1442
  context: "Solana" /* SOLANA */,
1143
1443
  displayName: "Solana",
1144
- explorerUrl: "https://explorer.solana.com/",
1145
- explorerName: "Solana Explorer",
1444
+ explorerUrl: "https://solscan.io",
1445
+ explorerName: "Solscan",
1146
1446
  chainId: 0,
1147
1447
  icon: "Solana",
1148
1448
  symbol: "SOL",
@@ -1294,15 +1594,15 @@ var mainnetTokens = {
1294
1594
 
1295
1595
  // src/utils/getUsdcBalance.ts
1296
1596
  var import_ts_sdk4 = require("@aptos-labs/ts-sdk");
1297
- var import_web34 = require("@solana/web3.js");
1597
+ var import_web35 = require("@solana/web3.js");
1298
1598
  var import_ethers2 = require("ethers");
1299
1599
  var import_client = require("@mysten/sui/client");
1300
1600
  var getSolanaWalletUSDCBalance = async (walletAddress, aptosNetwork, rpc) => {
1301
- const address = new import_web34.PublicKey(walletAddress);
1601
+ const address = new import_web35.PublicKey(walletAddress);
1302
1602
  const tokenAddress = aptosNetwork === import_ts_sdk4.Network.MAINNET ? mainnetTokens["Solana"].tokenId.address : testnetTokens["Solana"].tokenId.address;
1303
- const connection = new import_web34.Connection(rpc);
1603
+ const connection = new import_web35.Connection(rpc);
1304
1604
  const splToken = await connection.getTokenAccountsByOwner(address, {
1305
- mint: new import_web34.PublicKey(tokenAddress)
1605
+ mint: new import_web35.PublicKey(tokenAddress)
1306
1606
  });
1307
1607
  if (splToken.value.length === 0) {
1308
1608
  return "0";
@@ -1448,9 +1748,14 @@ var import_ts_sdk7 = require("@aptos-labs/ts-sdk");
1448
1748
  Network,
1449
1749
  NetworkToChainId,
1450
1750
  NetworkToNodeAPI,
1751
+ SolanaLocalSigner,
1752
+ WithdrawError,
1451
1753
  WormholeProvider,
1754
+ createCCTPRoute,
1755
+ deserializeReceipt,
1452
1756
  mainnetChains,
1453
1757
  mainnetTokens,
1758
+ serializeReceipt,
1454
1759
  signAndSendTransaction,
1455
1760
  testnetChains,
1456
1761
  testnetTokens