@aptos-labs/cross-chain-core 5.8.2 → 6.0.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/README.md +26 -0
- package/dist/CrossChainCore.d.ts +95 -0
- package/dist/CrossChainCore.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +908 -404
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +914 -409
- package/dist/index.mjs.map +1 -1
- package/dist/providers/wormhole/index.d.ts +2 -0
- package/dist/providers/wormhole/index.d.ts.map +1 -1
- package/dist/providers/wormhole/signers/AptosLocalSigner.d.ts +9 -7
- package/dist/providers/wormhole/signers/AptosLocalSigner.d.ts.map +1 -1
- package/dist/providers/wormhole/signers/AptosSigner.d.ts +2 -1
- package/dist/providers/wormhole/signers/AptosSigner.d.ts.map +1 -1
- package/dist/providers/wormhole/signers/EthereumSigner.d.ts +1 -1
- package/dist/providers/wormhole/signers/EthereumSigner.d.ts.map +1 -1
- package/dist/providers/wormhole/signers/Signer.d.ts +11 -3
- package/dist/providers/wormhole/signers/Signer.d.ts.map +1 -1
- package/dist/providers/wormhole/signers/SolanaLocalSigner.d.ts +69 -0
- package/dist/providers/wormhole/signers/SolanaLocalSigner.d.ts.map +1 -0
- package/dist/providers/wormhole/signers/SolanaSigner.d.ts +12 -20
- package/dist/providers/wormhole/signers/SolanaSigner.d.ts.map +1 -1
- package/dist/providers/wormhole/signers/solanaUtils.d.ts +68 -0
- package/dist/providers/wormhole/signers/solanaUtils.d.ts.map +1 -0
- package/dist/providers/wormhole/types.d.ts +120 -0
- package/dist/providers/wormhole/types.d.ts.map +1 -1
- package/dist/providers/wormhole/utils.d.ts +26 -0
- package/dist/providers/wormhole/utils.d.ts.map +1 -0
- package/dist/providers/wormhole/wormhole.d.ts +62 -6
- package/dist/providers/wormhole/wormhole.d.ts.map +1 -1
- package/dist/utils/receiptSerialization.d.ts +38 -0
- package/dist/utils/receiptSerialization.d.ts.map +1 -0
- package/dist/version.d.ts +1 -1
- package/package.json +3 -3
- package/src/CrossChainCore.ts +110 -3
- package/src/config/mainnet/chains.ts +2 -2
- package/src/config/testnet/chains.ts +2 -2
- package/src/index.ts +1 -0
- package/src/providers/wormhole/index.ts +2 -0
- package/src/providers/wormhole/signers/AptosLocalSigner.ts +31 -18
- package/src/providers/wormhole/signers/AptosSigner.ts +11 -2
- package/src/providers/wormhole/signers/EthereumSigner.ts +59 -8
- package/src/providers/wormhole/signers/Signer.ts +23 -6
- package/src/providers/wormhole/signers/SolanaLocalSigner.ts +250 -0
- package/src/providers/wormhole/signers/SolanaSigner.ts +49 -338
- package/src/providers/wormhole/signers/solanaUtils.ts +446 -0
- package/src/providers/wormhole/types.ts +167 -0
- package/src/providers/wormhole/utils.ts +72 -0
- package/src/providers/wormhole/wormhole.ts +309 -137
- package/src/utils/receiptSerialization.ts +141 -0
- package/src/version.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -32,18 +32,26 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
AptosLocalSigner: () => AptosLocalSigner,
|
|
34
34
|
Context: () => Context,
|
|
35
|
-
CrossChainCore: () =>
|
|
35
|
+
CrossChainCore: () => CrossChainCore2,
|
|
36
|
+
EVM_CHAIN_NAMES: () => EVM_CHAIN_NAMES,
|
|
36
37
|
EthereumChainIdToMainnetChain: () => EthereumChainIdToMainnetChain,
|
|
37
38
|
EthereumChainIdToTestnetChain: () => EthereumChainIdToTestnetChain,
|
|
38
39
|
Network: () => import_ts_sdk7.Network,
|
|
39
40
|
NetworkToChainId: () => import_ts_sdk6.NetworkToChainId,
|
|
40
41
|
NetworkToNodeAPI: () => import_ts_sdk6.NetworkToNodeAPI,
|
|
42
|
+
SolanaLocalSigner: () => SolanaLocalSigner,
|
|
43
|
+
TransferError: () => TransferError,
|
|
44
|
+
WithdrawError: () => WithdrawError,
|
|
41
45
|
WormholeProvider: () => WormholeProvider,
|
|
46
|
+
createCCTPRoute: () => createCCTPRoute,
|
|
47
|
+
deserializeReceipt: () => deserializeReceipt,
|
|
42
48
|
mainnetChains: () => mainnetChains,
|
|
43
49
|
mainnetTokens: () => mainnetTokens,
|
|
50
|
+
serializeReceipt: () => serializeReceipt,
|
|
44
51
|
signAndSendTransaction: () => signAndSendTransaction,
|
|
45
52
|
testnetChains: () => testnetChains,
|
|
46
|
-
testnetTokens: () => testnetTokens
|
|
53
|
+
testnetTokens: () => testnetTokens,
|
|
54
|
+
validateExpireTimestamp: () => validateExpireTimestamp
|
|
47
55
|
});
|
|
48
56
|
module.exports = __toCommonJS(index_exports);
|
|
49
57
|
|
|
@@ -51,7 +59,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
51
59
|
var import_ts_sdk5 = require("@aptos-labs/ts-sdk");
|
|
52
60
|
|
|
53
61
|
// src/providers/wormhole/wormhole.ts
|
|
54
|
-
var
|
|
62
|
+
var import_sdk3 = require("@wormhole-foundation/sdk");
|
|
55
63
|
var import_ts_sdk3 = require("@aptos-labs/ts-sdk");
|
|
56
64
|
var import_aptos = __toESM(require("@wormhole-foundation/sdk/aptos"));
|
|
57
65
|
var import_solana = __toESM(require("@wormhole-foundation/sdk/solana"));
|
|
@@ -77,16 +85,129 @@ var logger = {
|
|
|
77
85
|
}
|
|
78
86
|
};
|
|
79
87
|
|
|
88
|
+
// src/utils/receiptSerialization.ts
|
|
89
|
+
var import_sdk = require("@wormhole-foundation/sdk");
|
|
90
|
+
function uint8ArrayToBase64(bytes) {
|
|
91
|
+
let binary = "";
|
|
92
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
93
|
+
binary += String.fromCharCode(bytes[i]);
|
|
94
|
+
}
|
|
95
|
+
return btoa(binary);
|
|
96
|
+
}
|
|
97
|
+
function base64ToUint8Array(base64) {
|
|
98
|
+
const binary = atob(base64);
|
|
99
|
+
const bytes = new Uint8Array(binary.length);
|
|
100
|
+
for (let i = 0; i < binary.length; i++) {
|
|
101
|
+
bytes[i] = binary.charCodeAt(i);
|
|
102
|
+
}
|
|
103
|
+
return bytes;
|
|
104
|
+
}
|
|
105
|
+
function serializeReceipt(receipt) {
|
|
106
|
+
return JSON.parse(
|
|
107
|
+
JSON.stringify(receipt, (_key, value) => {
|
|
108
|
+
if (typeof value === "bigint") {
|
|
109
|
+
return { __type: "bigint", value: value.toString() };
|
|
110
|
+
}
|
|
111
|
+
if (value instanceof import_sdk.UniversalAddress) {
|
|
112
|
+
return {
|
|
113
|
+
__type: "UniversalAddress",
|
|
114
|
+
value: uint8ArrayToBase64(value.toUint8Array())
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (value instanceof Uint8Array) {
|
|
118
|
+
return {
|
|
119
|
+
__type: "Uint8Array",
|
|
120
|
+
value: uint8ArrayToBase64(value)
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return value;
|
|
124
|
+
})
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
function deserializeReceipt(obj) {
|
|
128
|
+
function revive(value, key) {
|
|
129
|
+
if (value && typeof value === "object") {
|
|
130
|
+
const objValue = value;
|
|
131
|
+
if ("__type" in objValue) {
|
|
132
|
+
if (objValue.__type === "bigint") {
|
|
133
|
+
return BigInt(objValue.value);
|
|
134
|
+
}
|
|
135
|
+
if (objValue.__type === "UniversalAddress") {
|
|
136
|
+
return new import_sdk.UniversalAddress(
|
|
137
|
+
base64ToUint8Array(objValue.value)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
if (objValue.__type === "Uint8Array") {
|
|
141
|
+
return base64ToUint8Array(objValue.value);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const addressFields = [
|
|
145
|
+
"sender",
|
|
146
|
+
"recipient",
|
|
147
|
+
"destinationCaller",
|
|
148
|
+
"burnToken",
|
|
149
|
+
"mintRecipient",
|
|
150
|
+
"messageSender"
|
|
151
|
+
];
|
|
152
|
+
if (key && addressFields.includes(key) && "address" in objValue) {
|
|
153
|
+
const addressBytes = revive(objValue.address);
|
|
154
|
+
if (addressBytes instanceof Uint8Array) {
|
|
155
|
+
return new import_sdk.UniversalAddress(addressBytes);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (Array.isArray(value)) {
|
|
159
|
+
return value.map((v, i) => revive(v, String(i)));
|
|
160
|
+
}
|
|
161
|
+
const result = {};
|
|
162
|
+
for (const k in objValue) {
|
|
163
|
+
result[k] = revive(objValue[k], k);
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
return value;
|
|
168
|
+
}
|
|
169
|
+
return revive(obj);
|
|
170
|
+
}
|
|
171
|
+
|
|
80
172
|
// src/providers/wormhole/signers/AptosLocalSigner.ts
|
|
81
173
|
var import_ts_sdk = require("@aptos-labs/ts-sdk");
|
|
174
|
+
|
|
175
|
+
// src/providers/wormhole/types.ts
|
|
176
|
+
function validateExpireTimestamp(value) {
|
|
177
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`getExpireTimestamp returned an invalid value (${value}). Expected a non-negative integer (epoch seconds).`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
var TransferError = class extends Error {
|
|
184
|
+
constructor(message, originChainTxnId, cause) {
|
|
185
|
+
super(message);
|
|
186
|
+
this.name = "TransferError";
|
|
187
|
+
this.originChainTxnId = originChainTxnId;
|
|
188
|
+
this.cause = cause;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
var WithdrawError = class extends Error {
|
|
192
|
+
constructor(message, originChainTxnId, phase, cause) {
|
|
193
|
+
super(message);
|
|
194
|
+
this.name = "WithdrawError";
|
|
195
|
+
this.originChainTxnId = originChainTxnId;
|
|
196
|
+
this.phase = phase;
|
|
197
|
+
this.cause = cause;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// src/providers/wormhole/signers/AptosLocalSigner.ts
|
|
82
202
|
var AptosLocalSigner = class {
|
|
83
|
-
constructor(chain, options, wallet, feePayerAccount,
|
|
203
|
+
constructor(chain, options, wallet, feePayerAccount, crossChainCore, onTransactionSigned) {
|
|
204
|
+
this._claimedTransactionHashes = [];
|
|
84
205
|
this._chain = chain;
|
|
85
206
|
this._options = options;
|
|
86
207
|
this._wallet = wallet;
|
|
87
208
|
this._sponsorAccount = feePayerAccount;
|
|
88
|
-
this.
|
|
89
|
-
this.
|
|
209
|
+
this._crossChainCore = crossChainCore;
|
|
210
|
+
this._onTransactionSigned = onTransactionSigned;
|
|
90
211
|
}
|
|
91
212
|
chain() {
|
|
92
213
|
return this._chain;
|
|
@@ -95,24 +216,27 @@ var AptosLocalSigner = class {
|
|
|
95
216
|
return this._wallet.accountAddress.toString();
|
|
96
217
|
}
|
|
97
218
|
claimedTransactionHashes() {
|
|
98
|
-
return this._claimedTransactionHashes;
|
|
219
|
+
return this._claimedTransactionHashes.join(",");
|
|
99
220
|
}
|
|
100
221
|
async signAndSend(txs) {
|
|
101
222
|
const txHashes = [];
|
|
223
|
+
this._claimedTransactionHashes = [];
|
|
102
224
|
for (const tx of txs) {
|
|
225
|
+
this._onTransactionSigned?.(tx.description, null);
|
|
103
226
|
const txId = await signAndSendTransaction(
|
|
104
227
|
tx,
|
|
105
228
|
this._wallet,
|
|
106
229
|
this._sponsorAccount,
|
|
107
|
-
this.
|
|
230
|
+
this._crossChainCore
|
|
108
231
|
);
|
|
232
|
+
this._onTransactionSigned?.(tx.description, txId);
|
|
109
233
|
txHashes.push(txId);
|
|
110
|
-
this._claimedTransactionHashes
|
|
234
|
+
this._claimedTransactionHashes.push(txId);
|
|
111
235
|
}
|
|
112
236
|
return txHashes;
|
|
113
237
|
}
|
|
114
238
|
};
|
|
115
|
-
async function signAndSendTransaction(request, wallet, sponsorAccount,
|
|
239
|
+
async function signAndSendTransaction(request, wallet, sponsorAccount, crossChainCore) {
|
|
116
240
|
if (!wallet) {
|
|
117
241
|
throw new Error("Wallet is undefined");
|
|
118
242
|
}
|
|
@@ -126,14 +250,20 @@ async function signAndSendTransaction(request, wallet, sponsorAccount, dappNetwo
|
|
|
126
250
|
return a;
|
|
127
251
|
}
|
|
128
252
|
});
|
|
253
|
+
const dappNetwork = crossChainCore._dappConfig.aptosNetwork;
|
|
129
254
|
const aptosConfig = new import_ts_sdk.AptosConfig({
|
|
130
255
|
network: dappNetwork
|
|
131
256
|
});
|
|
132
257
|
const aptos2 = new import_ts_sdk.Aptos(aptosConfig);
|
|
258
|
+
const expireTimestamp = crossChainCore._dappConfig.getExpireTimestamp?.();
|
|
259
|
+
if (typeof expireTimestamp !== "undefined") {
|
|
260
|
+
validateExpireTimestamp(expireTimestamp);
|
|
261
|
+
}
|
|
133
262
|
const txnToSign = await aptos2.transaction.build.simple({
|
|
134
263
|
data: payload,
|
|
135
264
|
sender: wallet.accountAddress.toString(),
|
|
136
|
-
withFeePayer: sponsorAccount ? true : false
|
|
265
|
+
withFeePayer: sponsorAccount ? true : false,
|
|
266
|
+
...typeof expireTimestamp !== "undefined" ? { options: { expireTimestamp } } : {}
|
|
137
267
|
});
|
|
138
268
|
const senderAuthenticator = await aptos2.transaction.sign({
|
|
139
269
|
signer: wallet,
|
|
@@ -157,120 +287,228 @@ async function signAndSendTransaction(request, wallet, sponsorAccount, dappNetwo
|
|
|
157
287
|
return tx.hash;
|
|
158
288
|
}
|
|
159
289
|
|
|
160
|
-
// src/providers/wormhole/signers/
|
|
161
|
-
var
|
|
162
|
-
var
|
|
163
|
-
var
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (!wallet || !(wallet instanceof import_derived_wallet_solana.SolanaDerivedWallet)) {
|
|
168
|
-
throw new Error("Invalid wallet type or missing Solana wallet").message;
|
|
290
|
+
// src/providers/wormhole/signers/AptosSigner.ts
|
|
291
|
+
var import_ts_sdk2 = require("@aptos-labs/ts-sdk");
|
|
292
|
+
var import_wallet_standard = require("@aptos-labs/wallet-standard");
|
|
293
|
+
var import_gas_station_client = require("@aptos-labs/gas-station-client");
|
|
294
|
+
async function signAndSendTransaction2(request, wallet, sponsorAccount, dappNetwork, crossChainCore) {
|
|
295
|
+
if (!wallet) {
|
|
296
|
+
throw new Error("wallet.sendTransaction is undefined");
|
|
169
297
|
}
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
298
|
+
const payload = request.transaction;
|
|
299
|
+
payload.functionArguments = payload.functionArguments.map((a) => {
|
|
300
|
+
if (a instanceof Uint8Array) {
|
|
301
|
+
return Array.from(a);
|
|
302
|
+
} else if (typeof a === "bigint") {
|
|
303
|
+
return a.toString();
|
|
304
|
+
} else {
|
|
305
|
+
return a;
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
let aptosConfig;
|
|
309
|
+
const useGasStation = sponsorAccount && !isAccount(sponsorAccount);
|
|
310
|
+
if (useGasStation) {
|
|
311
|
+
const gasStationClient = new import_gas_station_client.GasStationClient({
|
|
312
|
+
network: dappNetwork,
|
|
313
|
+
apiKey: sponsorAccount[dappNetwork]
|
|
314
|
+
});
|
|
315
|
+
const transactionSubmitter = new import_gas_station_client.GasStationTransactionSubmitter(gasStationClient);
|
|
316
|
+
aptosConfig = new import_ts_sdk2.AptosConfig({
|
|
317
|
+
network: dappNetwork,
|
|
318
|
+
pluginSettings: {
|
|
319
|
+
TRANSACTION_SUBMITTER: transactionSubmitter
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
} else {
|
|
323
|
+
aptosConfig = new import_ts_sdk2.AptosConfig({
|
|
324
|
+
network: dappNetwork
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
const aptos2 = new import_ts_sdk2.Aptos(aptosConfig);
|
|
328
|
+
const functionArguments = extractFunctionArguments(
|
|
329
|
+
payload.functionArguments
|
|
182
330
|
);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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);
|
|
189
339
|
}
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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");
|
|
194
349
|
}
|
|
195
|
-
const
|
|
350
|
+
const txnToSubmit = {
|
|
351
|
+
transaction: txnToSign,
|
|
352
|
+
senderAuthenticator: response.args
|
|
353
|
+
};
|
|
354
|
+
if (sponsorAccount && isAccount(sponsorAccount)) {
|
|
355
|
+
const feePayerSignerAuthenticator = aptos2.transaction.signAsFeePayer({
|
|
356
|
+
signer: sponsorAccount,
|
|
357
|
+
transaction: txnToSign
|
|
358
|
+
});
|
|
359
|
+
txnToSubmit.feePayerAuthenticator = feePayerSignerAuthenticator;
|
|
360
|
+
}
|
|
361
|
+
const txnSubmitted = await aptos2.transaction.submit.simple(txnToSubmit);
|
|
362
|
+
const tx = await aptos2.waitForTransaction({
|
|
363
|
+
transactionHash: txnSubmitted.hash
|
|
364
|
+
});
|
|
365
|
+
return tx.hash;
|
|
366
|
+
}
|
|
367
|
+
function extractFunctionArguments(functionArguments) {
|
|
368
|
+
const deserializer1 = new import_ts_sdk2.Deserializer(functionArguments[0].bcsToBytes());
|
|
369
|
+
const amount = deserializer1.deserializeU64();
|
|
370
|
+
const deserializer2 = new import_ts_sdk2.Deserializer(functionArguments[1].bcsToBytes());
|
|
371
|
+
const destination_domain = deserializer2.deserializeU32();
|
|
372
|
+
const mint_recipient = new import_ts_sdk2.AccountAddress(functionArguments[2].bcsToBytes());
|
|
373
|
+
const burn_token = new import_ts_sdk2.AccountAddress(functionArguments[3].bcsToBytes());
|
|
374
|
+
return [amount, destination_domain, mint_recipient, burn_token];
|
|
375
|
+
}
|
|
376
|
+
function isAccount(obj) {
|
|
377
|
+
return "accountAddress" in obj;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// src/providers/wormhole/signers/SolanaSigner.ts
|
|
381
|
+
var import_web32 = require("@solana/web3.js");
|
|
382
|
+
var import_web33 = require("@solana/web3.js");
|
|
383
|
+
var import_derived_wallet_solana = require("@aptos-labs/derived-wallet-solana");
|
|
384
|
+
|
|
385
|
+
// src/providers/wormhole/signers/solanaUtils.ts
|
|
386
|
+
var import_web3 = require("@solana/web3.js");
|
|
387
|
+
var import_sdk_solana = require("@wormhole-foundation/sdk-solana");
|
|
388
|
+
async function sendAndConfirmTransaction(serializedTx, blockhash, lastValidBlockHeight, config) {
|
|
389
|
+
const { connection, commitment, retryIntervalMs = 5e3, verbose = false } = config;
|
|
196
390
|
const sendOptions = {
|
|
197
391
|
skipPreflight: true,
|
|
198
392
|
maxRetries: 0,
|
|
199
|
-
|
|
200
|
-
// See PR and linked issue for why setting this matters: https://github.com/anza-xyz/agave/pull/483
|
|
393
|
+
preflightCommitment: commitment
|
|
201
394
|
};
|
|
202
|
-
signature = await connection.sendRawTransaction(serializedTx, sendOptions);
|
|
203
|
-
confirmTransactionPromise = connection.confirmTransaction(
|
|
204
|
-
{
|
|
205
|
-
signature,
|
|
206
|
-
blockhash,
|
|
207
|
-
lastValidBlockHeight
|
|
208
|
-
},
|
|
395
|
+
const signature = await connection.sendRawTransaction(serializedTx, sendOptions);
|
|
396
|
+
const confirmTransactionPromise = connection.confirmTransaction(
|
|
397
|
+
{ signature, blockhash, lastValidBlockHeight },
|
|
209
398
|
commitment
|
|
210
399
|
);
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
try {
|
|
228
|
-
await connection.sendRawTransaction(serializedTx, sendOptions);
|
|
229
|
-
} catch (e) {
|
|
230
|
-
console.error("Failed to resend transaction:", e);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
if (confirmedTx.value.err) {
|
|
234
|
-
let errorMessage = `Transaction failed: ${confirmedTx.value.err}`;
|
|
235
|
-
if (typeof confirmedTx.value.err === "object") {
|
|
400
|
+
let confirmedTx = null;
|
|
401
|
+
let txSendAttempts = 1;
|
|
402
|
+
try {
|
|
403
|
+
while (!confirmedTx) {
|
|
404
|
+
confirmedTx = await Promise.race([
|
|
405
|
+
confirmTransactionPromise,
|
|
406
|
+
new Promise(
|
|
407
|
+
(resolve) => setTimeout(() => resolve(null), retryIntervalMs)
|
|
408
|
+
)
|
|
409
|
+
]);
|
|
410
|
+
if (confirmedTx) break;
|
|
411
|
+
if (verbose) {
|
|
412
|
+
console.log(
|
|
413
|
+
`Tx not confirmed after ${retryIntervalMs * txSendAttempts++}ms, resending`
|
|
414
|
+
);
|
|
415
|
+
}
|
|
236
416
|
try {
|
|
237
|
-
|
|
238
|
-
confirmedTx.value.err,
|
|
239
|
-
(_key, value) => typeof value === "bigint" ? value.toString() : value
|
|
240
|
-
// Handle bigint props
|
|
241
|
-
)}`;
|
|
417
|
+
await connection.sendRawTransaction(serializedTx, sendOptions);
|
|
242
418
|
} catch (e) {
|
|
243
|
-
|
|
419
|
+
if (verbose) {
|
|
420
|
+
console.error("Failed to resend transaction:", e);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
} catch (e) {
|
|
425
|
+
const message = e instanceof Error ? e.message.toLowerCase() : "";
|
|
426
|
+
if (message.includes("block height exceeded") || message.includes("blockheightexceeded")) {
|
|
427
|
+
if (verbose) {
|
|
428
|
+
console.warn(
|
|
429
|
+
"Block height exceeded but tx was already sent, returning signature:",
|
|
430
|
+
signature
|
|
431
|
+
);
|
|
244
432
|
}
|
|
433
|
+
return signature;
|
|
245
434
|
}
|
|
246
|
-
throw
|
|
435
|
+
throw e;
|
|
436
|
+
}
|
|
437
|
+
if (confirmedTx.value.err) {
|
|
438
|
+
const errorMessage = formatTransactionError(confirmedTx.value.err);
|
|
439
|
+
throw new Error(errorMessage);
|
|
247
440
|
}
|
|
248
441
|
return signature;
|
|
249
442
|
}
|
|
250
|
-
|
|
251
|
-
|
|
443
|
+
function formatTransactionError(err) {
|
|
444
|
+
if (typeof err === "object" && err !== null) {
|
|
445
|
+
try {
|
|
446
|
+
return `Transaction failed: ${JSON.stringify(
|
|
447
|
+
err,
|
|
448
|
+
(_key, value) => typeof value === "bigint" ? value.toString() : value
|
|
449
|
+
)}`;
|
|
450
|
+
} catch {
|
|
451
|
+
return "Transaction failed: Unknown error";
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return `Transaction failed: ${err}`;
|
|
455
|
+
}
|
|
456
|
+
async function addPriorityFeeInstructions(connection, transaction, priorityFeeConfig, verbose = false) {
|
|
252
457
|
const computeBudgetIxFilter = (ix) => ix.programId.toString() !== "ComputeBudget111111111111111111111111111111";
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
458
|
+
transaction.instructions = transaction.instructions.filter(computeBudgetIxFilter);
|
|
459
|
+
const instructions = await createPriorityFeeInstructions(
|
|
460
|
+
connection,
|
|
461
|
+
transaction,
|
|
462
|
+
priorityFeeConfig,
|
|
463
|
+
verbose
|
|
257
464
|
);
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
465
|
+
transaction.add(...instructions);
|
|
466
|
+
return transaction;
|
|
467
|
+
}
|
|
468
|
+
async function createPriorityFeeInstructions(connection, transaction, priorityFeeConfig, verbose = false) {
|
|
469
|
+
const unitsUsed = await simulateAndGetComputeUnits(connection, transaction);
|
|
470
|
+
const unitBudget = Math.floor(unitsUsed * 1.2);
|
|
471
|
+
const instructions = [];
|
|
472
|
+
instructions.push(
|
|
473
|
+
import_web3.ComputeBudgetProgram.setComputeUnitLimit({
|
|
474
|
+
units: unitBudget
|
|
475
|
+
})
|
|
264
476
|
);
|
|
265
|
-
|
|
477
|
+
const {
|
|
478
|
+
percentile = 0.9,
|
|
479
|
+
percentileMultiple = 1,
|
|
480
|
+
min = 1e5,
|
|
481
|
+
max = 1e8
|
|
482
|
+
} = priorityFeeConfig ?? {};
|
|
483
|
+
const rpcProvider = determineRpcProvider(connection.rpcEndpoint);
|
|
484
|
+
const { fee, methodUsed } = await calculatePriorityFee(
|
|
485
|
+
connection,
|
|
486
|
+
transaction,
|
|
487
|
+
rpcProvider,
|
|
488
|
+
{ percentile, percentileMultiple, min, max }
|
|
489
|
+
);
|
|
490
|
+
if (verbose) {
|
|
491
|
+
const maxFeeInSol = fee / 1e6 / import_web3.LAMPORTS_PER_SOL * unitBudget;
|
|
492
|
+
console.table({
|
|
493
|
+
"RPC Provider": rpcProvider,
|
|
494
|
+
"Method used": methodUsed,
|
|
495
|
+
"Percentile used": percentile,
|
|
496
|
+
"Multiple used": percentileMultiple,
|
|
497
|
+
"Compute budget": unitBudget,
|
|
498
|
+
"Priority fee": fee,
|
|
499
|
+
"Max fee in SOL": maxFeeInSol
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
instructions.push(
|
|
503
|
+
import_web3.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: fee })
|
|
504
|
+
);
|
|
505
|
+
return instructions;
|
|
266
506
|
}
|
|
267
|
-
async function
|
|
507
|
+
async function simulateAndGetComputeUnits(connection, transaction) {
|
|
268
508
|
let unitsUsed = 2e5;
|
|
269
509
|
let simulationAttempts = 0;
|
|
270
510
|
simulationLoop: while (true) {
|
|
271
|
-
const response = await connection.simulateTransaction(
|
|
272
|
-
transaction
|
|
273
|
-
);
|
|
511
|
+
const response = await connection.simulateTransaction(transaction);
|
|
274
512
|
if (response.value.err) {
|
|
275
513
|
if (checkKnownSimulationError(response.value)) {
|
|
276
514
|
if (simulationAttempts < 5) {
|
|
@@ -287,7 +525,7 @@ async function createPriorityFeeInstructions(connection, transaction, crossChain
|
|
|
287
525
|
`Simulation failed: ${JSON.stringify(response.value.err)}
|
|
288
526
|
Logs:
|
|
289
527
|
${(response.value.logs || []).join("\n ")}`
|
|
290
|
-
)
|
|
528
|
+
);
|
|
291
529
|
} else {
|
|
292
530
|
if (response.value.unitsConsumed) {
|
|
293
531
|
unitsUsed = response.value.unitsConsumed;
|
|
@@ -295,41 +533,13 @@ ${(response.value.logs || []).join("\n ")}`
|
|
|
295
533
|
break;
|
|
296
534
|
}
|
|
297
535
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
units: unitBudget
|
|
304
|
-
})
|
|
305
|
-
);
|
|
306
|
-
const {
|
|
307
|
-
percentile = 0.9,
|
|
308
|
-
percentileMultiple = 1,
|
|
309
|
-
min = 1e5,
|
|
310
|
-
max = 1e8
|
|
311
|
-
} = crossChainCore?._dappConfig?.solanaConfig?.priorityFeeConfig ?? {};
|
|
312
|
-
const calculateFee = async (rpcProvider2) => {
|
|
313
|
-
if (rpcProvider2 === "triton") {
|
|
314
|
-
try {
|
|
315
|
-
const fee2 = await (0, import_sdk_solana.determinePriorityFeeTritonOne)(
|
|
316
|
-
connection,
|
|
317
|
-
transaction,
|
|
318
|
-
percentile,
|
|
319
|
-
percentileMultiple,
|
|
320
|
-
min,
|
|
321
|
-
max
|
|
322
|
-
);
|
|
323
|
-
return {
|
|
324
|
-
fee: fee2,
|
|
325
|
-
methodUsed: "triton"
|
|
326
|
-
};
|
|
327
|
-
} catch (e) {
|
|
328
|
-
console.warn(`Failed to determine priority fee using Triton RPC:`, e);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
536
|
+
return unitsUsed;
|
|
537
|
+
}
|
|
538
|
+
async function calculatePriorityFee(connection, transaction, rpcProvider, config) {
|
|
539
|
+
const { percentile, percentileMultiple, min, max } = config;
|
|
540
|
+
if (rpcProvider === "triton") {
|
|
331
541
|
try {
|
|
332
|
-
const
|
|
542
|
+
const fee = await (0, import_sdk_solana.determinePriorityFeeTritonOne)(
|
|
333
543
|
connection,
|
|
334
544
|
transaction,
|
|
335
545
|
percentile,
|
|
@@ -337,37 +547,25 @@ ${(response.value.logs || []).join("\n ")}`
|
|
|
337
547
|
min,
|
|
338
548
|
max
|
|
339
549
|
);
|
|
340
|
-
return {
|
|
341
|
-
fee: fee2,
|
|
342
|
-
methodUsed: "default"
|
|
343
|
-
};
|
|
550
|
+
return { fee, methodUsed: "triton" };
|
|
344
551
|
} catch (e) {
|
|
345
552
|
console.warn(`Failed to determine priority fee using Triton RPC:`, e);
|
|
346
|
-
return {
|
|
347
|
-
fee: min,
|
|
348
|
-
methodUsed: "minimum"
|
|
349
|
-
};
|
|
350
553
|
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
});
|
|
367
|
-
instructions.push(
|
|
368
|
-
import_web3.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: fee })
|
|
369
|
-
);
|
|
370
|
-
return instructions;
|
|
554
|
+
}
|
|
555
|
+
try {
|
|
556
|
+
const fee = await (0, import_sdk_solana.determinePriorityFee)(
|
|
557
|
+
connection,
|
|
558
|
+
transaction,
|
|
559
|
+
percentile,
|
|
560
|
+
percentileMultiple,
|
|
561
|
+
min,
|
|
562
|
+
max
|
|
563
|
+
);
|
|
564
|
+
return { fee, methodUsed: "default" };
|
|
565
|
+
} catch (e) {
|
|
566
|
+
console.warn(`Failed to determine priority fee:`, e);
|
|
567
|
+
return { fee: min, methodUsed: "minimum" };
|
|
568
|
+
}
|
|
371
569
|
}
|
|
372
570
|
function checkKnownSimulationError(response) {
|
|
373
571
|
const errors = {};
|
|
@@ -384,154 +582,148 @@ function checkKnownSimulationError(response) {
|
|
|
384
582
|
}
|
|
385
583
|
}
|
|
386
584
|
}
|
|
387
|
-
if (
|
|
585
|
+
if (Object.keys(errors).length === 0) {
|
|
388
586
|
return false;
|
|
389
587
|
}
|
|
390
588
|
console.table(errors);
|
|
391
589
|
return true;
|
|
392
590
|
}
|
|
393
|
-
|
|
394
|
-
return
|
|
591
|
+
function isHostOrSubdomainOf(hostname, base) {
|
|
592
|
+
return hostname === base || hostname.endsWith(`.${base}`);
|
|
395
593
|
}
|
|
396
|
-
var isEmptyObject = (value) => {
|
|
397
|
-
if (value === null || value === void 0) {
|
|
398
|
-
return true;
|
|
399
|
-
}
|
|
400
|
-
for (const key in value) {
|
|
401
|
-
if (value.hasOwnProperty.call(value, key)) {
|
|
402
|
-
return false;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
return true;
|
|
406
|
-
};
|
|
407
594
|
function determineRpcProvider(endpoint) {
|
|
408
595
|
try {
|
|
409
596
|
const url = new URL(endpoint);
|
|
410
597
|
const hostname = url.hostname;
|
|
411
|
-
if (hostname
|
|
598
|
+
if (isHostOrSubdomainOf(hostname, "rpcpool.com") || isHostOrSubdomainOf(hostname, "triton.one")) {
|
|
412
599
|
return "triton";
|
|
413
|
-
} else if (hostname
|
|
600
|
+
} else if (isHostOrSubdomainOf(hostname, "helius-rpc.com") || isHostOrSubdomainOf(hostname, "helius.xyz")) {
|
|
414
601
|
return "helius";
|
|
415
|
-
} else if (hostname
|
|
602
|
+
} else if (isHostOrSubdomainOf(hostname, "ankr.com")) {
|
|
416
603
|
return "ankr";
|
|
417
604
|
} else {
|
|
418
605
|
return "unknown";
|
|
419
606
|
}
|
|
420
|
-
} catch
|
|
607
|
+
} catch {
|
|
421
608
|
return "unknown";
|
|
422
609
|
}
|
|
423
610
|
}
|
|
611
|
+
async function sleep(timeout) {
|
|
612
|
+
return new Promise((resolve) => setTimeout(resolve, timeout));
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// src/providers/wormhole/signers/SolanaSigner.ts
|
|
616
|
+
async function signAndSendTransaction3(request, wallet, options, crossChainCore) {
|
|
617
|
+
if (!wallet || !(wallet instanceof import_derived_wallet_solana.SolanaDerivedWallet)) {
|
|
618
|
+
throw new Error("Invalid wallet type or missing Solana wallet");
|
|
619
|
+
}
|
|
620
|
+
const commitment = options?.commitment ?? crossChainCore?._dappConfig?.solanaConfig?.commitment ?? "finalized";
|
|
621
|
+
const connection = new import_web33.Connection(
|
|
622
|
+
crossChainCore?._dappConfig?.solanaConfig?.rpc ?? crossChainCore?.CHAINS["Solana"]?.defaultRpc ?? "https://api.devnet.solana.com"
|
|
623
|
+
// Last resort fallback
|
|
624
|
+
);
|
|
625
|
+
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash(commitment);
|
|
626
|
+
const unsignedTx = await setPriorityFeeInstructions(
|
|
627
|
+
connection,
|
|
628
|
+
blockhash,
|
|
629
|
+
lastValidBlockHeight,
|
|
630
|
+
request,
|
|
631
|
+
crossChainCore?._dappConfig?.solanaConfig?.priorityFeeConfig
|
|
632
|
+
);
|
|
633
|
+
if (!wallet.solanaWallet.signTransaction) {
|
|
634
|
+
throw new Error("Wallet does not support signing transactions");
|
|
635
|
+
}
|
|
636
|
+
const tx = await wallet.solanaWallet.signTransaction(unsignedTx);
|
|
637
|
+
if (!tx) throw new Error("Failed to sign transaction");
|
|
638
|
+
if (request.transaction.signers && tx instanceof import_web32.Transaction) {
|
|
639
|
+
tx.partialSign(...request.transaction.signers);
|
|
640
|
+
}
|
|
641
|
+
const serializedTx = tx.serialize();
|
|
642
|
+
const signature = await sendAndConfirmTransaction(
|
|
643
|
+
serializedTx,
|
|
644
|
+
blockhash,
|
|
645
|
+
lastValidBlockHeight,
|
|
646
|
+
{
|
|
647
|
+
connection,
|
|
648
|
+
commitment,
|
|
649
|
+
retryIntervalMs: 5e3,
|
|
650
|
+
verbose: false
|
|
651
|
+
}
|
|
652
|
+
);
|
|
653
|
+
return signature;
|
|
654
|
+
}
|
|
655
|
+
async function setPriorityFeeInstructions(connection, blockhash, lastValidBlockHeight, request, priorityFeeConfig) {
|
|
656
|
+
const unsignedTx = request.transaction.transaction;
|
|
657
|
+
unsignedTx.recentBlockhash = blockhash;
|
|
658
|
+
unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
|
|
659
|
+
await addPriorityFeeInstructions(
|
|
660
|
+
connection,
|
|
661
|
+
unsignedTx,
|
|
662
|
+
priorityFeeConfig,
|
|
663
|
+
false
|
|
664
|
+
);
|
|
665
|
+
return unsignedTx;
|
|
666
|
+
}
|
|
424
667
|
|
|
425
668
|
// src/providers/wormhole/signers/EthereumSigner.ts
|
|
426
669
|
var import_ethers = require("ethers");
|
|
427
|
-
async function
|
|
670
|
+
async function signAndSendTransaction4(request, wallet, chainName) {
|
|
428
671
|
if (!wallet) {
|
|
429
|
-
throw new Error("wallet.sendTransaction is undefined")
|
|
672
|
+
throw new Error("wallet.sendTransaction is undefined");
|
|
430
673
|
}
|
|
431
674
|
const chainId = await wallet.eip1193Provider.request({
|
|
432
675
|
method: "eth_chainId"
|
|
433
676
|
});
|
|
434
677
|
const actualChainId = parseInt(chainId, 16);
|
|
435
|
-
if (!actualChainId)
|
|
436
|
-
throw new Error("No signer found for chain" + chainName).message;
|
|
678
|
+
if (!actualChainId) throw new Error("No signer found for chain" + chainName);
|
|
437
679
|
const expectedChainId = request.transaction.chainId ? (0, import_ethers.getBigInt)(request.transaction.chainId) : void 0;
|
|
438
680
|
if (!actualChainId || !expectedChainId || BigInt(actualChainId) !== expectedChainId) {
|
|
439
681
|
throw new Error(
|
|
440
682
|
`Signer is not connected to the right chain. Expected ${expectedChainId}, got ${actualChainId}`
|
|
441
|
-
)
|
|
683
|
+
);
|
|
442
684
|
}
|
|
443
685
|
const provider = new import_ethers.ethers.BrowserProvider(
|
|
444
686
|
wallet.eip1193Provider
|
|
445
687
|
);
|
|
446
688
|
const signer = await provider.getSigner();
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
async function signAndSendTransaction4(request, wallet, sponsorAccount, dappNetwork) {
|
|
457
|
-
if (!wallet) {
|
|
458
|
-
throw new Error("wallet.sendTransaction is undefined").message;
|
|
459
|
-
}
|
|
460
|
-
const payload = request.transaction;
|
|
461
|
-
payload.functionArguments = payload.functionArguments.map((a) => {
|
|
462
|
-
if (a instanceof Uint8Array) {
|
|
463
|
-
return Array.from(a);
|
|
464
|
-
} else if (typeof a === "bigint") {
|
|
465
|
-
return a.toString();
|
|
466
|
-
} else {
|
|
467
|
-
return a;
|
|
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];
|
|
468
698
|
}
|
|
469
|
-
|
|
470
|
-
let aptosConfig;
|
|
471
|
-
const useGasStation = sponsorAccount && !isAccount(sponsorAccount);
|
|
472
|
-
if (useGasStation) {
|
|
473
|
-
const gasStationClient = new import_gas_station_client.GasStationClient({
|
|
474
|
-
network: dappNetwork,
|
|
475
|
-
apiKey: sponsorAccount[dappNetwork]
|
|
476
|
-
});
|
|
477
|
-
const transactionSubmitter = new import_gas_station_client.GasStationTransactionSubmitter(gasStationClient);
|
|
478
|
-
aptosConfig = new import_ts_sdk2.AptosConfig({
|
|
479
|
-
network: dappNetwork,
|
|
480
|
-
pluginSettings: {
|
|
481
|
-
TRANSACTION_SUBMITTER: transactionSubmitter
|
|
482
|
-
}
|
|
483
|
-
});
|
|
484
|
-
} else {
|
|
485
|
-
aptosConfig = new import_ts_sdk2.AptosConfig({
|
|
486
|
-
network: dappNetwork
|
|
487
|
-
});
|
|
488
|
-
}
|
|
489
|
-
const aptos2 = new import_ts_sdk2.Aptos(aptosConfig);
|
|
490
|
-
const functionArguments = extractFunctionArguments(
|
|
491
|
-
payload.functionArguments
|
|
492
|
-
);
|
|
493
|
-
const withdrawFunction = "0x5e2d961f06cd27aa07554a39d55f5ce1e58dff35d803c3529b1cd5c4fa3ab584::withdraw::deposit_for_burn";
|
|
494
|
-
const transactionData = {
|
|
495
|
-
function: withdrawFunction,
|
|
496
|
-
functionArguments
|
|
497
|
-
};
|
|
498
|
-
const txnToSign = await aptos2.transaction.build.simple({
|
|
499
|
-
data: transactionData,
|
|
500
|
-
sender: (await wallet.features["aptos:account"]?.account()).address.toString(),
|
|
501
|
-
withFeePayer: sponsorAccount ? true : false
|
|
502
|
-
});
|
|
503
|
-
const response = await wallet.features["aptos:signTransaction"]?.signTransaction(txnToSign);
|
|
504
|
-
if (response?.status === import_wallet_standard.UserResponseStatus.REJECTED) {
|
|
505
|
-
throw new Error("User has rejected the request");
|
|
699
|
+
throw e;
|
|
506
700
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
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;
|
|
517
726
|
}
|
|
518
|
-
const txnSubmitted = await aptos2.transaction.submit.simple(txnToSubmit);
|
|
519
|
-
const tx = await aptos2.waitForTransaction({
|
|
520
|
-
transactionHash: txnSubmitted.hash
|
|
521
|
-
});
|
|
522
|
-
return tx.hash;
|
|
523
|
-
}
|
|
524
|
-
function extractFunctionArguments(functionArguments) {
|
|
525
|
-
const deserializer1 = new import_ts_sdk2.Deserializer(functionArguments[0].bcsToBytes());
|
|
526
|
-
const amount = deserializer1.deserializeU64();
|
|
527
|
-
const deserializer2 = new import_ts_sdk2.Deserializer(functionArguments[1].bcsToBytes());
|
|
528
|
-
const destination_domain = deserializer2.deserializeU32();
|
|
529
|
-
const mint_recipient = new import_ts_sdk2.AccountAddress(functionArguments[2].bcsToBytes());
|
|
530
|
-
const burn_token = new import_ts_sdk2.AccountAddress(functionArguments[3].bcsToBytes());
|
|
531
|
-
return [amount, destination_domain, mint_recipient, burn_token];
|
|
532
|
-
}
|
|
533
|
-
function isAccount(obj) {
|
|
534
|
-
return "accountAddress" in obj;
|
|
535
727
|
}
|
|
536
728
|
|
|
537
729
|
// src/providers/wormhole/signers/SuiSigner.ts
|
|
@@ -554,14 +746,16 @@ async function signAndSendTransaction5(request, wallet) {
|
|
|
554
746
|
|
|
555
747
|
// src/providers/wormhole/signers/Signer.ts
|
|
556
748
|
var Signer = class {
|
|
557
|
-
constructor(chain, address, options, wallet, crossChainCore, sponsorAccount) {
|
|
749
|
+
constructor(chain, address, options, wallet, crossChainCore, sponsorAccount, onTransactionSigned, trackAsSourceChain = true) {
|
|
750
|
+
this._claimedTransactionHashes = [];
|
|
558
751
|
this._chain = chain;
|
|
559
752
|
this._address = address;
|
|
560
753
|
this._options = options;
|
|
561
754
|
this._wallet = wallet;
|
|
562
755
|
this._crossChainCore = crossChainCore;
|
|
563
756
|
this._sponsorAccount = sponsorAccount;
|
|
564
|
-
this.
|
|
757
|
+
this._onTransactionSigned = onTransactionSigned;
|
|
758
|
+
this._trackAsSourceChain = trackAsSourceChain;
|
|
565
759
|
}
|
|
566
760
|
chain() {
|
|
567
761
|
return this._chain.key;
|
|
@@ -570,11 +764,13 @@ var Signer = class {
|
|
|
570
764
|
return this._address;
|
|
571
765
|
}
|
|
572
766
|
claimedTransactionHashes() {
|
|
573
|
-
return this._claimedTransactionHashes;
|
|
767
|
+
return this._claimedTransactionHashes.join(",");
|
|
574
768
|
}
|
|
575
769
|
async signAndSend(txs) {
|
|
576
770
|
const txHashes = [];
|
|
771
|
+
this._claimedTransactionHashes = [];
|
|
577
772
|
for (const tx of txs) {
|
|
773
|
+
this._onTransactionSigned?.(tx.description, null);
|
|
578
774
|
const txId = await signAndSendTransaction6(
|
|
579
775
|
this._chain,
|
|
580
776
|
tx,
|
|
@@ -583,8 +779,12 @@ var Signer = class {
|
|
|
583
779
|
this._crossChainCore,
|
|
584
780
|
this._sponsorAccount
|
|
585
781
|
);
|
|
782
|
+
if (this._trackAsSourceChain) {
|
|
783
|
+
this._crossChainCore._lastSourceChainTxId = txId;
|
|
784
|
+
}
|
|
785
|
+
this._onTransactionSigned?.(tx.description, txId);
|
|
586
786
|
txHashes.push(txId);
|
|
587
|
-
this._claimedTransactionHashes
|
|
787
|
+
this._claimedTransactionHashes.push(txId);
|
|
588
788
|
}
|
|
589
789
|
return txHashes;
|
|
590
790
|
}
|
|
@@ -595,7 +795,7 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
|
|
|
595
795
|
}
|
|
596
796
|
const dappNetwork = crossChainCore._dappConfig.aptosNetwork;
|
|
597
797
|
if (chain.context === "Solana") {
|
|
598
|
-
const signature = await
|
|
798
|
+
const signature = await signAndSendTransaction3(
|
|
599
799
|
request,
|
|
600
800
|
wallet,
|
|
601
801
|
options,
|
|
@@ -603,11 +803,10 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
|
|
|
603
803
|
);
|
|
604
804
|
return signature;
|
|
605
805
|
} else if (chain.context === "Ethereum") {
|
|
606
|
-
const tx = await
|
|
806
|
+
const tx = await signAndSendTransaction4(
|
|
607
807
|
request,
|
|
608
808
|
wallet,
|
|
609
|
-
chain.displayName
|
|
610
|
-
options
|
|
809
|
+
chain.displayName
|
|
611
810
|
);
|
|
612
811
|
return tx;
|
|
613
812
|
} else if (chain.context === "Sui") {
|
|
@@ -617,11 +816,12 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
|
|
|
617
816
|
);
|
|
618
817
|
return tx;
|
|
619
818
|
} else if (chain.context === "Aptos") {
|
|
620
|
-
const tx = await
|
|
819
|
+
const tx = await signAndSendTransaction2(
|
|
621
820
|
request,
|
|
622
821
|
wallet,
|
|
623
822
|
sponsorAccount,
|
|
624
|
-
dappNetwork
|
|
823
|
+
dappNetwork,
|
|
824
|
+
crossChainCore
|
|
625
825
|
);
|
|
626
826
|
return tx;
|
|
627
827
|
} else {
|
|
@@ -629,6 +829,34 @@ var signAndSendTransaction6 = async (chain, request, wallet, options = {}, cross
|
|
|
629
829
|
}
|
|
630
830
|
};
|
|
631
831
|
|
|
832
|
+
// src/providers/wormhole/utils.ts
|
|
833
|
+
var import_sdk2 = require("@wormhole-foundation/sdk");
|
|
834
|
+
async function createCCTPRoute(wh, sourceChain, destChain, tokens) {
|
|
835
|
+
const sourceToken = import_sdk2.Wormhole.tokenId(
|
|
836
|
+
sourceChain,
|
|
837
|
+
tokens[sourceChain].tokenId.address
|
|
838
|
+
);
|
|
839
|
+
const destToken = import_sdk2.Wormhole.tokenId(
|
|
840
|
+
destChain,
|
|
841
|
+
tokens[destChain].tokenId.address
|
|
842
|
+
);
|
|
843
|
+
const destContext = wh.getPlatform((0, import_sdk2.chainToPlatform)(destChain)).getChain(destChain);
|
|
844
|
+
const sourceContext = wh.getPlatform((0, import_sdk2.chainToPlatform)(sourceChain)).getChain(sourceChain);
|
|
845
|
+
const request = await import_sdk2.routes.RouteTransferRequest.create(
|
|
846
|
+
wh,
|
|
847
|
+
{ source: sourceToken, destination: destToken },
|
|
848
|
+
sourceContext,
|
|
849
|
+
destContext
|
|
850
|
+
);
|
|
851
|
+
const resolver = wh.resolver([import_sdk2.routes.CCTPRoute]);
|
|
852
|
+
const foundRoutes = await resolver.findRoutes(request);
|
|
853
|
+
const cctpRoute = foundRoutes[0];
|
|
854
|
+
if (!cctpRoute || !import_sdk2.routes.isManual(cctpRoute)) {
|
|
855
|
+
throw new Error("Expected manual CCTP route");
|
|
856
|
+
}
|
|
857
|
+
return { route: cctpRoute, request };
|
|
858
|
+
}
|
|
859
|
+
|
|
632
860
|
// src/providers/wormhole/wormhole.ts
|
|
633
861
|
var WormholeProvider = class {
|
|
634
862
|
constructor(core) {
|
|
@@ -647,12 +875,22 @@ var WormholeProvider = class {
|
|
|
647
875
|
}
|
|
648
876
|
const isMainnet = dappNetwork === import_ts_sdk3.Network.MAINNET;
|
|
649
877
|
const platforms = [import_aptos.default, import_solana.default, import_evm.default, import_sui.default];
|
|
650
|
-
const
|
|
651
|
-
const
|
|
878
|
+
const dappConfig = this.crossChainCore._dappConfig;
|
|
879
|
+
const chains = this.crossChainCore.CHAINS;
|
|
880
|
+
const solanaRpc = dappConfig?.solanaConfig?.rpc ?? chains["Solana"]?.defaultRpc;
|
|
881
|
+
const suiRpc = dappConfig?.suiConfig?.rpc ?? chains["Sui"]?.defaultRpc;
|
|
882
|
+
const evmChainsConfig = {};
|
|
883
|
+
for (const name of EVM_CHAIN_NAMES) {
|
|
884
|
+
const rpc = dappConfig?.evmConfig?.[name]?.rpc ?? chains[name]?.defaultRpc;
|
|
885
|
+
if (rpc) {
|
|
886
|
+
evmChainsConfig[name] = { rpc };
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
const wh = await (0, import_sdk3.wormhole)(isMainnet ? "Mainnet" : "Testnet", platforms, {
|
|
652
890
|
chains: {
|
|
653
|
-
Solana: {
|
|
654
|
-
|
|
655
|
-
|
|
891
|
+
...solanaRpc ? { Solana: { rpc: solanaRpc } } : {},
|
|
892
|
+
...suiRpc ? { Sui: { rpc: suiRpc } } : {},
|
|
893
|
+
...evmChainsConfig
|
|
656
894
|
}
|
|
657
895
|
});
|
|
658
896
|
this._wormholeContext = wh;
|
|
@@ -661,33 +899,15 @@ var WormholeProvider = class {
|
|
|
661
899
|
if (!this._wormholeContext) {
|
|
662
900
|
throw new Error("Wormhole context not initialized");
|
|
663
901
|
}
|
|
664
|
-
const {
|
|
665
|
-
sourceChain,
|
|
666
|
-
destinationChain
|
|
667
|
-
);
|
|
668
|
-
const destContext = this._wormholeContext.getPlatform((0, import_sdk.chainToPlatform)(destinationChain)).getChain(destinationChain);
|
|
669
|
-
const sourceContext = this._wormholeContext.getPlatform((0, import_sdk.chainToPlatform)(sourceChain)).getChain(sourceChain);
|
|
670
|
-
logger.log("sourceContext", sourceContext);
|
|
671
|
-
logger.log("sourceToken", sourceToken);
|
|
672
|
-
logger.log("destContext", destContext);
|
|
673
|
-
logger.log("destToken", destToken);
|
|
674
|
-
const request = await import_sdk.routes.RouteTransferRequest.create(
|
|
902
|
+
const { route: cctpRoute, request } = await createCCTPRoute(
|
|
675
903
|
this._wormholeContext,
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
},
|
|
680
|
-
sourceContext,
|
|
681
|
-
destContext
|
|
904
|
+
sourceChain,
|
|
905
|
+
destinationChain,
|
|
906
|
+
this.crossChainCore.TOKENS
|
|
682
907
|
);
|
|
683
|
-
const resolver = this._wormholeContext.resolver([
|
|
684
|
-
import_sdk.routes.CCTPRoute
|
|
685
|
-
// manual CCTP
|
|
686
|
-
]);
|
|
687
|
-
const route = await resolver.findRoutes(request);
|
|
688
|
-
const cctpRoute = route[0];
|
|
689
908
|
this.wormholeRoute = cctpRoute;
|
|
690
909
|
this.wormholeRequest = request;
|
|
910
|
+
this.destinationChain = destinationChain;
|
|
691
911
|
return { route: cctpRoute, request };
|
|
692
912
|
}
|
|
693
913
|
async getQuote(input) {
|
|
@@ -709,19 +929,19 @@ var WormholeProvider = class {
|
|
|
709
929
|
const validated = await route.validate(request, transferParams);
|
|
710
930
|
if (!validated.valid) {
|
|
711
931
|
logger.log("invalid", validated.valid);
|
|
712
|
-
throw new Error(`Invalid quote: ${validated.error}`)
|
|
932
|
+
throw new Error(`Invalid quote: ${validated.error}`);
|
|
713
933
|
}
|
|
714
934
|
const quote = await route.quote(request, validated.params);
|
|
715
935
|
if (!quote.success) {
|
|
716
936
|
logger.log("quote failed", quote.success);
|
|
717
|
-
throw new Error(`Invalid quote: ${quote.error}`)
|
|
937
|
+
throw new Error(`Invalid quote: ${quote.error}`);
|
|
718
938
|
}
|
|
719
939
|
this.wormholeQuote = quote;
|
|
720
940
|
logger.log("quote", quote);
|
|
721
941
|
return quote;
|
|
722
942
|
}
|
|
723
943
|
async submitCCTPTransfer(input) {
|
|
724
|
-
const { sourceChain, wallet, destinationAddress } = input;
|
|
944
|
+
const { sourceChain, wallet, destinationAddress, onTransactionSigned } = input;
|
|
725
945
|
if (!this._wormholeContext) {
|
|
726
946
|
await this.setWormholeContext(sourceChain);
|
|
727
947
|
}
|
|
@@ -747,7 +967,9 @@ var WormholeProvider = class {
|
|
|
747
967
|
signerAddress,
|
|
748
968
|
{},
|
|
749
969
|
wallet,
|
|
750
|
-
this.crossChainCore
|
|
970
|
+
this.crossChainCore,
|
|
971
|
+
void 0,
|
|
972
|
+
onTransactionSigned
|
|
751
973
|
);
|
|
752
974
|
logger.log("signer", signer);
|
|
753
975
|
logger.log("wormholeRequest", this.wormholeRequest);
|
|
@@ -756,16 +978,21 @@ var WormholeProvider = class {
|
|
|
756
978
|
this.wormholeRequest,
|
|
757
979
|
signer,
|
|
758
980
|
this.wormholeQuote,
|
|
759
|
-
|
|
981
|
+
import_sdk3.Wormhole.chainAddress("Aptos", destinationAddress.toString())
|
|
760
982
|
);
|
|
761
983
|
const originChainTxnId = "originTxs" in receipt ? receipt.originTxs[receipt.originTxs.length - 1].txid : void 0;
|
|
762
984
|
return { originChainTxnId: originChainTxnId || "", receipt };
|
|
763
985
|
}
|
|
764
986
|
async claimCCTPTransfer(input) {
|
|
765
|
-
let { receipt, mainSigner, sponsorAccount } = input;
|
|
987
|
+
let { receipt, mainSigner, sponsorAccount, onTransactionSigned } = input;
|
|
766
988
|
if (!this.wormholeRoute) {
|
|
767
989
|
throw new Error("Wormhole route not initialized");
|
|
768
990
|
}
|
|
991
|
+
if (sponsorAccount && !isAccount(sponsorAccount)) {
|
|
992
|
+
throw new Error(
|
|
993
|
+
"AptosLocalSigner does not support GasStationApiKey as a sponsor account. Wormhole claim transactions are script-based and cannot be submitted via the gas station. Please provide an Account instance as the sponsor, or omit the sponsor account."
|
|
994
|
+
);
|
|
995
|
+
}
|
|
769
996
|
logger.log("mainSigner", mainSigner.accountAddress.toString());
|
|
770
997
|
let retries = 0;
|
|
771
998
|
const maxRetries = 5;
|
|
@@ -773,7 +1000,7 @@ var WormholeProvider = class {
|
|
|
773
1000
|
while (retries < maxRetries) {
|
|
774
1001
|
try {
|
|
775
1002
|
for await (receipt of this.wormholeRoute.track(receipt, 120 * 1e3)) {
|
|
776
|
-
if (receipt.state >=
|
|
1003
|
+
if (receipt.state >= import_sdk3.TransferState.SourceInitiated) {
|
|
777
1004
|
logger.log("Receipt is on track ", receipt);
|
|
778
1005
|
try {
|
|
779
1006
|
const signer = new AptosLocalSigner(
|
|
@@ -783,9 +1010,10 @@ var WormholeProvider = class {
|
|
|
783
1010
|
// the account that signs the "claim" transaction
|
|
784
1011
|
sponsorAccount,
|
|
785
1012
|
// the fee payer account
|
|
786
|
-
this.crossChainCore
|
|
1013
|
+
this.crossChainCore,
|
|
1014
|
+
onTransactionSigned
|
|
787
1015
|
);
|
|
788
|
-
if (
|
|
1016
|
+
if (import_sdk3.routes.isManual(this.wormholeRoute)) {
|
|
789
1017
|
const circleAttestationReceipt = await this.wormholeRoute.complete(signer, receipt);
|
|
790
1018
|
logger.log("Claim receipt: ", circleAttestationReceipt);
|
|
791
1019
|
const destinationChainTxnId = signer.claimedTransactionHashes();
|
|
@@ -828,22 +1056,30 @@ var WormholeProvider = class {
|
|
|
828
1056
|
});
|
|
829
1057
|
}
|
|
830
1058
|
let { originChainTxnId, receipt } = await this.submitCCTPTransfer(input);
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
await this.setWormholeContext(sourceChain);
|
|
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
|
|
1072
|
+
);
|
|
846
1073
|
}
|
|
1074
|
+
}
|
|
1075
|
+
// --- Split withdraw flow: initiateWithdraw + trackWithdraw + claimWithdraw ---
|
|
1076
|
+
/**
|
|
1077
|
+
* Phase 1: Initiates a withdraw by burning USDC on Aptos.
|
|
1078
|
+
* The user signs the Aptos burn transaction via their wallet.
|
|
1079
|
+
* Returns a receipt that can be tracked and later claimed.
|
|
1080
|
+
*/
|
|
1081
|
+
async initiateWithdraw(input) {
|
|
1082
|
+
const { wallet, destinationAddress, sponsorAccount, onTransactionSigned } = input;
|
|
847
1083
|
if (!this._wormholeContext) {
|
|
848
1084
|
throw new Error("Wormhole context not initialized");
|
|
849
1085
|
}
|
|
@@ -852,69 +1088,49 @@ var WormholeProvider = class {
|
|
|
852
1088
|
}
|
|
853
1089
|
const signer = new Signer(
|
|
854
1090
|
this.getChainConfig("Aptos"),
|
|
855
|
-
(await
|
|
1091
|
+
(await wallet.features["aptos:account"].account()).address.toString(),
|
|
856
1092
|
{},
|
|
857
|
-
|
|
1093
|
+
wallet,
|
|
858
1094
|
this.crossChainCore,
|
|
859
|
-
sponsorAccount
|
|
1095
|
+
sponsorAccount,
|
|
1096
|
+
onTransactionSigned
|
|
860
1097
|
);
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
logger.log(
|
|
865
|
-
"Wormhole.chainAddress",
|
|
866
|
-
import_sdk.Wormhole.chainAddress(sourceChain, input.destinationAddress.toString())
|
|
1098
|
+
const wormholeDestAddress = import_sdk3.Wormhole.chainAddress(
|
|
1099
|
+
this.destinationChain,
|
|
1100
|
+
destinationAddress.toString()
|
|
867
1101
|
);
|
|
868
|
-
|
|
1102
|
+
const receipt = await this.wormholeRoute.initiate(
|
|
869
1103
|
this.wormholeRequest,
|
|
870
1104
|
signer,
|
|
871
1105
|
this.wormholeQuote,
|
|
872
|
-
|
|
1106
|
+
wormholeDestAddress
|
|
873
1107
|
);
|
|
874
|
-
logger.log("receipt", receipt);
|
|
1108
|
+
logger.log("initiateWithdraw receipt", receipt);
|
|
875
1109
|
const originChainTxnId = "originTxs" in receipt ? receipt.originTxs[receipt.originTxs.length - 1].txid : void 0;
|
|
1110
|
+
return { originChainTxnId: originChainTxnId || "", receipt };
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* Phase 2: Tracks a withdraw receipt until attestation is ready.
|
|
1114
|
+
* This polls Wormhole and returns once the receipt reaches the Attested state.
|
|
1115
|
+
*/
|
|
1116
|
+
async trackWithdraw(receipt) {
|
|
1117
|
+
if (!this.wormholeRoute) {
|
|
1118
|
+
throw new Error("Wormhole route not initialized");
|
|
1119
|
+
}
|
|
876
1120
|
let retries = 0;
|
|
877
1121
|
const maxRetries = 5;
|
|
878
1122
|
const baseDelay = 1e3;
|
|
879
1123
|
while (retries < maxRetries) {
|
|
880
1124
|
try {
|
|
881
1125
|
for await (receipt of this.wormholeRoute.track(receipt, 120 * 1e3)) {
|
|
882
|
-
if (receipt.state >=
|
|
883
|
-
logger.log("
|
|
884
|
-
|
|
885
|
-
const signer2 = new Signer(
|
|
886
|
-
this.getChainConfig(sourceChain),
|
|
887
|
-
destinationAddress.toString(),
|
|
888
|
-
{},
|
|
889
|
-
wallet,
|
|
890
|
-
this.crossChainCore
|
|
891
|
-
);
|
|
892
|
-
if (import_sdk.routes.isManual(this.wormholeRoute)) {
|
|
893
|
-
const circleAttestationReceipt = await this.wormholeRoute.complete(signer2, receipt);
|
|
894
|
-
logger.log("Claim receipt: ", circleAttestationReceipt);
|
|
895
|
-
const destinationChainTxnId = signer2.claimedTransactionHashes();
|
|
896
|
-
return {
|
|
897
|
-
originChainTxnId: originChainTxnId || "",
|
|
898
|
-
destinationChainTxnId
|
|
899
|
-
};
|
|
900
|
-
} else {
|
|
901
|
-
return {
|
|
902
|
-
originChainTxnId: originChainTxnId || "",
|
|
903
|
-
destinationChainTxnId: ""
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
} catch (e) {
|
|
907
|
-
console.error("Failed to claim", e);
|
|
908
|
-
return {
|
|
909
|
-
originChainTxnId: originChainTxnId || "",
|
|
910
|
-
destinationChainTxnId: ""
|
|
911
|
-
};
|
|
912
|
-
}
|
|
1126
|
+
if (receipt.state >= import_sdk3.TransferState.Attested) {
|
|
1127
|
+
logger.log("trackWithdraw: receipt attested", receipt);
|
|
1128
|
+
return receipt;
|
|
913
1129
|
}
|
|
914
1130
|
}
|
|
915
1131
|
} catch (e) {
|
|
916
1132
|
console.error(
|
|
917
|
-
`Error tracking
|
|
1133
|
+
`Error tracking withdraw (attempt ${retries + 1} / ${maxRetries}):`,
|
|
918
1134
|
e
|
|
919
1135
|
);
|
|
920
1136
|
const delay = baseDelay * Math.pow(2, retries);
|
|
@@ -922,10 +1138,173 @@ var WormholeProvider = class {
|
|
|
922
1138
|
retries++;
|
|
923
1139
|
}
|
|
924
1140
|
}
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1141
|
+
throw new Error("Failed to track withdraw to attested state");
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Phase 3: Claims the withdraw on the destination chain.
|
|
1145
|
+
*
|
|
1146
|
+
* If the destination is Solana and `solanaConfig.serverClaimUrl` is configured
|
|
1147
|
+
* in the dapp config, the SDK automatically POSTs the attested receipt to that
|
|
1148
|
+
* URL — no wallet popup required. The dapp's server endpoint handles signing
|
|
1149
|
+
* and submitting the claim transaction.
|
|
1150
|
+
*
|
|
1151
|
+
* Otherwise falls back to the wallet-based Signer (triggers wallet popup).
|
|
1152
|
+
*/
|
|
1153
|
+
async claimWithdraw(input) {
|
|
1154
|
+
const { claimChain, destinationAddress, receipt } = input;
|
|
1155
|
+
const serverClaimUrl = this.crossChainCore._dappConfig?.solanaConfig?.serverClaimUrl;
|
|
1156
|
+
if (claimChain === "Solana" && serverClaimUrl) {
|
|
1157
|
+
logger.log("claimWithdraw: using server-side claim via", serverClaimUrl);
|
|
1158
|
+
const response = await fetch(serverClaimUrl, {
|
|
1159
|
+
method: "POST",
|
|
1160
|
+
headers: { "Content-Type": "application/json" },
|
|
1161
|
+
body: JSON.stringify({
|
|
1162
|
+
receipt: serializeReceipt(receipt),
|
|
1163
|
+
destinationAddress,
|
|
1164
|
+
claimChain
|
|
1165
|
+
})
|
|
1166
|
+
});
|
|
1167
|
+
if (!response.ok) {
|
|
1168
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1169
|
+
throw new Error(
|
|
1170
|
+
errorData.error || `Server-side claim failed with status ${response.status}`
|
|
1171
|
+
);
|
|
1172
|
+
}
|
|
1173
|
+
const result = await response.json();
|
|
1174
|
+
return { destinationChainTxnId: result.destinationChainTxnId };
|
|
1175
|
+
}
|
|
1176
|
+
if (!this.wormholeRoute) {
|
|
1177
|
+
throw new Error("Wormhole route not initialized");
|
|
1178
|
+
}
|
|
1179
|
+
if (!input.wallet) {
|
|
1180
|
+
throw new Error(
|
|
1181
|
+
"Wallet is required for claim when serverClaimUrl is not configured"
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
const claimSigner = new Signer(
|
|
1185
|
+
this.getChainConfig(claimChain),
|
|
1186
|
+
destinationAddress,
|
|
1187
|
+
{},
|
|
1188
|
+
input.wallet,
|
|
1189
|
+
this.crossChainCore,
|
|
1190
|
+
void 0,
|
|
1191
|
+
input.onTransactionSigned,
|
|
1192
|
+
false
|
|
1193
|
+
);
|
|
1194
|
+
if (import_sdk3.routes.isManual(this.wormholeRoute)) {
|
|
1195
|
+
const circleAttestationReceipt = await this.wormholeRoute.complete(
|
|
1196
|
+
claimSigner,
|
|
1197
|
+
receipt
|
|
1198
|
+
);
|
|
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
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Withdraws USDC from Aptos to a destination chain.
|
|
1208
|
+
* Orchestrates all three phases internally:
|
|
1209
|
+
* 1. Initiate — user signs the Aptos burn transaction
|
|
1210
|
+
* 2. Track — wait for Wormhole attestation
|
|
1211
|
+
* 3. Claim — if serverClaimUrl is configured for Solana, delegates to
|
|
1212
|
+
* the server; otherwise uses the wallet-based signer.
|
|
1213
|
+
*
|
|
1214
|
+
* The optional `onPhaseChange` callback lets the dapp update its UI
|
|
1215
|
+
* as the flow progresses.
|
|
1216
|
+
*/
|
|
1217
|
+
async withdraw(input) {
|
|
1218
|
+
const {
|
|
1219
|
+
sourceChain,
|
|
1220
|
+
wallet,
|
|
1221
|
+
destinationAddress,
|
|
1222
|
+
sponsorAccount,
|
|
1223
|
+
onPhaseChange,
|
|
1224
|
+
onTransactionSigned
|
|
1225
|
+
} = input;
|
|
1226
|
+
onPhaseChange?.("initiating");
|
|
1227
|
+
const { originChainTxnId, receipt } = await this.initiateWithdraw({
|
|
1228
|
+
wallet,
|
|
1229
|
+
destinationAddress,
|
|
1230
|
+
sponsorAccount,
|
|
1231
|
+
onTransactionSigned
|
|
1232
|
+
});
|
|
1233
|
+
let currentPhase = "tracking";
|
|
1234
|
+
try {
|
|
1235
|
+
onPhaseChange?.("tracking");
|
|
1236
|
+
const attestedReceipt = await this.trackWithdraw(receipt);
|
|
1237
|
+
currentPhase = "claiming";
|
|
1238
|
+
onPhaseChange?.("claiming");
|
|
1239
|
+
const { destinationChainTxnId } = await this.claimWithdraw({
|
|
1240
|
+
claimChain: sourceChain,
|
|
1241
|
+
destinationAddress: destinationAddress.toString(),
|
|
1242
|
+
receipt: attestedReceipt,
|
|
1243
|
+
wallet,
|
|
1244
|
+
onTransactionSigned
|
|
1245
|
+
});
|
|
1246
|
+
return { originChainTxnId, destinationChainTxnId };
|
|
1247
|
+
} catch (error) {
|
|
1248
|
+
throw new WithdrawError(
|
|
1249
|
+
error?.message ?? "Withdraw failed after Aptos burn",
|
|
1250
|
+
originChainTxnId,
|
|
1251
|
+
currentPhase,
|
|
1252
|
+
error
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Retries a failed `claimWithdraw` call with configurable exponential backoff.
|
|
1258
|
+
*
|
|
1259
|
+
* Use this when the claim phase of a withdrawal fails (e.g., RPC instability,
|
|
1260
|
+
* network congestion) but the Aptos burn transaction has already been submitted.
|
|
1261
|
+
* The attested receipt can be recovered from the `WithdrawError` thrown by
|
|
1262
|
+
* `withdraw()` and passed directly to this method.
|
|
1263
|
+
*
|
|
1264
|
+
* @example
|
|
1265
|
+
* ```ts
|
|
1266
|
+
* try {
|
|
1267
|
+
* await provider.withdraw({ ... });
|
|
1268
|
+
* } catch (error) {
|
|
1269
|
+
* if (error instanceof WithdrawError && error.phase === "claiming") {
|
|
1270
|
+
* const result = await provider.retryWithdrawClaim({
|
|
1271
|
+
* sourceChain,
|
|
1272
|
+
* destinationAddress,
|
|
1273
|
+
* receipt: attestedReceipt,
|
|
1274
|
+
* wallet,
|
|
1275
|
+
* maxRetries: 5,
|
|
1276
|
+
* });
|
|
1277
|
+
* }
|
|
1278
|
+
* }
|
|
1279
|
+
* ```
|
|
1280
|
+
*/
|
|
1281
|
+
async retryWithdrawClaim(input) {
|
|
1282
|
+
const {
|
|
1283
|
+
maxRetries = 5,
|
|
1284
|
+
initialDelayMs = 2e3,
|
|
1285
|
+
backoffMultiplier = 2,
|
|
1286
|
+
...claimInput
|
|
1287
|
+
} = input;
|
|
1288
|
+
let lastError;
|
|
1289
|
+
let delay = initialDelayMs;
|
|
1290
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1291
|
+
try {
|
|
1292
|
+
const result = await this.claimWithdraw(claimInput);
|
|
1293
|
+
return { ...result, retriesUsed: attempt };
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
lastError = error;
|
|
1296
|
+
logger.log(
|
|
1297
|
+
`retryWithdrawClaim: attempt ${attempt + 1}/${maxRetries + 1} failed: ${lastError.message}`
|
|
1298
|
+
);
|
|
1299
|
+
if (attempt < maxRetries) {
|
|
1300
|
+
await (0, import_ts_sdk3.sleep)(delay);
|
|
1301
|
+
delay *= backoffMultiplier;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
throw new Error(
|
|
1306
|
+
`Claim failed after ${maxRetries + 1} attempts: ${lastError?.message}`
|
|
1307
|
+
);
|
|
929
1308
|
}
|
|
930
1309
|
getChainConfig(chain) {
|
|
931
1310
|
const chainConfig = this.crossChainCore.CHAINS[chain];
|
|
@@ -934,16 +1313,122 @@ var WormholeProvider = class {
|
|
|
934
1313
|
}
|
|
935
1314
|
return chainConfig;
|
|
936
1315
|
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1316
|
+
};
|
|
1317
|
+
|
|
1318
|
+
// src/providers/wormhole/signers/SolanaLocalSigner.ts
|
|
1319
|
+
var import_web34 = require("@solana/web3.js");
|
|
1320
|
+
var SolanaLocalSigner = class {
|
|
1321
|
+
constructor(config) {
|
|
1322
|
+
this._claimedTransactionHashes = [];
|
|
1323
|
+
this.keypair = config.keypair;
|
|
1324
|
+
this.connection = config.connection;
|
|
1325
|
+
this.commitment = config.commitment ?? "finalized";
|
|
1326
|
+
this.retryIntervalMs = config.retryIntervalMs ?? 5e3;
|
|
1327
|
+
this.priorityFeeConfig = config.priorityFeeConfig;
|
|
1328
|
+
this.verbose = config.verbose ?? false;
|
|
1329
|
+
this._onTransactionSigned = config.onTransactionSigned;
|
|
1330
|
+
}
|
|
1331
|
+
chain() {
|
|
1332
|
+
return "Solana";
|
|
1333
|
+
}
|
|
1334
|
+
address() {
|
|
1335
|
+
return this.keypair.publicKey.toBase58();
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Returns all transaction hashes from the most recent signAndSend call,
|
|
1339
|
+
* joined by comma. If only one transaction was signed, returns a single hash string.
|
|
1340
|
+
*/
|
|
1341
|
+
claimedTransactionHashes() {
|
|
1342
|
+
return this._claimedTransactionHashes.join(",");
|
|
1343
|
+
}
|
|
1344
|
+
async signAndSend(txs) {
|
|
1345
|
+
const txHashes = [];
|
|
1346
|
+
this._claimedTransactionHashes = [];
|
|
1347
|
+
for (const tx of txs) {
|
|
1348
|
+
this._onTransactionSigned?.(tx.description, null);
|
|
1349
|
+
const txId = await this.signAndSendTransaction(tx);
|
|
1350
|
+
this._onTransactionSigned?.(tx.description, txId);
|
|
1351
|
+
txHashes.push(txId);
|
|
1352
|
+
this._claimedTransactionHashes.push(txId);
|
|
1353
|
+
}
|
|
1354
|
+
return txHashes;
|
|
1355
|
+
}
|
|
1356
|
+
async signAndSendTransaction(request) {
|
|
1357
|
+
const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash(this.commitment);
|
|
1358
|
+
let unsignedTx = request.transaction ?? request;
|
|
1359
|
+
const additionalSigners = request.transaction?.signers;
|
|
1360
|
+
const MAX_UNWRAP_DEPTH = 10;
|
|
1361
|
+
let unwrapDepth = 0;
|
|
1362
|
+
while (unsignedTx && typeof unsignedTx === "object" && "transaction" in unsignedTx && !(unsignedTx instanceof import_web34.Transaction) && !("signatures" in unsignedTx && "message" in unsignedTx)) {
|
|
1363
|
+
if (++unwrapDepth > MAX_UNWRAP_DEPTH) {
|
|
1364
|
+
throw new Error(
|
|
1365
|
+
"Transaction unwrapping exceeded maximum depth \u2014 possible circular nesting"
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
unsignedTx = unsignedTx.transaction;
|
|
1369
|
+
}
|
|
1370
|
+
const isVersioned = unsignedTx.message !== void 0 && unsignedTx.signatures !== void 0 && typeof unsignedTx.message.recentBlockhash !== "undefined";
|
|
1371
|
+
if (isVersioned) {
|
|
1372
|
+
unsignedTx.message.recentBlockhash = blockhash;
|
|
1373
|
+
if (this.verbose || this.priorityFeeConfig) {
|
|
1374
|
+
console.warn(
|
|
1375
|
+
"SolanaLocalSigner: Versioned transaction detected \u2014 priority fees are not applied. Consider using legacy transactions if priority fees are required."
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1378
|
+
unsignedTx.sign([this.keypair]);
|
|
1379
|
+
if (additionalSigners && additionalSigners.length > 0) {
|
|
1380
|
+
unsignedTx.sign(additionalSigners);
|
|
1381
|
+
}
|
|
1382
|
+
} else if (unsignedTx instanceof import_web34.Transaction) {
|
|
1383
|
+
unsignedTx.recentBlockhash = blockhash;
|
|
1384
|
+
unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
|
|
1385
|
+
if (this.priorityFeeConfig) {
|
|
1386
|
+
await addPriorityFeeInstructions(
|
|
1387
|
+
this.connection,
|
|
1388
|
+
unsignedTx,
|
|
1389
|
+
this.priorityFeeConfig,
|
|
1390
|
+
this.verbose
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
if (additionalSigners && additionalSigners.length > 0) {
|
|
1394
|
+
unsignedTx.sign(this.keypair, ...additionalSigners);
|
|
1395
|
+
} else {
|
|
1396
|
+
unsignedTx.sign(this.keypair);
|
|
1397
|
+
}
|
|
1398
|
+
} else if (unsignedTx.recentBlockhash !== void 0 || unsignedTx.feePayer !== void 0) {
|
|
1399
|
+
unsignedTx.recentBlockhash = blockhash;
|
|
1400
|
+
unsignedTx.lastValidBlockHeight = lastValidBlockHeight;
|
|
1401
|
+
if (this.priorityFeeConfig) {
|
|
1402
|
+
await addPriorityFeeInstructions(
|
|
1403
|
+
this.connection,
|
|
1404
|
+
unsignedTx,
|
|
1405
|
+
this.priorityFeeConfig,
|
|
1406
|
+
this.verbose
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
if (additionalSigners && additionalSigners.length > 0) {
|
|
1410
|
+
unsignedTx.sign(this.keypair, ...additionalSigners);
|
|
1411
|
+
} else {
|
|
1412
|
+
unsignedTx.sign(this.keypair);
|
|
1413
|
+
}
|
|
1414
|
+
} else {
|
|
1415
|
+
throw new Error(
|
|
1416
|
+
`Unsupported transaction type: ${unsignedTx?.constructor?.name}`
|
|
1417
|
+
);
|
|
1418
|
+
}
|
|
1419
|
+
const serializedTx = unsignedTx.serialize();
|
|
1420
|
+
const signature = await sendAndConfirmTransaction(
|
|
1421
|
+
serializedTx,
|
|
1422
|
+
blockhash,
|
|
1423
|
+
lastValidBlockHeight,
|
|
1424
|
+
{
|
|
1425
|
+
connection: this.connection,
|
|
1426
|
+
commitment: this.commitment,
|
|
1427
|
+
retryIntervalMs: this.retryIntervalMs,
|
|
1428
|
+
verbose: this.verbose
|
|
1429
|
+
}
|
|
945
1430
|
);
|
|
946
|
-
return
|
|
1431
|
+
return signature;
|
|
947
1432
|
}
|
|
948
1433
|
};
|
|
949
1434
|
|
|
@@ -1017,8 +1502,8 @@ var testnetChains = {
|
|
|
1017
1502
|
key: "Solana",
|
|
1018
1503
|
context: "Solana" /* SOLANA */,
|
|
1019
1504
|
displayName: "Solana",
|
|
1020
|
-
explorerUrl: "https://
|
|
1021
|
-
explorerName: "
|
|
1505
|
+
explorerUrl: "https://solscan.io",
|
|
1506
|
+
explorerName: "Solscan",
|
|
1022
1507
|
chainId: 0,
|
|
1023
1508
|
icon: "Solana",
|
|
1024
1509
|
symbol: "SOL",
|
|
@@ -1141,8 +1626,8 @@ var mainnetChains = {
|
|
|
1141
1626
|
key: "Solana",
|
|
1142
1627
|
context: "Solana" /* SOLANA */,
|
|
1143
1628
|
displayName: "Solana",
|
|
1144
|
-
explorerUrl: "https://
|
|
1145
|
-
explorerName: "
|
|
1629
|
+
explorerUrl: "https://solscan.io",
|
|
1630
|
+
explorerName: "Solscan",
|
|
1146
1631
|
chainId: 0,
|
|
1147
1632
|
icon: "Solana",
|
|
1148
1633
|
symbol: "SOL",
|
|
@@ -1294,15 +1779,15 @@ var mainnetTokens = {
|
|
|
1294
1779
|
|
|
1295
1780
|
// src/utils/getUsdcBalance.ts
|
|
1296
1781
|
var import_ts_sdk4 = require("@aptos-labs/ts-sdk");
|
|
1297
|
-
var
|
|
1782
|
+
var import_web35 = require("@solana/web3.js");
|
|
1298
1783
|
var import_ethers2 = require("ethers");
|
|
1299
1784
|
var import_client = require("@mysten/sui/client");
|
|
1300
1785
|
var getSolanaWalletUSDCBalance = async (walletAddress, aptosNetwork, rpc) => {
|
|
1301
|
-
const address = new
|
|
1786
|
+
const address = new import_web35.PublicKey(walletAddress);
|
|
1302
1787
|
const tokenAddress = aptosNetwork === import_ts_sdk4.Network.MAINNET ? mainnetTokens["Solana"].tokenId.address : testnetTokens["Solana"].tokenId.address;
|
|
1303
|
-
const connection = new
|
|
1788
|
+
const connection = new import_web35.Connection(rpc);
|
|
1304
1789
|
const splToken = await connection.getTokenAccountsByOwner(address, {
|
|
1305
|
-
mint: new
|
|
1790
|
+
mint: new import_web35.PublicKey(tokenAddress)
|
|
1306
1791
|
});
|
|
1307
1792
|
if (splToken.value.length === 0) {
|
|
1308
1793
|
return "0";
|
|
@@ -1353,6 +1838,18 @@ var getSuiWalletUSDCBalance = async (walletAddress, aptosNetwork, rpc) => {
|
|
|
1353
1838
|
|
|
1354
1839
|
// src/CrossChainCore.ts
|
|
1355
1840
|
var import_ts_sdk6 = require("@aptos-labs/ts-sdk");
|
|
1841
|
+
var _evmChainRecord = {
|
|
1842
|
+
Ethereum: true,
|
|
1843
|
+
Sepolia: true,
|
|
1844
|
+
BaseSepolia: true,
|
|
1845
|
+
ArbitrumSepolia: true,
|
|
1846
|
+
Avalanche: true,
|
|
1847
|
+
Base: true,
|
|
1848
|
+
Arbitrum: true,
|
|
1849
|
+
PolygonSepolia: true,
|
|
1850
|
+
Polygon: true
|
|
1851
|
+
};
|
|
1852
|
+
var EVM_CHAIN_NAMES = Object.keys(_evmChainRecord);
|
|
1356
1853
|
var EthereumChainIdToTestnetChain = {
|
|
1357
1854
|
11155111: testnetChains.Sepolia,
|
|
1358
1855
|
84532: testnetChains.BaseSepolia,
|
|
@@ -1367,7 +1864,7 @@ var EthereumChainIdToMainnetChain = {
|
|
|
1367
1864
|
43114: mainnetChains.Avalanche,
|
|
1368
1865
|
137: mainnetChains.Polygon
|
|
1369
1866
|
};
|
|
1370
|
-
var
|
|
1867
|
+
var CrossChainCore2 = class {
|
|
1371
1868
|
constructor(args) {
|
|
1372
1869
|
this._dappConfig = {
|
|
1373
1870
|
aptosNetwork: import_ts_sdk5.Network.TESTNET
|
|
@@ -1421,14 +1918,13 @@ var CrossChainCore = class {
|
|
|
1421
1918
|
walletAddress,
|
|
1422
1919
|
this._dappConfig.aptosNetwork,
|
|
1423
1920
|
sourceChain,
|
|
1424
|
-
|
|
1425
|
-
this.CHAINS[sourceChain].defaultRpc
|
|
1921
|
+
this._dappConfig?.evmConfig?.[sourceChain]?.rpc ?? this.CHAINS[sourceChain].defaultRpc
|
|
1426
1922
|
);
|
|
1427
1923
|
case "Sui":
|
|
1428
1924
|
return await getSuiWalletUSDCBalance(
|
|
1429
1925
|
walletAddress,
|
|
1430
1926
|
this._dappConfig.aptosNetwork,
|
|
1431
|
-
this.CHAINS[sourceChain].defaultRpc
|
|
1927
|
+
this._dappConfig?.suiConfig?.rpc ?? this.CHAINS[sourceChain].defaultRpc
|
|
1432
1928
|
);
|
|
1433
1929
|
default:
|
|
1434
1930
|
throw new Error(`Unsupported chain: ${sourceChain}`);
|
|
@@ -1443,16 +1939,24 @@ var import_ts_sdk7 = require("@aptos-labs/ts-sdk");
|
|
|
1443
1939
|
AptosLocalSigner,
|
|
1444
1940
|
Context,
|
|
1445
1941
|
CrossChainCore,
|
|
1942
|
+
EVM_CHAIN_NAMES,
|
|
1446
1943
|
EthereumChainIdToMainnetChain,
|
|
1447
1944
|
EthereumChainIdToTestnetChain,
|
|
1448
1945
|
Network,
|
|
1449
1946
|
NetworkToChainId,
|
|
1450
1947
|
NetworkToNodeAPI,
|
|
1948
|
+
SolanaLocalSigner,
|
|
1949
|
+
TransferError,
|
|
1950
|
+
WithdrawError,
|
|
1451
1951
|
WormholeProvider,
|
|
1952
|
+
createCCTPRoute,
|
|
1953
|
+
deserializeReceipt,
|
|
1452
1954
|
mainnetChains,
|
|
1453
1955
|
mainnetTokens,
|
|
1956
|
+
serializeReceipt,
|
|
1454
1957
|
signAndSendTransaction,
|
|
1455
1958
|
testnetChains,
|
|
1456
|
-
testnetTokens
|
|
1959
|
+
testnetTokens,
|
|
1960
|
+
validateExpireTimestamp
|
|
1457
1961
|
});
|
|
1458
1962
|
//# sourceMappingURL=index.js.map
|