@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.mjs CHANGED
@@ -3,9 +3,8 @@ import { Network as Network3 } from "@aptos-labs/ts-sdk";
3
3
 
4
4
  // src/providers/wormhole/wormhole.ts
5
5
  import {
6
- chainToPlatform,
7
- routes,
8
- Wormhole,
6
+ routes as routes3,
7
+ Wormhole as Wormhole2,
9
8
  wormhole,
10
9
  TransferState
11
10
  } from "@wormhole-foundation/sdk";
@@ -34,6 +33,92 @@ var logger = {
34
33
  }
35
34
  };
36
35
 
36
+ // src/utils/receiptSerialization.ts
37
+ import {
38
+ UniversalAddress
39
+ } from "@wormhole-foundation/sdk";
40
+ function uint8ArrayToBase64(bytes) {
41
+ let binary = "";
42
+ for (let i = 0; i < bytes.length; i++) {
43
+ binary += String.fromCharCode(bytes[i]);
44
+ }
45
+ return btoa(binary);
46
+ }
47
+ function base64ToUint8Array(base64) {
48
+ const binary = atob(base64);
49
+ const bytes = new Uint8Array(binary.length);
50
+ for (let i = 0; i < binary.length; i++) {
51
+ bytes[i] = binary.charCodeAt(i);
52
+ }
53
+ return bytes;
54
+ }
55
+ function serializeReceipt(receipt) {
56
+ return JSON.parse(
57
+ JSON.stringify(receipt, (_key, value) => {
58
+ if (typeof value === "bigint") {
59
+ return { __type: "bigint", value: value.toString() };
60
+ }
61
+ if (value instanceof UniversalAddress) {
62
+ return {
63
+ __type: "UniversalAddress",
64
+ value: uint8ArrayToBase64(value.toUint8Array())
65
+ };
66
+ }
67
+ if (value instanceof Uint8Array) {
68
+ return {
69
+ __type: "Uint8Array",
70
+ value: uint8ArrayToBase64(value)
71
+ };
72
+ }
73
+ return value;
74
+ })
75
+ );
76
+ }
77
+ function deserializeReceipt(obj) {
78
+ function revive(value, key) {
79
+ if (value && typeof value === "object") {
80
+ const objValue = value;
81
+ if ("__type" in objValue) {
82
+ if (objValue.__type === "bigint") {
83
+ return BigInt(objValue.value);
84
+ }
85
+ if (objValue.__type === "UniversalAddress") {
86
+ return new UniversalAddress(
87
+ base64ToUint8Array(objValue.value)
88
+ );
89
+ }
90
+ if (objValue.__type === "Uint8Array") {
91
+ return base64ToUint8Array(objValue.value);
92
+ }
93
+ }
94
+ const addressFields = [
95
+ "sender",
96
+ "recipient",
97
+ "destinationCaller",
98
+ "burnToken",
99
+ "mintRecipient",
100
+ "messageSender"
101
+ ];
102
+ if (key && addressFields.includes(key) && "address" in objValue) {
103
+ const addressBytes = revive(objValue.address);
104
+ if (addressBytes instanceof Uint8Array) {
105
+ return new UniversalAddress(addressBytes);
106
+ }
107
+ }
108
+ if (Array.isArray(value)) {
109
+ return value.map((v, i) => revive(v, String(i)));
110
+ }
111
+ const result = {};
112
+ for (const k in objValue) {
113
+ result[k] = revive(objValue[k], k);
114
+ }
115
+ return result;
116
+ }
117
+ return value;
118
+ }
119
+ return revive(obj);
120
+ }
121
+
37
122
  // src/providers/wormhole/signers/AptosLocalSigner.ts
