@aptos-labs/cross-chain-core 6.0.1 → 6.1.1

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 (72) hide show
  1. package/dist/CrossChainCore.d.ts +2 -2
  2. package/dist/CrossChainCore.d.ts.map +1 -1
  3. package/dist/config/index.d.ts +1 -1
  4. package/dist/config/mainnet/chains.d.ts +1 -1
  5. package/dist/config/mainnet/chains.d.ts.map +1 -1
  6. package/dist/config/mainnet/tokens.d.ts +1 -1
  7. package/dist/config/mainnet/tokens.d.ts.map +1 -1
  8. package/dist/config/testnet/chains.d.ts +1 -1
  9. package/dist/config/testnet/chains.d.ts.map +1 -1
  10. package/dist/config/testnet/tokens.d.ts +1 -1
  11. package/dist/config/testnet/tokens.d.ts.map +1 -1
  12. package/dist/config/types.d.ts +1 -1
  13. package/dist/config/types.d.ts.map +1 -1
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +1366 -1297
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.mjs +1377 -1302
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/providers/wormhole/index.d.ts +4 -4
  21. package/dist/providers/wormhole/index.d.ts.map +1 -1
  22. package/dist/providers/wormhole/signers/AptosLocalSigner.d.ts +5 -5
  23. package/dist/providers/wormhole/signers/AptosLocalSigner.d.ts.map +1 -1
  24. package/dist/providers/wormhole/signers/AptosSigner.d.ts +6 -6
  25. package/dist/providers/wormhole/signers/AptosSigner.d.ts.map +1 -1
  26. package/dist/providers/wormhole/signers/EthereumSigner.d.ts +3 -3
  27. package/dist/providers/wormhole/signers/EthereumSigner.d.ts.map +1 -1
  28. package/dist/providers/wormhole/signers/Signer.d.ts +6 -6
  29. package/dist/providers/wormhole/signers/Signer.d.ts.map +1 -1
  30. package/dist/providers/wormhole/signers/SolanaLocalSigner.d.ts +4 -4
  31. package/dist/providers/wormhole/signers/SolanaLocalSigner.d.ts.map +1 -1
  32. package/dist/providers/wormhole/signers/SolanaSigner.d.ts +8 -9
  33. package/dist/providers/wormhole/signers/SolanaSigner.d.ts.map +1 -1
  34. package/dist/providers/wormhole/signers/SuiSigner.d.ts +3 -3
  35. package/dist/providers/wormhole/signers/SuiSigner.d.ts.map +1 -1
  36. package/dist/providers/wormhole/signers/solanaUtils.d.ts +1 -1
  37. package/dist/providers/wormhole/signers/solanaUtils.d.ts.map +1 -1
  38. package/dist/providers/wormhole/types.d.ts +10 -4
  39. package/dist/providers/wormhole/types.d.ts.map +1 -1
  40. package/dist/providers/wormhole/utils.d.ts +2 -2
  41. package/dist/providers/wormhole/utils.d.ts.map +1 -1
  42. package/dist/providers/wormhole/wormhole.d.ts +3 -3
  43. package/dist/providers/wormhole/wormhole.d.ts.map +1 -1
  44. package/dist/utils/getUsdcBalance.d.ts +1 -1
  45. package/dist/utils/getUsdcBalance.d.ts.map +1 -1
  46. package/dist/utils/receiptSerialization.d.ts +1 -1
  47. package/dist/utils/receiptSerialization.d.ts.map +1 -1
  48. package/dist/version.d.ts +1 -1
  49. package/package.json +3 -5
  50. package/src/CrossChainCore.ts +15 -17
  51. package/src/config/index.ts +1 -1
  52. package/src/config/mainnet/chains.ts +1 -1
  53. package/src/config/mainnet/tokens.ts +1 -1
  54. package/src/config/testnet/chains.ts +1 -1
  55. package/src/config/testnet/tokens.ts +1 -1
  56. package/src/config/types.ts +1 -1
  57. package/src/index.ts +1 -1
  58. package/src/providers/wormhole/index.ts +4 -4
  59. package/src/providers/wormhole/signers/AptosLocalSigner.ts +12 -16
  60. package/src/providers/wormhole/signers/AptosSigner.ts +29 -22
  61. package/src/providers/wormhole/signers/EthereumSigner.ts +6 -6
  62. package/src/providers/wormhole/signers/Signer.ts +20 -22
  63. package/src/providers/wormhole/signers/SolanaLocalSigner.ts +7 -7
  64. package/src/providers/wormhole/signers/SolanaSigner.ts +13 -14
  65. package/src/providers/wormhole/signers/SuiSigner.ts +8 -8
  66. package/src/providers/wormhole/signers/solanaUtils.ts +43 -25
  67. package/src/providers/wormhole/types.ts +28 -16
  68. package/src/providers/wormhole/utils.ts +3 -4
  69. package/src/providers/wormhole/wormhole.ts +50 -48
  70. package/src/utils/getUsdcBalance.ts +8 -10
  71. package/src/utils/receiptSerialization.ts +2 -3
  72. package/src/version.ts +1 -1
package/dist/index.js CHANGED
@@ -32,7 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  AptosLocalSigner: () => AptosLocalSigner,
34
34
  Context: () => Context,
35
- CrossChainCore: () => CrossChainCore2,
35
+ CrossChainCore: () => CrossChainCore,
36
36
  EVM_CHAIN_NAMES: () => EVM_CHAIN_NAMES,
37
37
  EthereumChainIdToMainnetChain: () => EthereumChainIdToMainnetChain,
38
38
  EthereumChainIdToTestnetChain: () => EthereumChainIdToTestnetChain,
@@ -54,120 +54,355 @@ __export(index_exports, {
54
54
  validateExpireTimestamp: () => validateExpireTimestamp
55
55
  });
56
56
  module.exports = __toCommonJS(index_exports);
57
+ var import_ts_sdk7 = require("@aptos-labs/ts-sdk");
57
58
 
58
59
  // src/CrossChainCore.ts
59
60
  var import_ts_sdk5 = require("@aptos-labs/ts-sdk");
60
61
 
61
- // src/providers/wormhole/wormhole.ts
62
- var import_sdk3 = require("@wormhole-foundation/sdk");
63
- var import_ts_sdk3 = require("@aptos-labs/ts-sdk");
64
- var import_aptos = __toESM(require("@wormhole-foundation/sdk/aptos"));
65
- var import_solana = __toESM(require("@wormhole-foundation/sdk/solana"));
66
- var import_evm = __toESM(require("@wormhole-foundation/sdk/evm"));
67
- var import_sui = __toESM(require("@wormhole-foundation/sdk/sui"));
62
+ // src/config/types.ts
63
+ var Context = /* @__PURE__ */ ((Context2) => {
64
+ Context2["ETH"] = "Ethereum";
65
+ Context2["SOLANA"] = "Solana";
66
+ Context2["APTOS"] = "Aptos";
67
+ Context2["SUI"] = "Sui";
68
+ return Context2;
69
+ })(Context || {});
68
70
 
