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