@aptos-labs/cross-chain-core 6.0.0 → 6.1.0

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