@agglayer/sdk 0.1.0-beta.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 +136 -0
- package/dist/index.d.mts +803 -0
- package/dist/index.d.ts +803 -0
- package/dist/index.js +1863 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1842 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +78 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1863 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AggLayerSDK: () => AggLayerSDK,
|
|
24
|
+
SDK_MODES: () => SDK_MODES
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/native/chains/registry.ts
|
|
29
|
+
var ChainRegistry = class _ChainRegistry {
|
|
30
|
+
constructor() {
|
|
31
|
+
this.chains = /* @__PURE__ */ new Map();
|
|
32
|
+
this.viemChains = /* @__PURE__ */ new Map();
|
|
33
|
+
this.initializeDefaultChains();
|
|
34
|
+
}
|
|
35
|
+
static getInstance() {
|
|
36
|
+
if (!_ChainRegistry.instance) {
|
|
37
|
+
_ChainRegistry.instance = new _ChainRegistry();
|
|
38
|
+
}
|
|
39
|
+
return _ChainRegistry.instance;
|
|
40
|
+
}
|
|
41
|
+
initializeDefaultChains() {
|
|
42
|
+
this.registerChain({
|
|
43
|
+
chainId: 11155111,
|
|
44
|
+
networkId: 0,
|
|
45
|
+
name: "Ethereum Sepolia",
|
|
46
|
+
rpcUrl: "https://rpc.sepolia.org",
|
|
47
|
+
nativeCurrency: { name: "Sepolia Ether", symbol: "ETH", decimals: 18 },
|
|
48
|
+
blockExplorer: {
|
|
49
|
+
name: "Sepolia Etherscan",
|
|
50
|
+
url: "https://sepolia.etherscan.io"
|
|
51
|
+
},
|
|
52
|
+
bridgeAddress: "0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582",
|
|
53
|
+
proofApiUrl: "https://api-gateway.polygon.technology/api/v3/proof/testnet/",
|
|
54
|
+
isTestnet: true
|
|
55
|
+
});
|
|
56
|
+
this.registerChain({
|
|
57
|
+
chainId: 2442,
|
|
58
|
+
networkId: 1,
|
|
59
|
+
name: "Polygon Cardona",
|
|
60
|
+
rpcUrl: "https://rpc.cardona.zkevm-rpc.com",
|
|
61
|
+
nativeCurrency: { name: "Ethereum", symbol: "ETH", decimals: 18 },
|
|
62
|
+
blockExplorer: {
|
|
63
|
+
name: "Cardona PolygonScan",
|
|
64
|
+
url: "https://cardona-zkevm.polygonscan.com"
|
|
65
|
+
},
|
|
66
|
+
bridgeAddress: "0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582",
|
|
67
|
+
proofApiUrl: "https://api-gateway.polygon.technology/api/v3/proof/testnet/",
|
|
68
|
+
isTestnet: true
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Register a new chain
|
|
73
|
+
*/
|
|
74
|
+
registerChain(config) {
|
|
75
|
+
this.chains.set(config.chainId, config);
|
|
76
|
+
const viemChain = {
|
|
77
|
+
id: config.chainId,
|
|
78
|
+
name: config.name,
|
|
79
|
+
nativeCurrency: config.nativeCurrency,
|
|
80
|
+
rpcUrls: {
|
|
81
|
+
default: { http: [config.rpcUrl] }
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
this.viemChains.set(config.chainId, viemChain);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get chain configuration by ID
|
|
88
|
+
*/
|
|
89
|
+
getChain(chainId) {
|
|
90
|
+
const chain = this.chains.get(chainId);
|
|
91
|
+
if (!chain) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`Chain ${chainId} not found. Available chains: ${Array.from(this.chains.keys()).join(", ")}`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
return chain;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get chain configuration by network ID
|
|
100
|
+
*/
|
|
101
|
+
getChainByNetworkId(networkId) {
|
|
102
|
+
const chain = Array.from(this.chains.values()).find(
|
|
103
|
+
(chain2) => chain2.networkId === networkId
|
|
104
|
+
);
|
|
105
|
+
if (!chain) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
`Chain with network ID ${networkId} not found. Available network IDs: ${Array.from(
|
|
108
|
+
this.chains.values()
|
|
109
|
+
).map((chain2) => chain2.networkId).filter(Boolean).join(", ")}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
return chain;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get viem chain object by ID
|
|
116
|
+
*/
|
|
117
|
+
getViemChain(chainId) {
|
|
118
|
+
const chain = this.viemChains.get(chainId);
|
|
119
|
+
if (!chain) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
`Chain ${chainId} not found. Available chains: ${Array.from(this.viemChains.keys()).join(", ")}`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
return chain;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get all registered chain IDs
|
|
128
|
+
*/
|
|
129
|
+
getSupportedChainIds() {
|
|
130
|
+
return Array.from(this.chains.keys());
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get all registered chains
|
|
134
|
+
*/
|
|
135
|
+
getAllChains() {
|
|
136
|
+
return Array.from(this.chains.values());
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Check if chain is supported
|
|
140
|
+
*/
|
|
141
|
+
isChainSupported(chainId) {
|
|
142
|
+
return this.chains.has(chainId);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Check if chain is supported by network ID
|
|
146
|
+
*/
|
|
147
|
+
isChainSupportedByNetworkId(networkId) {
|
|
148
|
+
return Array.from(this.chains.values()).some(
|
|
149
|
+
(chain) => chain.networkId === networkId
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Get chains by type
|
|
154
|
+
*/
|
|
155
|
+
getChainsByType(type) {
|
|
156
|
+
return Array.from(this.chains.values()).filter((chain) => {
|
|
157
|
+
if (type === "mainnet") {
|
|
158
|
+
return !chain.isTestnet && !chain.isLocal;
|
|
159
|
+
}
|
|
160
|
+
if (type === "testnet") {
|
|
161
|
+
return chain.isTestnet;
|
|
162
|
+
}
|
|
163
|
+
if (type === "local") {
|
|
164
|
+
return chain.isLocal;
|
|
165
|
+
}
|
|
166
|
+
return false;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Add custom RPC URL for existing chain
|
|
171
|
+
*/
|
|
172
|
+
addCustomRpcUrl(chainId, rpcUrl) {
|
|
173
|
+
const chain = this.getChain(chainId);
|
|
174
|
+
const customChain = {
|
|
175
|
+
...chain,
|
|
176
|
+
rpcUrl
|
|
177
|
+
};
|
|
178
|
+
this.registerChain(customChain);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
var chainRegistry = ChainRegistry.getInstance();
|
|
182
|
+
|
|
183
|
+
// src/native/utils/validation.ts
|
|
184
|
+
var ValidationUtils = class {
|
|
185
|
+
/**
|
|
186
|
+
* Convert value to BigInt safely
|
|
187
|
+
*/
|
|
188
|
+
static toBigInt(value) {
|
|
189
|
+
return BigInt(value.toString());
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Validate Ethereum address format
|
|
193
|
+
*/
|
|
194
|
+
static validateAddress(address, name = "Address") {
|
|
195
|
+
if (!address || !address.startsWith("0x") || address.length !== 42) {
|
|
196
|
+
throw new Error(`${name} must be a valid 0x-prefixed address`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Validate amount (must be positive)
|
|
201
|
+
*/
|
|
202
|
+
static validateAmount(amount, name = "Amount") {
|
|
203
|
+
const amountStr = amount.toString();
|
|
204
|
+
if (!amountStr || amountStr === "0" || this.toBigInt(amount) <= 0n) {
|
|
205
|
+
throw new Error(`${name} must be a positive value`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Check if address is valid without throwing
|
|
210
|
+
*/
|
|
211
|
+
static isValidAddress(address) {
|
|
212
|
+
return Boolean(address) && address.startsWith("0x") && address.length === 42;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Check if amount is valid without throwing
|
|
216
|
+
*/
|
|
217
|
+
static isValidAmount(amount) {
|
|
218
|
+
try {
|
|
219
|
+
const amountStr = amount.toString();
|
|
220
|
+
return Boolean(amountStr) && amountStr !== "0" && this.toBigInt(amount) > 0n;
|
|
221
|
+
} catch {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Validate chain ID
|
|
227
|
+
*/
|
|
228
|
+
static validateChainId(chainId) {
|
|
229
|
+
if (!Number.isInteger(chainId) || chainId <= 0) {
|
|
230
|
+
throw new Error("Chain ID must be a positive integer");
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Validate RPC URL
|
|
235
|
+
*/
|
|
236
|
+
static validateRpcUrl(rpcUrl) {
|
|
237
|
+
if (!rpcUrl || !rpcUrl.startsWith("http")) {
|
|
238
|
+
throw new Error("RPC URL must be a valid HTTP/HTTPS URL");
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// src/native/base/contract.ts
|
|
244
|
+
var import_viem = require("viem");
|
|
245
|
+
var BaseContract = class {
|
|
246
|
+
constructor(config) {
|
|
247
|
+
const chain = chainRegistry.getViemChain(config.chainId);
|
|
248
|
+
this.client = (0, import_viem.createPublicClient)({
|
|
249
|
+
chain,
|
|
250
|
+
transport: (0, import_viem.http)(config.rpcUrl)
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get nonce for an address
|
|
255
|
+
*/
|
|
256
|
+
async getNonce(address) {
|
|
257
|
+
if (!address) return void 0;
|
|
258
|
+
const nonceValue = await this.client.getTransactionCount({
|
|
259
|
+
address
|
|
260
|
+
});
|
|
261
|
+
return `0x${nonceValue.toString(16)}`;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Estimate gas for transaction
|
|
265
|
+
*/
|
|
266
|
+
async estimateGas(data, to, from) {
|
|
267
|
+
const gasEstimate = await this.client.estimateGas({
|
|
268
|
+
account: from,
|
|
269
|
+
to,
|
|
270
|
+
data
|
|
271
|
+
});
|
|
272
|
+
return gasEstimate.toString();
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// src/native/tokens/build.ts
|
|
277
|
+
var import_viem2 = require("viem");
|
|
278
|
+
|
|
279
|
+
// src/native/tokens/abi/erc20.ts
|
|
280
|
+
var erc20Abi = [
|
|
281
|
+
// Standard ERC20 functions
|
|
282
|
+
{
|
|
283
|
+
name: "approve",
|
|
284
|
+
type: "function",
|
|
285
|
+
stateMutability: "nonpayable",
|
|
286
|
+
inputs: [
|
|
287
|
+
{ name: "spender", type: "address" },
|
|
288
|
+
{ name: "amount", type: "uint256" }
|
|
289
|
+
],
|
|
290
|
+
outputs: [{ name: "", type: "bool" }]
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
name: "transfer",
|
|
294
|
+
type: "function",
|
|
295
|
+
stateMutability: "nonpayable",
|
|
296
|
+
inputs: [
|
|
297
|
+
{ name: "to", type: "address" },
|
|
298
|
+
{ name: "amount", type: "uint256" }
|
|
299
|
+
],
|
|
300
|
+
outputs: [{ name: "", type: "bool" }]
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: "transferFrom",
|
|
304
|
+
type: "function",
|
|
305
|
+
stateMutability: "nonpayable",
|
|
306
|
+
inputs: [
|
|
307
|
+
{ name: "from", type: "address" },
|
|
308
|
+
{ name: "to", type: "address" },
|
|
309
|
+
{ name: "amount", type: "uint256" }
|
|
310
|
+
],
|
|
311
|
+
outputs: [{ name: "", type: "bool" }]
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
name: "allowance",
|
|
315
|
+
type: "function",
|
|
316
|
+
stateMutability: "view",
|
|
317
|
+
inputs: [
|
|
318
|
+
{ name: "owner", type: "address" },
|
|
319
|
+
{ name: "spender", type: "address" }
|
|
320
|
+
],
|
|
321
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
name: "balanceOf",
|
|
325
|
+
type: "function",
|
|
326
|
+
stateMutability: "view",
|
|
327
|
+
inputs: [{ name: "account", type: "address" }],
|
|
328
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
329
|
+
},
|
|
330
|
+
// Additional ERC20 functions
|
|
331
|
+
{
|
|
332
|
+
name: "name",
|
|
333
|
+
type: "function",
|
|
334
|
+
stateMutability: "view",
|
|
335
|
+
inputs: [],
|
|
336
|
+
outputs: [{ name: "", type: "string" }]
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
name: "symbol",
|
|
340
|
+
type: "function",
|
|
341
|
+
stateMutability: "view",
|
|
342
|
+
inputs: [],
|
|
343
|
+
outputs: [{ name: "", type: "string" }]
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
name: "decimals",
|
|
347
|
+
type: "function",
|
|
348
|
+
stateMutability: "view",
|
|
349
|
+
inputs: [],
|
|
350
|
+
outputs: [{ name: "", type: "uint8" }]
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
name: "totalSupply",
|
|
354
|
+
type: "function",
|
|
355
|
+
stateMutability: "view",
|
|
356
|
+
inputs: [],
|
|
357
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
358
|
+
},
|
|
359
|
+
// Events
|
|
360
|
+
{
|
|
361
|
+
name: "Transfer",
|
|
362
|
+
type: "event",
|
|
363
|
+
inputs: [
|
|
364
|
+
{ name: "from", type: "address", indexed: true },
|
|
365
|
+
{ name: "to", type: "address", indexed: true },
|
|
366
|
+
{ name: "value", type: "uint256", indexed: false }
|
|
367
|
+
]
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
name: "Approval",
|
|
371
|
+
type: "event",
|
|
372
|
+
inputs: [
|
|
373
|
+
{ name: "owner", type: "address", indexed: true },
|
|
374
|
+
{ name: "spender", type: "address", indexed: true },
|
|
375
|
+
{ name: "value", type: "uint256", indexed: false }
|
|
376
|
+
]
|
|
377
|
+
}
|
|
378
|
+
];
|
|
379
|
+
|
|
380
|
+
// src/native/tokens/build.ts
|
|
381
|
+
async function buildApprove(ctx, spender, amount, from) {
|
|
382
|
+
const data = (0, import_viem2.encodeFunctionData)({
|
|
383
|
+
abi: erc20Abi,
|
|
384
|
+
functionName: "approve",
|
|
385
|
+
args: [spender, amount]
|
|
386
|
+
});
|
|
387
|
+
const [nonce, gas] = await Promise.all([
|
|
388
|
+
ctx.getNonce(from),
|
|
389
|
+
ctx.estimateGas(data, from)
|
|
390
|
+
]);
|
|
391
|
+
return {
|
|
392
|
+
from,
|
|
393
|
+
to: ctx.tokenAddress,
|
|
394
|
+
data,
|
|
395
|
+
gas,
|
|
396
|
+
nonce
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
async function buildTransfer(ctx, to, amount, from) {
|
|
400
|
+
const data = (0, import_viem2.encodeFunctionData)({
|
|
401
|
+
abi: erc20Abi,
|
|
402
|
+
functionName: "transfer",
|
|
403
|
+
args: [to, amount]
|
|
404
|
+
});
|
|
405
|
+
const [nonce, gas] = await Promise.all([
|
|
406
|
+
ctx.getNonce(from),
|
|
407
|
+
ctx.estimateGas(data, from)
|
|
408
|
+
]);
|
|
409
|
+
return {
|
|
410
|
+
from,
|
|
411
|
+
to: ctx.tokenAddress,
|
|
412
|
+
data,
|
|
413
|
+
gas,
|
|
414
|
+
nonce
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
async function buildTransferFrom(ctx, fromAddress, to, amount, spender) {
|
|
418
|
+
const data = (0, import_viem2.encodeFunctionData)({
|
|
419
|
+
abi: erc20Abi,
|
|
420
|
+
functionName: "transferFrom",
|
|
421
|
+
args: [fromAddress, to, amount]
|
|
422
|
+
});
|
|
423
|
+
const [nonce, gas] = await Promise.all([
|
|
424
|
+
ctx.getNonce(spender),
|
|
425
|
+
ctx.estimateGas(data, spender)
|
|
426
|
+
]);
|
|
427
|
+
return {
|
|
428
|
+
from: spender,
|
|
429
|
+
to: ctx.tokenAddress,
|
|
430
|
+
data,
|
|
431
|
+
gas,
|
|
432
|
+
nonce
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/native/bridge/build.ts
|
|
437
|
+
var import_viem3 = require("viem");
|
|
438
|
+
|
|
439
|
+
// src/native/bridge/abi/bridge.ts
|
|
440
|
+
var bridgeAbi = [
|
|
441
|
+
{
|
|
442
|
+
inputs: [
|
|
443
|
+
{ internalType: "uint32", name: "destinationNetwork", type: "uint32" },
|
|
444
|
+
{ internalType: "address", name: "destinationAddress", type: "address" },
|
|
445
|
+
{ internalType: "uint256", name: "amount", type: "uint256" },
|
|
446
|
+
{ internalType: "address", name: "token", type: "address" },
|
|
447
|
+
{ internalType: "bool", name: "forceUpdateGlobalExitRoot", type: "bool" },
|
|
448
|
+
{ internalType: "bytes", name: "permitData", type: "bytes" }
|
|
449
|
+
],
|
|
450
|
+
name: "bridgeAsset",
|
|
451
|
+
outputs: [],
|
|
452
|
+
stateMutability: "payable",
|
|
453
|
+
type: "function"
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
inputs: [
|
|
457
|
+
{
|
|
458
|
+
internalType: "bytes32[32]",
|
|
459
|
+
name: "smtProofLocalExitRoot",
|
|
460
|
+
type: "bytes32[32]"
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
internalType: "bytes32[32]",
|
|
464
|
+
name: "smtProofRollupExitRoot",
|
|
465
|
+
type: "bytes32[32]"
|
|
466
|
+
},
|
|
467
|
+
{ internalType: "uint256", name: "globalIndex", type: "uint256" },
|
|
468
|
+
{ internalType: "bytes32", name: "mainnetExitRoot", type: "bytes32" },
|
|
469
|
+
{ internalType: "bytes32", name: "rollupExitRoot", type: "bytes32" },
|
|
470
|
+
{ internalType: "uint32", name: "originNetwork", type: "uint32" },
|
|
471
|
+
{ internalType: "address", name: "originTokenAddress", type: "address" },
|
|
472
|
+
{ internalType: "uint32", name: "destinationNetwork", type: "uint32" },
|
|
473
|
+
{ internalType: "address", name: "destinationAddress", type: "address" },
|
|
474
|
+
{ internalType: "uint256", name: "amount", type: "uint256" },
|
|
475
|
+
{ internalType: "bytes", name: "metadata", type: "bytes" }
|
|
476
|
+
],
|
|
477
|
+
name: "claimAsset",
|
|
478
|
+
outputs: [],
|
|
479
|
+
stateMutability: "nonpayable",
|
|
480
|
+
type: "function"
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
inputs: [
|
|
484
|
+
{ internalType: "uint32", name: "leafIndex", type: "uint32" },
|
|
485
|
+
{ internalType: "uint32", name: "sourceBridgeNetwork", type: "uint32" }
|
|
486
|
+
],
|
|
487
|
+
name: "isClaimed",
|
|
488
|
+
outputs: [{ internalType: "bool", name: "", type: "bool" }],
|
|
489
|
+
stateMutability: "view",
|
|
490
|
+
type: "function"
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
inputs: [
|
|
494
|
+
{ internalType: "uint32", name: "originNetwork", type: "uint32" },
|
|
495
|
+
{ internalType: "address", name: "originTokenAddress", type: "address" }
|
|
496
|
+
],
|
|
497
|
+
name: "getTokenWrappedAddress",
|
|
498
|
+
outputs: [{ internalType: "address", name: "", type: "address" }],
|
|
499
|
+
stateMutability: "view",
|
|
500
|
+
type: "function"
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
inputs: [
|
|
504
|
+
{ internalType: "uint32", name: "destinationNetwork", type: "uint32" },
|
|
505
|
+
{ internalType: "address", name: "destinationAddress", type: "address" },
|
|
506
|
+
{ internalType: "bool", name: "forceUpdateGlobalExitRoot", type: "bool" },
|
|
507
|
+
{ internalType: "bytes", name: "permitData", type: "bytes" }
|
|
508
|
+
],
|
|
509
|
+
name: "bridgeMessage",
|
|
510
|
+
outputs: [],
|
|
511
|
+
stateMutability: "payable",
|
|
512
|
+
type: "function"
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
inputs: [
|
|
516
|
+
{
|
|
517
|
+
internalType: "bytes32[32]",
|
|
518
|
+
name: "smtProofLocalExitRoot",
|
|
519
|
+
type: "bytes32[32]"
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
internalType: "bytes32[32]",
|
|
523
|
+
name: "smtProofRollupExitRoot",
|
|
524
|
+
type: "bytes32[32]"
|
|
525
|
+
},
|
|
526
|
+
{ internalType: "uint256", name: "globalIndex", type: "uint256" },
|
|
527
|
+
{ internalType: "bytes32", name: "mainnetExitRoot", type: "bytes32" },
|
|
528
|
+
{ internalType: "bytes32", name: "rollupExitRoot", type: "bytes32" },
|
|
529
|
+
{ internalType: "uint32", name: "originNetwork", type: "uint32" },
|
|
530
|
+
{ internalType: "address", name: "originTokenAddress", type: "address" },
|
|
531
|
+
{ internalType: "uint32", name: "destinationNetwork", type: "uint32" },
|
|
532
|
+
{ internalType: "address", name: "destinationAddress", type: "address" },
|
|
533
|
+
{ internalType: "uint256", name: "amount", type: "uint256" },
|
|
534
|
+
{ internalType: "bytes", name: "metadata", type: "bytes" }
|
|
535
|
+
],
|
|
536
|
+
name: "claimMessage",
|
|
537
|
+
outputs: [],
|
|
538
|
+
stateMutability: "nonpayable",
|
|
539
|
+
type: "function"
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
inputs: [
|
|
543
|
+
{ internalType: "uint32", name: "originNetwork", type: "uint32" },
|
|
544
|
+
{ internalType: "address", name: "originTokenAddress", type: "address" }
|
|
545
|
+
],
|
|
546
|
+
name: "precalculatedWrapperAddress",
|
|
547
|
+
outputs: [{ internalType: "address", name: "", type: "address" }],
|
|
548
|
+
stateMutability: "view",
|
|
549
|
+
type: "function"
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
inputs: [
|
|
553
|
+
{ internalType: "address", name: "wrappedToken", type: "address" }
|
|
554
|
+
],
|
|
555
|
+
name: "wrappedTokenToTokenInfo",
|
|
556
|
+
outputs: [
|
|
557
|
+
{ internalType: "uint32", name: "originNetwork", type: "uint32" },
|
|
558
|
+
{ internalType: "address", name: "originTokenAddress", type: "address" }
|
|
559
|
+
],
|
|
560
|
+
stateMutability: "view",
|
|
561
|
+
type: "function"
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
inputs: [],
|
|
565
|
+
name: "networkID",
|
|
566
|
+
outputs: [{ internalType: "uint32", name: "", type: "uint32" }],
|
|
567
|
+
stateMutability: "view",
|
|
568
|
+
type: "function"
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
anonymous: false,
|
|
572
|
+
inputs: [
|
|
573
|
+
{
|
|
574
|
+
indexed: false,
|
|
575
|
+
internalType: "uint8",
|
|
576
|
+
name: "leafType",
|
|
577
|
+
type: "uint8"
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
indexed: false,
|
|
581
|
+
internalType: "uint32",
|
|
582
|
+
name: "originNetwork",
|
|
583
|
+
type: "uint32"
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
indexed: false,
|
|
587
|
+
internalType: "address",
|
|
588
|
+
name: "originAddress",
|
|
589
|
+
type: "address"
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
indexed: false,
|
|
593
|
+
internalType: "uint32",
|
|
594
|
+
name: "destinationNetwork",
|
|
595
|
+
type: "uint32"
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
indexed: false,
|
|
599
|
+
internalType: "address",
|
|
600
|
+
name: "destinationAddress",
|
|
601
|
+
type: "address"
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
indexed: false,
|
|
605
|
+
internalType: "uint256",
|
|
606
|
+
name: "amount",
|
|
607
|
+
type: "uint256"
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
indexed: false,
|
|
611
|
+
internalType: "bytes",
|
|
612
|
+
name: "metadata",
|
|
613
|
+
type: "bytes"
|
|
614
|
+
},
|
|
615
|
+
{
|
|
616
|
+
indexed: false,
|
|
617
|
+
internalType: "uint32",
|
|
618
|
+
name: "depositCount",
|
|
619
|
+
type: "uint32"
|
|
620
|
+
}
|
|
621
|
+
],
|
|
622
|
+
name: "BridgeEvent",
|
|
623
|
+
type: "event"
|
|
624
|
+
}
|
|
625
|
+
];
|
|
626
|
+
|
|
627
|
+
// src/native/bridge/build.ts
|
|
628
|
+
async function buildBridgeAsset(ctx, destinationNetwork, destinationAddress, amount, token, forceUpdateGlobalExitRoot, permitData = "0x", from) {
|
|
629
|
+
const data = (0, import_viem3.encodeFunctionData)({
|
|
630
|
+
abi: bridgeAbi,
|
|
631
|
+
functionName: "bridgeAsset",
|
|
632
|
+
args: [
|
|
633
|
+
destinationNetwork,
|
|
634
|
+
destinationAddress,
|
|
635
|
+
amount,
|
|
636
|
+
token,
|
|
637
|
+
forceUpdateGlobalExitRoot,
|
|
638
|
+
permitData
|
|
639
|
+
]
|
|
640
|
+
});
|
|
641
|
+
const [nonce, gas] = await Promise.all([
|
|
642
|
+
ctx.getNonce(from),
|
|
643
|
+
ctx.estimateGas(data, ctx.bridgeAddress, from)
|
|
644
|
+
]);
|
|
645
|
+
return {
|
|
646
|
+
from,
|
|
647
|
+
to: ctx.bridgeAddress,
|
|
648
|
+
data,
|
|
649
|
+
gas,
|
|
650
|
+
nonce
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
async function buildClaimAsset(ctx, smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originTokenAddress, destinationNetwork, destinationAddress, amount, metadata, from) {
|
|
654
|
+
const data = (0, import_viem3.encodeFunctionData)({
|
|
655
|
+
abi: bridgeAbi,
|
|
656
|
+
functionName: "claimAsset",
|
|
657
|
+
args: [
|
|
658
|
+
// @ts-ignore - Viem expects exact tuple types but we're passing arrays
|
|
659
|
+
smtProofLocalExitRoot,
|
|
660
|
+
// @ts-ignore - Viem expects exact tuple types but we're passing arrays
|
|
661
|
+
smtProofRollupExitRoot,
|
|
662
|
+
globalIndex,
|
|
663
|
+
mainnetExitRoot,
|
|
664
|
+
rollupExitRoot,
|
|
665
|
+
originNetwork,
|
|
666
|
+
originTokenAddress,
|
|
667
|
+
destinationNetwork,
|
|
668
|
+
destinationAddress,
|
|
669
|
+
amount,
|
|
670
|
+
metadata
|
|
671
|
+
]
|
|
672
|
+
});
|
|
673
|
+
const [nonce, gas] = await Promise.all([
|
|
674
|
+
ctx.getNonce(from),
|
|
675
|
+
ctx.estimateGas(data, ctx.bridgeAddress, from)
|
|
676
|
+
]);
|
|
677
|
+
return {
|
|
678
|
+
from,
|
|
679
|
+
to: ctx.bridgeAddress,
|
|
680
|
+
data,
|
|
681
|
+
gas,
|
|
682
|
+
nonce
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// src/native/bridge/message.ts
|
|
687
|
+
var import_viem4 = require("viem");
|
|
688
|
+
async function buildBridgeMessage(ctx, destinationNetwork, destinationAddress, forceUpdateGlobalExitRoot, permitData = "0x", from) {
|
|
689
|
+
const data = (0, import_viem4.encodeFunctionData)({
|
|
690
|
+
abi: bridgeAbi,
|
|
691
|
+
functionName: "bridgeMessage",
|
|
692
|
+
args: [
|
|
693
|
+
destinationNetwork,
|
|
694
|
+
destinationAddress,
|
|
695
|
+
forceUpdateGlobalExitRoot,
|
|
696
|
+
permitData
|
|
697
|
+
]
|
|
698
|
+
});
|
|
699
|
+
const [nonce, gas] = await Promise.all([
|
|
700
|
+
ctx.getNonce(from),
|
|
701
|
+
ctx.estimateGas(data, ctx.bridgeAddress, from)
|
|
702
|
+
]);
|
|
703
|
+
return {
|
|
704
|
+
from,
|
|
705
|
+
to: ctx.bridgeAddress,
|
|
706
|
+
data,
|
|
707
|
+
gas,
|
|
708
|
+
nonce
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
async function buildClaimMessage(ctx, smtProofLocalExitRoot, smtProofRollupExitRoot, globalIndex, mainnetExitRoot, rollupExitRoot, originNetwork, originTokenAddress, destinationNetwork, destinationAddress, amount, metadata, from) {
|
|
712
|
+
const data = (0, import_viem4.encodeFunctionData)({
|
|
713
|
+
abi: bridgeAbi,
|
|
714
|
+
functionName: "claimMessage",
|
|
715
|
+
args: [
|
|
716
|
+
// @ts-ignore - Viem expects exact tuple types but we're passing arrays
|
|
717
|
+
smtProofLocalExitRoot,
|
|
718
|
+
// @ts-ignore - Viem expects exact tuple types but we're passing arrays
|
|
719
|
+
smtProofRollupExitRoot,
|
|
720
|
+
globalIndex,
|
|
721
|
+
mainnetExitRoot,
|
|
722
|
+
rollupExitRoot,
|
|
723
|
+
originNetwork,
|
|
724
|
+
originTokenAddress,
|
|
725
|
+
destinationNetwork,
|
|
726
|
+
destinationAddress,
|
|
727
|
+
amount,
|
|
728
|
+
metadata
|
|
729
|
+
]
|
|
730
|
+
});
|
|
731
|
+
const [nonce, gas] = await Promise.all([
|
|
732
|
+
ctx.getNonce(from),
|
|
733
|
+
ctx.estimateGas(data, ctx.bridgeAddress, from)
|
|
734
|
+
]);
|
|
735
|
+
return {
|
|
736
|
+
from,
|
|
737
|
+
to: ctx.bridgeAddress,
|
|
738
|
+
data,
|
|
739
|
+
gas,
|
|
740
|
+
nonce
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// src/native/bridge/util.ts
|
|
745
|
+
var import_viem5 = require("viem");
|
|
746
|
+
var BridgeUtil = class _BridgeUtil {
|
|
747
|
+
constructor(client, proofApiUrl) {
|
|
748
|
+
this.BRIDGE_TOPIC = "0x501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b";
|
|
749
|
+
this.client = client;
|
|
750
|
+
this.proofApiUrl = proofApiUrl;
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Create BridgeUtil instance from network ID using chain registry
|
|
754
|
+
*
|
|
755
|
+
* @param sourceNetworkId - Network ID of the source network
|
|
756
|
+
* @returns BridgeUtil instance configured for the source network
|
|
757
|
+
*/
|
|
758
|
+
static async fromNetworkId(sourceNetworkId) {
|
|
759
|
+
const chain = _BridgeUtil.findChain(sourceNetworkId);
|
|
760
|
+
if (!chain.proofApiUrl) {
|
|
761
|
+
throw new Error(
|
|
762
|
+
`No proof API URL configured for network ${sourceNetworkId}`
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
const sourceClient = (0, import_viem5.createPublicClient)({
|
|
766
|
+
transport: (0, import_viem5.http)(chain.rpcUrl)
|
|
767
|
+
});
|
|
768
|
+
return new _BridgeUtil(sourceClient, chain.proofApiUrl);
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Find chain configuration by network ID
|
|
772
|
+
*
|
|
773
|
+
* @param sourceNetworkId - Network ID to search for
|
|
774
|
+
* @returns Chain configuration
|
|
775
|
+
* @throws Error if chain not found
|
|
776
|
+
*/
|
|
777
|
+
static findChain(sourceNetworkId) {
|
|
778
|
+
try {
|
|
779
|
+
return chainRegistry.getChainByNetworkId(sourceNetworkId);
|
|
780
|
+
} catch {
|
|
781
|
+
const allChains = chainRegistry.getAllChains();
|
|
782
|
+
const availableNetworkIds = allChains.map((chain) => chain.networkId).filter(Boolean).join(", ");
|
|
783
|
+
throw new Error(
|
|
784
|
+
`Source network ${sourceNetworkId} not found in chain registry. Available network IDs: ${availableNetworkIds}`
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Extract bridge event data from transaction receipt
|
|
790
|
+
*/
|
|
791
|
+
async extractBridgeEvent(transactionHash, _networkId, bridgeIndex = 0) {
|
|
792
|
+
try {
|
|
793
|
+
const receipt = await this.client.getTransactionReceipt({
|
|
794
|
+
hash: transactionHash
|
|
795
|
+
});
|
|
796
|
+
const bridgeLogs = receipt.logs.filter(
|
|
797
|
+
(log2) => log2.topics[0] && log2.topics[0].toLowerCase() === this.BRIDGE_TOPIC.toLowerCase()
|
|
798
|
+
);
|
|
799
|
+
if (!bridgeLogs.length) {
|
|
800
|
+
throw new Error("No bridge event found in transaction receipt");
|
|
801
|
+
}
|
|
802
|
+
if (bridgeIndex >= bridgeLogs.length) {
|
|
803
|
+
throw new Error(
|
|
804
|
+
`Bridge index ${bridgeIndex} not found. Available indices: 0-${bridgeLogs.length - 1}`
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
const log = bridgeLogs[bridgeIndex];
|
|
808
|
+
if (!log) {
|
|
809
|
+
throw new Error("Bridge log not found");
|
|
810
|
+
}
|
|
811
|
+
const decoded = (0, import_viem5.decodeEventLog)({
|
|
812
|
+
abi: bridgeAbi,
|
|
813
|
+
data: log.data,
|
|
814
|
+
topics: log.topics
|
|
815
|
+
});
|
|
816
|
+
if (decoded.eventName !== "BridgeEvent") {
|
|
817
|
+
throw new Error("Invalid bridge event");
|
|
818
|
+
}
|
|
819
|
+
const args = decoded.args;
|
|
820
|
+
const {
|
|
821
|
+
originNetwork,
|
|
822
|
+
originAddress,
|
|
823
|
+
destinationNetwork,
|
|
824
|
+
destinationAddress,
|
|
825
|
+
amount,
|
|
826
|
+
metadata,
|
|
827
|
+
depositCount
|
|
828
|
+
} = args;
|
|
829
|
+
return {
|
|
830
|
+
originNetwork: Number(originNetwork),
|
|
831
|
+
originTokenAddress: originAddress,
|
|
832
|
+
destinationNetwork: Number(destinationNetwork),
|
|
833
|
+
destinationAddress,
|
|
834
|
+
amount,
|
|
835
|
+
metadata: metadata || "0x",
|
|
836
|
+
depositCount: Number(depositCount)
|
|
837
|
+
};
|
|
838
|
+
} catch (error) {
|
|
839
|
+
if (error instanceof Error) {
|
|
840
|
+
throw new Error(`Failed to extract bridge event: ${error.message}`);
|
|
841
|
+
}
|
|
842
|
+
throw new Error("Failed to extract bridge event: Unknown error");
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Fetch merkle proof from Polygon's proof API
|
|
847
|
+
*/
|
|
848
|
+
async fetchMerkleProof(networkId, depositCount) {
|
|
849
|
+
try {
|
|
850
|
+
const baseUrl = this.proofApiUrl.endsWith("/") ? this.proofApiUrl : `${this.proofApiUrl}/`;
|
|
851
|
+
const url = `${baseUrl}merkle-proof?networkId=${networkId}&depositCount=${depositCount}`;
|
|
852
|
+
const response = await fetch(url);
|
|
853
|
+
if (!response.ok) {
|
|
854
|
+
throw new Error(
|
|
855
|
+
`Failed to fetch merkle proof: ${response.statusText} (${response.status})`
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
const data = await response.json();
|
|
859
|
+
if (!data.proof) {
|
|
860
|
+
throw new Error("Invalid response format: missing proof data");
|
|
861
|
+
}
|
|
862
|
+
return data.proof;
|
|
863
|
+
} catch (error) {
|
|
864
|
+
if (error instanceof Error) {
|
|
865
|
+
throw new Error(`Failed to fetch merkle proof: ${error.message}`);
|
|
866
|
+
}
|
|
867
|
+
throw new Error("Failed to fetch merkle proof: Unknown error");
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Compute global index from local index and network ID
|
|
872
|
+
*/
|
|
873
|
+
computeGlobalIndex(indexLocal, sourceNetworkId) {
|
|
874
|
+
const MAINNET_FLAG = BigInt(2 ** 64);
|
|
875
|
+
if (BigInt(sourceNetworkId) === BigInt(0)) {
|
|
876
|
+
return BigInt(indexLocal) + MAINNET_FLAG;
|
|
877
|
+
} else {
|
|
878
|
+
return BigInt(indexLocal) + BigInt(sourceNetworkId - 1) * BigInt(2 ** 32);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Build claim payload from transaction hash (user-friendly method)
|
|
883
|
+
*/
|
|
884
|
+
async buildPayloadForClaim(transactionHash, sourceNetworkId, bridgeIndex = 0) {
|
|
885
|
+
const bridgeEvent = await this.extractBridgeEvent(
|
|
886
|
+
transactionHash,
|
|
887
|
+
sourceNetworkId,
|
|
888
|
+
bridgeIndex
|
|
889
|
+
);
|
|
890
|
+
const proof = await this.fetchMerkleProof(
|
|
891
|
+
sourceNetworkId,
|
|
892
|
+
bridgeEvent.depositCount
|
|
893
|
+
);
|
|
894
|
+
const globalIndex = this.computeGlobalIndex(
|
|
895
|
+
bridgeEvent.depositCount,
|
|
896
|
+
sourceNetworkId
|
|
897
|
+
);
|
|
898
|
+
return {
|
|
899
|
+
smtProof: proof.merkle_proof,
|
|
900
|
+
smtProofRollup: proof.rollup_merkle_proof,
|
|
901
|
+
globalIndex: globalIndex.toString(),
|
|
902
|
+
mainnetExitRoot: proof.main_exit_root,
|
|
903
|
+
rollupExitRoot: proof.rollup_exit_root,
|
|
904
|
+
originNetwork: bridgeEvent.originNetwork,
|
|
905
|
+
originTokenAddress: bridgeEvent.originTokenAddress,
|
|
906
|
+
destinationNetwork: bridgeEvent.destinationNetwork,
|
|
907
|
+
destinationAddress: bridgeEvent.destinationAddress,
|
|
908
|
+
amount: bridgeEvent.amount,
|
|
909
|
+
metadata: bridgeEvent.metadata
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Build claim asset parameters from transaction hash
|
|
914
|
+
*/
|
|
915
|
+
async buildClaimAssetParams(transactionHash, sourceNetworkId, bridgeIndex = 0) {
|
|
916
|
+
const payload = await this.buildPayloadForClaim(
|
|
917
|
+
transactionHash,
|
|
918
|
+
sourceNetworkId,
|
|
919
|
+
bridgeIndex
|
|
920
|
+
);
|
|
921
|
+
return {
|
|
922
|
+
smtProofLocalExitRoot: payload.smtProof,
|
|
923
|
+
smtProofRollupExitRoot: payload.smtProofRollup,
|
|
924
|
+
globalIndex: BigInt(payload.globalIndex),
|
|
925
|
+
mainnetExitRoot: payload.mainnetExitRoot,
|
|
926
|
+
rollupExitRoot: payload.rollupExitRoot,
|
|
927
|
+
originNetwork: payload.originNetwork,
|
|
928
|
+
originTokenAddress: payload.originTokenAddress,
|
|
929
|
+
destinationNetwork: payload.destinationNetwork,
|
|
930
|
+
destinationAddress: payload.destinationAddress,
|
|
931
|
+
amount: payload.amount,
|
|
932
|
+
metadata: payload.metadata
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Build claim message parameters from transaction hash
|
|
937
|
+
*/
|
|
938
|
+
async buildClaimMessageParams(transactionHash, sourceNetworkId, bridgeIndex = 0) {
|
|
939
|
+
const payload = await this.buildPayloadForClaim(
|
|
940
|
+
transactionHash,
|
|
941
|
+
sourceNetworkId,
|
|
942
|
+
bridgeIndex
|
|
943
|
+
);
|
|
944
|
+
return {
|
|
945
|
+
smtProofLocalExitRoot: payload.smtProof,
|
|
946
|
+
smtProofRollupExitRoot: payload.smtProofRollup,
|
|
947
|
+
globalIndex: BigInt(payload.globalIndex),
|
|
948
|
+
mainnetExitRoot: payload.mainnetExitRoot,
|
|
949
|
+
rollupExitRoot: payload.rollupExitRoot,
|
|
950
|
+
originNetwork: payload.originNetwork,
|
|
951
|
+
originTokenAddress: payload.originTokenAddress,
|
|
952
|
+
destinationNetwork: payload.destinationNetwork,
|
|
953
|
+
destinationAddress: payload.destinationAddress,
|
|
954
|
+
amount: payload.amount,
|
|
955
|
+
metadata: payload.metadata
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Get bridge event info from transaction hash
|
|
960
|
+
*/
|
|
961
|
+
async getBridgeEventInfo(transactionHash, sourceNetworkId, bridgeIndex = 0) {
|
|
962
|
+
return this.extractBridgeEvent(
|
|
963
|
+
transactionHash,
|
|
964
|
+
sourceNetworkId,
|
|
965
|
+
bridgeIndex
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
};
|
|
969
|
+
|
|
970
|
+
// src/native/bridge/bridge.ts
|
|
971
|
+
var Bridge = class extends BaseContract {
|
|
972
|
+
constructor(config) {
|
|
973
|
+
super({ rpcUrl: config.rpcUrl, chainId: config.chainId });
|
|
974
|
+
this.bridgeAddress = config.bridgeAddress;
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Build bridge asset transaction
|
|
978
|
+
*/
|
|
979
|
+
async buildBridgeAsset(params, from) {
|
|
980
|
+
ValidationUtils.validateAddress(
|
|
981
|
+
params.destinationAddress,
|
|
982
|
+
"Destination address"
|
|
983
|
+
);
|
|
984
|
+
ValidationUtils.validateAddress(params.token, "Token address");
|
|
985
|
+
return buildBridgeAsset(
|
|
986
|
+
{
|
|
987
|
+
bridgeAddress: this.bridgeAddress,
|
|
988
|
+
estimateGas: (data, to, from2) => this.estimateGas(data, to, from2),
|
|
989
|
+
getNonce: (address) => this.getNonce(address)
|
|
990
|
+
},
|
|
991
|
+
params.destinationNetwork,
|
|
992
|
+
params.destinationAddress,
|
|
993
|
+
BigInt(params.amount),
|
|
994
|
+
params.token,
|
|
995
|
+
params.forceUpdateGlobalExitRoot,
|
|
996
|
+
params.permitData,
|
|
997
|
+
from
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Build claim asset transaction
|
|
1002
|
+
*/
|
|
1003
|
+
async buildClaimAsset(params, from) {
|
|
1004
|
+
ValidationUtils.validateAddress(
|
|
1005
|
+
params.originTokenAddress,
|
|
1006
|
+
"Origin token address"
|
|
1007
|
+
);
|
|
1008
|
+
ValidationUtils.validateAddress(
|
|
1009
|
+
params.destinationAddress,
|
|
1010
|
+
"Destination address"
|
|
1011
|
+
);
|
|
1012
|
+
return buildClaimAsset(
|
|
1013
|
+
{
|
|
1014
|
+
bridgeAddress: this.bridgeAddress,
|
|
1015
|
+
estimateGas: (data, to, from2) => this.estimateGas(data, to, from2),
|
|
1016
|
+
getNonce: (address) => this.getNonce(address)
|
|
1017
|
+
},
|
|
1018
|
+
params.smtProofLocalExitRoot,
|
|
1019
|
+
params.smtProofRollupExitRoot,
|
|
1020
|
+
params.globalIndex,
|
|
1021
|
+
params.mainnetExitRoot,
|
|
1022
|
+
params.rollupExitRoot,
|
|
1023
|
+
params.originNetwork,
|
|
1024
|
+
params.originTokenAddress,
|
|
1025
|
+
params.destinationNetwork,
|
|
1026
|
+
params.destinationAddress,
|
|
1027
|
+
params.amount,
|
|
1028
|
+
params.metadata,
|
|
1029
|
+
from
|
|
1030
|
+
);
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Check if bridge deposit is claimed
|
|
1034
|
+
*/
|
|
1035
|
+
async isClaimed(params) {
|
|
1036
|
+
const result = await this.client.readContract({
|
|
1037
|
+
address: this.bridgeAddress,
|
|
1038
|
+
abi: bridgeAbi,
|
|
1039
|
+
functionName: "isClaimed",
|
|
1040
|
+
args: [params.leafIndex, params.sourceBridgeNetwork]
|
|
1041
|
+
});
|
|
1042
|
+
return result;
|
|
1043
|
+
}
|
|
1044
|
+
/**
|
|
1045
|
+
* Get wrapped token address
|
|
1046
|
+
*/
|
|
1047
|
+
async getWrappedTokenAddress(params) {
|
|
1048
|
+
ValidationUtils.validateAddress(
|
|
1049
|
+
params.originTokenAddress,
|
|
1050
|
+
"Origin token address"
|
|
1051
|
+
);
|
|
1052
|
+
const result = await this.client.readContract({
|
|
1053
|
+
address: this.bridgeAddress,
|
|
1054
|
+
abi: bridgeAbi,
|
|
1055
|
+
functionName: "getTokenWrappedAddress",
|
|
1056
|
+
args: [params.originNetwork, params.originTokenAddress]
|
|
1057
|
+
});
|
|
1058
|
+
return result;
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Get network ID
|
|
1062
|
+
*/
|
|
1063
|
+
async getNetworkId() {
|
|
1064
|
+
const result = await this.client.readContract({
|
|
1065
|
+
address: this.bridgeAddress,
|
|
1066
|
+
abi: bridgeAbi,
|
|
1067
|
+
functionName: "networkID",
|
|
1068
|
+
args: []
|
|
1069
|
+
});
|
|
1070
|
+
return Number(result);
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Get bridge contract address
|
|
1074
|
+
*/
|
|
1075
|
+
getBridgeAddress() {
|
|
1076
|
+
return this.bridgeAddress;
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Build bridge message transaction
|
|
1080
|
+
*/
|
|
1081
|
+
async buildBridgeMessage(params, from) {
|
|
1082
|
+
ValidationUtils.validateAddress(
|
|
1083
|
+
params.destinationAddress,
|
|
1084
|
+
"Destination address"
|
|
1085
|
+
);
|
|
1086
|
+
return buildBridgeMessage(
|
|
1087
|
+
{
|
|
1088
|
+
bridgeAddress: this.bridgeAddress,
|
|
1089
|
+
estimateGas: (data, to, from2) => this.estimateGas(data, to, from2),
|
|
1090
|
+
getNonce: (address) => this.getNonce(address)
|
|
1091
|
+
},
|
|
1092
|
+
params.destinationNetwork,
|
|
1093
|
+
params.destinationAddress,
|
|
1094
|
+
params.forceUpdateGlobalExitRoot,
|
|
1095
|
+
params.permitData || "0x",
|
|
1096
|
+
from
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Build claim message transaction
|
|
1101
|
+
*/
|
|
1102
|
+
async buildClaimMessage(params, from) {
|
|
1103
|
+
ValidationUtils.validateAddress(
|
|
1104
|
+
params.originTokenAddress,
|
|
1105
|
+
"Origin token address"
|
|
1106
|
+
);
|
|
1107
|
+
ValidationUtils.validateAddress(
|
|
1108
|
+
params.destinationAddress,
|
|
1109
|
+
"Destination address"
|
|
1110
|
+
);
|
|
1111
|
+
return buildClaimMessage(
|
|
1112
|
+
{
|
|
1113
|
+
bridgeAddress: this.bridgeAddress,
|
|
1114
|
+
estimateGas: (data, to, from2) => this.estimateGas(data, to, from2),
|
|
1115
|
+
getNonce: (address) => this.getNonce(address)
|
|
1116
|
+
},
|
|
1117
|
+
params.smtProofLocalExitRoot,
|
|
1118
|
+
params.smtProofRollupExitRoot,
|
|
1119
|
+
params.globalIndex,
|
|
1120
|
+
params.mainnetExitRoot,
|
|
1121
|
+
params.rollupExitRoot,
|
|
1122
|
+
params.originNetwork,
|
|
1123
|
+
params.originTokenAddress,
|
|
1124
|
+
params.destinationNetwork,
|
|
1125
|
+
params.destinationAddress,
|
|
1126
|
+
params.amount,
|
|
1127
|
+
params.metadata,
|
|
1128
|
+
from
|
|
1129
|
+
);
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Get precalculated wrapper address
|
|
1133
|
+
*/
|
|
1134
|
+
async getPrecalculatedWrapperAddress(params) {
|
|
1135
|
+
ValidationUtils.validateAddress(
|
|
1136
|
+
params.originTokenAddress,
|
|
1137
|
+
"Origin token address"
|
|
1138
|
+
);
|
|
1139
|
+
const result = await this.client.readContract({
|
|
1140
|
+
address: this.bridgeAddress,
|
|
1141
|
+
abi: bridgeAbi,
|
|
1142
|
+
functionName: "precalculatedWrapperAddress",
|
|
1143
|
+
args: [params.originNetwork, params.originTokenAddress]
|
|
1144
|
+
});
|
|
1145
|
+
return result;
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Get origin token info from wrapped token
|
|
1149
|
+
*/
|
|
1150
|
+
async getOriginTokenInfo(params) {
|
|
1151
|
+
ValidationUtils.validateAddress(
|
|
1152
|
+
params.wrappedToken,
|
|
1153
|
+
"Wrapped token address"
|
|
1154
|
+
);
|
|
1155
|
+
const result = await this.client.readContract({
|
|
1156
|
+
address: this.bridgeAddress,
|
|
1157
|
+
abi: bridgeAbi,
|
|
1158
|
+
functionName: "wrappedTokenToTokenInfo",
|
|
1159
|
+
args: [params.wrappedToken]
|
|
1160
|
+
});
|
|
1161
|
+
return result;
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Build claim asset transaction from bridge transaction hash
|
|
1165
|
+
*
|
|
1166
|
+
* @param transactionHash - Hash of the bridge transaction on the source network
|
|
1167
|
+
* @param sourceNetworkId - Network ID of the source network (where bridge tx happened)
|
|
1168
|
+
* @param bridgeIndex - Index of bridge event in transaction (default: 0)
|
|
1169
|
+
* @param from - From address for the claim transaction
|
|
1170
|
+
*/
|
|
1171
|
+
async buildClaimAssetFromHash(transactionHash, sourceNetworkId, bridgeIndex = 0, from) {
|
|
1172
|
+
const bridgeUtil = await BridgeUtil.fromNetworkId(sourceNetworkId);
|
|
1173
|
+
const params = await bridgeUtil.buildClaimAssetParams(
|
|
1174
|
+
transactionHash,
|
|
1175
|
+
sourceNetworkId,
|
|
1176
|
+
bridgeIndex
|
|
1177
|
+
);
|
|
1178
|
+
return this.buildClaimAsset(params, from);
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Build claim message transaction from bridge transaction hash
|
|
1182
|
+
*
|
|
1183
|
+
* @param transactionHash - Hash of the bridge transaction on the source network
|
|
1184
|
+
* @param sourceNetworkId - Network ID of the source network (where bridge tx happened)
|
|
1185
|
+
* @param bridgeIndex - Index of bridge event in transaction (default: 0)
|
|
1186
|
+
* @param from - From address for the claim transaction
|
|
1187
|
+
*/
|
|
1188
|
+
async buildClaimMessageFromHash(transactionHash, sourceNetworkId, bridgeIndex = 0, from) {
|
|
1189
|
+
const bridgeUtil = await BridgeUtil.fromNetworkId(sourceNetworkId);
|
|
1190
|
+
const params = await bridgeUtil.buildClaimMessageParams(
|
|
1191
|
+
transactionHash,
|
|
1192
|
+
sourceNetworkId,
|
|
1193
|
+
bridgeIndex
|
|
1194
|
+
);
|
|
1195
|
+
return this.buildClaimMessage(params, from);
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* Get bridge event info from transaction hash
|
|
1199
|
+
*
|
|
1200
|
+
* @param transactionHash - Hash of the bridge transaction on the source network
|
|
1201
|
+
* @param sourceNetworkId - Network ID of the source network (where bridge tx happened)
|
|
1202
|
+
* @param bridgeIndex - Index of bridge event in transaction (default: 0)
|
|
1203
|
+
*/
|
|
1204
|
+
async getBridgeEventInfo(transactionHash, sourceNetworkId, bridgeIndex = 0) {
|
|
1205
|
+
const bridgeUtil = await BridgeUtil.fromNetworkId(sourceNetworkId);
|
|
1206
|
+
return bridgeUtil.getBridgeEventInfo(
|
|
1207
|
+
transactionHash,
|
|
1208
|
+
sourceNetworkId,
|
|
1209
|
+
bridgeIndex
|
|
1210
|
+
);
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1214
|
+
// src/native/services/abi.ts
|
|
1215
|
+
var ABIS = {
|
|
1216
|
+
BRIDGE: bridgeAbi,
|
|
1217
|
+
ERC20: erc20Abi
|
|
1218
|
+
};
|
|
1219
|
+
function getAbi(contractType) {
|
|
1220
|
+
return ABIS[contractType];
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
// src/native/tokens/erc20.ts
|
|
1224
|
+
var ERC20 = class extends BaseContract {
|
|
1225
|
+
constructor(config) {
|
|
1226
|
+
super({ rpcUrl: config.rpcUrl, chainId: config.chainId });
|
|
1227
|
+
this.tokenAddress = config.tokenAddress;
|
|
1228
|
+
this.config = config;
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* Get ERC20 token balance in wei
|
|
1232
|
+
*/
|
|
1233
|
+
async getBalance(address) {
|
|
1234
|
+
ValidationUtils.validateAddress(address, "Address");
|
|
1235
|
+
const balance = await this.client.readContract({
|
|
1236
|
+
address: this.tokenAddress,
|
|
1237
|
+
abi: getAbi("ERC20"),
|
|
1238
|
+
functionName: "balanceOf",
|
|
1239
|
+
args: [address]
|
|
1240
|
+
});
|
|
1241
|
+
return balance.toString();
|
|
1242
|
+
}
|
|
1243
|
+
/**
|
|
1244
|
+
* Get allowance in wei
|
|
1245
|
+
*/
|
|
1246
|
+
async getAllowance(owner, spender) {
|
|
1247
|
+
ValidationUtils.validateAddress(owner, "Owner address");
|
|
1248
|
+
ValidationUtils.validateAddress(spender, "Spender address");
|
|
1249
|
+
try {
|
|
1250
|
+
const allowance = await this.client.readContract({
|
|
1251
|
+
address: this.tokenAddress,
|
|
1252
|
+
abi: getAbi("ERC20"),
|
|
1253
|
+
functionName: "allowance",
|
|
1254
|
+
args: [owner, spender]
|
|
1255
|
+
});
|
|
1256
|
+
return allowance.toString();
|
|
1257
|
+
} catch (error) {
|
|
1258
|
+
throw new Error(
|
|
1259
|
+
`Failed to get allowance: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1260
|
+
);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Build approve transaction
|
|
1265
|
+
*/
|
|
1266
|
+
async buildApprove(spender, amount, from) {
|
|
1267
|
+
ValidationUtils.validateAddress(spender, "Spender address");
|
|
1268
|
+
ValidationUtils.validateAmount(amount, "Amount");
|
|
1269
|
+
return buildApprove(
|
|
1270
|
+
{
|
|
1271
|
+
tokenAddress: this.tokenAddress,
|
|
1272
|
+
estimateGas: (data, from2) => this.estimateGas(data, this.tokenAddress, from2),
|
|
1273
|
+
getNonce: (address) => this.getNonce(address)
|
|
1274
|
+
},
|
|
1275
|
+
spender,
|
|
1276
|
+
BigInt(amount),
|
|
1277
|
+
from
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Build transfer transaction
|
|
1282
|
+
*/
|
|
1283
|
+
async buildTransfer(to, amount, from) {
|
|
1284
|
+
ValidationUtils.validateAddress(to, "Recipient address");
|
|
1285
|
+
ValidationUtils.validateAmount(amount, "Amount");
|
|
1286
|
+
return buildTransfer(
|
|
1287
|
+
{
|
|
1288
|
+
tokenAddress: this.tokenAddress,
|
|
1289
|
+
estimateGas: (data, from2) => this.estimateGas(data, this.tokenAddress, from2),
|
|
1290
|
+
getNonce: (address) => this.getNonce(address)
|
|
1291
|
+
},
|
|
1292
|
+
to,
|
|
1293
|
+
BigInt(amount),
|
|
1294
|
+
from
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1298
|
+
* Build transferFrom transaction
|
|
1299
|
+
*/
|
|
1300
|
+
async buildTransferFrom(from, to, amount, spender) {
|
|
1301
|
+
ValidationUtils.validateAddress(from, "Owner address");
|
|
1302
|
+
ValidationUtils.validateAddress(to, "Recipient address");
|
|
1303
|
+
ValidationUtils.validateAmount(amount, "Amount");
|
|
1304
|
+
return buildTransferFrom(
|
|
1305
|
+
{
|
|
1306
|
+
tokenAddress: this.tokenAddress,
|
|
1307
|
+
estimateGas: (data, from2) => this.estimateGas(data, this.tokenAddress, from2),
|
|
1308
|
+
getNonce: (address) => this.getNonce(address)
|
|
1309
|
+
},
|
|
1310
|
+
from,
|
|
1311
|
+
to,
|
|
1312
|
+
BigInt(amount),
|
|
1313
|
+
spender
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Bridge this token to another network
|
|
1318
|
+
*/
|
|
1319
|
+
async bridgeTo(destinationNetwork, destinationAddress, amount, from, options = {}) {
|
|
1320
|
+
ValidationUtils.validateAddress(destinationAddress, "Destination address");
|
|
1321
|
+
ValidationUtils.validateAmount(amount, "Amount");
|
|
1322
|
+
const bridge = this.getBridge();
|
|
1323
|
+
return bridge.buildBridgeAsset(
|
|
1324
|
+
{
|
|
1325
|
+
destinationNetwork,
|
|
1326
|
+
destinationAddress,
|
|
1327
|
+
amount,
|
|
1328
|
+
token: this.tokenAddress,
|
|
1329
|
+
forceUpdateGlobalExitRoot: options.forceUpdateGlobalExitRoot ?? true,
|
|
1330
|
+
permitData: options.permitData || "0x"
|
|
1331
|
+
},
|
|
1332
|
+
from
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Get wrapped version of this token on destination network
|
|
1337
|
+
*/
|
|
1338
|
+
async getWrappedToken() {
|
|
1339
|
+
const bridge = this.getBridge();
|
|
1340
|
+
return bridge.getWrappedTokenAddress({
|
|
1341
|
+
originNetwork: this.config.chainId,
|
|
1342
|
+
originTokenAddress: this.tokenAddress
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1345
|
+
/**
|
|
1346
|
+
* Claim asset from bridge transaction hash
|
|
1347
|
+
*
|
|
1348
|
+
* @param transactionHash - Hash of the bridge transaction on the source network
|
|
1349
|
+
* @param sourceNetworkId - Network ID of the source network (where bridge tx happened)
|
|
1350
|
+
* @param bridgeIndex - Index of bridge event in transaction (default: 0)
|
|
1351
|
+
* @param from - From address for the claim transaction
|
|
1352
|
+
*/
|
|
1353
|
+
async claimAsset(transactionHash, sourceNetworkId, bridgeIndex = 0, from) {
|
|
1354
|
+
const bridge = this.getBridge();
|
|
1355
|
+
return bridge.buildClaimAssetFromHash(
|
|
1356
|
+
transactionHash,
|
|
1357
|
+
sourceNetworkId,
|
|
1358
|
+
bridgeIndex,
|
|
1359
|
+
from
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* Claim message from bridge transaction hash
|
|
1364
|
+
*
|
|
1365
|
+
* @param transactionHash - Hash of the bridge transaction on the source network
|
|
1366
|
+
* @param sourceNetworkId - Network ID of the source network (where bridge tx happened)
|
|
1367
|
+
* @param bridgeIndex - Index of bridge event in transaction (default: 0)
|
|
1368
|
+
* @param from - From address for the claim transaction
|
|
1369
|
+
*/
|
|
1370
|
+
async claimMessage(transactionHash, sourceNetworkId, bridgeIndex = 0, from) {
|
|
1371
|
+
const bridge = this.getBridge();
|
|
1372
|
+
return bridge.buildClaimMessageFromHash(
|
|
1373
|
+
transactionHash,
|
|
1374
|
+
sourceNetworkId,
|
|
1375
|
+
bridgeIndex,
|
|
1376
|
+
from
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
/**
|
|
1380
|
+
* Get bridge event info from transaction hash
|
|
1381
|
+
*
|
|
1382
|
+
* @param transactionHash - Hash of the bridge transaction on the source network
|
|
1383
|
+
* @param sourceNetworkId - Network ID of the source network (where bridge tx happened)
|
|
1384
|
+
* @param bridgeIndex - Index of bridge event in transaction (default: 0)
|
|
1385
|
+
*/
|
|
1386
|
+
async getBridgeEventInfo(transactionHash, sourceNetworkId, bridgeIndex = 0) {
|
|
1387
|
+
const bridge = this.getBridge();
|
|
1388
|
+
return bridge.getBridgeEventInfo(
|
|
1389
|
+
transactionHash,
|
|
1390
|
+
sourceNetworkId,
|
|
1391
|
+
bridgeIndex
|
|
1392
|
+
);
|
|
1393
|
+
}
|
|
1394
|
+
getBridge() {
|
|
1395
|
+
const chain = chainRegistry.getChain(this.config.chainId);
|
|
1396
|
+
if (!chain.bridgeAddress) {
|
|
1397
|
+
throw new Error(
|
|
1398
|
+
`No bridge address configured for network ${this.config.chainId}`
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
return new Bridge({
|
|
1402
|
+
bridgeAddress: chain.bridgeAddress,
|
|
1403
|
+
rpcUrl: this.config.rpcUrl,
|
|
1404
|
+
chainId: this.config.chainId
|
|
1405
|
+
});
|
|
1406
|
+
}
|
|
1407
|
+
};
|
|
1408
|
+
|
|
1409
|
+
// src/native/index.ts
|
|
1410
|
+
var import_viem6 = require("viem");
|
|
1411
|
+
|
|
1412
|
+
// src/constants.ts
|
|
1413
|
+
var NETWORKS = {
|
|
1414
|
+
SEPOLIA: 11155111,
|
|
1415
|
+
CARDONA: 2442
|
|
1416
|
+
};
|
|
1417
|
+
var DEFAULT_NETWORK = NETWORKS.SEPOLIA;
|
|
1418
|
+
|
|
1419
|
+
// src/native/index.ts
|
|
1420
|
+
var NativeClient = class {
|
|
1421
|
+
constructor(config) {
|
|
1422
|
+
this.config = config;
|
|
1423
|
+
this.defaultNetwork = this.config.defaultNetwork || DEFAULT_NETWORK;
|
|
1424
|
+
if (this.config.chains) {
|
|
1425
|
+
this.config.chains.forEach((chain) => {
|
|
1426
|
+
chainRegistry.registerChain(chain);
|
|
1427
|
+
});
|
|
1428
|
+
}
|
|
1429
|
+
if (this.config.customRpcUrls) {
|
|
1430
|
+
Object.entries(this.config.customRpcUrls).forEach(([chainId, rpcUrl]) => {
|
|
1431
|
+
chainRegistry.addCustomRpcUrl(Number(chainId), rpcUrl);
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* Get network configuration from chain registry
|
|
1437
|
+
* @param networkId - The network ID (chain ID)
|
|
1438
|
+
* @returns Chain configuration
|
|
1439
|
+
*/
|
|
1440
|
+
getNetwork(networkId) {
|
|
1441
|
+
return chainRegistry.getChain(networkId);
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* Get all supported networks
|
|
1445
|
+
* @returns Array of network IDs
|
|
1446
|
+
*/
|
|
1447
|
+
getSupportedNetworks() {
|
|
1448
|
+
return chainRegistry.getSupportedChainIds();
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Get default network ID
|
|
1452
|
+
* @returns Default network ID
|
|
1453
|
+
*/
|
|
1454
|
+
getDefaultNetwork() {
|
|
1455
|
+
return this.defaultNetwork;
|
|
1456
|
+
}
|
|
1457
|
+
/**
|
|
1458
|
+
* Get chain registry for advanced usage
|
|
1459
|
+
*/
|
|
1460
|
+
getChainRegistry() {
|
|
1461
|
+
return chainRegistry;
|
|
1462
|
+
}
|
|
1463
|
+
/**
|
|
1464
|
+
* Create an ERC20 instance for a specific token on a specific network
|
|
1465
|
+
* @param tokenAddress - The ERC20 token contract address
|
|
1466
|
+
* @param networkId - The network ID (optional, uses default if not provided)
|
|
1467
|
+
* @returns ERC20 instance
|
|
1468
|
+
*/
|
|
1469
|
+
erc20(tokenAddress, networkId) {
|
|
1470
|
+
const network = this.getNetwork(networkId || this.defaultNetwork);
|
|
1471
|
+
return new ERC20({
|
|
1472
|
+
tokenAddress,
|
|
1473
|
+
rpcUrl: network.rpcUrl,
|
|
1474
|
+
chainId: network.chainId
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
/**
|
|
1478
|
+
* Get native token balance in wei
|
|
1479
|
+
* @param address - The address to check balance for
|
|
1480
|
+
* @param networkId - The network ID (optional, uses default if not provided)
|
|
1481
|
+
* @returns Native token balance as string
|
|
1482
|
+
*/
|
|
1483
|
+
async getNativeBalance(address, networkId) {
|
|
1484
|
+
ValidationUtils.validateAddress(address, "Address");
|
|
1485
|
+
const network = this.getNetwork(networkId || this.defaultNetwork);
|
|
1486
|
+
const client = (0, import_viem6.createPublicClient)({
|
|
1487
|
+
chain: {
|
|
1488
|
+
id: network.chainId,
|
|
1489
|
+
name: network.name,
|
|
1490
|
+
nativeCurrency: network.nativeCurrency,
|
|
1491
|
+
rpcUrls: {
|
|
1492
|
+
default: { http: [network.rpcUrl] },
|
|
1493
|
+
public: { http: [network.rpcUrl] }
|
|
1494
|
+
}
|
|
1495
|
+
},
|
|
1496
|
+
transport: (0, import_viem6.http)(network.rpcUrl)
|
|
1497
|
+
});
|
|
1498
|
+
const balance = await client.getBalance({ address });
|
|
1499
|
+
return balance.toString();
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Create a Bridge instance for a specific network
|
|
1503
|
+
* @param bridgeAddress - The bridge contract address
|
|
1504
|
+
* @param networkId - The network ID (optional, uses default if not provided)
|
|
1505
|
+
* @returns Bridge instance
|
|
1506
|
+
*/
|
|
1507
|
+
bridge(bridgeAddress, networkId) {
|
|
1508
|
+
const network = this.getNetwork(networkId || this.defaultNetwork);
|
|
1509
|
+
return new Bridge({
|
|
1510
|
+
bridgeAddress,
|
|
1511
|
+
rpcUrl: network.rpcUrl,
|
|
1512
|
+
chainId: network.chainId
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
};
|
|
1516
|
+
|
|
1517
|
+
// src/types/config.ts
|
|
1518
|
+
var SDK_MODES = {
|
|
1519
|
+
CORE: "CORE",
|
|
1520
|
+
NATIVE: "NATIVE"
|
|
1521
|
+
};
|
|
1522
|
+
|
|
1523
|
+
// src/core/utils/httpClient.ts
|
|
1524
|
+
var HttpClient = class {
|
|
1525
|
+
constructor(config) {
|
|
1526
|
+
this.config = {
|
|
1527
|
+
timeout: 3e4,
|
|
1528
|
+
retries: 3,
|
|
1529
|
+
retryDelay: 1e3,
|
|
1530
|
+
defaultHeaders: {
|
|
1531
|
+
"Content-Type": "application/json"
|
|
1532
|
+
},
|
|
1533
|
+
...config
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
async request(url, config) {
|
|
1537
|
+
const fullUrl = this.buildUrl(url);
|
|
1538
|
+
const requestConfig = this.buildRequestConfig(config);
|
|
1539
|
+
let lastError;
|
|
1540
|
+
for (let attempt = 0; attempt <= (this.config.retries ?? 3); attempt++) {
|
|
1541
|
+
try {
|
|
1542
|
+
const response = await this.makeRequest(fullUrl, requestConfig);
|
|
1543
|
+
return response;
|
|
1544
|
+
} catch (error) {
|
|
1545
|
+
lastError = error;
|
|
1546
|
+
if (attempt === (this.config.retries ?? 3) || !this.isRetryableError(error)) {
|
|
1547
|
+
break;
|
|
1548
|
+
}
|
|
1549
|
+
if (attempt < (this.config.retries ?? 3)) {
|
|
1550
|
+
await this.delay(
|
|
1551
|
+
(this.config.retryDelay ?? 1e3) * Math.pow(2, attempt)
|
|
1552
|
+
);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
throw new Error(
|
|
1557
|
+
`Request failed after ${this.config.retries ?? 3} retries: ${lastError?.message ?? "Unknown error"}`
|
|
1558
|
+
);
|
|
1559
|
+
}
|
|
1560
|
+
async get(url, params) {
|
|
1561
|
+
const queryString = params ? this.buildQueryString(params) : "";
|
|
1562
|
+
const fullUrl = queryString ? `${url}?${queryString}` : url;
|
|
1563
|
+
return this.request(fullUrl, { method: "GET" });
|
|
1564
|
+
}
|
|
1565
|
+
async post(url, data, config) {
|
|
1566
|
+
return this.request(url, {
|
|
1567
|
+
method: "POST",
|
|
1568
|
+
body: data,
|
|
1569
|
+
...config
|
|
1570
|
+
});
|
|
1571
|
+
}
|
|
1572
|
+
buildUrl(url) {
|
|
1573
|
+
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
1574
|
+
return url;
|
|
1575
|
+
}
|
|
1576
|
+
return `${this.config.baseUrl}${url.startsWith("/") ? url : `/${url}`}`;
|
|
1577
|
+
}
|
|
1578
|
+
buildRequestConfig(config) {
|
|
1579
|
+
const headers = new Headers(this.config.defaultHeaders);
|
|
1580
|
+
if (config.headers) {
|
|
1581
|
+
Object.entries(config.headers).forEach(([key, value]) => {
|
|
1582
|
+
headers.set(key, value);
|
|
1583
|
+
});
|
|
1584
|
+
}
|
|
1585
|
+
const requestConfig = {
|
|
1586
|
+
method: config.method,
|
|
1587
|
+
headers
|
|
1588
|
+
};
|
|
1589
|
+
if (config.body) {
|
|
1590
|
+
if (typeof config.body === "string") {
|
|
1591
|
+
requestConfig.body = config.body;
|
|
1592
|
+
} else {
|
|
1593
|
+
requestConfig.body = JSON.stringify(config.body);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
return requestConfig;
|
|
1597
|
+
}
|
|
1598
|
+
async makeRequest(url, config) {
|
|
1599
|
+
const controller = new AbortController();
|
|
1600
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
1601
|
+
try {
|
|
1602
|
+
const response = await fetch(url, {
|
|
1603
|
+
...config,
|
|
1604
|
+
signal: controller.signal
|
|
1605
|
+
});
|
|
1606
|
+
clearTimeout(timeoutId);
|
|
1607
|
+
if (!response.ok) {
|
|
1608
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
1609
|
+
}
|
|
1610
|
+
let data;
|
|
1611
|
+
const contentType = response.headers.get("content-type");
|
|
1612
|
+
if (contentType?.includes("application/json")) {
|
|
1613
|
+
data = await response.json();
|
|
1614
|
+
} else {
|
|
1615
|
+
data = await response.text();
|
|
1616
|
+
}
|
|
1617
|
+
return {
|
|
1618
|
+
data,
|
|
1619
|
+
status: response.status,
|
|
1620
|
+
statusText: response.statusText,
|
|
1621
|
+
headers: response.headers,
|
|
1622
|
+
ok: response.ok
|
|
1623
|
+
};
|
|
1624
|
+
} catch (error) {
|
|
1625
|
+
clearTimeout(timeoutId);
|
|
1626
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1627
|
+
throw new Error(`Request timeout after ${this.config.timeout}ms`);
|
|
1628
|
+
}
|
|
1629
|
+
throw error;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
buildQueryString(params) {
|
|
1633
|
+
const flattenedParams = this.flattenParams(params);
|
|
1634
|
+
return Object.entries(flattenedParams).filter(([, value]) => value !== void 0 && value !== null).map(
|
|
1635
|
+
([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`
|
|
1636
|
+
).join("&");
|
|
1637
|
+
}
|
|
1638
|
+
flattenParams(params, prefix = "") {
|
|
1639
|
+
const result = {};
|
|
1640
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1641
|
+
const fullKey = prefix ? `${prefix}[${key}]` : key;
|
|
1642
|
+
if (value === void 0 || value === null) {
|
|
1643
|
+
continue;
|
|
1644
|
+
}
|
|
1645
|
+
if (Array.isArray(value)) {
|
|
1646
|
+
value.forEach((item, index) => {
|
|
1647
|
+
if (item !== void 0 && item !== null) {
|
|
1648
|
+
result[`${fullKey}[${index}]`] = String(item);
|
|
1649
|
+
}
|
|
1650
|
+
});
|
|
1651
|
+
} else if (typeof value === "object") {
|
|
1652
|
+
Object.assign(
|
|
1653
|
+
result,
|
|
1654
|
+
this.flattenParams(value, fullKey)
|
|
1655
|
+
);
|
|
1656
|
+
} else {
|
|
1657
|
+
result[fullKey] = String(value);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
return result;
|
|
1661
|
+
}
|
|
1662
|
+
isRetryableError(error) {
|
|
1663
|
+
if (error instanceof Error) {
|
|
1664
|
+
const message = error.message.toLowerCase();
|
|
1665
|
+
return message.includes("timeout") || message.includes("network") || message.includes("fetch");
|
|
1666
|
+
}
|
|
1667
|
+
return false;
|
|
1668
|
+
}
|
|
1669
|
+
delay(ms) {
|
|
1670
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1671
|
+
}
|
|
1672
|
+
};
|
|
1673
|
+
|
|
1674
|
+
// src/core/services/arcApi.ts
|
|
1675
|
+
var ArcApiService = class {
|
|
1676
|
+
constructor({ baseUrl, timeout }) {
|
|
1677
|
+
this.httpClient = new HttpClient({ baseUrl, timeout });
|
|
1678
|
+
}
|
|
1679
|
+
// responsible for both chains metadata and tokens
|
|
1680
|
+
async chains({
|
|
1681
|
+
withSupportedTokens = false,
|
|
1682
|
+
limit = 20,
|
|
1683
|
+
startAfter = 0,
|
|
1684
|
+
chainIds
|
|
1685
|
+
} = {}) {
|
|
1686
|
+
return this.httpClient.get("/metadata/chains", {
|
|
1687
|
+
withSupportedTokens,
|
|
1688
|
+
limit,
|
|
1689
|
+
startAfter,
|
|
1690
|
+
chainIds
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
async routes(routesRequestParams) {
|
|
1694
|
+
return this.httpClient.post("/routes", routesRequestParams);
|
|
1695
|
+
}
|
|
1696
|
+
async buildTransaction(builtTransactionRequestBody) {
|
|
1697
|
+
return this.httpClient.post(
|
|
1698
|
+
"/build-transaction",
|
|
1699
|
+
builtTransactionRequestBody
|
|
1700
|
+
);
|
|
1701
|
+
}
|
|
1702
|
+
async transactions(transactionsRequestQueryParams) {
|
|
1703
|
+
return this.httpClient.get("/transactions", {
|
|
1704
|
+
transactionsRequestQueryParams
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
};
|
|
1708
|
+
|
|
1709
|
+
// src/core/index.ts
|
|
1710
|
+
var CoreClient = class {
|
|
1711
|
+
constructor(config) {
|
|
1712
|
+
this.config = config;
|
|
1713
|
+
if (!this.config) {
|
|
1714
|
+
throw new Error("Config is required");
|
|
1715
|
+
}
|
|
1716
|
+
if (!this.config.apiBaseUrl) {
|
|
1717
|
+
throw new Error("API base URL is required");
|
|
1718
|
+
}
|
|
1719
|
+
const { apiBaseUrl, apiTimeout } = this.config;
|
|
1720
|
+
this.arcApiService = new ArcApiService({
|
|
1721
|
+
baseUrl: apiBaseUrl,
|
|
1722
|
+
timeout: apiTimeout ?? 3e4
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
/**
|
|
1726
|
+
* Get all chains metadata from AggLayer API
|
|
1727
|
+
*/
|
|
1728
|
+
async getAllChains() {
|
|
1729
|
+
const response = await this.arcApiService.chains();
|
|
1730
|
+
if (response.data.status === "success") {
|
|
1731
|
+
return response.data.data;
|
|
1732
|
+
}
|
|
1733
|
+
throw new Error(response.data.message);
|
|
1734
|
+
}
|
|
1735
|
+
/**
|
|
1736
|
+
* Get chain metadata by id from AggLayer API
|
|
1737
|
+
* @param ids - the ids of the chains to get metadata for
|
|
1738
|
+
*/
|
|
1739
|
+
async getChainMetadataByChainIds(ids) {
|
|
1740
|
+
const response = await this.arcApiService.chains({ chainIds: ids });
|
|
1741
|
+
if (response.data.status === "success") {
|
|
1742
|
+
return response.data.data;
|
|
1743
|
+
}
|
|
1744
|
+
throw new Error(response.data.message);
|
|
1745
|
+
}
|
|
1746
|
+
/**
|
|
1747
|
+
* Get all tokens from AggLayer API
|
|
1748
|
+
*/
|
|
1749
|
+
async getTokens() {
|
|
1750
|
+
const response = await this.arcApiService.chains({
|
|
1751
|
+
withSupportedTokens: true
|
|
1752
|
+
});
|
|
1753
|
+
if (response.data.status === "success") {
|
|
1754
|
+
return response.data.data;
|
|
1755
|
+
}
|
|
1756
|
+
throw new Error(response.data.message);
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Get chain data and tokens by AggLayer API
|
|
1760
|
+
* @param ids - the ids of the chains to get data and tokens for
|
|
1761
|
+
*/
|
|
1762
|
+
async getChainDataAndTokensByChainIds(ids) {
|
|
1763
|
+
const response = await this.arcApiService.chains({
|
|
1764
|
+
chainIds: ids,
|
|
1765
|
+
withSupportedTokens: true
|
|
1766
|
+
});
|
|
1767
|
+
if (response.data.status === "success") {
|
|
1768
|
+
return response.data.data;
|
|
1769
|
+
}
|
|
1770
|
+
throw new Error(response.data.message);
|
|
1771
|
+
}
|
|
1772
|
+
/**
|
|
1773
|
+
* Get all routes from AggLayer API
|
|
1774
|
+
*/
|
|
1775
|
+
async getRoutes(routesRequestParams) {
|
|
1776
|
+
const response = await this.arcApiService.routes(routesRequestParams);
|
|
1777
|
+
if (response.data.status === "success") {
|
|
1778
|
+
return response.data.data;
|
|
1779
|
+
}
|
|
1780
|
+
throw new Error(response.data.message);
|
|
1781
|
+
}
|
|
1782
|
+
/**
|
|
1783
|
+
* Build transaction from a step object
|
|
1784
|
+
*/
|
|
1785
|
+
async buildTransaction(builtTransactionRequestBody) {
|
|
1786
|
+
const response = await this.arcApiService.buildTransaction(
|
|
1787
|
+
builtTransactionRequestBody
|
|
1788
|
+
);
|
|
1789
|
+
if (response.data.status === "success") {
|
|
1790
|
+
return response.data.data;
|
|
1791
|
+
}
|
|
1792
|
+
throw new Error(response.data.message);
|
|
1793
|
+
}
|
|
1794
|
+
/**
|
|
1795
|
+
* Get all transactions via web sockets
|
|
1796
|
+
*/
|
|
1797
|
+
async getTransactions(transactionsRequestQueryParams) {
|
|
1798
|
+
const response = await this.arcApiService.transactions(
|
|
1799
|
+
transactionsRequestQueryParams
|
|
1800
|
+
);
|
|
1801
|
+
if (response.data.status === "success") {
|
|
1802
|
+
return response.data.data;
|
|
1803
|
+
}
|
|
1804
|
+
throw new Error(response.data.message);
|
|
1805
|
+
}
|
|
1806
|
+
};
|
|
1807
|
+
|
|
1808
|
+
// src/index.ts
|
|
1809
|
+
var AggLayerSDK = class {
|
|
1810
|
+
constructor(config) {
|
|
1811
|
+
this.config = config;
|
|
1812
|
+
if (!config.mode || config.mode && config.mode.length === 0) {
|
|
1813
|
+
this.config.mode = ["CORE"];
|
|
1814
|
+
}
|
|
1815
|
+
if (config.mode.includes(SDK_MODES.CORE)) {
|
|
1816
|
+
if (!this.config.core) {
|
|
1817
|
+
throw new Error("Core config is required");
|
|
1818
|
+
}
|
|
1819
|
+
this.core = new CoreClient(this.config.core);
|
|
1820
|
+
}
|
|
1821
|
+
if (this.config.mode?.includes(SDK_MODES.NATIVE)) {
|
|
1822
|
+
if (!this.config.native) {
|
|
1823
|
+
throw new Error("NATIVE config is required");
|
|
1824
|
+
}
|
|
1825
|
+
const nativeConfig = {
|
|
1826
|
+
defaultNetwork: this.config.native?.defaultNetwork || DEFAULT_NETWORK,
|
|
1827
|
+
...this.config.native?.chains && {
|
|
1828
|
+
chains: this.config.native.chains
|
|
1829
|
+
},
|
|
1830
|
+
...this.config.native?.customRpcUrls && {
|
|
1831
|
+
customRpcUrls: this.config.native.customRpcUrls
|
|
1832
|
+
}
|
|
1833
|
+
};
|
|
1834
|
+
this.native = new NativeClient(nativeConfig);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
/**
|
|
1838
|
+
* Get core submodule
|
|
1839
|
+
*/
|
|
1840
|
+
getCore() {
|
|
1841
|
+
if (!this.core) {
|
|
1842
|
+
throw new Error('Core module not initialized. Add "core" to mode array.');
|
|
1843
|
+
}
|
|
1844
|
+
return this.core;
|
|
1845
|
+
}
|
|
1846
|
+
/**
|
|
1847
|
+
* Get native submodule
|
|
1848
|
+
*/
|
|
1849
|
+
getNative() {
|
|
1850
|
+
if (!this.native) {
|
|
1851
|
+
throw new Error(
|
|
1852
|
+
'NATIVE module not initialized. Add "native" to mode array.'
|
|
1853
|
+
);
|
|
1854
|
+
}
|
|
1855
|
+
return this.native;
|
|
1856
|
+
}
|
|
1857
|
+
};
|
|
1858
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1859
|
+
0 && (module.exports = {
|
|
1860
|
+
AggLayerSDK,
|
|
1861
|
+
SDK_MODES
|
|
1862
|
+
});
|
|
1863
|
+
//# sourceMappingURL=index.js.map
|