69
- // src/utils/logger.ts
70
- var logger = {
71
- log: (...args) => {
72
- if (process.env.NODE_ENV === "development") {
73
- console.log(...args);
71
+ // src/config/mainnet/chains.ts
72
+ var mainnetChains = {
73
+ Ethereum: {
74
+ key: "Ethereum",
75
+ context: "Ethereum" /* ETH */,
76
+ displayName: "Ethereum",
77
+ explorerUrl: "https://etherscan.io/",
78
+ explorerName: "Etherscan",
79
+ chainId: 1,
80
+ icon: "Ethereum",
81
+ symbol: "ETH",
82
+ defaultRpc: "https://rpc.ankr.com/eth"
83
+ },
84
+ Solana: {
85
+ key: "Solana",
86
+ context: "Solana" /* SOLANA */,
87
+ displayName: "Solana",
88
+ explorerUrl: "https://solscan.io",
89
+ explorerName: "Solscan",
90
+ chainId: 0,
91
+ icon: "Solana",
92
+ symbol: "SOL",
93
+ defaultRpc: "https://solana-rpc.publicnode.com"
94
+ },
95
+ Aptos: {
96
+ key: "Aptos",
97
+ context: "Aptos" /* APTOS */,
98
+ displayName: "Aptos",
99
+ explorerUrl: "https://explorer.aptoslabs.com/",
100
+ explorerName: "Aptos Explorer",
101
+ chainId: 0,
102
+ icon: "Aptos",
103
+ symbol: "APT",
104
+ defaultRpc: "https://fullnode.mainnet.aptos.dev"
105
+ },
106
+ Avalanche: {
107
+ key: "Avalanche",
108
+ context: "Ethereum" /* ETH */,
109
+ chainId: 43114,
110
+ displayName: "Avalanche",
111
+ explorerUrl: "https://snowtrace.io",
112
+ explorerName: "Avascan",
113
+ icon: "Avalanche",
114
+ symbol: "AVAX",
115
+ defaultRpc: "https://avalanche-c-chain-rpc.publicnode.com"
116
+ },
117
+ Base: {
118
+ key: "Base",
119
+ context: "Ethereum" /* ETH */,
120
+ chainId: 8453,
121
+ displayName: "Base",
122
+ explorerUrl: "https://basescan.org",
123
+ explorerName: "BaseScan",
124
+ icon: "Base",
125
+ symbol: "BASE",
126
+ defaultRpc: "https://mainnet.base.org"
127
+ },
128
+ Arbitrum: {
129
+ key: "Arbitrum",
130
+ context: "Ethereum" /* ETH */,
131
+ chainId: 42161,
132
+ displayName: "Arbitrum",
133
+ explorerUrl: "https://arbiscan.io/",
134
+ explorerName: "Arbitrum Explorer",
135
+ icon: "Arbitrum",
136
+ symbol: "ARB",
137
+ defaultRpc: "https://arb1.arbitrum.io/rpc"
138
+ },
139
+ Polygon: {
140
+ key: "Polygon",
141
+ context: "Ethereum" /* ETH */,
142
+ chainId: 137,
143
+ displayName: "Polygon",
144
+ explorerUrl: "https://polygonscan.com/",
145
+ explorerName: "PolygonScan",
146
+ icon: "Polygon",
147
+ symbol: "MATIC",
148
+ defaultRpc: "https://polygon-bor-rpc.publicnode.com"
149
+ },
150
+ Sui: {
151
+ key: "Sui",
152
+ context: "Sui" /* SUI */,
153
+ displayName: "Sui",
154
+ explorerUrl: "https://suiscan.xyz/",
155
+ explorerName: "Suiscan",
156
+ chainId: 0,
157
+ icon: "Sui",
158
+ symbol: "SUI",
159
+ defaultRpc: "https://fullnode.mainnet.sui.io:443"
160
+ }
161
+ };
162
+
163
+ // src/config/mainnet/tokens.ts
164
+ var mainnetTokens = {
165
+ Ethereum: {
166
+ symbol: "USDC",
167
+ tokenId: {
168
+ chain: "Ethereum",
169
+ address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
170
+ },
171
+ icon: "USDC",
172
+ decimals: 6
173
+ },
174
+ Solana: {
175
+ symbol: "USDC",
176
+ tokenId: {
177
+ chain: "Solana",
178
+ address: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
179
+ },
180
+ icon: "USDC",
181
+ decimals: 6
182
+ },
183
+ Aptos: {
184
+ symbol: "USDC",
185
+ decimals: 6,
186
+ tokenId: {
187
+ chain: "Aptos",
188
+ address: "0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b"
189
+ },
190
+ icon: "USDC"
191
+ },
192
+ Base: {
193
+ symbol: "USDC",
194
+ decimals: 6,
195
+ icon: "USDC",
196
+ tokenId: {
197
+ chain: "Base",
198
+ address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
74
199
  }
75
200
  },
76
- warn: (...args) => {
77
- if (process.env.NODE_ENV === "development") {
78
- console.warn(...args);
201
+ Arbitrum: {
202
+ symbol: "USDC",
203
+ decimals: 6,
204
+ icon: "USDC",
205
+ tokenId: {
206
+ chain: "Arbitrum",
207
+ address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
79
208
  }
80
209
  },
81
- error: (...args) => {
82
- if (process.env.NODE_ENV === "development") {
83
- console.error(...args);
210
+ Avalanche: {
211
+ symbol: "USDC",
212
+ decimals: 6,
213
+ icon: "USDC",
214
+ tokenId: {
215
+ chain: "Avalanche",
216
+ address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E"
217
+ }
218
+ },
219
+ Polygon: {
220
+ symbol: "USDC",
221
+ decimals: 6,
222
+ icon: "USDC",
223
+ tokenId: {
224
+ chain: "Polygon",
225
+ address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
84
226
  }
227
+ },
228
+ Sui: {
229
+ symbol: "USDC",
230
+ decimals: 6,
231
+ tokenId: {
232
+ chain: "Sui",
233
+ address: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC"
234
+ },
235
+ icon: "USDC"
85
236
  }
86
237
  };
87
238
 
88
- // src/utils/receiptSerialization.ts
89
- var import_sdk = require("@wormhole-foundation/sdk");
90
- function uint8ArrayToBase64(bytes) {
91
- let binary = "";
92
- for (let i = 0; i < bytes.length; i++) {
93
- binary += String.fromCharCode(bytes[i]);
94
- }
95
- return btoa(binary);
96
- }
97
- function base64ToUint8Array(base64) {
98
- const binary = atob(base64);
99
- const bytes = new Uint8Array(binary.length);
100
- for (let i = 0; i < binary.length; i++) {
101
- bytes[i] = binary.charCodeAt(i);
102
- }
103
- return bytes;
104
- }
105
- function serializeReceipt(receipt) {
106
- return JSON.parse(
107
- JSON.stringify(receipt, (_key, value) => {
108
- if (typeof value === "bigint") {
109
- return { __type: "bigint", value: value.toString() };
110
- }
111
- if (value instanceof import_sdk.UniversalAddress) {
112
- return {
113
- __type: "UniversalAddress",
114
- value: uint8ArrayToBase64(value.toUint8Array())
115
- };
116
- }
117
- if (value instanceof Uint8Array) {
118
- return {
119
- __type: "Uint8Array",
120
- value: uint8ArrayToBase64(value)
121
- };
122
- }
123
- return value;
124
- })
125
- );
126
- }
127
- function deserializeReceipt(obj) {
128
- function revive(value, key) {
129
- if (value && typeof value === "object") {
130
- const objValue = value;
131
- if ("__type" in objValue) {
132
- if (objValue.__type === "bigint") {
133
- return BigInt(objValue.value);
134
- }
135
- if (objValue.__type === "UniversalAddress") {
136
- return new import_sdk.UniversalAddress(
137
- base64ToUint8Array(objValue.value)
138
- );
139
- }
140
- if (objValue.__type === "Uint8Array") {
141
- return base64ToUint8Array(objValue.value);
142
- }
143
- }
144
- const addressFields = [
145
- "sender",
146
- "recipient",
147
- "destinationCaller",
148
- "burnToken",
149
- "mintRecipient",
150
- "messageSender"
151
- ];
152
- if (key && addressFields.includes(key) && "address" in objValue) {
153
- const addressBytes = revive(objValue.address);
154
- if (addressBytes instanceof Uint8Array) {
155
- return new import_sdk.UniversalAddress(addressBytes);
156
- }
157
- }
158
- if (Array.isArray(value)) {
159
- return value.map((v, i) => revive(v, String(i)));
160
- }
161
- const result = {};
162
- for (const k in objValue) {
163
- result[k] = revive(objValue[k], k);
164
- }
165
- return result;
239
+ // src/config/testnet/chains.ts
240
+ var testnetChains = {
241
+ Sepolia: {
242
+ key: "Sepolia",
243
+ context: "Ethereum" /* ETH */,
244
+ chainId: 11155111,
245
+ displayName: "Sepolia",
246
+ explorerUrl: "https://sepolia.etherscan.io/",
247
+ explorerName: "Etherscan",
248
+ icon: "Ethereum",
249
+ symbol: "ETH",
250
+ defaultRpc: "https://ethereum-sepolia-rpc.publicnode.com"
251
+ },
252
+ BaseSepolia: {
253
+ key: "BaseSepolia",
254
+ context: "Ethereum" /* ETH */,
255
+ chainId: 84532,
256
+ displayName: "Base Sepolia",
257
+ explorerUrl: "https://sepolia.basescan.org",
258
+ explorerName: "Basescan",
259
+ icon: "BaseSepolia",
260
+ symbol: "BASE",
261
+ defaultRpc: "https://chain-proxy.wallet.coinbase.com?targetName=base-sepolia"
262
+ },
263
+ ArbitrumSepolia: {
264
+ key: "ArbitrumSepolia",
265
+ context: "Ethereum" /* ETH */,
266
+ chainId: 421614,
267
+ displayName: "Arbitrum Sepolia",
268
+ explorerUrl: "https://sepolia.arbiscan.io",
269
+ explorerName: "Etherscan",
270
+ icon: "Arbitrum",
271
+ symbol: "ARB",
272
+ defaultRpc: "https://sepolia-rollup.arbitrum.io/rpc"
273
+ },
274
+ Avalanche: {
275
+ key: "Avalanche",
276
+ context: "Ethereum" /* ETH */,
277
+ chainId: 43113,
278
+ displayName: "Avalanche Fuji",
279
+ explorerUrl: "https://testnet.snowtrace.io",
280
+ explorerName: "Avascan",
281
+ icon: "Avalanche",
282
+ symbol: "AVAX",
283
+ defaultRpc: "https://api.avax-test.network/ext/bc/C/rpc"
284
+ },
285
+ PolygonSepolia: {
286
+ key: "PolygonSepolia",
287
+ context: "Ethereum" /* ETH */,
288
+ chainId: 80002,
289
+ displayName: "Polygon",
290
+ explorerUrl: "https://amoy.polygonscan.com/",
291
+ explorerName: "PolygonScan",
292
+ icon: "Polygon",
293
+ symbol: "MATIC",
294
+ defaultRpc: "https://rpc-amoy.polygon.technology/"
295
+ },
296
+ Solana: {
297
+ key: "Solana",
298
+ context: "Solana" /* SOLANA */,
299
+ displayName: "Solana",
300
+ explorerUrl: "https://solscan.io",
301
+ explorerName: "Solscan",
302
+ chainId: 0,
303
+ icon: "Solana",
304
+ symbol: "SOL",
305
+ defaultRpc: "https://api.devnet.solana.com"
306
+ },
307
+ Aptos: {
308
+ key: "Aptos",
309
+ context: "Aptos" /* APTOS */,
310
+ displayName: "Aptos",
311
+ explorerUrl: "https://explorer.aptoslabs.com?network=testnet",
312
+ explorerName: "Aptos Explorer",
313
+ chainId: 0,
314
+ icon: "Aptos",
315
+ symbol: "APT",
316
+ defaultRpc: "https://fullnode.testnet.aptos.dev"
317
+ },
318
+ Sui: {
319
+ key: "Sui",
320
+ context: "Sui" /* SUI */,
321
+ displayName: "Sui",
322
+ explorerUrl: "https://suiscan.xyz/testnet",
323
+ explorerName: "Suiscan",
324
+ chainId: 0,
325
+ icon: "Sui",
326
+ symbol: "SUI",
327
+ defaultRpc: "https://fullnode.testnet.sui.io:443"
328
+ }
329
+ };
330
+
331
+ // src/config/testnet/tokens.ts
332
+ var testnetTokens = {
333
+ Sepolia: {
334
+ symbol: "USDC",
335
+ icon: "USDC",
336
+ decimals: 6,
337
+ tokenId: {
338
+ chain: "Sepolia",
339
+ address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
166
340
  }
167
- return value;
341
+ },
342
+ Solana: {
343
+ symbol: "USDC",
344
+ tokenId: {
345
+ chain: "Solana",
346
+ address: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"
347
+ },
348
+ icon: "USDC",
349
+ decimals: 6
350
+ },
351
+ Aptos: {
352
+ symbol: "USDC",
353
+ decimals: 6,
354
+ tokenId: {
355
+ chain: "Aptos",
356
+ address: "0x69091fbab5f7d635ee7ac5098cf0c1efbe31d68fec0f2cd565e8d168daf52832"
357
+ },
358
+ icon: "USDC"
359
+ },
360
+ BaseSepolia: {
361
+ symbol: "USDC",
362
+ icon: "USDC",
363
+ decimals: 6,
364
+ tokenId: {
365
+ chain: "BaseSepolia",
366
+ address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
367
+ }
368
+ },
369
+ Avalanche: {
370
+ symbol: "USDC",
371
+ icon: "USDC",
372
+ decimals: 6,
373
+ tokenId: {
374
+ chain: "Avalanche",
375
+ address: "0x5425890298aed601595a70AB815c96711a31Bc65"
376
+ }
377
+ },
378
+ ArbitrumSepolia: {
379
+ symbol: "USDC",
380
+ icon: "USDC",
381
+ decimals: 6,
382
+ tokenId: {
383
+ chain: "ArbitrumSepolia",
384
+ address: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d"
385
+ }
386
+ },
387
+ PolygonSepolia: {
388
+ symbol: "USDC",
389
+ icon: "USDC",
390
+ decimals: 6,
391
+ tokenId: {
392
+ chain: "PolygonSepolia",
393
+ address: "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582"
394
+ }
395
+ },
396
+ Sui: {
397
+ symbol: "USDC",
398
+ tokenId: {
399
+ chain: "Sui",
400
+ address: "0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC"
401
+ },
402
+ icon: "USDC",
403
+ decimals: 6
168
404
  }
169
- return revive(obj);
170
- }
405
+ };
171
406
 
172
407
  // src/providers/wormhole/signers/AptosLocalSigner.ts
173
408
  var import_ts_sdk = require("@aptos-labs/ts-sdk");
@@ -181,6 +416,14 @@ function validateExpireTimestamp(value) {
181
416
  }
182
417
  }
183
418
  var TransferError = class extends Error {
419
+ /** Source-chain burn transaction hash — available when the burn succeeded before the failure. */
420
+ originChainTxnId;
421
+ /**
422
+ * The underlying error that caused this failure.
423
+ * Mirrors ES2022 Error.cause — declared explicitly because the project's
424
+ * TypeScript lib target does not include ES2022 ErrorOptions.
425
+ */
426
+ cause;
184
427
  constructor(message, originChainTxnId, cause) {
185
428
  super(message);
186
429
  this.name = "TransferError";
@@ -189,6 +432,16 @@ var TransferError = class extends Error {
189
432
  }
190
433
  };
191
434
  var WithdrawError = class extends Error {
435
+ /** Aptos burn transaction hash — always available when this error is thrown. */
436
+ originChainTxnId;
437
+ /** The withdraw phase that failed ("tracking" or "claiming"). */
438
+ phase;
439
+ /**
440
+ * The underlying error that caused this failure.
441
+ * Mirrors ES2022 Error.cause — declared explicitly because the project's
442
+ * TypeScript lib target does not include ES2022 ErrorOptions.
443
+ */
444
+ cause;
192
445
  constructor(message, originChainTxnId, phase, cause) {
193
446
  super(message);
194
447
  this.name = "WithdrawError";
@@ -200,8 +453,14 @@ var WithdrawError = class extends Error {
200
453
 
201
454
  // src/providers/wormhole/signers/AptosLocalSigner.ts
202
455
  var AptosLocalSigner = class {
456
+ _chain;
457
+ _options;
458
+ _wallet;
459
+ _sponsorAccount;
460
+ _onTransactionSigned;
461
+ _crossChainCore;
462
+ _claimedTransactionHashes = [];
203
463
  constructor(chain, options, wallet, feePayerAccount, crossChainCore, onTransactionSigned) {
204
- this._claimedTransactionHashes = [];
205
464
  this._chain = chain;
206
465
  this._options = options;
207
466
  this._wallet = wallet;
@@ -262,7 +521,7 @@ async function signAndSendTransaction(request, wallet, sponsorAccount, crossChai
262
521
  const txnToSign = await aptos2.transaction.build.simple({
263
522
  data: payload,
264
523
  sender: wallet.accountAddress.toString(),
265
- withFeePayer: sponsorAccount ? true : false,
524
+ withFeePayer: !!sponsorAccount,
266
525
  ...typeof expireTimestamp !== "undefined" ? { options: { expireTimestamp } } : {}
267
526
  });
268
527
  const senderAuthenticator = await aptos2.transaction.sign({
@@ -287,112 +546,28 @@ async function signAndSendTransaction(request, wallet, sponsorAccount, crossChai
287
546
  return tx.hash;
288
547
  }
289
548
 
290
- // src/providers/wormhole/signers/AptosSigner.ts
291
- var import_ts_sdk2 = require("@aptos-labs/ts-sdk");
292
- var import_wallet_standard = require("@aptos-labs/wallet-standard");
293
- var import_gas_station_client = require("@aptos-labs/gas-station-client");
294
- async function signAndSendTransaction2(request, wallet, sponsorAccount, dappNetwork, crossChainCore) {
295
- if (!wallet) {
296
- throw new Error("wallet.sendTransaction is undefined");
297
- }
298
- const payload = request.transaction;
299
- payload.functionArguments = payload.functionArguments.map((a) => {
300
- if (a instanceof Uint8Array) {
301
- return Array.from(a);
302
- } else if (typeof a === "bigint") {
303
- return a.toString();
304
- } else {
305
- return a;
306
- }
307
- });
308
- let aptosConfig;
309
- const useGasStation = sponsorAccount && !isAccount(sponsorAccount);
310
- if (useGasStation) {
311
- const gasStationClient = new import_gas_station_client.GasStationClient({
312
- network: dappNetwork,
313
- apiKey: sponsorAccount[dappNetwork]
314
- });
315
- const transactionSubmitter = new import_gas_station_client.GasStationTransactionSubmitter(gasStationClient);
316
- aptosConfig = new import_ts_sdk2.AptosConfig({
317
- network: dappNetwork,
318
- pluginSettings: {
319
- TRANSACTION_SUBMITTER: transactionSubmitter
320
- }
321
- });
322
- } else {
323
- aptosConfig = new import_ts_sdk2.AptosConfig({
324
- network: dappNetwork
325
- });
326
- }
327
- const aptos2 = new import_ts_sdk2.Aptos(aptosConfig);
328
- const functionArguments = extractFunctionArguments(
329
- payload.functionArguments
330
- );
331
- const withdrawFunction = "0x5e2d961f06cd27aa07554a39d55f5ce1e58dff35d803c3529b1cd5c4fa3ab584::withdraw::deposit_for_burn";
332
- const transactionData = {
333
- function: withdrawFunction,
334
- functionArguments
335
- };
336
- const expireTimestamp = crossChainCore?._dappConfig?.getExpireTimestamp?.();
337
- if (typeof expireTimestamp !== "undefined") {
338
- validateExpireTimestamp(expireTimestamp);
339
- }
340
- const txnToSign = await aptos2.transaction.build.simple({
341
- data: transactionData,
342
- sender: (await wallet.features["aptos:account"]?.account()).address.toString(),
343
- withFeePayer: sponsorAccount ? true : false,
344
- ...typeof expireTimestamp !== "undefined" ? { options: { expireTimestamp } } : {}
345
- });
346
- const response = await wallet.features["aptos:signTransaction"]?.signTransaction(txnToSign);
347
- if (response?.status === import_wallet_standard.UserResponseStatus.REJECTED) {
348
- throw new Error("User has rejected the request");
349
- }
350
- const txnToSubmit = {
351
- transaction: txnToSign,
352
- senderAuthenticator: response.args
549
+ // src/providers/wormhole/signers/SolanaLocalSigner.ts
550
+ var import_web32 = require("@solana/web3.js");
551
+
552
+ // src/providers/wormhole/signers/solanaUtils.ts
553
+ var import_web3 = require("@solana/web3.js");
554
+ var import_sdk_solana = require("@wormhole-foundation/sdk-solana");
555
+ async function sendAndConfirmTransaction(serializedTx, blockhash, lastValidBlockHeight, config) {
556
+ const {
557
+ connection,
558
+ commitment,
559
+ retryIntervalMs = 5e3,
560
+ verbose = false
561
+ } = config;
562
+ const sendOptions = {
563
+ skipPreflight: true,
564
+ maxRetries: 0,
565
+ preflightCommitment: commitment
353
566
  };
354
- if (sponsorAccount && isAccount(sponsorAccount)) {
355
- const feePayerSignerAuthenticator = aptos2.transaction.signAsFeePayer({
356
- signer: sponsorAccount,
357
- transaction: txnToSign
358
- });
359
- txnToSubmit.feePayerAuthenticator = feePayerSignerAuthenticator;
360
- }
361
- const txnSubmitted = await aptos2.transaction.submit.simple(txnToSubmit);
362
- const tx = await aptos2.waitForTransaction({
363
- transactionHash: txnSubmitted.hash
364
- });
365
- return tx.hash;
366
- }
367
- function extractFunctionArguments(functionArguments) {
368
- const deserializer1 = new import_ts_sdk2.Deserializer(functionArguments[0].bcsToBytes());
369
- const amount = deserializer1.deserializeU64();
370
- const deserializer2 = new import_ts_sdk2.Deserializer(functionArguments[1].bcsToBytes());
371
- const destination_domain = deserializer2.deserializeU32();
372
- const mint_recipient = new import_ts_sdk2.AccountAddress(functionArguments[2].bcsToBytes());
373
- const burn_token = new import_ts_sdk2.AccountAddress(functionArguments[3].bcsToBytes());
374
- return [amount, destination_domain, mint_recipient, burn_token];
375
- }
376
- function isAccount(obj) {
377
- return "accountAddress" in obj;
378
- }
379
-
380
- // src/providers/wormhole/signers/SolanaSigner.ts
381
- var import_web32 = require("@solana/web3.js");
382
- var import_web33 = require("@solana/web3.js");
383
- var import_derived_wallet_solana = require("@aptos-labs/derived-wallet-solana");
384
-
385
- // src/providers/wormhole/signers/solanaUtils.ts
386
- var import_web3 = require("@solana/web3.js");
387
- var import_sdk_solana = require("@wormhole-foundation/sdk-solana");
388
- async function sendAndConfirmTransaction(serializedTx, blockhash, lastValidBlockHeight, config) {
389
- const { connection, commitment, retryIntervalMs = 5e3, verbose = false } = config;
390
- const sendOptions = {
391
- skipPreflight: true,
392
- maxRetries: 0,
393
- preflightCommitment: commitment
394
- };
395
- const signature = await connection.sendRawTransaction(serializedTx, sendOptions);
567
+ const signature = await connection.sendRawTransaction(
568
+ serializedTx,
569
+ sendOptions
570
+ );
396
571
  const confirmTransactionPromise = connection.confirmTransaction(
397
572
  { signature, blockhash, lastValidBlockHeight },
398
573
  commitment
@@ -455,7 +630,9 @@ function formatTransactionError(err) {
455
630
  }
456
631
  async function addPriorityFeeInstructions(connection, transaction, priorityFeeConfig, verbose = false) {
457
632
  const computeBudgetIxFilter = (ix) => ix.programId.toString() !== "ComputeBudget111111111111111111111111111111";
458
- transaction.instructions = transaction.instructions.filter(computeBudgetIxFilter);
633
+ transaction.instructions = transaction.instructions.filter(
634
+ computeBudgetIxFilter
635
+ );
459
636
  const instructions = await createPriorityFeeInstructions(
460
637
  connection,
461
638
  transaction,
@@ -507,19 +684,21 @@ async function createPriorityFeeInstructions(connection, transaction, priorityFe
507
684
  async function simulateAndGetComputeUnits(connection, transaction) {
508
685
  let unitsUsed = 2e5;
509
686
  let simulationAttempts = 0;
510
- simulationLoop: while (true) {
511
- const response = await connection.simulateTransaction(transaction);
687
+ while (true) {
688
+ const response = await connection.simulateTransaction(
689
+ transaction
690
+ );
512
691
  if (response.value.err) {
513
692
  if (checkKnownSimulationError(response.value)) {
514
693
  if (simulationAttempts < 5) {
515
694
  simulationAttempts++;
516
695
  await sleep(1e3);
517
- continue simulationLoop;
696
+ continue;
518
697
  }
519
698
  } else if (simulationAttempts < 3) {
520
699
  simulationAttempts++;
521
700
  await sleep(1e3);
522
- continue simulationLoop;
701
+ continue;
523
702
  }
524
703
  throw new Error(
525
704
  `Simulation failed: ${JSON.stringify(response.value.err)}
@@ -570,15 +749,15 @@ async function calculatePriorityFee(connection, transaction, rpcProvider, config
570
749
  function checkKnownSimulationError(response) {
571
750
  const errors = {};
572
751
  if (response.err === "BlockhashNotFound") {
573
- errors["BlockhashNotFound"] = "Blockhash not found during simulation. Trying again.";
752
+ errors.BlockhashNotFound = "Blockhash not found during simulation. Trying again.";
574
753
  }
575
754
  if (response.logs) {
576
755
  for (const line of response.logs) {
577
756
  if (line.includes("SlippageToleranceExceeded")) {
578
- errors["SlippageToleranceExceeded"] = "Slippage failure during simulation. Trying again.";
757
+ errors.SlippageToleranceExceeded = "Slippage failure during simulation. Trying again.";
579
758
  }
580
759
  if (line.includes("RequireGteViolated")) {
581
- errors["RequireGteViolated"] = "Swap instruction failure during simulation. Trying again.";
760
+ errors.RequireGteViolated = "Swap instruction failure during simulation. Trying again.";
582
761
  }
583
762
  }
584
763
  }
@@ -612,157 +791,35 @@ async function sleep(timeout) {
612
791
  return new Promise((resolve) => setTimeout(resolve, timeout));
613
792
  }
614
793
 
615
- // src/providers/wormhole/signers/SolanaSigner.ts
616
- async function signAndSendTransaction3(request, wallet, options, crossChainCore) {
617
- if (!wallet || !(wallet instanceof import_derived_wallet_solana.SolanaDerivedWallet)) {
618
- throw new Error("Invalid wallet type or missing Solana wallet");
619
- }
620
- const commitment = options?.commitment ?? crossChainCore?._dappConfig?.solanaConfig?.commitment ?? "finalized";
621
- const connection = new import_web33.Connection(
622
- crossChainCore?._dappConfig?.solanaConfig?.rpc ?? crossChainCore?.CHAINS["Solana"]?.defaultRpc ?? "https://api.devnet.solana.com"
623
- // Last resort fallback
624
- );
625
- const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash(commitment);
626
- const unsignedTx = await setPriorityFeeInstructions(
627
- connection,
628
- blockhash,
629
- lastValidBlockHeight,
630
- request,
631
- crossChainCore?._dappConfig?.solanaConfig?.priorityFeeConfig
632
- );
633
- if (!wallet.solanaWallet.signTransaction) {
634
- throw new Error("Wallet does not support signing transactions");
635
- }
636
- const tx = await wallet.solanaWallet.signTransaction(unsignedTx);
637
- if (!tx) throw new Error("Failed to sign transaction");
638
- if (request.transaction.signers && tx instanceof import_web32.Transaction) {
639
- tx.partialSign(...request.transaction.signers);
640
- }
641
- const serializedTx = tx.serialize();
642
- const signature = await sendAndConfirmTransaction(
643
- serializedTx,
644
- blockhash,
645
- lastValidBlockHeight,
646
- {
647
- connection,
648
- commitment,
649
- retryIntervalMs: 5e3,
650
- verbose: false
651
- }
652
- );
653
- return signature;
654
- }
655
- async function setPriorityFeeInstructions(connection, blockhash, lastValidBlockHeight, request, priorityFeeConfig) {
656
- const unsignedTx = request.transaction.transaction;
657
- unsignedTx.recentBlockhash = blockhash;
658
- unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
659
- await addPriorityFeeInstructions(
660
- connection,
661
- unsignedTx,
662
- priorityFeeConfig,
663
- false
664
- );
665
- return unsignedTx;
666
- }
667
-
668
- // src/providers/wormhole/signers/EthereumSigner.ts
669
- var import_ethers = require("ethers");
670
- async function signAndSendTransaction4(request, wallet, chainName) {
671
- if (!wallet) {
672
- throw new Error("wallet.sendTransaction is undefined");
673
- }
674
- const chainId = await wallet.eip1193Provider.request({
675
- method: "eth_chainId"
676
- });
677
- const actualChainId = parseInt(chainId, 16);
678
- if (!actualChainId) throw new Error("No signer found for chain" + chainName);
679
- const expectedChainId = request.transaction.chainId ? (0, import_ethers.getBigInt)(request.transaction.chainId) : void 0;
680
- if (!actualChainId || !expectedChainId || BigInt(actualChainId) !== expectedChainId) {
681
- throw new Error(
682
- `Signer is not connected to the right chain. Expected ${expectedChainId}, got ${actualChainId}`
683
- );
684
- }
685
- const provider = new import_ethers.ethers.BrowserProvider(
686
- wallet.eip1193Provider
687
- );
688
- const signer = await provider.getSigner();
689
- let response;
690
- try {
691
- response = await signer.sendTransaction(request.transaction);
692
- } catch (e) {
693
- const message = e instanceof Error ? e.message : String(e);
694
- const hashMatch = message.match(/"hash":\s*"(0x[a-fA-F0-9]{64})"/);
695
- if (hashMatch) {
696
- console.warn("Extracted EVM tx hash from error:", hashMatch[1]);
697
- return hashMatch[1];
698
- }
699
- throw e;
700
- }
701
- try {
702
- const receipt = await response.wait();
703
- return receipt?.hash || response.hash || "";
704
- } catch (e) {
705
- if (e?.code === "TRANSACTION_REPLACED") {
706
- if (e.reason === "repriced") {
707
- const replacementHash = e.receipt?.hash || e.replacement?.hash;
708
- if (replacementHash) {
709
- console.warn(
710
- "EVM transaction was repriced. Using replacement hash:",
711
- replacementHash
712
- );
713
- return replacementHash;
714
- }
715
- }
716
- throw e;
717
- }
718
- if (response.hash) {
719
- console.warn(
720
- "EVM transaction wait failed but tx was submitted:",
721
- response.hash
722
- );
723
- return response.hash;
724
- }
725
- throw e;
726
- }
727
- }
728
-
729
- // src/providers/wormhole/signers/SuiSigner.ts
730
- async function signAndSendTransaction5(request, wallet) {
731
- if (!wallet) {
732
- throw new Error("wallet is undefined");
733
- }
734
- const suiDerivedWallet = wallet;
735
- const signAndExecuteTransactionFeature = suiDerivedWallet.suiWallet.features["sui:signAndExecuteTransaction"];
736
- if (!signAndExecuteTransactionFeature) {
737
- throw new Error("wallet does not support signAndExecuteTransaction");
738
- }
739
- const { digest } = await signAndExecuteTransactionFeature.signAndExecuteTransaction({
740
- transaction: request.transaction,
741
- account: suiDerivedWallet.suiWallet.accounts[0],
742
- chain: `sui:${request.network.toLocaleLowerCase()}`
743
- });
744
- return digest;
745
- }
746
-
747
- // src/providers/wormhole/signers/Signer.ts
748
- var Signer = class {
749
- constructor(chain, address, options, wallet, crossChainCore, sponsorAccount, onTransactionSigned, trackAsSourceChain = true) {
750
- this._claimedTransactionHashes = [];
751
- this._chain = chain;
752
- this._address = address;
753
- this._options = options;
754
- this._wallet = wallet;
755
- this._crossChainCore = crossChainCore;
756
- this._sponsorAccount = sponsorAccount;
757
- this._onTransactionSigned = onTransactionSigned;
758
- this._trackAsSourceChain = trackAsSourceChain;
794
+ // src/providers/wormhole/signers/SolanaLocalSigner.ts
795
+ var SolanaLocalSigner = class {
796
+ keypair;
797
+ connection;
798
+ commitment;
799
+ retryIntervalMs;
800
+ priorityFeeConfig;
801
+ verbose;
802
+ _onTransactionSigned;
803
+ _claimedTransactionHashes = [];
804
+ constructor(config) {
805
+ this.keypair = config.keypair;
806
+ this.connection = config.connection;
807
+ this.commitment = config.commitment ?? "finalized";
808
+ this.retryIntervalMs = config.retryIntervalMs ?? 5e3;
809
+ this.priorityFeeConfig = config.priorityFeeConfig;
810
+ this.verbose = config.verbose ?? false;
811
+ this._onTransactionSigned = config.onTransactionSigned;
759
812
  }
760
813
  chain() {
761
- return this._chain.key;
814
+ return "Solana";
762
815
  }
763
816
  address() {
764
- return this._address;
817
+ return this.keypair.publicKey.toBase58();
765
818
  }
819
+ /**
820
+ * Returns all transaction hashes from the most recent signAndSend call,
821
+ * joined by comma. If only one transaction was signed, returns a single hash string.
822
+ */
766
823
  claimedTransactionHashes() {
767
824
  return this._claimedTransactionHashes.join(",");
768
825
  }
@@ -771,1023 +828,1031 @@ var Signer = class {
771
828
  this._claimedTransactionHashes = [];
772
829
  for (const tx of txs) {
773
830
  this._onTransactionSigned?.(tx.description, null);
774
- const txId = await signAndSendTransaction6(
775
- this._chain,
776
- tx,
777
- this._wallet,
778
- this._options,
779
- this._crossChainCore,
780
- this._sponsorAccount
781
- );
782
- if (this._trackAsSourceChain) {
783
- this._crossChainCore._lastSourceChainTxId = txId;
784
- }
831
+ const txId = await this.signAndSendTransaction(tx);
785
832
  this._onTransactionSigned?.(tx.description, txId);
786
833
  txHashes.push(txId);
787
834
  this._claimedTransactionHashes.push(txId);
788
835
  }
789
836
  return txHashes;
790
837
  }
791
- };
792
- var signAndSendTransaction6 = async (chain, request, wallet, options = {}, crossChainCore, sponsorAccount) => {
793
- if (!wallet) {
794
- throw new Error("wallet is undefined");
795
- }
796
- const dappNetwork = crossChainCore._dappConfig.aptosNetwork;
797
- if (chain.context === "Solana") {
798
- const signature = await signAndSendTransaction3(
799
- request,
800
- wallet,
801
- options,
802
- crossChainCore
803
- );
804
- return signature;
805
- } else if (chain.context === "Ethereum") {
806
- const tx = await signAndSendTransaction4(
807
- request,
808
- wallet,
809
- chain.displayName
810
- );
811
- return tx;
812
- } else if (chain.context === "Sui") {
813
- const tx = await signAndSendTransaction5(
814
- request,
815
- wallet
816
- );
817
- return tx;
818
- } else if (chain.context === "Aptos") {
819
- const tx = await signAndSendTransaction2(
820
- request,
821
- wallet,
822
- sponsorAccount,
823
- dappNetwork,
824
- crossChainCore
825
- );
826
- return tx;
827
- } else {
828
- throw new Error(`Unsupported chain: ${chain}`);
829
- }
830
- };
831
-
832
- // src/providers/wormhole/utils.ts
833
- var import_sdk2 = require("@wormhole-foundation/sdk");
834
- async function createCCTPRoute(wh, sourceChain, destChain, tokens) {
835
- const sourceToken = import_sdk2.Wormhole.tokenId(
836
- sourceChain,
837
- tokens[sourceChain].tokenId.address
838
- );
839
- const destToken = import_sdk2.Wormhole.tokenId(
840
- destChain,
838
+ async signAndSendTransaction(request) {
839
+ const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash(this.commitment);
840
+ let unsignedTx = request.transaction ?? request;
841
+ const additionalSigners = request.transaction?.signers;
842
+ const MAX_UNWRAP_DEPTH = 10;
843
+ let unwrapDepth = 0;
844
+ while (unsignedTx && typeof unsignedTx === "object" && "transaction" in unsignedTx && !(unsignedTx instanceof import_web32.Transaction) && !("signatures" in unsignedTx && "message" in unsignedTx)) {
845
+ if (++unwrapDepth > MAX_UNWRAP_DEPTH) {
846
+ throw new Error(
847
+ "Transaction unwrapping exceeded maximum depth \u2014 possible circular nesting"
848
+ );
849
+ }
850
+ unsignedTx = unsignedTx.transaction;
851
+ }
852
+ const isVersioned = unsignedTx.message !== void 0 && unsignedTx.signatures !== void 0 && typeof unsignedTx.message.recentBlockhash !== "undefined";
853
+ if (isVersioned) {
854
+ unsignedTx.message.recentBlockhash = blockhash;
855
+ if (this.verbose || this.priorityFeeConfig) {
856
+ console.warn(
857
+ "SolanaLocalSigner: Versioned transaction detected \u2014 priority fees are not applied. Consider using legacy transactions if priority fees are required."
858
+ );
859
+ }
860
+ unsignedTx.sign([this.keypair]);
861
+ if (additionalSigners && additionalSigners.length > 0) {
862
+ unsignedTx.sign(additionalSigners);
863
+ }
864
+ } else if (unsignedTx instanceof import_web32.Transaction) {
865
+ unsignedTx.recentBlockhash = blockhash;
866
+ unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
867
+ if (this.priorityFeeConfig) {
868
+ await addPriorityFeeInstructions(
869
+ this.connection,
870
+ unsignedTx,
871
+ this.priorityFeeConfig,
872
+ this.verbose
873
+ );
874
+ }
875
+ if (additionalSigners && additionalSigners.length > 0) {
876
+ unsignedTx.sign(this.keypair, ...additionalSigners);
877
+ } else {
878
+ unsignedTx.sign(this.keypair);
879
+ }
880
+ } else if (unsignedTx.recentBlockhash !== void 0 || unsignedTx.feePayer !== void 0) {
881
+ unsignedTx.recentBlockhash = blockhash;
882
+ unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
883
+ if (this.priorityFeeConfig) {
884
+ await addPriorityFeeInstructions(
885
+ this.connection,
886
+ unsignedTx,
887
+ this.priorityFeeConfig,
888
+ this.verbose
889
+ );
890
+ }
891
+ if (additionalSigners && additionalSigners.length > 0) {
892
+ unsignedTx.sign(this.keypair, ...additionalSigners);
893
+ } else {
894
+ unsignedTx.sign(this.keypair);
895
+ }
896
+ } else {
897
+ throw new Error(
898
+ `Unsupported transaction type: ${unsignedTx?.constructor?.name}`
899
+ );
900
+ }
901
+ const serializedTx = unsignedTx.serialize();
902
+ const signature = await sendAndConfirmTransaction(
903
+ serializedTx,
904
+ blockhash,
905
+ lastValidBlockHeight,
906
+ {
907
+ connection: this.connection,
908
+ commitment: this.commitment,
909
+ retryIntervalMs: this.retryIntervalMs,
910
+ verbose: this.verbose
911
+ }
912
+ );
913
+ return signature;
914
+ }
915
+ };
916
+
917
+ // src/providers/wormhole/utils.ts
918
+ var import_sdk = require("@wormhole-foundation/sdk");
919
+ async function createCCTPRoute(wh, sourceChain, destChain, tokens) {
920
+ const sourceToken = import_sdk.Wormhole.tokenId(
921
+ sourceChain,
922
+ tokens[sourceChain].tokenId.address
923
+ );
924
+ const destToken = import_sdk.Wormhole.tokenId(
925
+ destChain,
841
926
  tokens[destChain].tokenId.address
842
927
  );
843
- const destContext = wh.getPlatform((0, import_sdk2.chainToPlatform)(destChain)).getChain(destChain);
844
- const sourceContext = wh.getPlatform((0, import_sdk2.chainToPlatform)(sourceChain)).getChain(sourceChain);
845
- const request = await import_sdk2.routes.RouteTransferRequest.create(
928
+ const destContext = wh.getPlatform((0, import_sdk.chainToPlatform)(destChain)).getChain(destChain);
929
+ const sourceContext = wh.getPlatform((0, import_sdk.chainToPlatform)(sourceChain)).getChain(sourceChain);
930
+ const request = await import_sdk.routes.RouteTransferRequest.create(
846
931
  wh,
847
932
  { source: sourceToken, destination: destToken },
848
933
  sourceContext,
849
934
  destContext
850
935
  );
851
- const resolver = wh.resolver([import_sdk2.routes.CCTPRoute]);
936
+ const resolver = wh.resolver([import_sdk.routes.CCTPRoute]);
852
937
  const foundRoutes = await resolver.findRoutes(request);
853
938
  const cctpRoute = foundRoutes[0];
854
- if (!cctpRoute || !import_sdk2.routes.isManual(cctpRoute)) {
939
+ if (!cctpRoute || !import_sdk.routes.isManual(cctpRoute)) {
855
940
  throw new Error("Expected manual CCTP route");
856
941
  }
857
942
  return { route: cctpRoute, request };
858
943
  }
859
944
 
860
945
  // src/providers/wormhole/wormhole.ts
861
- var WormholeProvider = class {
862
- constructor(core) {
863
- this.crossChainCore = core;
864
- }
865
- get wormholeContext() {
866
- return this._wormholeContext;
867
- }
868
- async setWormholeContext(sourceChain) {
869
- const dappNetwork = this.crossChainCore._dappConfig?.aptosNetwork;
870
- if (dappNetwork === import_ts_sdk3.Network.DEVNET) {
871
- throw new Error("Devnet is not supported on Wormhole");
946
+ var import_ts_sdk3 = require("@aptos-labs/ts-sdk");
947
+ var import_sdk3 = require("@wormhole-foundation/sdk");
948
+ var import_aptos = __toESM(require("@wormhole-foundation/sdk/aptos"));
949
+ var import_evm = __toESM(require("@wormhole-foundation/sdk/evm"));
950
+ var import_solana = __toESM(require("@wormhole-foundation/sdk/solana"));
951
+ var import_sui = __toESM(require("@wormhole-foundation/sdk/sui"));
952
+
953
+ // src/utils/logger.ts
954
+ var logger = {
955
+ log: (...args) => {
956
+ if (process.env.NODE_ENV === "development") {
957
+ console.log(...args);
872
958
  }
873
- if (!sourceChain) {
874
- throw new Error("Origin chain not selected");
959
+ },
960
+ warn: (...args) => {
961
+ if (process.env.NODE_ENV === "development") {
962
+ console.warn(...args);
875
963
  }
876
- const isMainnet = dappNetwork === import_ts_sdk3.Network.MAINNET;
877
- const platforms = [import_aptos.default, import_solana.default, import_evm.default, import_sui.default];
878
- const dappConfig = this.crossChainCore._dappConfig;
879
- const chains = this.crossChainCore.CHAINS;
880
- const solanaRpc = dappConfig?.solanaConfig?.rpc ?? chains["Solana"]?.defaultRpc;
881
- const suiRpc = dappConfig?.suiConfig?.rpc ?? chains["Sui"]?.defaultRpc;
882
- const evmChainsConfig = {};
883
- for (const name of EVM_CHAIN_NAMES) {
884
- const rpc = dappConfig?.evmConfig?.[name]?.rpc ?? chains[name]?.defaultRpc;
885
- if (rpc) {
886
- evmChainsConfig[name] = { rpc };
887
- }
964
+ },
965
+ error: (...args) => {
966
+ if (process.env.NODE_ENV === "development") {
967
+ console.error(...args);
888
968
  }
889
- const wh = await (0, import_sdk3.wormhole)(isMainnet ? "Mainnet" : "Testnet", platforms, {
890
- chains: {
891
- ...solanaRpc ? { Solana: { rpc: solanaRpc } } : {},
892
- ...suiRpc ? { Sui: { rpc: suiRpc } } : {},
893
- ...evmChainsConfig
894
- }
895
- });
896
- this._wormholeContext = wh;
897
969
  }
898
- async getRoute(sourceChain, destinationChain) {
899
- if (!this._wormholeContext) {
900
- throw new Error("Wormhole context not initialized");
901
- }
902
- const { route: cctpRoute, request } = await createCCTPRoute(
903
- this._wormholeContext,
904
- sourceChain,
905
- destinationChain,
906
- this.crossChainCore.TOKENS
907
- );
908
- this.wormholeRoute = cctpRoute;
909
- this.wormholeRequest = request;
910
- this.destinationChain = destinationChain;
911
- return { route: cctpRoute, request };
970
+ };
971
+
972
+ // src/utils/receiptSerialization.ts
973
+ var import_sdk2 = require("@wormhole-foundation/sdk");
974
+ function uint8ArrayToBase64(bytes) {
975
+ let binary = "";
976
+ for (let i = 0; i < bytes.length; i++) {
977
+ binary += String.fromCharCode(bytes[i]);
912
978
  }
913
- async getQuote(input) {
914
- const { amount, originChain, type } = input;
915
- if (!this._wormholeContext) {
916
- await this.setWormholeContext(originChain);
917
- }
918
- logger.log("type", type);
919
- const sourceChain = type === "transfer" ? originChain : "Aptos";
920
- const destinationChain = type === "transfer" ? "Aptos" : originChain;
921
- const { route, request } = await this.getRoute(
922
- sourceChain,
923
- destinationChain
924
- );
925
- const transferParams = {
926
- amount,
927
- options: { nativeGas: 0 }
928
- };
929
- const validated = await route.validate(request, transferParams);
930
- if (!validated.valid) {
931
- logger.log("invalid", validated.valid);
932
- throw new Error(`Invalid quote: ${validated.error}`);
933
- }
934
- const quote = await route.quote(request, validated.params);
935
- if (!quote.success) {
936
- logger.log("quote failed", quote.success);
937
- throw new Error(`Invalid quote: ${quote.error}`);
979
+ return btoa(binary);
980
+ }
981
+ function base64ToUint8Array(base64) {
982
+ const binary = atob(base64);
983
+ const bytes = new Uint8Array(binary.length);
984
+ for (let i = 0; i < binary.length; i++) {
985
+ bytes[i] = binary.charCodeAt(i);
986
+ }
987
+ return bytes;
988
+ }
989
+ function serializeReceipt(receipt) {
990
+ return JSON.parse(
991
+ JSON.stringify(receipt, (_key, value) => {
992
+ if (typeof value === "bigint") {
993
+ return { __type: "bigint", value: value.toString() };
994
+ }
995
+ if (value instanceof import_sdk2.UniversalAddress) {
996
+ return {
997
+ __type: "UniversalAddress",
998
+ value: uint8ArrayToBase64(value.toUint8Array())
999
+ };
1000
+ }
1001
+ if (value instanceof Uint8Array) {
1002
+ return {
1003
+ __type: "Uint8Array",
1004
+ value: uint8ArrayToBase64(value)
1005
+ };
1006
+ }
1007
+ return value;
1008
+ })
1009
+ );
1010
+ }
1011
+ function deserializeReceipt(obj) {
1012
+ function revive(value, key) {
1013
+ if (value && typeof value === "object") {
1014
+ const objValue = value;
1015
+ if ("__type" in objValue) {
1016
+ if (objValue.__type === "bigint") {
1017
+ return BigInt(objValue.value);
1018
+ }
1019
+ if (objValue.__type === "UniversalAddress") {
1020
+ return new import_sdk2.UniversalAddress(
1021
+ base64ToUint8Array(objValue.value)
1022
+ );
1023
+ }
1024
+ if (objValue.__type === "Uint8Array") {
1025
+ return base64ToUint8Array(objValue.value);
1026
+ }
1027
+ }
1028
+ const addressFields = [
1029
+ "sender",
1030
+ "recipient",
1031
+ "destinationCaller",
1032
+ "burnToken",
1033
+ "mintRecipient",
1034
+ "messageSender"
1035
+ ];
1036
+ if (key && addressFields.includes(key) && "address" in objValue) {
1037
+ const addressBytes = revive(objValue.address);
1038
+ if (addressBytes instanceof Uint8Array) {
1039
+ return new import_sdk2.UniversalAddress(addressBytes);
1040
+ }
1041
+ }
1042
+ if (Array.isArray(value)) {
1043
+ return value.map((v, i) => revive(v, String(i)));
1044
+ }
1045
+ const result = {};
1046
+ for (const k in objValue) {
1047
+ result[k] = revive(objValue[k], k);
1048
+ }
1049
+ return result;
938
1050
  }
939
- this.wormholeQuote = quote;
940
- logger.log("quote", quote);
941
- return quote;
1051
+ return value;
942
1052
  }
943
- async submitCCTPTransfer(input) {
944
- const { sourceChain, wallet, destinationAddress, onTransactionSigned } = input;
945
- if (!this._wormholeContext) {
946
- await this.setWormholeContext(sourceChain);
947
- }
948
- if (!this.wormholeRoute || !this.wormholeRequest || !this.wormholeQuote) {
949
- throw new Error("Wormhole route, request, or quote not initialized");
950
- }
951
- let signerAddress;
952
- const chainContext = this.getChainConfig(sourceChain).context;
953
- if (chainContext === "Solana") {
954
- signerAddress = wallet.solanaWallet.publicKey?.toBase58() || "";
955
- } else if (chainContext === "Ethereum") {
956
- [signerAddress] = await wallet.eip1193Provider.request({
957
- method: "eth_requestAccounts"
958
- });
959
- } else if (chainContext === "Sui") {
960
- signerAddress = wallet.suiWallet.accounts[0].address || "";
1053
+ return revive(obj);
1054
+ }
1055
+
1056
+ // src/providers/wormhole/signers/AptosSigner.ts
1057
+ var import_gas_station_client = require("@aptos-labs/gas-station-client");
1058
+ var import_ts_sdk2 = require("@aptos-labs/ts-sdk");
1059
+ var import_wallet_standard = require("@aptos-labs/wallet-standard");
1060
+ async function signAndSendTransaction2(request, wallet, sponsorAccount, dappNetwork, crossChainCore) {
1061
+ if (!wallet) {
1062
+ throw new Error("wallet.sendTransaction is undefined");
1063
+ }
1064
+ const payload = request.transaction;
1065
+ payload.functionArguments = payload.functionArguments.map((a) => {
1066
+ if (a instanceof Uint8Array) {
1067
+ return Array.from(a);
1068
+ } else if (typeof a === "bigint") {
1069
+ return a.toString();
961
1070
  } else {
962
- throw new Error("Unsupported chain context: " + chainContext);
1071
+ return a;
963
1072
  }
964
- logger.log("signerAddress", signerAddress);
965
- const signer = new Signer(
966
- this.getChainConfig(sourceChain),
967
- signerAddress,
968
- {},
969
- wallet,
970
- this.crossChainCore,
971
- void 0,
972
- onTransactionSigned
1073
+ });
1074
+ let aptosConfig;
1075
+ const useGasStation = sponsorAccount && !isAccount(sponsorAccount);
1076
+ if (useGasStation) {
1077
+ const gasStationClient = new import_gas_station_client.GasStationClient({
1078
+ network: dappNetwork,
1079
+ apiKey: sponsorAccount[dappNetwork]
1080
+ });
1081
+ const transactionSubmitter = new import_gas_station_client.GasStationTransactionSubmitter(
1082
+ gasStationClient
973
1083
  );
974
- logger.log("signer", signer);
975
- logger.log("wormholeRequest", this.wormholeRequest);
976
- logger.log("wormholeQuote", this.wormholeQuote);
977
- let receipt = await this.wormholeRoute.initiate(
978
- this.wormholeRequest,
979
- signer,
980
- this.wormholeQuote,
981
- import_sdk3.Wormhole.chainAddress("Aptos", destinationAddress.toString())
1084
+ aptosConfig = new import_ts_sdk2.AptosConfig({
1085
+ network: dappNetwork,
1086
+ pluginSettings: {
1087
+ TRANSACTION_SUBMITTER: transactionSubmitter
1088
+ }
1089
+ });
1090
+ } else {
1091
+ aptosConfig = new import_ts_sdk2.AptosConfig({
1092
+ network: dappNetwork
1093
+ });
1094
+ }
1095
+ const aptos2 = new import_ts_sdk2.Aptos(aptosConfig);
1096
+ const functionArguments = extractFunctionArguments(
1097
+ payload.functionArguments
1098
+ );
1099
+ const withdrawFunction = "0x5e2d961f06cd27aa07554a39d55f5ce1e58dff35d803c3529b1cd5c4fa3ab584::withdraw::deposit_for_burn";
1100
+ const transactionData = {
1101
+ function: withdrawFunction,
1102
+ functionArguments
1103
+ };
1104
+ const expireTimestamp = crossChainCore?._dappConfig?.getExpireTimestamp?.();
1105
+ if (typeof expireTimestamp !== "undefined") {
1106
+ validateExpireTimestamp(expireTimestamp);
1107
+ }
1108
+ const txnToSign = await aptos2.transaction.build.simple({
1109
+ data: transactionData,
1110
+ sender: (await wallet.features["aptos:account"]?.account()).address.toString(),
1111
+ withFeePayer: !!sponsorAccount,
1112
+ ...typeof expireTimestamp !== "undefined" ? { options: { expireTimestamp } } : {}
1113
+ });
1114
+ const response = await wallet.features["aptos:signTransaction"]?.signTransaction(txnToSign);
1115
+ if (response?.status === import_wallet_standard.UserResponseStatus.REJECTED) {
1116
+ throw new Error("User has rejected the request");
1117
+ }
1118
+ const txnToSubmit = {
1119
+ transaction: txnToSign,
1120
+ senderAuthenticator: response.args
1121
+ };
1122
+ if (sponsorAccount && isAccount(sponsorAccount)) {
1123
+ const feePayerSignerAuthenticator = aptos2.transaction.signAsFeePayer({
1124
+ signer: sponsorAccount,
1125
+ transaction: txnToSign
1126
+ });
1127
+ txnToSubmit.feePayerAuthenticator = feePayerSignerAuthenticator;
1128
+ }
1129
+ const txnSubmitted = await aptos2.transaction.submit.simple(txnToSubmit);
1130
+ const tx = await aptos2.waitForTransaction({
1131
+ transactionHash: txnSubmitted.hash
1132
+ });
1133
+ return tx.hash;
1134
+ }
1135
+ function extractFunctionArguments(functionArguments) {
1136
+ const deserializer1 = new import_ts_sdk2.Deserializer(functionArguments[0].bcsToBytes());
1137
+ const amount = deserializer1.deserializeU64();
1138
+ const deserializer2 = new import_ts_sdk2.Deserializer(functionArguments[1].bcsToBytes());
1139
+ const destination_domain = deserializer2.deserializeU32();
1140
+ const mint_recipient = new import_ts_sdk2.AccountAddress(functionArguments[2].bcsToBytes());
1141
+ const burn_token = new import_ts_sdk2.AccountAddress(functionArguments[3].bcsToBytes());
1142
+ return [amount, destination_domain, mint_recipient, burn_token];
1143
+ }
1144
+ function isAccount(obj) {
1145
+ return "accountAddress" in obj;
1146
+ }
1147
+
1148
+ // src/providers/wormhole/signers/EthereumSigner.ts
1149
+ var import_ethers = require("ethers");
1150
+ async function signAndSendTransaction3(request, wallet, chainName) {
1151
+ if (!wallet) {
1152
+ throw new Error("wallet.sendTransaction is undefined");
1153
+ }
1154
+ const chainId = await wallet.eip1193Provider.request({
1155
+ method: "eth_chainId"
1156
+ });
1157
+ const actualChainId = parseInt(chainId, 16);
1158
+ if (!actualChainId) throw new Error(`No signer found for chain${chainName}`);
1159
+ const expectedChainId = request.transaction.chainId ? (0, import_ethers.getBigInt)(request.transaction.chainId) : void 0;
1160
+ if (!actualChainId || !expectedChainId || BigInt(actualChainId) !== expectedChainId) {
1161
+ throw new Error(
1162
+ `Signer is not connected to the right chain. Expected ${expectedChainId}, got ${actualChainId}`
982
1163
  );
983
- const originChainTxnId = "originTxs" in receipt ? receipt.originTxs[receipt.originTxs.length - 1].txid : void 0;
984
- return { originChainTxnId: originChainTxnId || "", receipt };
985
1164
  }
986
- async claimCCTPTransfer(input) {
987
- let { receipt, mainSigner, sponsorAccount, onTransactionSigned } = input;
988
- if (!this.wormholeRoute) {
989
- throw new Error("Wormhole route not initialized");
990
- }
991
- if (sponsorAccount && !isAccount(sponsorAccount)) {
992
- throw new Error(
993
- "AptosLocalSigner does not support GasStationApiKey as a sponsor account. Wormhole claim transactions are script-based and cannot be submitted via the gas station. Please provide an Account instance as the sponsor, or omit the sponsor account."
994
- );
1165
+ const provider = new import_ethers.ethers.BrowserProvider(
1166
+ wallet.eip1193Provider
1167
+ );
1168
+ const signer = await provider.getSigner();
1169
+ let response;
1170
+ try {
1171
+ response = await signer.sendTransaction(request.transaction);
1172
+ } catch (e) {
1173
+ const message = e instanceof Error ? e.message : String(e);
1174
+ const hashMatch = message.match(/"hash":\s*"(0x[a-fA-F0-9]{64})"/);
1175
+ if (hashMatch) {
1176
+ console.warn("Extracted EVM tx hash from error:", hashMatch[1]);
1177
+ return hashMatch[1];
995
1178
  }
996
- logger.log("mainSigner", mainSigner.accountAddress.toString());
997
- let retries = 0;
998
- const maxRetries = 5;
999
- const baseDelay = 1e3;
1000
- while (retries < maxRetries) {
1001
- try {
1002
- for await (receipt of this.wormholeRoute.track(receipt, 120 * 1e3)) {
1003
- if (receipt.state >= import_sdk3.TransferState.SourceInitiated) {
1004
- logger.log("Receipt is on track ", receipt);
1005
- try {
1006
- const signer = new AptosLocalSigner(
1007
- "Aptos",
1008
- {},
1009
- mainSigner,
1010
- // the account that signs the "claim" transaction
1011
- sponsorAccount,
1012
- // the fee payer account
1013
- this.crossChainCore,
1014
- onTransactionSigned
1015
- );
1016
- if (import_sdk3.routes.isManual(this.wormholeRoute)) {
1017
- const circleAttestationReceipt = await this.wormholeRoute.complete(signer, receipt);
1018
- logger.log("Claim receipt: ", circleAttestationReceipt);
1019
- const destinationChainTxnId = signer.claimedTransactionHashes();
1020
- return { destinationChainTxnId };
1021
- } else {
1022
- return { destinationChainTxnId: "" };
1023
- }
1024
- } catch (e) {
1025
- console.error("Failed to claim", e);
1026
- return { destinationChainTxnId: "" };
1027
- }
1028
- }
1179
+ throw e;
1180
+ }
1181
+ try {
1182
+ const receipt = await response.wait();
1183
+ return receipt?.hash || response.hash || "";
1184
+ } catch (e) {
1185
+ if (e?.code === "TRANSACTION_REPLACED") {
1186
+ if (e.reason === "repriced") {
1187
+ const replacementHash = e.receipt?.hash || e.replacement?.hash;
1188
+ if (replacementHash) {
1189
+ console.warn(
1190
+ "EVM transaction was repriced. Using replacement hash:",
1191
+ replacementHash
1192
+ );
1193
+ return replacementHash;
1029
1194
  }
1030
- } catch (e) {
1031
- console.error(
1032
- `Error tracking transfer (attempt ${retries + 1} / ${maxRetries}):`,
1033
- e
1034
- );
1035
- const delay = baseDelay * Math.pow(2, retries);
1036
- await (0, import_ts_sdk3.sleep)(delay);
1037
- retries++;
1038
1195
  }
1196
+ throw e;
1039
1197
  }
1040
- return { destinationChainTxnId: "" };
1041
- }
1042
- /**
1043
- * Initiates a transfer of USDC funds from the source chain wallet to the destination chain wallet
1044
- * @param args
1045
- * @returns
1046
- */
1047
- async transfer(input) {
1048
- if (this.crossChainCore._dappConfig?.aptosNetwork === import_ts_sdk3.Network.DEVNET) {
1049
- throw new Error("Devnet is not supported on Wormhole");
1050
- }
1051
- if (input.amount) {
1052
- await this.getQuote({
1053
- amount: input.amount,
1054
- originChain: input.sourceChain,
1055
- type: "transfer"
1056
- });
1057
- }
1058
- let { originChainTxnId, receipt } = await this.submitCCTPTransfer(input);
1059
- try {
1060
- const { destinationChainTxnId } = await this.claimCCTPTransfer({
1061
- receipt,
1062
- mainSigner: input.mainSigner,
1063
- sponsorAccount: input.sponsorAccount,
1064
- onTransactionSigned: input.onTransactionSigned
1065
- });
1066
- return { originChainTxnId, destinationChainTxnId };
1067
- } catch (error) {
1068
- throw new TransferError(
1069
- error?.message ?? "Transfer claim failed after source-chain burn",
1070
- originChainTxnId,
1071
- error
1198
+ if (response.hash) {
1199
+ console.warn(
1200
+ "EVM transaction wait failed but tx was submitted:",
1201
+ response.hash
1072
1202
  );
1203
+ return response.hash;
1073
1204
  }
1205
+ throw e;
1074
1206
  }
1075
- // --- Split withdraw flow: initiateWithdraw + trackWithdraw + claimWithdraw ---
1076
- /**
1077
- * Phase 1: Initiates a withdraw by burning USDC on Aptos.
1078
- * The user signs the Aptos burn transaction via their wallet.
1079
- * Returns a receipt that can be tracked and later claimed.
1080
- */
1081
- async initiateWithdraw(input) {
1082
- const { wallet, destinationAddress, sponsorAccount, onTransactionSigned } = input;
1083
- if (!this._wormholeContext) {
1084
- throw new Error("Wormhole context not initialized");
1207
+ }
1208
+
1209
+ // src/providers/wormhole/signers/SolanaSigner.ts
1210
+ var import_derived_wallet_solana = require("@aptos-labs/derived-wallet-solana");
1211
+ var import_web33 = require("@solana/web3.js");
1212
+ async function signAndSendTransaction4(request, wallet, options, crossChainCore) {
1213
+ if (!wallet || !(wallet instanceof import_derived_wallet_solana.SolanaDerivedWallet)) {
1214
+ throw new Error("Invalid wallet type or missing Solana wallet");
1215
+ }
1216
+ const commitment = options?.commitment ?? crossChainCore?._dappConfig?.solanaConfig?.commitment ?? "finalized";
1217
+ const connection = new import_web33.Connection(
1218
+ crossChainCore?._dappConfig?.solanaConfig?.rpc ?? crossChainCore?.CHAINS.Solana?.defaultRpc ?? "https://api.devnet.solana.com"
1219
+ // Last resort fallback
1220
+ );
1221
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash(commitment);
1222
+ const unsignedTx = await setPriorityFeeInstructions(
1223
+ connection,
1224
+ blockhash,
1225
+ lastValidBlockHeight,
1226
+ request,
1227
+ crossChainCore?._dappConfig?.solanaConfig?.priorityFeeConfig
1228
+ );
1229
+ if (!wallet.solanaWallet.signTransaction) {
1230
+ throw new Error("Wallet does not support signing transactions");
1231
+ }
1232
+ const tx = await wallet.solanaWallet.signTransaction(unsignedTx);
1233
+ if (!tx) throw new Error("Failed to sign transaction");
1234
+ if (request.transaction.signers && tx instanceof import_web33.Transaction) {
1235
+ tx.partialSign(...request.transaction.signers);
1236
+ }
1237
+ const serializedTx = tx.serialize();
1238
+ const signature = await sendAndConfirmTransaction(
1239
+ serializedTx,
1240
+ blockhash,
1241
+ lastValidBlockHeight,
1242
+ {
1243
+ connection,
1244
+ commitment,
1245
+ retryIntervalMs: 5e3,
1246
+ verbose: false
1085
1247
  }
1086
- if (!this.wormholeRoute || !this.wormholeRequest || !this.wormholeQuote) {
1087
- throw new Error("Wormhole route, request, or quote not initialized");
1248
+ );
1249
+ return signature;
1250
+ }
1251
+ async function setPriorityFeeInstructions(connection, blockhash, lastValidBlockHeight, request, priorityFeeConfig) {
1252
+ const unsignedTx = request.transaction.transaction;
1253
+ unsignedTx.recentBlockhash = blockhash;
1254
+ unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
1255
+ await addPriorityFeeInstructions(
1256
+ connection,
1257
+ unsignedTx,
1258
+ priorityFeeConfig,
1259
+ false
1260
+ );
1261
+ return unsignedTx;
1262
+ }
1263
+
1264
+ // src/providers/wormhole/signers/SuiSigner.ts
1265
+ async function signAndSendTransaction5(request, wallet) {
1266
+ if (!wallet) {
1267
+ throw new Error("wallet is undefined");
1268
+ }
1269
+ const suiDerivedWallet = wallet;
1270
+ const signAndExecuteTransactionFeature = suiDerivedWallet.suiWallet.features["sui:signAndExecuteTransaction"];
1271
+ if (!signAndExecuteTransactionFeature) {
1272
+ throw new Error("wallet does not support signAndExecuteTransaction");
1273
+ }
1274
+ const { digest } = await signAndExecuteTransactionFeature.signAndExecuteTransaction({
1275
+ transaction: request.transaction,
1276
+ account: suiDerivedWallet.suiWallet.accounts[0],
1277
+ chain: `sui:${request.network.toLocaleLowerCase()}`
1278
+ });
1279
+ return digest;
1280
+ }
1281
+
1282
+ // src/providers/wormhole/signers/Signer.ts
1283
+ var Signer = class {
1284
+ _chain;
1285
+ _address;
1286
+ _options;
1287
+ _wallet;
1288
+ _crossChainCore;
1289
+ _sponsorAccount;
1290
+ _onTransactionSigned;
1291
+ _claimedTransactionHashes = [];
1292
+ /**
1293
+ * When true, signed tx hashes are written to
1294
+ * `_crossChainCore._lastSourceChainTxId` as a recovery side-channel.
1295
+ * Set to false for destination-chain claim signers so they don't
1296
+ * overwrite the source-chain burn hash.
1297
+ */
1298
+ _trackAsSourceChain;
1299
+ constructor(chain, address, options, wallet, crossChainCore, sponsorAccount, onTransactionSigned, trackAsSourceChain = true) {
1300
+ this._chain = chain;
1301
+ this._address = address;
1302
+ this._options = options;
1303
+ this._wallet = wallet;
1304
+ this._crossChainCore = crossChainCore;
1305
+ this._sponsorAccount = sponsorAccount;
1306
+ this._onTransactionSigned = onTransactionSigned;
1307
+ this._trackAsSourceChain = trackAsSourceChain;
1308
+ }
1309
+ chain() {
1310
+ return this._chain.key;
1311
+ }
1312
+ address() {
1313
+ return this._address;
1314
+ }
1315
+ claimedTransactionHashes() {
1316
+ return this._claimedTransactionHashes.join(",");
1317
+ }
1318
+ async signAndSend(txs) {
1319
+ const txHashes = [];
1320
+ this._claimedTransactionHashes = [];
1321
+ for (const tx of txs) {
1322
+ this._onTransactionSigned?.(tx.description, null);
1323
+ const txId = await signAndSendTransaction6(
1324
+ this._chain,
1325
+ tx,
1326
+ this._wallet,
1327
+ this._options,
1328
+ this._crossChainCore,
1329
+ this._sponsorAccount
1330
+ );
1331
+ if (this._trackAsSourceChain) {
1332
+ this._crossChainCore._lastSourceChainTxId = txId;
1333
+ }
1334
+ this._onTransactionSigned?.(tx.description, txId);
1335
+ txHashes.push(txId);
1336
+ this._claimedTransactionHashes.push(txId);
1088
1337
  }
1089
- const signer = new Signer(
1090
- this.getChainConfig("Aptos"),
1091
- (await wallet.features["aptos:account"].account()).address.toString(),
1092
- {},
1338
+ return txHashes;
1339
+ }
1340
+ };
1341
+ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, crossChainCore, sponsorAccount) => {
1342
+ if (!wallet) {
1343
+ throw new Error("wallet is undefined");
1344
+ }
1345
+ const dappNetwork = crossChainCore._dappConfig.aptosNetwork;
1346
+ if (chain.context === "Solana") {
1347
+ const signature = await signAndSendTransaction4(
1348
+ request,
1093
1349
  wallet,
1094
- this.crossChainCore,
1095
- sponsorAccount,
1096
- onTransactionSigned
1350
+ options,
1351
+ crossChainCore
1097
1352
  );
1098
- const wormholeDestAddress = import_sdk3.Wormhole.chainAddress(
1099
- this.destinationChain,
1100
- destinationAddress.toString()
1353
+ return signature;
1354
+ } else if (chain.context === "Ethereum") {
1355
+ const tx = await signAndSendTransaction3(
1356
+ request,
1357
+ wallet,
1358
+ chain.displayName
1101
1359
  );
1102
- const receipt = await this.wormholeRoute.initiate(
1103
- this.wormholeRequest,
1104
- signer,
1105
- this.wormholeQuote,
1106
- wormholeDestAddress
1360
+ return tx;
1361
+ } else if (chain.context === "Sui") {
1362
+ const tx = await signAndSendTransaction5(
1363
+ request,
1364
+ wallet
1107
1365
  );
1108
- logger.log("initiateWithdraw receipt", receipt);
1109
- const originChainTxnId = "originTxs" in receipt ? receipt.originTxs[receipt.originTxs.length - 1].txid : void 0;
1110
- return { originChainTxnId: originChainTxnId || "", receipt };
1366
+ return tx;
1367
+ } else if (chain.context === "Aptos") {
1368
+ const tx = await signAndSendTransaction2(
1369
+ request,
1370
+ wallet,
1371
+ sponsorAccount,
1372
+ dappNetwork,
1373
+ crossChainCore
1374
+ );
1375
+ return tx;
1376
+ } else {
1377
+ throw new Error(`Unsupported chain: ${chain}`);
1111
1378
  }
1112
- /**
1113
- * Phase 2: Tracks a withdraw receipt until attestation is ready.
1114
- * This polls Wormhole and returns once the receipt reaches the Attested state.
1115
- */
1116
- async trackWithdraw(receipt) {
1117
- if (!this.wormholeRoute) {
1118
- throw new Error("Wormhole route not initialized");
1379
+ };
1380
+
1381
+ // src/providers/wormhole/wormhole.ts
1382
+ var WormholeProvider = class {
1383
+ crossChainCore;
1384
+ _wormholeContext;
1385
+ wormholeRoute;
1386
+ wormholeRequest;
1387
+ wormholeQuote;
1388
+ destinationChain;
1389
+ constructor(core) {
1390
+ this.crossChainCore = core;
1391
+ }
1392
+ get wormholeContext() {
1393
+ return this._wormholeContext;
1394
+ }
1395
+ async setWormholeContext(sourceChain) {
1396
+ const dappNetwork = this.crossChainCore._dappConfig?.aptosNetwork;
1397
+ if (dappNetwork === import_ts_sdk3.Network.DEVNET) {
1398
+ throw new Error("Devnet is not supported on Wormhole");
1119
1399
  }
1120
- let retries = 0;
1121
- const maxRetries = 5;
1122
- const baseDelay = 1e3;
1123
- while (retries < maxRetries) {
1124
- try {
1125
- for await (receipt of this.wormholeRoute.track(receipt, 120 * 1e3)) {
1126
- if (receipt.state >= import_sdk3.TransferState.Attested) {
1127
- logger.log("trackWithdraw: receipt attested", receipt);
1128
- return receipt;
1129
- }
1130
- }
1131
- } catch (e) {
1132
- console.error(
1133
- `Error tracking withdraw (attempt ${retries + 1} / ${maxRetries}):`,
1134
- e
1135
- );
1136
- const delay = baseDelay * Math.pow(2, retries);
1137
- await (0, import_ts_sdk3.sleep)(delay);
1138
- retries++;
1139
- }
1400
+ if (!sourceChain) {
1401
+ throw new Error("Origin chain not selected");
1140
1402
  }
1141
- throw new Error("Failed to track withdraw to attested state");
1142
- }
1143
- /**
1144
- * Phase 3: Claims the withdraw on the destination chain.
1145
- *
1146
- * If the destination is Solana and `solanaConfig.serverClaimUrl` is configured
1147
- * in the dapp config, the SDK automatically POSTs the attested receipt to that
1148
- * URL no wallet popup required. The dapp's server endpoint handles signing
1149
- * and submitting the claim transaction.
1150
- *
1151
- * Otherwise falls back to the wallet-based Signer (triggers wallet popup).
1152
- */
1153
- async claimWithdraw(input) {
1154
- const { claimChain, destinationAddress, receipt } = input;
1155
- const serverClaimUrl = this.crossChainCore._dappConfig?.solanaConfig?.serverClaimUrl;
1156
- if (claimChain === "Solana" && serverClaimUrl) {
1157
- logger.log("claimWithdraw: using server-side claim via", serverClaimUrl);
1158
- const response = await fetch(serverClaimUrl, {
1159
- method: "POST",
1160
- headers: { "Content-Type": "application/json" },
1161
- body: JSON.stringify({
1162
- receipt: serializeReceipt(receipt),
1163
- destinationAddress,
1164
- claimChain
1165
- })
1166
- });
1167
- if (!response.ok) {
1168
- const errorData = await response.json().catch(() => ({}));
1169
- throw new Error(
1170
- errorData.error || `Server-side claim failed with status ${response.status}`
1171
- );
1403
+ const isMainnet = dappNetwork === import_ts_sdk3.Network.MAINNET;
1404
+ const platforms = [import_aptos.default, import_solana.default, import_evm.default, import_sui.default];
1405
+ const dappConfig = this.crossChainCore._dappConfig;
1406
+ const chains = this.crossChainCore.CHAINS;
1407
+ const solanaRpc = dappConfig?.solanaConfig?.rpc ?? chains.Solana?.defaultRpc;
1408
+ const suiRpc = dappConfig?.suiConfig?.rpc ?? chains.Sui?.defaultRpc;
1409
+ const evmChainsConfig = {};
1410
+ for (const name of EVM_CHAIN_NAMES) {
1411
+ const rpc = dappConfig?.evmConfig?.[name]?.rpc ?? chains[name]?.defaultRpc;
1412
+ if (rpc) {
1413
+ evmChainsConfig[name] = { rpc };
1172
1414
  }
1173
- const result = await response.json();
1174
- return { destinationChainTxnId: result.destinationChainTxnId };
1175
1415
  }
1176
- if (!this.wormholeRoute) {
1177
- throw new Error("Wormhole route not initialized");
1416
+ const wh = await (0, import_sdk3.wormhole)(isMainnet ? "Mainnet" : "Testnet", platforms, {
1417
+ chains: {
1418
+ ...solanaRpc ? { Solana: { rpc: solanaRpc } } : {},
1419
+ ...suiRpc ? { Sui: { rpc: suiRpc } } : {},
1420
+ ...evmChainsConfig
1421
+ }
1422
+ });
1423
+ this._wormholeContext = wh;
1424
+ }
1425
+ async getRoute(sourceChain, destinationChain) {
1426
+ if (!this._wormholeContext) {
1427
+ throw new Error("Wormhole context not initialized");
1178
1428
  }
1179
- if (!input.wallet) {
1180
- throw new Error(
1181
- "Wallet is required for claim when serverClaimUrl is not configured"
1182
- );
1429
+ const { route: cctpRoute, request } = await createCCTPRoute(
1430
+ this._wormholeContext,
1431
+ sourceChain,
1432
+ destinationChain,
1433
+ this.crossChainCore.TOKENS
1434
+ );
1435
+ this.wormholeRoute = cctpRoute;
1436
+ this.wormholeRequest = request;
1437
+ this.destinationChain = destinationChain;
1438
+ return { route: cctpRoute, request };
1439
+ }
1440
+ async getQuote(input) {
1441
+ const { amount, originChain, type } = input;
1442
+ if (!this._wormholeContext) {
1443
+ await this.setWormholeContext(originChain);
1183
1444
  }
1184
- const claimSigner = new Signer(
1185
- this.getChainConfig(claimChain),
1186
- destinationAddress,
1445
+ logger.log("type", type);
1446
+ const sourceChain = type === "transfer" ? originChain : "Aptos";
1447
+ const destinationChain = type === "transfer" ? "Aptos" : originChain;
1448
+ const { route, request } = await this.getRoute(
1449
+ sourceChain,
1450
+ destinationChain
1451
+ );
1452
+ const transferParams = {
1453
+ amount,
1454
+ options: { nativeGas: 0 }
1455
+ };
1456
+ const validated = await route.validate(request, transferParams);
1457
+ if (!validated.valid) {
1458
+ logger.log("invalid", validated.valid);
1459
+ throw new Error(`Invalid quote: ${validated.error}`);
1460
+ }
1461
+ const quote = await route.quote(request, validated.params);
1462
+ if (!quote.success) {
1463
+ logger.log("quote failed", quote.success);
1464
+ throw new Error(`Invalid quote: ${quote.error}`);
1465
+ }
1466
+ this.wormholeQuote = quote;
1467
+ logger.log("quote", quote);
1468
+ return quote;
1469
+ }
1470
+ async submitCCTPTransfer(input) {
1471
+ const { sourceChain, wallet, destinationAddress, onTransactionSigned } = input;
1472
+ if (!this._wormholeContext) {
1473
+ await this.setWormholeContext(sourceChain);
1474
+ }
1475
+ if (!this.wormholeRoute || !this.wormholeRequest || !this.wormholeQuote) {
1476
+ throw new Error("Wormhole route, request, or quote not initialized");
1477
+ }
1478
+ let signerAddress;
1479
+ const chainContext = this.getChainConfig(sourceChain).context;
1480
+ if (chainContext === "Solana") {
1481
+ signerAddress = wallet.solanaWallet.publicKey?.toBase58() || "";
1482
+ } else if (chainContext === "Ethereum") {
1483
+ [signerAddress] = await wallet.eip1193Provider.request({
1484
+ method: "eth_requestAccounts"
1485
+ });
1486
+ } else if (chainContext === "Sui") {
1487
+ signerAddress = wallet.suiWallet.accounts[0].address || "";
1488
+ } else {
1489
+ throw new Error(`Unsupported chain context: ${chainContext}`);
1490
+ }
1491
+ logger.log("signerAddress", signerAddress);
1492
+ const signer = new Signer(
1493
+ this.getChainConfig(sourceChain),
1494
+ signerAddress,
1187
1495
  {},
1188
- input.wallet,
1496
+ wallet,
1189
1497
  this.crossChainCore,
1190
1498
  void 0,
1191
- input.onTransactionSigned,
1192
- false
1499
+ onTransactionSigned
1193
1500
  );
1194
- if (import_sdk3.routes.isManual(this.wormholeRoute)) {
1195
- const circleAttestationReceipt = await this.wormholeRoute.complete(
1196
- claimSigner,
1197
- receipt
1501
+ logger.log("signer", signer);
1502
+ logger.log("wormholeRequest", this.wormholeRequest);
1503
+ logger.log("wormholeQuote", this.wormholeQuote);
1504
+ const receipt = await this.wormholeRoute.initiate(
1505
+ this.wormholeRequest,
1506
+ signer,
1507
+ this.wormholeQuote,
1508
+ import_sdk3.Wormhole.chainAddress("Aptos", destinationAddress.toString())
1509
+ );
1510
+ const originChainTxnId = "originTxs" in receipt ? receipt.originTxs[receipt.originTxs.length - 1].txid : void 0;
1511
+ return { originChainTxnId: originChainTxnId || "", receipt };
1512
+ }
1513
+ async claimCCTPTransfer(input) {
1514
+ let { receipt, mainSigner, sponsorAccount, onTransactionSigned } = input;
1515
+ if (!this.wormholeRoute) {
1516
+ throw new Error("Wormhole route not initialized");
1517
+ }
1518
+ if (sponsorAccount && !isAccount(sponsorAccount)) {
1519
+ throw new Error(
1520
+ "AptosLocalSigner does not support GasStationApiKey as a sponsor account. Wormhole claim transactions are script-based and cannot be submitted via the gas station. Please provide an Account instance as the sponsor, or omit the sponsor account."
1198
1521
  );
1199
- logger.log("claimWithdraw receipt:", circleAttestationReceipt);
1200
- const destinationChainTxnId = claimSigner.claimedTransactionHashes();
1201
- return { destinationChainTxnId };
1202
- } else {
1203
- throw new Error("Automatic route not supported for manual claim");
1204
1522
  }
1523
+ logger.log("mainSigner", mainSigner.accountAddress.toString());
1524
+ let retries = 0;
1525
+ const maxRetries = 5;
1526
+ const baseDelay = 1e3;
1527
+ while (retries < maxRetries) {
1528
+ try {
1529
+ for await (receipt of this.wormholeRoute.track(receipt, 120 * 1e3)) {
1530
+ if (receipt.state >= import_sdk3.TransferState.SourceInitiated) {
1531
+ logger.log("Receipt is on track ", receipt);
1532
+ try {
1533
+ const signer = new AptosLocalSigner(
1534
+ "Aptos",
1535
+ {},
1536
+ mainSigner,
1537
+ // the account that signs the "claim" transaction
1538
+ sponsorAccount,
1539
+ // the fee payer account
1540
+ this.crossChainCore,
1541
+ onTransactionSigned
1542
+ );
1543
+ if (import_sdk3.routes.isManual(this.wormholeRoute)) {
1544
+ const circleAttestationReceipt = await this.wormholeRoute.complete(signer, receipt);
1545
+ logger.log("Claim receipt: ", circleAttestationReceipt);
1546
+ const destinationChainTxnId = signer.claimedTransactionHashes();
1547
+ return { destinationChainTxnId };
1548
+ } else {
1549
+ return { destinationChainTxnId: "" };
1550
+ }
1551
+ } catch (e) {
1552
+ console.error("Failed to claim", e);
1553
+ return { destinationChainTxnId: "" };
1554
+ }
1555
+ }
1556
+ }
1557
+ } catch (e) {
1558
+ console.error(
1559
+ `Error tracking transfer (attempt ${retries + 1} / ${maxRetries}):`,
1560
+ e
1561
+ );
1562
+ const delay = baseDelay * 2 ** retries;
1563
+ await (0, import_ts_sdk3.sleep)(delay);
1564
+ retries++;
1565
+ }
1566
+ }
1567
+ return { destinationChainTxnId: "" };
1205
1568
  }
1206
1569
  /**
1207
- * Withdraws USDC from Aptos to a destination chain.
1208
- * Orchestrates all three phases internally:
1209
- * 1. Initiate — user signs the Aptos burn transaction
1210
- * 2. Track — wait for Wormhole attestation
1211
- * 3. Claim — if serverClaimUrl is configured for Solana, delegates to
1212
- * the server; otherwise uses the wallet-based signer.
1213
- *
1214
- * The optional `onPhaseChange` callback lets the dapp update its UI
1215
- * as the flow progresses.
1570
+ * Initiates a transfer of USDC funds from the source chain wallet to the destination chain wallet
1571
+ * @param args
1572
+ * @returns
1216
1573
  */
1217
- async withdraw(input) {
1218
- const {
1219
- sourceChain,
1220
- wallet,
1221
- destinationAddress,
1222
- sponsorAccount,
1223
- onPhaseChange,
1224
- onTransactionSigned
1225
- } = input;
1226
- onPhaseChange?.("initiating");
1227
- const { originChainTxnId, receipt } = await this.initiateWithdraw({
1228
- wallet,
1229
- destinationAddress,
1230
- sponsorAccount,
1231
- onTransactionSigned
1232
- });
1233
- let currentPhase = "tracking";
1574
+ async transfer(input) {
1575
+ if (this.crossChainCore._dappConfig?.aptosNetwork === import_ts_sdk3.Network.DEVNET) {
1576
+ throw new Error("Devnet is not supported on Wormhole");
1577
+ }
1578
+ if (input.amount) {
1579
+ await this.getQuote({
1580
+ amount: input.amount,
1581
+ originChain: input.sourceChain,
1582
+ type: "transfer"
1583
+ });
1584
+ }
1585
+ const { originChainTxnId, receipt } = await this.submitCCTPTransfer(input);
1234
1586
  try {
1235
- onPhaseChange?.("tracking");
1236
- const attestedReceipt = await this.trackWithdraw(receipt);
1237
- currentPhase = "claiming";
1238
- onPhaseChange?.("claiming");
1239
- const { destinationChainTxnId } = await this.claimWithdraw({
1240
- claimChain: sourceChain,
1241
- destinationAddress: destinationAddress.toString(),
1242
- receipt: attestedReceipt,
1243
- wallet,
1244
- onTransactionSigned
1587
+ const { destinationChainTxnId } = await this.claimCCTPTransfer({
1588
+ receipt,
1589
+ mainSigner: input.mainSigner,
1590
+ sponsorAccount: input.sponsorAccount,
1591
+ onTransactionSigned: input.onTransactionSigned
1245
1592
  });
1246
1593
  return { originChainTxnId, destinationChainTxnId };
1247
1594
  } catch (error) {
1248
- throw new WithdrawError(
1249
- error?.message ?? "Withdraw failed after Aptos burn",
1595
+ throw new TransferError(
1596
+ error?.message ?? "Transfer claim failed after source-chain burn",
1250
1597
  originChainTxnId,
1251
- currentPhase,
1252
1598
  error
1253
1599
  );
1254
1600
  }
1255
1601
  }
1602
+ // --- Split withdraw flow: initiateWithdraw + trackWithdraw + claimWithdraw ---
1256
1603
  /**
1257
- * Retries a failed `claimWithdraw` call with configurable exponential backoff.
1258
- *
1259
- * Use this when the claim phase of a withdrawal fails (e.g., RPC instability,
1260
- * network congestion) but the Aptos burn transaction has already been submitted.
1261
- * The attested receipt can be recovered from the `WithdrawError` thrown by
1262
- * `withdraw()` and passed directly to this method.
1263
- *
1264
- * @example
1265
- * ```ts
1266
- * try {
1267
- * await provider.withdraw({ ... });
1268
- * } catch (error) {
1269
- * if (error instanceof WithdrawError && error.phase === "claiming") {
1270
- * const result = await provider.retryWithdrawClaim({
1271
- * sourceChain,
1272
- * destinationAddress,
1273
- * receipt: attestedReceipt,
1274
- * wallet,
1275
- * maxRetries: 5,
1276
- * });
1277
- * }
1278
- * }
1279
- * ```
1604
+ * Phase 1: Initiates a withdraw by burning USDC on Aptos.
1605
+ * The user signs the Aptos burn transaction via their wallet.
1606
+ * Returns a receipt that can be tracked and later claimed.
1280
1607
  */
1281
- async retryWithdrawClaim(input) {
1282
- const {
1283
- maxRetries = 5,
1284
- initialDelayMs = 2e3,
1285
- backoffMultiplier = 2,
1286
- ...claimInput
1287
- } = input;
1288
- let lastError;
1289
- let delay = initialDelayMs;
1290
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
1291
- try {
1292
- const result = await this.claimWithdraw(claimInput);
1293
- return { ...result, retriesUsed: attempt };
1294
- } catch (error) {
1295
- lastError = error;
1296
- logger.log(
1297
- `retryWithdrawClaim: attempt ${attempt + 1}/${maxRetries + 1} failed: ${lastError.message}`
1298
- );
1299
- if (attempt < maxRetries) {
1300
- await (0, import_ts_sdk3.sleep)(delay);
1301
- delay *= backoffMultiplier;
1302
- }
1303
- }
1608
+ async initiateWithdraw(input) {
1609
+ const { wallet, destinationAddress, sponsorAccount, onTransactionSigned } = input;
1610
+ if (!this._wormholeContext) {
1611
+ throw new Error("Wormhole context not initialized");
1304
1612
  }
1305
- throw new Error(
1306
- `Claim failed after ${maxRetries + 1} attempts: ${lastError?.message}`
1307
- );
1308
- }
1309
- getChainConfig(chain) {
1310
- const chainConfig = this.crossChainCore.CHAINS[chain];
1311
- if (!chainConfig) {
1312
- throw new Error(`Chain config not found for chain: ${chain}`);
1613
+ if (!this.wormholeRoute || !this.wormholeRequest || !this.wormholeQuote) {
1614
+ throw new Error("Wormhole route, request, or quote not initialized");
1313
1615
  }
1314
- return chainConfig;
1315
- }
1316
- };
1317
-
1318
- // src/providers/wormhole/signers/SolanaLocalSigner.ts
1319
- var import_web34 = require("@solana/web3.js");
1320
- var SolanaLocalSigner = class {
1321
- constructor(config) {
1322
- this._claimedTransactionHashes = [];
1323
- this.keypair = config.keypair;
1324
- this.connection = config.connection;
1325
- this.commitment = config.commitment ?? "finalized";
1326
- this.retryIntervalMs = config.retryIntervalMs ?? 5e3;
1327
- this.priorityFeeConfig = config.priorityFeeConfig;
1328
- this.verbose = config.verbose ?? false;
1329
- this._onTransactionSigned = config.onTransactionSigned;
1330
- }
1331
- chain() {
1332
- return "Solana";
1333
- }
1334
- address() {
1335
- return this.keypair.publicKey.toBase58();
1616
+ const signer = new Signer(
1617
+ this.getChainConfig("Aptos"),
1618
+ (await wallet.features["aptos:account"].account()).address.toString(),
1619
+ {},
1620
+ wallet,
1621
+ this.crossChainCore,
1622
+ sponsorAccount,
1623
+ onTransactionSigned
1624
+ );
1625
+ const wormholeDestAddress = import_sdk3.Wormhole.chainAddress(
1626
+ this.destinationChain,
1627
+ destinationAddress.toString()
1628
+ );
1629
+ const receipt = await this.wormholeRoute.initiate(
1630
+ this.wormholeRequest,
1631
+ signer,
1632
+ this.wormholeQuote,
1633
+ wormholeDestAddress
1634
+ );
1635
+ logger.log("initiateWithdraw receipt", receipt);
1636
+ const originChainTxnId = "originTxs" in receipt ? receipt.originTxs[receipt.originTxs.length - 1].txid : void 0;
1637
+ return { originChainTxnId: originChainTxnId || "", receipt };
1336
1638
  }
1337
1639
  /**
1338
- * Returns all transaction hashes from the most recent signAndSend call,
1339
- * joined by comma. If only one transaction was signed, returns a single hash string.
1640
+ * Phase 2: Tracks a withdraw receipt until attestation is ready.
1641
+ * This polls Wormhole and returns once the receipt reaches the Attested state.
1340
1642
  */
1341
- claimedTransactionHashes() {
1342
- return this._claimedTransactionHashes.join(",");
1343
- }
1344
- async signAndSend(txs) {
1345
- const txHashes = [];
1346
- this._claimedTransactionHashes = [];
1347
- for (const tx of txs) {
1348
- this._onTransactionSigned?.(tx.description, null);
1349
- const txId = await this.signAndSendTransaction(tx);
1350
- this._onTransactionSigned?.(tx.description, txId);
1351
- txHashes.push(txId);
1352
- this._claimedTransactionHashes.push(txId);
1353
- }
1354
- return txHashes;
1355
- }
1356
- async signAndSendTransaction(request) {
1357
- const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash(this.commitment);
1358
- let unsignedTx = request.transaction ?? request;
1359
- const additionalSigners = request.transaction?.signers;
1360
- const MAX_UNWRAP_DEPTH = 10;
1361
- let unwrapDepth = 0;
1362
- while (unsignedTx && typeof unsignedTx === "object" && "transaction" in unsignedTx && !(unsignedTx instanceof import_web34.Transaction) && !("signatures" in unsignedTx && "message" in unsignedTx)) {
1363
- if (++unwrapDepth > MAX_UNWRAP_DEPTH) {
1364
- throw new Error(
1365
- "Transaction unwrapping exceeded maximum depth \u2014 possible circular nesting"
1366
- );
1367
- }
1368
- unsignedTx = unsignedTx.transaction;
1369
- }
1370
- const isVersioned = unsignedTx.message !== void 0 && unsignedTx.signatures !== void 0 && typeof unsignedTx.message.recentBlockhash !== "undefined";
1371
- if (isVersioned) {
1372
- unsignedTx.message.recentBlockhash = blockhash;
1373
- if (this.verbose || this.priorityFeeConfig) {
1374
- console.warn(
1375
- "SolanaLocalSigner: Versioned transaction detected \u2014 priority fees are not applied. Consider using legacy transactions if priority fees are required."
1376
- );
1377
- }
1378
- unsignedTx.sign([this.keypair]);
1379
- if (additionalSigners && additionalSigners.length > 0) {
1380
- unsignedTx.sign(additionalSigners);
1381
- }
1382
- } else if (unsignedTx instanceof import_web34.Transaction) {
1383
- unsignedTx.recentBlockhash = blockhash;
1384
- unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
1385
- if (this.priorityFeeConfig) {
1386
- await addPriorityFeeInstructions(
1387
- this.connection,
1388
- unsignedTx,
1389
- this.priorityFeeConfig,
1390
- this.verbose
1391
- );
1392
- }
1393
- if (additionalSigners && additionalSigners.length > 0) {
1394
- unsignedTx.sign(this.keypair, ...additionalSigners);
1395
- } else {
1396
- unsignedTx.sign(this.keypair);
1397
- }
1398
- } else if (unsignedTx.recentBlockhash !== void 0 || unsignedTx.feePayer !== void 0) {
1399
- unsignedTx.recentBlockhash = blockhash;
1400
- unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
1401
- if (this.priorityFeeConfig) {
1402
- await addPriorityFeeInstructions(
1403
- this.connection,
1404
- unsignedTx,
1405
- this.priorityFeeConfig,
1406
- this.verbose
1407
- );
1408
- }
1409
- if (additionalSigners && additionalSigners.length > 0) {
1410
- unsignedTx.sign(this.keypair, ...additionalSigners);
1411
- } else {
1412
- unsignedTx.sign(this.keypair);
1413
- }
1414
- } else {
1415
- throw new Error(
1416
- `Unsupported transaction type: ${unsignedTx?.constructor?.name}`
1417
- );
1418
- }
1419
- const serializedTx = unsignedTx.serialize();
1420
- const signature = await sendAndConfirmTransaction(
1421
- serializedTx,
1422
- blockhash,
1423
- lastValidBlockHeight,
1424
- {
1425
- connection: this.connection,
1426
- commitment: this.commitment,
1427
- retryIntervalMs: this.retryIntervalMs,
1428
- verbose: this.verbose
1429
- }
1430
- );
1431
- return signature;
1432
- }
1433
- };
1434
-
1435
- // src/config/types.ts
1436
- var Context = /* @__PURE__ */ ((Context2) => {
1437
- Context2["ETH"] = "Ethereum";
1438
- Context2["SOLANA"] = "Solana";
1439
- Context2["APTOS"] = "Aptos";
1440
- Context2["SUI"] = "Sui";
1441
- return Context2;
1442
- })(Context || {});
1443
-
1444
- // src/config/testnet/chains.ts
1445
- var testnetChains = {
1446
- Sepolia: {
1447
- key: "Sepolia",
1448
- context: "Ethereum" /* ETH */,
1449
- chainId: 11155111,
1450
- displayName: "Sepolia",
1451
- explorerUrl: "https://sepolia.etherscan.io/",
1452
- explorerName: "Etherscan",
1453
- icon: "Ethereum",
1454
- symbol: "ETH",
1455
- defaultRpc: "https://ethereum-sepolia-rpc.publicnode.com"
1456
- },
1457
- BaseSepolia: {
1458
- key: "BaseSepolia",
1459
- context: "Ethereum" /* ETH */,
1460
- chainId: 84532,
1461
- displayName: "Base Sepolia",
1462
- explorerUrl: "https://sepolia.basescan.org",
1463
- explorerName: "Basescan",
1464
- icon: "BaseSepolia",
1465
- symbol: "BASE",
1466
- defaultRpc: "https://chain-proxy.wallet.coinbase.com?targetName=base-sepolia"
1467
- },
1468
- ArbitrumSepolia: {
1469
- key: "ArbitrumSepolia",
1470
- context: "Ethereum" /* ETH */,
1471
- chainId: 421614,
1472
- displayName: "Arbitrum Sepolia",
1473
- explorerUrl: "https://sepolia.arbiscan.io",
1474
- explorerName: "Etherscan",
1475
- icon: "Arbitrum",
1476
- symbol: "ARB",
1477
- defaultRpc: "https://sepolia-rollup.arbitrum.io/rpc"
1478
- },
1479
- Avalanche: {
1480
- key: "Avalanche",
1481
- context: "Ethereum" /* ETH */,
1482
- chainId: 43113,
1483
- displayName: "Avalanche Fuji",
1484
- explorerUrl: "https://testnet.snowtrace.io",
1485
- explorerName: "Avascan",
1486
- icon: "Avalanche",
1487
- symbol: "AVAX",
1488
- defaultRpc: "https://api.avax-test.network/ext/bc/C/rpc"
1489
- },
1490
- PolygonSepolia: {
1491
- key: "PolygonSepolia",
1492
- context: "Ethereum" /* ETH */,
1493
- chainId: 80002,
1494
- displayName: "Polygon",
1495
- explorerUrl: "https://amoy.polygonscan.com/",
1496
- explorerName: "PolygonScan",
1497
- icon: "Polygon",
1498
- symbol: "MATIC",
1499
- defaultRpc: "https://rpc-amoy.polygon.technology/"
1500
- },
1501
- Solana: {
1502
- key: "Solana",
1503
- context: "Solana" /* SOLANA */,
1504
- displayName: "Solana",
1505
- explorerUrl: "https://solscan.io",
1506
- explorerName: "Solscan",
1507
- chainId: 0,
1508
- icon: "Solana",
1509
- symbol: "SOL",
1510
- defaultRpc: "https://api.devnet.solana.com"
1511
- },
1512
- Aptos: {
1513
- key: "Aptos",
1514
- context: "Aptos" /* APTOS */,
1515
- displayName: "Aptos",
1516
- explorerUrl: "https://explorer.aptoslabs.com?network=testnet",
1517
- explorerName: "Aptos Explorer",
1518
- chainId: 0,
1519
- icon: "Aptos",
1520
- symbol: "APT",
1521
- defaultRpc: "https://fullnode.testnet.aptos.dev"
1522
- },
1523
- Sui: {
1524
- key: "Sui",
1525
- context: "Sui" /* SUI */,
1526
- displayName: "Sui",
1527
- explorerUrl: "https://suiscan.xyz/testnet",
1528
- explorerName: "Suiscan",
1529
- chainId: 0,
1530
- icon: "Sui",
1531
- symbol: "SUI",
1532
- defaultRpc: "https://fullnode.testnet.sui.io:443"
1533
- }
1534
- };
1535
-
1536
- // src/config/testnet/tokens.ts
1537
- var testnetTokens = {
1538
- Sepolia: {
1539
- symbol: "USDC",
1540
- icon: "USDC",
1541
- decimals: 6,
1542
- tokenId: {
1543
- chain: "Sepolia",
1544
- address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"
1545
- }
1546
- },
1547
- Solana: {
1548
- symbol: "USDC",
1549
- tokenId: {
1550
- chain: "Solana",
1551
- address: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"
1552
- },
1553
- icon: "USDC",
1554
- decimals: 6
1555
- },
1556
- Aptos: {
1557
- symbol: "USDC",
1558
- decimals: 6,
1559
- tokenId: {
1560
- chain: "Aptos",
1561
- address: "0x69091fbab5f7d635ee7ac5098cf0c1efbe31d68fec0f2cd565e8d168daf52832"
1562
- },
1563
- icon: "USDC"
1564
- },
1565
- BaseSepolia: {
1566
- symbol: "USDC",
1567
- icon: "USDC",
1568
- decimals: 6,
1569
- tokenId: {
1570
- chain: "BaseSepolia",
1571
- address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
1572
- }
1573
- },
1574
- Avalanche: {
1575
- symbol: "USDC",
1576
- icon: "USDC",
1577
- decimals: 6,
1578
- tokenId: {
1579
- chain: "Avalanche",
1580
- address: "0x5425890298aed601595a70AB815c96711a31Bc65"
1581
- }
1582
- },
1583
- ArbitrumSepolia: {
1584
- symbol: "USDC",
1585
- icon: "USDC",
1586
- decimals: 6,
1587
- tokenId: {
1588
- chain: "ArbitrumSepolia",
1589
- address: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d"
1590
- }
1591
- },
1592
- PolygonSepolia: {
1593
- symbol: "USDC",
1594
- icon: "USDC",
1595
- decimals: 6,
1596
- tokenId: {
1597
- chain: "PolygonSepolia",
1598
- address: "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582"
1643
+ async trackWithdraw(receipt) {
1644
+ if (!this.wormholeRoute) {
1645
+ throw new Error("Wormhole route not initialized");
1599
1646
  }
1600
- },
1601
- Sui: {
1602
- symbol: "USDC",
1603
- tokenId: {
1604
- chain: "Sui",
1605
- address: "0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC"
1606
- },
1607
- icon: "USDC",
1608
- decimals: 6
1609
- }
1610
- };
1611
-
1612
- // src/config/mainnet/chains.ts
1613
- var mainnetChains = {
1614
- Ethereum: {
1615
- key: "Ethereum",
1616
- context: "Ethereum" /* ETH */,
1617
- displayName: "Ethereum",
1618
- explorerUrl: "https://etherscan.io/",
1619
- explorerName: "Etherscan",
1620
- chainId: 1,
1621
- icon: "Ethereum",
1622
- symbol: "ETH",
1623
- defaultRpc: "https://rpc.ankr.com/eth"
1624
- },
1625
- Solana: {
1626
- key: "Solana",
1627
- context: "Solana" /* SOLANA */,
1628
- displayName: "Solana",
1629
- explorerUrl: "https://solscan.io",
1630
- explorerName: "Solscan",
1631
- chainId: 0,
1632
- icon: "Solana",
1633
- symbol: "SOL",
1634
- defaultRpc: "https://solana-rpc.publicnode.com"
1635
- },
1636
- Aptos: {
1637
- key: "Aptos",
1638
- context: "Aptos" /* APTOS */,
1639
- displayName: "Aptos",
1640
- explorerUrl: "https://explorer.aptoslabs.com/",
1641
- explorerName: "Aptos Explorer",
1642
- chainId: 0,
1643
- icon: "Aptos",
1644
- symbol: "APT",
1645
- defaultRpc: "https://fullnode.mainnet.aptos.dev"
1646
- },
1647
- Avalanche: {
1648
- key: "Avalanche",
1649
- context: "Ethereum" /* ETH */,
1650
- chainId: 43114,
1651
- displayName: "Avalanche",
1652
- explorerUrl: "https://snowtrace.io",
1653
- explorerName: "Avascan",
1654
- icon: "Avalanche",
1655
- symbol: "AVAX",
1656
- defaultRpc: "https://avalanche-c-chain-rpc.publicnode.com"
1657
- },
1658
- Base: {
1659
- key: "Base",
1660
- context: "Ethereum" /* ETH */,
1661
- chainId: 8453,
1662
- displayName: "Base",
1663
- explorerUrl: "https://basescan.org",
1664
- explorerName: "BaseScan",
1665
- icon: "Base",
1666
- symbol: "BASE",
1667
- defaultRpc: "https://mainnet.base.org"
1668
- },
1669
- Arbitrum: {
1670
- key: "Arbitrum",
1671
- context: "Ethereum" /* ETH */,
1672
- chainId: 42161,
1673
- displayName: "Arbitrum",
1674
- explorerUrl: "https://arbiscan.io/",
1675
- explorerName: "Arbitrum Explorer",
1676
- icon: "Arbitrum",
1677
- symbol: "ARB",
1678
- defaultRpc: "https://arb1.arbitrum.io/rpc"
1679
- },
1680
- Polygon: {
1681
- key: "Polygon",
1682
- context: "Ethereum" /* ETH */,
1683
- chainId: 137,
1684
- displayName: "Polygon",
1685
- explorerUrl: "https://polygonscan.com/",
1686
- explorerName: "PolygonScan",
1687
- icon: "Polygon",
1688
- symbol: "MATIC",
1689
- defaultRpc: "https://polygon-bor-rpc.publicnode.com"
1690
- },
1691
- Sui: {
1692
- key: "Sui",
1693
- context: "Sui" /* SUI */,
1694
- displayName: "Sui",
1695
- explorerUrl: "https://suiscan.xyz/",
1696
- explorerName: "Suiscan",
1697
- chainId: 0,
1698
- icon: "Sui",
1699
- symbol: "SUI",
1700
- defaultRpc: "https://fullnode.mainnet.sui.io:443"
1647
+ let retries = 0;
1648
+ const maxRetries = 5;
1649
+ const baseDelay = 1e3;
1650
+ while (retries < maxRetries) {
1651
+ try {
1652
+ for await (receipt of this.wormholeRoute.track(receipt, 120 * 1e3)) {
1653
+ if (receipt.state >= import_sdk3.TransferState.Attested) {
1654
+ logger.log("trackWithdraw: receipt attested", receipt);
1655
+ return receipt;
1656
+ }
1657
+ }
1658
+ } catch (e) {
1659
+ console.error(
1660
+ `Error tracking withdraw (attempt ${retries + 1} / ${maxRetries}):`,
1661
+ e
1662
+ );
1663
+ const delay = baseDelay * 2 ** retries;
1664
+ await (0, import_ts_sdk3.sleep)(delay);
1665
+ retries++;
1666
+ }
1667
+ }
1668
+ throw new Error("Failed to track withdraw to attested state");
1701
1669
  }
1702
- };
1703
-
1704
- // src/config/mainnet/tokens.ts
1705
- var mainnetTokens = {
1706
- Ethereum: {
1707
- symbol: "USDC",
1708
- tokenId: {
1709
- chain: "Ethereum",
1710
- address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
1711
- },
1712
- icon: "USDC",
1713
- decimals: 6
1714
- },
1715
- Solana: {
1716
- symbol: "USDC",
1717
- tokenId: {
1718
- chain: "Solana",
1719
- address: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
1720
- },
1721
- icon: "USDC",
1722
- decimals: 6
1723
- },
1724
- Aptos: {
1725
- symbol: "USDC",
1726
- decimals: 6,
1727
- tokenId: {
1728
- chain: "Aptos",
1729
- address: "0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b"
1730
- },
1731
- icon: "USDC"
1732
- },
1733
- Base: {
1734
- symbol: "USDC",
1735
- decimals: 6,
1736
- icon: "USDC",
1737
- tokenId: {
1738
- chain: "Base",
1739
- address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
1670
+ /**
1671
+ * Phase 3: Claims the withdraw on the destination chain.
1672
+ *
1673
+ * If the destination is Solana and `solanaConfig.serverClaimUrl` is configured
1674
+ * in the dapp config, the SDK automatically POSTs the attested receipt to that
1675
+ * URL — no wallet popup required. The dapp's server endpoint handles signing
1676
+ * and submitting the claim transaction.
1677
+ *
1678
+ * Otherwise falls back to the wallet-based Signer (triggers wallet popup).
1679
+ */
1680
+ async claimWithdraw(input) {
1681
+ const { claimChain, destinationAddress, receipt } = input;
1682
+ const serverClaimUrl = this.crossChainCore._dappConfig?.solanaConfig?.serverClaimUrl;
1683
+ if (claimChain === "Solana" && serverClaimUrl && !input.skipServerClaim) {
1684
+ logger.log("claimWithdraw: using server-side claim via", serverClaimUrl);
1685
+ const response = await fetch(serverClaimUrl, {
1686
+ method: "POST",
1687
+ headers: { "Content-Type": "application/json" },
1688
+ body: JSON.stringify({
1689
+ receipt: serializeReceipt(receipt),
1690
+ destinationAddress,
1691
+ claimChain
1692
+ })
1693
+ });
1694
+ if (!response.ok) {
1695
+ const errorData = await response.json().catch(() => ({}));
1696
+ throw new Error(
1697
+ errorData.error || `Server-side claim failed with status ${response.status}`
1698
+ );
1699
+ }
1700
+ const result = await response.json();
1701
+ return { destinationChainTxnId: result.destinationChainTxnId };
1740
1702
  }
1741
- },
1742
- Arbitrum: {
1743
- symbol: "USDC",
1744
- decimals: 6,
1745
- icon: "USDC",
1746
- tokenId: {
1747
- chain: "Arbitrum",
1748
- address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
1703
+ if (!this.wormholeRoute) {
1704
+ throw new Error("Wormhole route not initialized");
1749
1705
  }
1750
- },
1751
- Avalanche: {
1752
- symbol: "USDC",
1753
- decimals: 6,
1754
- icon: "USDC",
1755
- tokenId: {
1756
- chain: "Avalanche",
1757
- address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E"
1706
+ if (!input.wallet) {
1707
+ throw new Error(
1708
+ "Wallet is required for claim when serverClaimUrl is not configured"
1709
+ );
1758
1710
  }
1759
- },
1760
- Polygon: {
1761
- symbol: "USDC",
1762
- decimals: 6,
1763
- icon: "USDC",
1764
- tokenId: {
1765
- chain: "Polygon",
1766
- address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
1711
+ const claimSigner = new Signer(
1712
+ this.getChainConfig(claimChain),
1713
+ destinationAddress,
1714
+ {},
1715
+ input.wallet,
1716
+ this.crossChainCore,
1717
+ void 0,
1718
+ input.onTransactionSigned,
1719
+ false
1720
+ );
1721
+ if (import_sdk3.routes.isManual(this.wormholeRoute)) {
1722
+ const circleAttestationReceipt = await this.wormholeRoute.complete(
1723
+ claimSigner,
1724
+ receipt
1725
+ );
1726
+ logger.log("claimWithdraw receipt:", circleAttestationReceipt);
1727
+ const destinationChainTxnId = claimSigner.claimedTransactionHashes();
1728
+ return { destinationChainTxnId };
1729
+ } else {
1730
+ throw new Error("Automatic route not supported for manual claim");
1767
1731
  }
1768
- },
1769
- Sui: {
1770
- symbol: "USDC",
1771
- decimals: 6,
1772
- tokenId: {
1773
- chain: "Sui",
1774
- address: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC"
1775
- },
1776
- icon: "USDC"
1732
+ }
1733
+ /**
1734
+ * Withdraws USDC from Aptos to a destination chain.
1735
+ * Orchestrates all three phases internally:
1736
+ * 1. Initiate — user signs the Aptos burn transaction
1737
+ * 2. Track — wait for Wormhole attestation
1738
+ * 3. Claim — if serverClaimUrl is configured for Solana, delegates to
1739
+ * the server; otherwise uses the wallet-based signer.
1740
+ *
1741
+ * The optional `onPhaseChange` callback lets the dapp update its UI
1742
+ * as the flow progresses.
1743
+ */
1744
+ async withdraw(input) {
1745
+ const {
1746
+ sourceChain,
1747
+ wallet,
1748
+ destinationAddress,
1749
+ sponsorAccount,
1750
+ onPhaseChange,
1751
+ onTransactionSigned
1752
+ } = input;
1753
+ onPhaseChange?.("initiating");
1754
+ const { originChainTxnId, receipt } = await this.initiateWithdraw({
1755
+ wallet,
1756
+ destinationAddress,
1757
+ sponsorAccount,
1758
+ onTransactionSigned
1759
+ });
1760
+ let currentPhase = "tracking";
1761
+ try {
1762
+ onPhaseChange?.("tracking");
1763
+ const attestedReceipt = await this.trackWithdraw(receipt);
1764
+ currentPhase = "claiming";
1765
+ onPhaseChange?.("claiming");
1766
+ const { destinationChainTxnId } = await this.claimWithdraw({
1767
+ claimChain: sourceChain,
1768
+ destinationAddress: destinationAddress.toString(),
1769
+ receipt: attestedReceipt,
1770
+ wallet,
1771
+ onTransactionSigned
1772
+ });
1773
+ return { originChainTxnId, destinationChainTxnId };
1774
+ } catch (error) {
1775
+ throw new WithdrawError(
1776
+ error?.message ?? "Withdraw failed after Aptos burn",
1777
+ originChainTxnId,
1778
+ currentPhase,
1779
+ error
1780
+ );
1781
+ }
1782
+ }
1783
+ /**
1784
+ * Retries a failed `claimWithdraw` call with configurable exponential backoff.
1785
+ *
1786
+ * Use this when the claim phase of a withdrawal fails (e.g., RPC instability,
1787
+ * network congestion) but the Aptos burn transaction has already been submitted.
1788
+ * The attested receipt can be recovered from the `WithdrawError` thrown by
1789
+ * `withdraw()` and passed directly to this method.
1790
+ *
1791
+ * @example
1792
+ * ```ts
1793
+ * try {
1794
+ * await provider.withdraw({ ... });
1795
+ * } catch (error) {
1796
+ * if (error instanceof WithdrawError && error.phase === "claiming") {
1797
+ * const result = await provider.retryWithdrawClaim({
1798
+ * sourceChain,
1799
+ * destinationAddress,
1800
+ * receipt: attestedReceipt,
1801
+ * wallet,
1802
+ * maxRetries: 5,
1803
+ * });
1804
+ * }
1805
+ * }
1806
+ * ```
1807
+ */
1808
+ async retryWithdrawClaim(input) {
1809
+ const {
1810
+ maxRetries = 5,
1811
+ initialDelayMs = 2e3,
1812
+ backoffMultiplier = 2,
1813
+ ...claimInput
1814
+ } = input;
1815
+ let lastError;
1816
+ let delay = initialDelayMs;
1817
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
1818
+ try {
1819
+ const result = await this.claimWithdraw(claimInput);
1820
+ return { ...result, retriesUsed: attempt };
1821
+ } catch (error) {
1822
+ lastError = error;
1823
+ logger.log(
1824
+ `retryWithdrawClaim: attempt ${attempt + 1}/${maxRetries + 1} failed: ${lastError.message}`
1825
+ );
1826
+ if (attempt < maxRetries) {
1827
+ await (0, import_ts_sdk3.sleep)(delay);
1828
+ delay *= backoffMultiplier;
1829
+ }
1830
+ }
1831
+ }
1832
+ throw new Error(
1833
+ `Claim failed after ${maxRetries + 1} attempts: ${lastError?.message}`
1834
+ );
1835
+ }
1836
+ getChainConfig(chain) {
1837
+ const chainConfig = this.crossChainCore.CHAINS[chain];
1838
+ if (!chainConfig) {
1839
+ throw new Error(`Chain config not found for chain: ${chain}`);
1840
+ }
1841
+ return chainConfig;
1777
1842
  }
1778
1843
  };
1779
1844
 
1780
1845
  // src/utils/getUsdcBalance.ts
1781
1846
  var import_ts_sdk4 = require("@aptos-labs/ts-sdk");
1782
- var import_web35 = require("@solana/web3.js");
1783
- var import_ethers2 = require("ethers");
1784
1847
  var import_client = require("@mysten/sui/client");
1848
+ var import_web34 = require("@solana/web3.js");
1849
+ var import_ethers2 = require("ethers");
1785
1850
  var getSolanaWalletUSDCBalance = async (walletAddress, aptosNetwork, rpc) => {
1786
- const address = new import_web35.PublicKey(walletAddress);
1787
- const tokenAddress = aptosNetwork === import_ts_sdk4.Network.MAINNET ? mainnetTokens["Solana"].tokenId.address : testnetTokens["Solana"].tokenId.address;
1788
- const connection = new import_web35.Connection(rpc);
1851
+ const address = new import_web34.PublicKey(walletAddress);
1852
+ const tokenAddress = aptosNetwork === import_ts_sdk4.Network.MAINNET ? mainnetTokens.Solana.tokenId.address : testnetTokens.Solana.tokenId.address;
1853
+ const connection = new import_web34.Connection(rpc);
1789
1854
  const splToken = await connection.getTokenAccountsByOwner(address, {
1790
- mint: new import_web35.PublicKey(tokenAddress)
1855
+ mint: new import_web34.PublicKey(tokenAddress)
1791
1856
  });
1792
1857
  if (splToken.value.length === 0) {
1793
1858
  return "0";
@@ -1807,7 +1872,7 @@ var getEthereumWalletUSDCBalance = async (walletAddress, aptosNetwork, chain, rp
1807
1872
  return import_ethers2.ethers.formatUnits(balance, token.decimals).toString();
1808
1873
  };
1809
1874
  var getAptosWalletUSDCBalance = async (walletAddress, aptosNetwork) => {
1810
- const token = aptosNetwork === import_ts_sdk4.Network.MAINNET ? mainnetTokens["Aptos"] : testnetTokens["Aptos"];
1875
+ const token = aptosNetwork === import_ts_sdk4.Network.MAINNET ? mainnetTokens.Aptos : testnetTokens.Aptos;
1811
1876
  const tokenAddress = token.tokenId.address;
1812
1877
  const aptosConfig = new import_ts_sdk4.AptosConfig({ network: aptosNetwork });
1813
1878
  const connection = new import_ts_sdk4.Aptos(aptosConfig);
@@ -1825,7 +1890,7 @@ var getAptosWalletUSDCBalance = async (walletAddress, aptosNetwork) => {
1825
1890
  return import_ethers2.ethers.formatUnits(BigInt(response[0].amount), token.decimals);
1826
1891
  };
1827
1892
  var getSuiWalletUSDCBalance = async (walletAddress, aptosNetwork, rpc) => {
1828
- const token = aptosNetwork === import_ts_sdk4.Network.MAINNET ? mainnetTokens["Sui"] : testnetTokens["Sui"];
1893
+ const token = aptosNetwork === import_ts_sdk4.Network.MAINNET ? mainnetTokens.Sui : testnetTokens.Sui;
1829
1894
  const client = new import_client.SuiClient({
1830
1895
  url: rpc
1831
1896
  });
@@ -1864,13 +1929,20 @@ var EthereumChainIdToMainnetChain = {
1864
1929
  43114: mainnetChains.Avalanche,
1865
1930
  137: mainnetChains.Polygon
1866
1931
  };
1867
- var CrossChainCore2 = class {
1932
+ var CrossChainCore = class {
1933
+ _dappConfig = {
1934
+ aptosNetwork: import_ts_sdk5.Network.TESTNET
1935
+ };
1936
+ CHAINS = testnetChains;
1937
+ TOKENS = testnetTokens;
1938
+ /**
1939
+ * Last known source-chain transaction ID, set by signers immediately after
1940
+ * a transaction is submitted. Acts as a recovery side-channel so that
1941
+ * callers can retrieve the tx hash even when the orchestration layer throws
1942
+ * before returning it (e.g. claim failure after a successful burn).
1943
+ */
1944
+ _lastSourceChainTxId;
1868
1945
  constructor(args) {
1869
- this._dappConfig = {
1870
- aptosNetwork: import_ts_sdk5.Network.TESTNET
1871
- };
1872
- this.CHAINS = testnetChains;
1873
- this.TOKENS = testnetTokens;
1874
1946
  this._dappConfig = args.dappConfig;
1875
1947
  if (args.dappConfig?.aptosNetwork === import_ts_sdk5.Network.MAINNET) {
1876
1948
  this.CHAINS = mainnetChains;
@@ -1931,9 +2003,6 @@ var CrossChainCore2 = class {
1931
2003
  }
1932
2004
  }
1933
2005
  };
1934
-
1935
- // src/index.ts
1936
- var import_ts_sdk7 = require("@aptos-labs/ts-sdk");
1937
2006
  // Annotate the CommonJS export names for ESM import in node:
1938
2007
  0 && (module.exports = {
1939
2008
  AptosLocalSigner,