38
123
  import {
39
124
  Aptos,
@@ -41,11 +126,11 @@ import {
41
126
  } from "@aptos-labs/ts-sdk";
42
127
  var AptosLocalSigner = class {
43
128
  constructor(chain, options, wallet, feePayerAccount, dappNetwork) {
129
+ this._claimedTransactionHashes = [];
44
130
  this._chain = chain;
45
131
  this._options = options;
46
132
  this._wallet = wallet;
47
133
  this._sponsorAccount = feePayerAccount;
48
- this._claimedTransactionHashes = "";
49
134
  this._dappNetwork = dappNetwork;
50
135
  }
51
136
  chain() {
@@ -55,10 +140,11 @@ var AptosLocalSigner = class {
55
140
  return this._wallet.accountAddress.toString();
56
141
  }
57
142
  claimedTransactionHashes() {
58
- return this._claimedTransactionHashes;
143
+ return this._claimedTransactionHashes.join(",");
59
144
  }
60
145
  async signAndSend(txs) {
61
146
  const txHashes = [];
147
+ this._claimedTransactionHashes = [];
62
148
  for (const tx of txs) {
63
149
  const txId = await signAndSendTransaction(
64
150
  tx,
@@ -67,7 +153,7 @@ var AptosLocalSigner = class {
67
153
  this._dappNetwork
68
154
  );
69
155
  txHashes.push(txId);
70
- this._claimedTransactionHashes = txId;
156
+ this._claimedTransactionHashes.push(txId);
71
157
  }
72
158
  return txHashes;
73
159
  }
@@ -118,125 +204,131 @@ async function signAndSendTransaction(request, wallet, sponsorAccount, dappNetwo
118
204
  }
119
205
 
120
206
  // src/providers/wormhole/signers/SolanaSigner.ts
207
+ import {
208
+ Transaction as Transaction2
209
+ } from "@solana/web3.js";
210
+ import { Connection as Connection2 } from "@solana/web3.js";
211
+ import { SolanaDerivedWallet } from "@aptos-labs/derived-wallet-solana";
212
+
213
+ // src/providers/wormhole/signers/solanaUtils.ts
121
214
  import {
122
215
  ComputeBudgetProgram,
123
216
  LAMPORTS_PER_SOL
124
217
  } from "@solana/web3.js";
125
- import { Transaction } from "@solana/web3.js";
126
218
  import {
127
219
  determinePriorityFee,
128
220
  determinePriorityFeeTritonOne
129
221
  } from "@wormhole-foundation/sdk-solana";
130
- import { Connection } from "@solana/web3.js";
131
- import { SolanaDerivedWallet } from "@aptos-labs/derived-wallet-solana";
132
- async function signAndSendTransaction2(request, wallet, options, crossChainCore) {
133
- if (!wallet || !(wallet instanceof SolanaDerivedWallet)) {
134
- throw new Error("Invalid wallet type or missing Solana wallet").message;
135
- }
136
- const commitment = options?.commitment ?? "finalized";
137
- const connection = new Connection(
138
- crossChainCore?._dappConfig?.solanaConfig?.rpc ?? crossChainCore?.CHAINS["Solana"]?.defaultRpc ?? "https://api.devnet.solana.com"
139
- // Last resort fallback
140
- );
141
- const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash(commitment);
142
- const unsignedTx = await setPriorityFeeInstructions(
143
- connection,
144
- blockhash,
145
- lastValidBlockHeight,
146
- request,
147
- crossChainCore
148
- );
149
- let confirmTransactionPromise = null;
150
- let confirmedTx = null;
151
- let txSendAttempts = 1;
152
- let signature = "";
153
- if (!wallet.solanaWallet.signTransaction) {
154
- throw new Error("Wallet does not support signing transactions").message;
155
- }
156
- const tx = await wallet.solanaWallet.signTransaction(unsignedTx);
157
- if (!tx) throw new Error("Failed to sign transaction").message;
158
- if (request.transaction.signers && tx instanceof Transaction) {
159
- tx.partialSign(...request.transaction.signers);
160
- }
161
- const serializedTx = tx.serialize();
222
+ async function sendAndConfirmTransaction(serializedTx, blockhash, lastValidBlockHeight, config) {
223
+ const { connection, commitment, retryIntervalMs = 5e3, verbose = false } = config;
162
224
  const sendOptions = {
163
225
  skipPreflight: true,
164
226
  maxRetries: 0,
165
- preFlightCommitment: commitment
166
- // See PR and linked issue for why setting this matters: https://github.com/anza-xyz/agave/pull/483
227
+ preflightCommitment: commitment
167
228
  };
168
- signature = await connection.sendRawTransaction(serializedTx, sendOptions);
169
- confirmTransactionPromise = connection.confirmTransaction(
170
- {
171
- signature,
172
- blockhash,
173
- lastValidBlockHeight
174
- },
229
+ const signature = await connection.sendRawTransaction(serializedTx, sendOptions);
230
+ const confirmTransactionPromise = connection.confirmTransaction(
231
+ { signature, blockhash, lastValidBlockHeight },
175
232
  commitment
176
233
  );
177
- const txRetryInterval = 5e3;
234
+ let confirmedTx = null;
235
+ let txSendAttempts = 1;
178
236
  while (!confirmedTx) {
179
237
  confirmedTx = await Promise.race([
180
238
  confirmTransactionPromise,
181
239
  new Promise(
182
- (resolve) => setTimeout(() => {
183
- resolve(null);
184
- }, txRetryInterval)
240
+ (resolve) => setTimeout(() => resolve(null), retryIntervalMs)
185
241
  )
186
242
  ]);
187
- if (confirmedTx) {
188
- break;
243
+ if (confirmedTx) break;
244
+ if (verbose) {
245
+ console.log(
246
+ `Tx not confirmed after ${retryIntervalMs * txSendAttempts++}ms, resending`
247
+ );
189
248
  }
190
- console.log(
191
- `Tx not confirmed after ${txRetryInterval * txSendAttempts++}ms, resending`
192
- );
193
249
  try {
194
250
  await connection.sendRawTransaction(serializedTx, sendOptions);
195
251
  } catch (e) {
196
- console.error("Failed to resend transaction:", e);
252
+ if (verbose) {
253
+ console.error("Failed to resend transaction:", e);
254
+ }
197
255
  }
198
256
  }
199
257
  if (confirmedTx.value.err) {
200
- let errorMessage = `Transaction failed: ${confirmedTx.value.err}`;
201
- if (typeof confirmedTx.value.err === "object") {
202
- try {
203
- errorMessage = `Transaction failed: ${JSON.stringify(
204
- confirmedTx.value.err,
205
- (_key, value) => typeof value === "bigint" ? value.toString() : value
206
- // Handle bigint props
207
- )}`;
208
- } catch (e) {
209
- errorMessage = `Transaction failed: Unknown error`;
210
- }
211
- }
212
- throw new Error(`Transaction failed: ${errorMessage}`).message;
258
+ const errorMessage = formatTransactionError(confirmedTx.value.err);
259
+ throw new Error(errorMessage);
213
260
  }
214
261
  return signature;
215
262
  }
216
- async function setPriorityFeeInstructions(connection, blockhash, lastValidBlockHeight, request, crossChainCore) {
217
- const unsignedTx = request.transaction.transaction;
263
+ function formatTransactionError(err) {
264
+ if (typeof err === "object" && err !== null) {
265
+ try {
266
+ return `Transaction failed: ${JSON.stringify(
267
+ err,
268
+ (_key, value) => typeof value === "bigint" ? value.toString() : value
269
+ )}`;
270
+ } catch {
271
+ return "Transaction failed: Unknown error";
272
+ }
273
+ }
274
+ return `Transaction failed: ${err}`;
275
+ }
276
+ async function addPriorityFeeInstructions(connection, transaction, priorityFeeConfig, verbose = false) {
218
277
  const computeBudgetIxFilter = (ix) => ix.programId.toString() !== "ComputeBudget111111111111111111111111111111";
219
- unsignedTx.recentBlockhash = blockhash;
220
- unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
221
- unsignedTx.instructions = unsignedTx.instructions.filter(
222
- computeBudgetIxFilter
278
+ transaction.instructions = transaction.instructions.filter(computeBudgetIxFilter);
279
+ const instructions = await createPriorityFeeInstructions(
280
+ connection,
281
+ transaction,
282
+ priorityFeeConfig,
283
+ verbose
223
284
  );
224
- unsignedTx.add(
225
- ...await createPriorityFeeInstructions(
226
- connection,
227
- unsignedTx,
228
- crossChainCore
229
- )
285
+ transaction.add(...instructions);
286
+ return transaction;
287
+ }
288
+ async function createPriorityFeeInstructions(connection, transaction, priorityFeeConfig, verbose = false) {
289
+ const unitsUsed = await simulateAndGetComputeUnits(connection, transaction);
290
+ const unitBudget = Math.floor(unitsUsed * 1.2);
291
+ const instructions = [];
292
+ instructions.push(
293
+ ComputeBudgetProgram.setComputeUnitLimit({
294
+ units: unitBudget
295
+ })
230
296
  );
231
- return unsignedTx;
297
+ const {
298
+ percentile = 0.9,
299
+ percentileMultiple = 1,
300
+ min = 1e5,
301
+ max = 1e8
302
+ } = priorityFeeConfig ?? {};
303
+ const rpcProvider = determineRpcProvider(connection.rpcEndpoint);
304
+ const { fee, methodUsed } = await calculatePriorityFee(
305
+ connection,
306
+ transaction,
307
+ rpcProvider,
308
+ { percentile, percentileMultiple, min, max }
309
+ );
310
+ if (verbose) {
311
+ const maxFeeInSol = fee / 1e6 / LAMPORTS_PER_SOL * unitBudget;
312
+ console.table({
313
+ "RPC Provider": rpcProvider,
314
+ "Method used": methodUsed,
315
+ "Percentile used": percentile,
316
+ "Multiple used": percentileMultiple,
317
+ "Compute budget": unitBudget,
318
+ "Priority fee": fee,
319
+ "Max fee in SOL": maxFeeInSol
320
+ });
321
+ }
322
+ instructions.push(
323
+ ComputeBudgetProgram.setComputeUnitPrice({ microLamports: fee })
324
+ );
325
+ return instructions;
232
326
  }
233
- async function createPriorityFeeInstructions(connection, transaction, crossChainCore) {
327
+ async function simulateAndGetComputeUnits(connection, transaction) {
234
328
  let unitsUsed = 2e5;
235
329
  let simulationAttempts = 0;
236
330
  simulationLoop: while (true) {
237
- const response = await connection.simulateTransaction(
238
- transaction
239
- );
331
+ const response = await connection.simulateTransaction(transaction);
240
332
  if (response.value.err) {
241
333
  if (checkKnownSimulationError(response.value)) {
242
334
  if (simulationAttempts < 5) {
@@ -253,7 +345,7 @@ async function createPriorityFeeInstructions(connection, transaction, crossChain
253
345
  `Simulation failed: ${JSON.stringify(response.value.err)}
254
346
  Logs:
255
347
  ${(response.value.logs || []).join("\n ")}`
256
- ).message;
348
+ );
257
349
  } else {
258
350
  if (response.value.unitsConsumed) {
259
351
  unitsUsed = response.value.unitsConsumed;
@@ -261,41 +353,13 @@ ${(response.value.logs || []).join("\n ")}`
261
353
  break;
262
354
  }
263
355
  }
264
- const unitBudget = Math.floor(unitsUsed * 1.2);
265
- const instructions = [];
266
- instructions.push(
267
- ComputeBudgetProgram.setComputeUnitLimit({
268
- // Set compute budget to 120% of the units used in the simulated transaction
269
- units: unitBudget
270
- })
271
- );
272
- const {
273
- percentile = 0.9,
274
- percentileMultiple = 1,
275
- min = 1e5,
276
- max = 1e8
277
- } = crossChainCore?._dappConfig?.solanaConfig?.priorityFeeConfig ?? {};
278
- const calculateFee = async (rpcProvider2) => {
279
- if (rpcProvider2 === "triton") {
280
- try {
281
- const fee2 = await determinePriorityFeeTritonOne(
282
- connection,
283
- transaction,
284
- percentile,
285
- percentileMultiple,
286
- min,
287
- max
288
- );
289
- return {
290
- fee: fee2,
291
- methodUsed: "triton"
292
- };
293
- } catch (e) {
294
- console.warn(`Failed to determine priority fee using Triton RPC:`, e);
295
- }
296
- }
356
+ return unitsUsed;
357
+ }
358
+ async function calculatePriorityFee(connection, transaction, rpcProvider, config) {
359
+ const { percentile, percentileMultiple, min, max } = config;
360
+ if (rpcProvider === "triton") {
297
361
  try {
298
- const fee2 = await determinePriorityFee(
362
+ const fee = await determinePriorityFeeTritonOne(
299
363
  connection,
300
364
  transaction,
301
365
  percentile,
@@ -303,37 +367,25 @@ ${(response.value.logs || []).join("\n ")}`
303
367
  min,
304
368
  max
305
369
  );
306
- return {
307
- fee: fee2,
308
- methodUsed: "default"
309
- };
370
+ return { fee, methodUsed: "triton" };
310
371
  } catch (e) {
311
372
  console.warn(`Failed to determine priority fee using Triton RPC:`, e);
312
- return {
313
- fee: min,
314
- methodUsed: "minimum"
315
- };
316
373
  }
317
- };
318
- const rpcProvider = determineRpcProvider(connection.rpcEndpoint);
319
- const { fee, methodUsed } = await calculateFee(rpcProvider);
320
- const maxFeeInSol = fee / // convert microlamports to lamports
321
- 1e6 / // convert lamports to SOL
322
- LAMPORTS_PER_SOL * // multiply by maximum compute units used
323
- unitBudget;
324
- console.table({
325
- "RPC Provider": rpcProvider,
326
- "Method used": methodUsed,
327
- "Percentile used": percentile,
328
- "Multiple used": percentileMultiple,
329
- "Compute budget": unitBudget,
330
- "Priority fee": fee,
331
- "Max fee in SOL": maxFeeInSol
332
- });
333
- instructions.push(
334
- ComputeBudgetProgram.setComputeUnitPrice({ microLamports: fee })
335
- );
336
- return instructions;
374
+ }
375
+ try {
376
+ const fee = await determinePriorityFee(
377
+ connection,
378
+ transaction,
379
+ percentile,
380
+ percentileMultiple,
381
+ min,
382
+ max
383
+ );
384
+ return { fee, methodUsed: "default" };
385
+ } catch (e) {
386
+ console.warn(`Failed to determine priority fee:`, e);
387
+ return { fee: min, methodUsed: "minimum" };
388
+ }
337
389
  }
338
390
  function checkKnownSimulationError(response) {
339
391
  const errors = {};
@@ -350,61 +402,106 @@ function checkKnownSimulationError(response) {
350
402
  }
351
403
  }
352
404
  }
353
- if (isEmptyObject(errors)) {
405
+ if (Object.keys(errors).length === 0) {
354
406
  return false;
355
407
  }
356
408
  console.table(errors);
357
409
  return true;
358
410
  }
359
- async function sleep(timeout) {
360
- return new Promise((resolve) => setTimeout(resolve, timeout));
411
+ function isHostOrSubdomainOf(hostname, base) {
412
+ return hostname === base || hostname.endsWith(`.${base}`);
361
413
  }
362
- var isEmptyObject = (value) => {
363
- if (value === null || value === void 0) {
364
- return true;
365
- }
366
- for (const key in value) {
367
- if (value.hasOwnProperty.call(value, key)) {
368
- return false;
369
- }
370
- }
371
- return true;
372
- };
373
414
  function determineRpcProvider(endpoint) {
374
415
  try {
375
416
  const url = new URL(endpoint);
376
417
  const hostname = url.hostname;
377
- if (hostname === "rpcpool.com") {
418
+ if (isHostOrSubdomainOf(hostname, "rpcpool.com") || isHostOrSubdomainOf(hostname, "triton.one")) {
378
419
  return "triton";
379
- } else if (hostname === "helius-rpc.com") {
420
+ } else if (isHostOrSubdomainOf(hostname, "helius-rpc.com") || isHostOrSubdomainOf(hostname, "helius.xyz")) {
380
421
  return "helius";
381
- } else if (hostname === "rpc.ankr.com") {
422
+ } else if (isHostOrSubdomainOf(hostname, "ankr.com")) {
382
423
  return "ankr";
383
424
  } else {
384
425
  return "unknown";
385
426
  }
386
- } catch (e) {
427
+ } catch {
387
428
  return "unknown";
388
429
  }
389
430
  }
431
+ async function sleep(timeout) {
432
+ return new Promise((resolve) => setTimeout(resolve, timeout));
433
+ }
434
+
435
+ // src/providers/wormhole/signers/SolanaSigner.ts
436
+ async function signAndSendTransaction2(request, wallet, options, crossChainCore) {
437
+ if (!wallet || !(wallet instanceof SolanaDerivedWallet)) {
438
+ throw new Error("Invalid wallet type or missing Solana wallet");
439
+ }
440
+ const commitment = options?.commitment ?? "finalized";
441
+ const connection = new Connection2(
442
+ crossChainCore?._dappConfig?.solanaConfig?.rpc ?? crossChainCore?.CHAINS["Solana"]?.defaultRpc ?? "https://api.devnet.solana.com"
443
+ // Last resort fallback
444
+ );
445
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash(commitment);
446
+ const unsignedTx = await setPriorityFeeInstructions(
447
+ connection,
448
+ blockhash,
449
+ lastValidBlockHeight,
450
+ request,
451
+ crossChainCore?._dappConfig?.solanaConfig?.priorityFeeConfig
452
+ );
453
+ if (!wallet.solanaWallet.signTransaction) {
454
+ throw new Error("Wallet does not support signing transactions");
455
+ }
456
+ const tx = await wallet.solanaWallet.signTransaction(unsignedTx);
457
+ if (!tx) throw new Error("Failed to sign transaction");
458
+ if (request.transaction.signers && tx instanceof Transaction2) {
459
+ tx.partialSign(...request.transaction.signers);
460
+ }
461
+ const serializedTx = tx.serialize();
462
+ const signature = await sendAndConfirmTransaction(
463
+ serializedTx,
464
+ blockhash,
465
+ lastValidBlockHeight,
466
+ {
467
+ connection,
468
+ commitment,
469
+ retryIntervalMs: 5e3,
470
+ verbose: false
471
+ }
472
+ );
473
+ return signature;
474
+ }
475
+ async function setPriorityFeeInstructions(connection, blockhash, lastValidBlockHeight, request, priorityFeeConfig) {
476
+ const unsignedTx = request.transaction.transaction;
477
+ unsignedTx.recentBlockhash = blockhash;
478
+ unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
479
+ await addPriorityFeeInstructions(
480
+ connection,
481
+ unsignedTx,
482
+ priorityFeeConfig,
483
+ false
484
+ );
485
+ return unsignedTx;
486
+ }
390
487
 
391
488
  // src/providers/wormhole/signers/EthereumSigner.ts
392
489
  import { ethers, getBigInt } from "ethers";
393
490
  async function signAndSendTransaction3(request, wallet, chainName, options) {
394
491
  if (!wallet) {
395
- throw new Error("wallet.sendTransaction is undefined").message;
492
+ throw new Error("wallet.sendTransaction is undefined");
396
493
  }
397
494
  const chainId = await wallet.eip1193Provider.request({
398
495
  method: "eth_chainId"
399
496
  });
400
497
  const actualChainId = parseInt(chainId, 16);
401
498
  if (!actualChainId)
402
- throw new Error("No signer found for chain" + chainName).message;
499
+ throw new Error("No signer found for chain" + chainName);
403
500
  const expectedChainId = request.transaction.chainId ? getBigInt(request.transaction.chainId) : void 0;
404
501
  if (!actualChainId || !expectedChainId || BigInt(actualChainId) !== expectedChainId) {
405
502
  throw new Error(
406
503
  `Signer is not connected to the right chain. Expected ${expectedChainId}, got ${actualChainId}`
407
- ).message;
504
+ );
408
505
  }
409
506
  const provider = new ethers.BrowserProvider(
410
507
  wallet.eip1193Provider
@@ -426,7 +523,7 @@ import { UserResponseStatus } from "@aptos-labs/wallet-standard";
426
523
  import { GasStationClient, GasStationTransactionSubmitter } from "@aptos-labs/gas-station-client";
427
524
  async function signAndSendTransaction4(request, wallet, sponsorAccount, dappNetwork) {
428
525
  if (!wallet) {
429
- throw new Error("wallet.sendTransaction is undefined").message;
526
+ throw new Error("wallet.sendTransaction is undefined");
430
527
  }
431
528
  const payload = request.transaction;
432
529
  payload.functionArguments = payload.functionArguments.map((a) => {
@@ -526,13 +623,13 @@ async function signAndSendTransaction5(request, wallet) {
526
623
  // src/providers/wormhole/signers/Signer.ts
527
624
  var Signer = class {
528
625
  constructor(chain, address, options, wallet, crossChainCore, sponsorAccount) {
626
+ this._claimedTransactionHashes = [];
529
627
  this._chain = chain;
530
628
  this._address = address;
531
629
  this._options = options;
532
630
  this._wallet = wallet;
533
631
  this._crossChainCore = crossChainCore;
534
632
  this._sponsorAccount = sponsorAccount;
535
- this._claimedTransactionHashes = "";
536
633
  }
537
634
  chain() {
538
635
  return this._chain.key;
@@ -541,10 +638,11 @@ var Signer = class {
541
638
  return this._address;
542
639
  }
543
640
  claimedTransactionHashes() {
544
- return this._claimedTransactionHashes;
641
+ return this._claimedTransactionHashes.join(",");
545
642
  }
546
643
  async signAndSend(txs) {
547
644
  const txHashes = [];
645
+ this._claimedTransactionHashes = [];
548
646
  for (const tx of txs) {
549
647
  const txId = await signAndSendTransaction6(
550
648
  this._chain,
@@ -555,7 +653,7 @@ var Signer = class {
555
653
  this._sponsorAccount
556
654
  );
557
655
  txHashes.push(txId);
558
- this._claimedTransactionHashes = txId;
656
+ this._claimedTransactionHashes.push(txId);
559
657
  }
560
658
  return txHashes;
561
659
  }
@@ -600,6 +698,49 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
600
698
  }
601
699
  };
602
700
 
701
+ // src/providers/wormhole/utils.ts
702
+ import {
703
+ chainToPlatform,
704
+ routes as routes2,
705
+ Wormhole
706
+ } from "@wormhole-foundation/sdk";
707
+ async function createCCTPRoute(wh, sourceChain, destChain, tokens) {
708
+ const sourceToken = Wormhole.tokenId(
709
+ sourceChain,
710
+ tokens[sourceChain].tokenId.address
711
+ );
712
+ const destToken = Wormhole.tokenId(
713
+ destChain,
714
+ tokens[destChain].tokenId.address
715
+ );
716
+ const destContext = wh.getPlatform(chainToPlatform(destChain)).getChain(destChain);
717
+ const sourceContext = wh.getPlatform(chainToPlatform(sourceChain)).getChain(sourceChain);
718
+ const request = await routes2.RouteTransferRequest.create(
719
+ wh,
720
+ { source: sourceToken, destination: destToken },
721
+ sourceContext,
722
+ destContext
723
+ );
724
+ const resolver = wh.resolver([routes2.CCTPRoute]);
725
+ const foundRoutes = await resolver.findRoutes(request);
726
+ const cctpRoute = foundRoutes[0];
727
+ if (!cctpRoute || !routes2.isManual(cctpRoute)) {
728
+ throw new Error("Expected manual CCTP route");
729
+ }
730
+ return { route: cctpRoute, request };
731
+ }
732
+
733
+ // src/providers/wormhole/types.ts
734
+ var WithdrawError = class extends Error {
735
+ constructor(message, originChainTxnId, phase, cause) {
736
+ super(message);
737
+ this.name = "WithdrawError";
738
+ this.originChainTxnId = originChainTxnId;
739
+ this.phase = phase;
740
+ this.cause = cause;
741
+ }
742
+ };
743
+
603
744
  // src/providers/wormhole/wormhole.ts
604
745
  var WormholeProvider = class {
605
746
  constructor(core) {
@@ -632,33 +773,15 @@ var WormholeProvider = class {
632
773
  if (!this._wormholeContext) {
633
774
  throw new Error("Wormhole context not initialized");
634
775
  }
635
- const { sourceToken, destToken } = this.getTokenInfo(
636
- sourceChain,
637
- destinationChain
638
- );
639
- const destContext = this._wormholeContext.getPlatform(chainToPlatform(destinationChain)).getChain(destinationChain);
640
- const sourceContext = this._wormholeContext.getPlatform(chainToPlatform(sourceChain)).getChain(sourceChain);
641
- logger.log("sourceContext", sourceContext);
642
- logger.log("sourceToken", sourceToken);
643
- logger.log("destContext", destContext);
644
- logger.log("destToken", destToken);
645
- const request = await routes.RouteTransferRequest.create(
776
+ const { route: cctpRoute, request } = await createCCTPRoute(
646
777
  this._wormholeContext,
647
- {
648
- source: sourceToken,
649
- destination: destToken
650
- },
651
- sourceContext,
652
- destContext
778
+ sourceChain,
779
+ destinationChain,
780
+ this.crossChainCore.TOKENS
653
781
  );
654
- const resolver = this._wormholeContext.resolver([
655
- routes.CCTPRoute
656
- // manual CCTP
657
- ]);
658
- const route = await resolver.findRoutes(request);
659
- const cctpRoute = route[0];
660
782
  this.wormholeRoute = cctpRoute;
661
783
  this.wormholeRequest = request;
784
+ this.destinationChain = destinationChain;
662
785
  return { route: cctpRoute, request };
663
786
  }
664
787
  async getQuote(input) {
@@ -680,12 +803,12 @@ var WormholeProvider = class {
680
803
  const validated = await route.validate(request, transferParams);
681
804
  if (!validated.valid) {
682
805
  logger.log("invalid", validated.valid);
683
- throw new Error(`Invalid quote: ${validated.error}`).message;
806
+ throw new Error(`Invalid quote: ${validated.error}`);
684
807
  }
685
808
  const quote = await route.quote(request, validated.params);
686
809
  if (!quote.success) {
687
810
  logger.log("quote failed", quote.success);
688
- throw new Error(`Invalid quote: ${quote.error}`).message;
811
+ throw new Error(`Invalid quote: ${quote.error}`);
689
812
  }
690
813
  this.wormholeQuote = quote;
691
814
  logger.log("quote", quote);
@@ -727,7 +850,7 @@ var WormholeProvider = class {
727
850
  this.wormholeRequest,
728
851
  signer,
729
852
  this.wormholeQuote,
730
- Wormhole.chainAddress("Aptos", destinationAddress.toString())
853
+ Wormhole2.chainAddress("Aptos", destinationAddress.toString())
731
854
  );
732
855
  const originChainTxnId = "originTxs" in receipt ? receipt.originTxs[receipt.originTxs.length - 1].txid : void 0;
733
856
  return { originChainTxnId: originChainTxnId || "", receipt };
@@ -756,7 +879,7 @@ var WormholeProvider = class {
756
879
  // the fee payer account
757
880
  this.crossChainCore._dappConfig?.aptosNetwork
758
881
  );
759
- if (routes.isManual(this.wormholeRoute)) {
882
+ if (routes3.isManual(this.wormholeRoute)) {
760
883
  const circleAttestationReceipt = await this.wormholeRoute.complete(signer, receipt);
761
884
  logger.log("Claim receipt: ", circleAttestationReceipt);
762
885
  const destinationChainTxnId = signer.claimedTransactionHashes();
@@ -806,15 +929,14 @@ var WormholeProvider = class {
806
929
  });
807
930
  return { originChainTxnId, destinationChainTxnId };
808
931
  }
809
- async withdraw(input) {
810
- const { sourceChain, wallet, destinationAddress, sponsorAccount } = input;
811
- logger.log("sourceChain", sourceChain);
812
- logger.log("wallet", wallet);
813
- logger.log("destinationAddress", destinationAddress);
814
- logger.log("sponsorAccount", sponsorAccount);
815
- if (!this._wormholeContext) {
816
- await this.setWormholeContext(sourceChain);
817
- }
932
+ // --- Split withdraw flow: initiateWithdraw + trackWithdraw + claimWithdraw ---
933
+ /**
934
+ * Phase 1: Initiates a withdraw by burning USDC on Aptos.
935
+ * The user signs the Aptos burn transaction via their wallet.
936
+ * Returns a receipt that can be tracked and later claimed.
937
+ */
938
+ async initiateWithdraw(input) {
939
+ const { wallet, destinationAddress, sponsorAccount } = input;
818
940
  if (!this._wormholeContext) {
819
941
  throw new Error("Wormhole context not initialized");
820
942
  }
@@ -823,69 +945,48 @@ var WormholeProvider = class {
823
945
  }
824
946
  const signer = new Signer(
825
947
  this.getChainConfig("Aptos"),
826
- (await input.wallet.features["aptos:account"].account()).address.toString(),
948
+ (await wallet.features["aptos:account"].account()).address.toString(),
827
949
  {},
828
- input.wallet,
950
+ wallet,
829
951
  this.crossChainCore,
830
952
  sponsorAccount
831
953
  );
832
- logger.log("signer", signer);
833
- logger.log("wormholeRequest", this.wormholeRequest);
834
- logger.log("wormholeQuote", this.wormholeQuote);
835
- logger.log(
836
- "Wormhole.chainAddress",
837
- Wormhole.chainAddress(sourceChain, input.destinationAddress.toString())
954
+ const wormholeDestAddress = Wormhole2.chainAddress(
955
+ this.destinationChain,
956
+ destinationAddress.toString()
838
957
  );
839
- let receipt = await this.wormholeRoute.initiate(
958
+ const receipt = await this.wormholeRoute.initiate(
840
959
  this.wormholeRequest,
841
960
  signer,
842
961
  this.wormholeQuote,
843
- Wormhole.chainAddress(sourceChain, input.destinationAddress.toString())
962
+ wormholeDestAddress
844
963
  );
845
- logger.log("receipt", receipt);
964
+ logger.log("initiateWithdraw receipt", receipt);
846
965
  const originChainTxnId = "originTxs" in receipt ? receipt.originTxs[receipt.originTxs.length - 1].txid : void 0;
966
+ return { originChainTxnId: originChainTxnId || "", receipt };
967
+ }
968
+ /**
969
+ * Phase 2: Tracks a withdraw receipt until attestation is ready.
970
+ * This polls Wormhole and returns once the receipt reaches the Attested state.
971
+ */
972
+ async trackWithdraw(receipt) {
973
+ if (!this.wormholeRoute) {
974
+ throw new Error("Wormhole route not initialized");
975
+ }
847
976
  let retries = 0;
848
977
  const maxRetries = 5;
849
978
  const baseDelay = 1e3;
850
979
  while (retries < maxRetries) {
851
980
  try {
852
981
  for await (receipt of this.wormholeRoute.track(receipt, 120 * 1e3)) {
853
- if (receipt.state >= TransferState.SourceInitiated) {
854
- logger.log("Receipt is on track ", receipt);
855
- try {
856
- const signer2 = new Signer(
857
- this.getChainConfig(sourceChain),
858
- destinationAddress.toString(),
859
- {},
860
- wallet,
861
- this.crossChainCore
862
- );
863
- if (routes.isManual(this.wormholeRoute)) {
864
- const circleAttestationReceipt = await this.wormholeRoute.complete(signer2, receipt);
865
- logger.log("Claim receipt: ", circleAttestationReceipt);
866
- const destinationChainTxnId = signer2.claimedTransactionHashes();
867
- return {
868
- originChainTxnId: originChainTxnId || "",
869
- destinationChainTxnId
870
- };
871
- } else {
872
- return {
873
- originChainTxnId: originChainTxnId || "",
874
- destinationChainTxnId: ""
875
- };
876
- }
877
- } catch (e) {
878
- console.error("Failed to claim", e);
879
- return {
880
- originChainTxnId: originChainTxnId || "",
881
- destinationChainTxnId: ""
882
- };
883
- }
982
+ if (receipt.state >= TransferState.Attested) {
983
+ logger.log("trackWithdraw: receipt attested", receipt);
984
+ return receipt;
884
985
  }
885
986
  }
886
987
  } catch (e) {
887
988
  console.error(
888
- `Error tracking transfer (attempt ${retries + 1} / ${maxRetries}):`,
989
+ `Error tracking withdraw (attempt ${retries + 1} / ${maxRetries}):`,
889
990
  e
890
991
  );
891
992
  const delay = baseDelay * Math.pow(2, retries);
@@ -893,10 +994,108 @@ var WormholeProvider = class {
893
994
  retries++;
894
995
  }
895
996
  }
896
- return {
897
- originChainTxnId: originChainTxnId || "",
898
- destinationChainTxnId: ""
899
- };
997
+ throw new Error("Failed to track withdraw to attested state");
998
+ }
999
+ /**
1000
+ * Phase 3: Claims the withdraw on the destination chain.
1001
+ *
1002
+ * If the destination is Solana and `solanaConfig.serverClaimUrl` is configured
1003
+ * in the dapp config, the SDK automatically POSTs the attested receipt to that
1004
+ * URL — no wallet popup required. The dapp's server endpoint handles signing
1005
+ * and submitting the claim transaction.
1006
+ *
1007
+ * Otherwise falls back to the wallet-based Signer (triggers wallet popup).
1008
+ */
1009
+ async claimWithdraw(input) {
1010
+ const { sourceChain, destinationAddress, receipt } = input;
1011
+ const serverClaimUrl = this.crossChainCore._dappConfig?.solanaConfig?.serverClaimUrl;
1012
+ if (sourceChain === "Solana" && serverClaimUrl) {
1013
+ logger.log("claimWithdraw: using server-side claim via", serverClaimUrl);
1014
+ const response = await fetch(serverClaimUrl, {
1015
+ method: "POST",
1016
+ headers: { "Content-Type": "application/json" },
1017
+ body: JSON.stringify({
1018
+ receipt: serializeReceipt(receipt),
1019
+ destinationAddress,
1020
+ sourceChain
1021
+ })
1022
+ });
1023
+ if (!response.ok) {
1024
+ const errorData = await response.json().catch(() => ({}));
1025
+ throw new Error(
1026
+ errorData.error || `Server-side claim failed with status ${response.status}`
1027
+ );
1028
+ }
1029
+ const result = await response.json();
1030
+ return { destinationChainTxnId: result.destinationChainTxnId };
1031
+ }
1032
+ if (!this.wormholeRoute) {
1033
+ throw new Error("Wormhole route not initialized");
1034
+ }
1035
+ if (!input.wallet) {
1036
+ throw new Error(
1037
+ "Wallet is required for claim when serverClaimUrl is not configured"
1038
+ );
1039
+ }
1040
+ const claimSigner = new Signer(
1041
+ this.getChainConfig(sourceChain),
1042
+ destinationAddress,
1043
+ {},
1044
+ input.wallet,
1045
+ this.crossChainCore
1046
+ );
1047
+ if (routes3.isManual(this.wormholeRoute)) {
1048
+ const circleAttestationReceipt = await this.wormholeRoute.complete(
1049
+ claimSigner,
1050
+ receipt
1051
+ );
1052
+ logger.log("claimWithdraw receipt:", circleAttestationReceipt);
1053
+ const destinationChainTxnId = claimSigner.claimedTransactionHashes();
1054
+ return { destinationChainTxnId };
1055
+ } else {
1056
+ throw new Error("Automatic route not supported for manual claim");
1057
+ }
1058
+ }
1059
+ /**
1060
+ * Withdraws USDC from Aptos to a destination chain.
1061
+ * Orchestrates all three phases internally:
1062
+ * 1. Initiate — user signs the Aptos burn transaction
1063
+ * 2. Track — wait for Wormhole attestation
1064
+ * 3. Claim — if serverClaimUrl is configured for Solana, delegates to
1065
+ * the server; otherwise uses the wallet-based signer.
1066
+ *
1067
+ * The optional `onPhaseChange` callback lets the dapp update its UI
1068
+ * as the flow progresses.
1069
+ */
1070
+ async withdraw(input) {
1071
+ const { sourceChain, wallet, destinationAddress, sponsorAccount, onPhaseChange } = input;
1072
+ onPhaseChange?.("initiating");
1073
+ const { originChainTxnId, receipt } = await this.initiateWithdraw({
1074
+ wallet,
1075
+ destinationAddress,
1076
+ sponsorAccount
1077
+ });
1078
+ let currentPhase = "tracking";
1079
+ try {
1080
+ onPhaseChange?.("tracking");
1081
+ const attestedReceipt = await this.trackWithdraw(receipt);
1082
+ currentPhase = "claiming";
1083
+ onPhaseChange?.("claiming");
1084
+ const { destinationChainTxnId } = await this.claimWithdraw({
1085
+ sourceChain,
1086
+ destinationAddress: destinationAddress.toString(),
1087
+ receipt: attestedReceipt,
1088
+ wallet
1089
+ });
1090
+ return { originChainTxnId, destinationChainTxnId };
1091
+ } catch (error) {
1092
+ throw new WithdrawError(
1093
+ error?.message ?? "Withdraw failed after Aptos burn",
1094
+ originChainTxnId,
1095
+ currentPhase,
1096
+ error
1097
+ );
1098
+ }
900
1099
  }
901
1100
  getChainConfig(chain) {
902
1101
  const chainConfig = this.crossChainCore.CHAINS[chain];
@@ -905,16 +1104,121 @@ var WormholeProvider = class {
905
1104
  }
906
1105
  return chainConfig;
907
1106
  }
908
- getTokenInfo(sourceChain, destinationChain) {
909
- const sourceToken = Wormhole.tokenId(
910
- this.crossChainCore.TOKENS[sourceChain].tokenId.chain,
911
- this.crossChainCore.TOKENS[sourceChain].tokenId.address
912
- );
913
- const destToken = Wormhole.tokenId(
914
- this.crossChainCore.TOKENS[destinationChain].tokenId.chain,
915
- this.crossChainCore.TOKENS[destinationChain].tokenId.address
1107
+ };
1108
+
1109
+ // src/providers/wormhole/signers/SolanaLocalSigner.ts
1110
+ import {
1111
+ Transaction as Transaction3
1112
+ } from "@solana/web3.js";
1113
+ var SolanaLocalSigner = class {
1114
+ constructor(config) {
1115
+ this._claimedTransactionHashes = [];
1116
+ this.keypair = config.keypair;
1117
+ this.connection = config.connection;
1118
+ this.commitment = config.commitment ?? "finalized";
1119
+ this.retryIntervalMs = config.retryIntervalMs ?? 5e3;
1120
+ this.priorityFeeConfig = config.priorityFeeConfig;
1121
+ this.verbose = config.verbose ?? false;
1122
+ }
1123
+ chain() {
1124
+ return "Solana";
1125
+ }
1126
+ address() {
1127
+ return this.keypair.publicKey.toBase58();
1128
+ }
1129
+ /**
1130
+ * Returns all transaction hashes from the most recent signAndSend call,
1131
+ * joined by comma. If only one transaction was signed, returns a single hash string.
1132
+ */
1133
+ claimedTransactionHashes() {
1134
+ return this._claimedTransactionHashes.join(",");
1135
+ }
1136
+ async signAndSend(txs) {
1137
+ const txHashes = [];
1138
+ this._claimedTransactionHashes = [];
1139
+ for (const tx of txs) {
1140
+ const txId = await this.signAndSendTransaction(tx);
1141
+ txHashes.push(txId);
1142
+ this._claimedTransactionHashes.push(txId);
1143
+ }
1144
+ return txHashes;
1145
+ }
1146
+ async signAndSendTransaction(request) {
1147
+ const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash(this.commitment);
1148
+ let unsignedTx = request.transaction ?? request;
1149
+ const additionalSigners = request.transaction?.signers;
1150
+ const MAX_UNWRAP_DEPTH = 10;
1151
+ let unwrapDepth = 0;
1152
+ while (unsignedTx && typeof unsignedTx === "object" && "transaction" in unsignedTx && !(unsignedTx instanceof Transaction3) && !("signatures" in unsignedTx && "message" in unsignedTx)) {
1153
+ if (++unwrapDepth > MAX_UNWRAP_DEPTH) {
1154
+ throw new Error(
1155
+ "Transaction unwrapping exceeded maximum depth \u2014 possible circular nesting"
1156
+ );
1157
+ }
1158
+ unsignedTx = unsignedTx.transaction;
1159
+ }
1160
+ const isVersioned = unsignedTx.message !== void 0 && unsignedTx.signatures !== void 0 && typeof unsignedTx.message.recentBlockhash !== "undefined";
1161
+ if (isVersioned) {
1162
+ unsignedTx.message.recentBlockhash = blockhash;
1163
+ if (this.verbose || this.priorityFeeConfig) {
1164
+ console.warn(
1165
+ "SolanaLocalSigner: Versioned transaction detected \u2014 priority fees are not applied. Consider using legacy transactions if priority fees are required."
1166
+ );
1167
+ }
1168
+ unsignedTx.sign([this.keypair]);
1169
+ if (additionalSigners && additionalSigners.length > 0) {
1170
+ unsignedTx.sign(additionalSigners);
1171
+ }
1172
+ } else if (unsignedTx instanceof Transaction3) {
1173
+ unsignedTx.recentBlockhash = blockhash;
1174
+ unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
1175
+ if (this.priorityFeeConfig) {
1176
+ await addPriorityFeeInstructions(
1177
+ this.connection,
1178
+ unsignedTx,
1179
+ this.priorityFeeConfig,
1180
+ this.verbose
1181
+ );
1182
+ }
1183
+ if (additionalSigners && additionalSigners.length > 0) {
1184
+ unsignedTx.sign(this.keypair, ...additionalSigners);
1185
+ } else {
1186
+ unsignedTx.sign(this.keypair);
1187
+ }
1188
+ } else if (unsignedTx.recentBlockhash !== void 0 || unsignedTx.feePayer !== void 0) {
1189
+ unsignedTx.recentBlockhash = blockhash;
1190
+ unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
1191
+ if (this.priorityFeeConfig) {
1192
+ await addPriorityFeeInstructions(
1193
+ this.connection,
1194
+ unsignedTx,
1195
+ this.priorityFeeConfig,
1196
+ this.verbose
1197
+ );
1198
+ }
1199
+ if (additionalSigners && additionalSigners.length > 0) {
1200
+ unsignedTx.sign(this.keypair, ...additionalSigners);
1201
+ } else {
1202
+ unsignedTx.sign(this.keypair);
1203
+ }
1204
+ } else {
1205
+ throw new Error(
1206
+ `Unsupported transaction type: ${unsignedTx?.constructor?.name}`
1207
+ );
1208
+ }
1209
+ const serializedTx = unsignedTx.serialize();
1210
+ const signature = await sendAndConfirmTransaction(
1211
+ serializedTx,
1212
+ blockhash,
1213
+ lastValidBlockHeight,
1214
+ {
1215
+ connection: this.connection,
1216
+ commitment: this.commitment,
1217
+ retryIntervalMs: this.retryIntervalMs,
1218
+ verbose: this.verbose
1219
+ }
916
1220
  );
917
- return { sourceToken, destToken };
1221
+ return signature;
918
1222
  }
919
1223
  };
920
1224
 
@@ -988,8 +1292,8 @@ var testnetChains = {
988
1292
  key: "Solana",
989
1293
  context: "Solana" /* SOLANA */,
990
1294
  displayName: "Solana",
991
- explorerUrl: "https://explorer.solana.com/",
992
- explorerName: "Solana Explorer",
1295
+ explorerUrl: "https://solscan.io",
1296
+ explorerName: "Solscan",
993
1297
  chainId: 0,
994
1298
  icon: "Solana",
995
1299
  symbol: "SOL",
@@ -1112,8 +1416,8 @@ var mainnetChains = {
1112
1416
  key: "Solana",
1113
1417
  context: "Solana" /* SOLANA */,
1114
1418
  displayName: "Solana",
1115
- explorerUrl: "https://explorer.solana.com/",
1116
- explorerName: "Solana Explorer",
1419
+ explorerUrl: "https://solscan.io",
1420
+ explorerName: "Solscan",
1117
1421
  chainId: 0,
1118
1422
  icon: "Solana",
1119
1423
  symbol: "SOL",
@@ -1265,13 +1569,13 @@ var mainnetTokens = {
1265
1569
 
1266
1570
  // src/utils/getUsdcBalance.ts
1267
1571
  import { Aptos as Aptos3, AptosConfig as AptosConfig3, Network as Network2 } from "@aptos-labs/ts-sdk";
1268
- import { Connection as Connection2, PublicKey } from "@solana/web3.js";
1572
+ import { Connection as Connection4, PublicKey } from "@solana/web3.js";
1269
1573
  import { ethers as ethers2, JsonRpcProvider } from "ethers";
1270
1574
  import { SuiClient } from "@mysten/sui/client";
1271
1575
  var getSolanaWalletUSDCBalance = async (walletAddress, aptosNetwork, rpc) => {
1272
1576
  const address = new PublicKey(walletAddress);
1273
1577
  const tokenAddress = aptosNetwork === Network2.MAINNET ? mainnetTokens["Solana"].tokenId.address : testnetTokens["Solana"].tokenId.address;
1274
- const connection = new Connection2(rpc);
1578
+ const connection = new Connection4(rpc);
1275
1579
  const splToken = await connection.getTokenAccountsByOwner(address, {
1276
1580
  mint: new PublicKey(tokenAddress)
1277
1581
  });
@@ -1418,9 +1722,14 @@ export {
1418
1722
  Network4 as Network,
1419
1723
  NetworkToChainId,
1420
1724
  NetworkToNodeAPI,
1725
+ SolanaLocalSigner,
1726
+ WithdrawError,
1421
1727
  WormholeProvider,
1728
+ createCCTPRoute,
1729
+ deserializeReceipt,
1422
1730
  mainnetChains,
1423
1731
  mainnetTokens,
1732
+ serializeReceipt,
1424
1733
  signAndSendTransaction,
1425
1734
  testnetChains,
1426
1735
  testnetTokens