@matterlabs/zksync-js 0.0.13 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/ethers/client.cjs +13 -4
- package/dist/adapters/ethers/client.cjs.map +1 -1
- package/dist/adapters/ethers/client.d.ts +1 -2
- package/dist/adapters/ethers/client.js +6 -6
- package/dist/adapters/ethers/index.cjs +607 -259
- package/dist/adapters/ethers/index.cjs.map +1 -1
- package/dist/adapters/ethers/index.js +9 -9
- package/dist/adapters/ethers/resources/deposits/routes/priority.d.ts +12 -0
- package/dist/adapters/ethers/resources/deposits/services/gas.d.ts +4 -0
- package/dist/adapters/ethers/resources/interop/index.d.ts +14 -14
- package/dist/adapters/ethers/resources/interop/resolvers.d.ts +3 -8
- package/dist/adapters/ethers/resources/interop/routes/types.d.ts +2 -1
- package/dist/adapters/ethers/resources/interop/services/erc20.d.ts +10 -0
- package/dist/adapters/ethers/resources/interop/services/fee.d.ts +12 -0
- package/dist/adapters/ethers/resources/interop/services/finalization/index.d.ts +1 -1
- package/dist/adapters/ethers/resources/interop/services/finalization/polling.d.ts +1 -1
- package/dist/adapters/ethers/resources/interop/services/gas.d.ts +12 -0
- package/dist/adapters/ethers/resources/interop/types.d.ts +6 -14
- package/dist/adapters/ethers/sdk.cjs +1008 -259
- package/dist/adapters/ethers/sdk.cjs.map +1 -1
- package/dist/adapters/ethers/sdk.d.ts +6 -1
- package/dist/adapters/ethers/sdk.js +7 -7
- package/dist/adapters/viem/client.cjs +795 -7
- package/dist/adapters/viem/client.cjs.map +1 -1
- package/dist/adapters/viem/client.d.ts +6 -1
- package/dist/adapters/viem/client.js +6 -6
- package/dist/adapters/viem/index.cjs +6490 -2799
- package/dist/adapters/viem/index.cjs.map +1 -1
- package/dist/adapters/viem/index.d.ts +5 -0
- package/dist/adapters/viem/index.js +9 -9
- package/dist/adapters/viem/resources/deposits/routes/priority.d.ts +13 -0
- package/dist/adapters/viem/resources/deposits/services/gas.d.ts +4 -0
- package/dist/adapters/viem/resources/interop/address.d.ts +18 -0
- package/dist/adapters/viem/resources/interop/attributes/resource.d.ts +6 -0
- package/dist/adapters/viem/resources/interop/context.d.ts +31 -0
- package/dist/adapters/viem/resources/interop/index.d.ts +62 -0
- package/dist/adapters/viem/resources/interop/resolvers.d.ts +4 -0
- package/dist/adapters/viem/resources/interop/routes/direct.d.ts +2 -0
- package/dist/adapters/viem/resources/interop/routes/indirect.d.ts +2 -0
- package/dist/adapters/viem/resources/interop/routes/types.d.ts +23 -0
- package/dist/adapters/viem/resources/interop/services/erc20.d.ts +25 -0
- package/dist/adapters/viem/resources/interop/services/fee.d.ts +12 -0
- package/dist/adapters/viem/resources/interop/services/finalization/bundle.d.ts +15 -0
- package/dist/adapters/viem/resources/interop/services/finalization/data-fetchers.d.ts +17 -0
- package/dist/adapters/viem/resources/interop/services/finalization/decoders.d.ts +11 -0
- package/dist/adapters/viem/resources/interop/services/finalization/index.d.ts +13 -0
- package/dist/adapters/viem/resources/interop/services/finalization/polling.d.ts +7 -0
- package/dist/adapters/viem/resources/interop/services/finalization/status.d.ts +5 -0
- package/dist/adapters/viem/resources/interop/services/finalization/topics.d.ts +4 -0
- package/dist/adapters/viem/resources/interop/services/gas.d.ts +12 -0
- package/dist/adapters/viem/resources/interop/services/starter-data.d.ts +6 -0
- package/dist/adapters/viem/resources/interop/types.d.ts +8 -0
- package/dist/adapters/viem/sdk.cjs +6401 -2758
- package/dist/adapters/viem/sdk.cjs.map +1 -1
- package/dist/adapters/viem/sdk.d.ts +8 -1
- package/dist/adapters/viem/sdk.js +7 -7
- package/dist/{chunk-E3KP7XCG.js → chunk-3HHUZXSV.js} +1 -1
- package/dist/{chunk-EDWBCPO3.js → chunk-4PZCNTQ3.js} +1387 -71
- package/dist/{chunk-UDBRUBEK.js → chunk-65HAYKVL.js} +2 -2
- package/dist/chunk-BWKWWLY4.js +9 -0
- package/dist/{chunk-JHO2UQ5F.js → chunk-HGB3DOV2.js} +445 -554
- package/dist/{chunk-HI64OOAR.js → chunk-HVHMLAYH.js} +1 -1
- package/dist/{chunk-2RIARDXZ.js → chunk-JHRYNLZG.js} +65 -7
- package/dist/{chunk-RI73VJSH.js → chunk-JXR5V5YK.js} +463 -27
- package/dist/chunk-K2UVKMLN.js +658 -0
- package/dist/{chunk-53MC5BR2.js → chunk-MDPX5LNW.js} +1 -1
- package/dist/{chunk-QQ2OR434.js → chunk-MT4X5FEO.js} +18 -2
- package/dist/{chunk-R5WRFPK2.js → chunk-MZBKM3GH.js} +4 -4
- package/dist/{chunk-5R7L5NM5.js → chunk-YIWXIP2M.js} +10 -2
- package/dist/core/constants.cjs +17 -1
- package/dist/core/constants.cjs.map +1 -1
- package/dist/core/constants.d.ts +9 -1
- package/dist/core/constants.js +1 -1
- package/dist/core/index.cjs +52 -24
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +5 -5
- package/dist/core/internal/abis/IERC7786Attributes.d.ts +21 -11
- package/dist/core/internal/abis/IInteropCenter.d.ts +4 -0
- package/dist/core/resources/deposits/chains.d.ts +1 -0
- package/dist/core/resources/deposits/gas.d.ts +7 -0
- package/dist/core/resources/deposits/priority.d.ts +41 -0
- package/dist/core/resources/interop/attributes/bundle.d.ts +1 -0
- package/dist/core/resources/interop/attributes/resource.d.ts +1 -0
- package/dist/core/resources/interop/plan.d.ts +11 -3
- package/dist/core/resources/interop/protocol.d.ts +3 -0
- package/dist/core/rpc/types.d.ts +1 -0
- package/dist/core/rpc/zks.d.ts +5 -1
- package/dist/core/types/errors.d.ts +5 -0
- package/dist/core/types/flows/interop.d.ts +11 -20
- package/dist/core/types/primitives.d.ts +2 -0
- package/dist/index.cjs +69 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -5
- package/package.json +1 -1
- package/dist/chunk-4S4XDA4N.js +0 -415
- package/dist/chunk-5L6EYUJB.js +0 -237
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { createErrorHandlers, toZKsyncError, classifyReadinessFromRevert } from './chunk-
|
|
2
|
-
import { createNTVCodec, toGasOverrides, buildFeeBreakdown, quoteL2Gas, quoteL2BaseCost, quoteL1Gas, quoteL2Gas2 } from './chunk-
|
|
3
|
-
import { findL1MessageSentLog, messengerLogIndex,
|
|
4
|
-
import { isHash66, IL1Nullifier_default, OP_WITHDRAWALS, createError, normalizeL1Token, isAddressEq, hexEq, OP_DEPOSITS, IERC20_default, isZKsyncError, isReceiptNotFound, OP_INTEROP, IInteropHandler_default, IERC7786Attributes_default,
|
|
5
|
-
import { ETH_ADDRESS, TOPIC_CANONICAL_ASSIGNED, TOPIC_CANONICAL_SUCCESS, L1_MESSENGER_ADDRESS, L2_BASE_TOKEN_ADDRESS, L2_NATIVE_TOKEN_VAULT_ADDRESS,
|
|
6
|
-
import { Interface, AbiCoder, ethers, getBytes, Contract, NonceManager, JsonRpcProvider,
|
|
1
|
+
import { createErrorHandlers, toZKsyncError, classifyReadinessFromRevert } from './chunk-65HAYKVL.js';
|
|
2
|
+
import { createNTVCodec, resolveCreateDepositL1GasLimit, isInteropFinalizationInfo, DEFAULT_POLL_MS, DEFAULT_TIMEOUT_MS, resolveIdsFromWaitable, parseBundleReceiptInfo, buildFinalizationInfo, parseBundleSentFromReceipt, createAttributesResource, pickInteropRoute, ZERO_HASH, toGasOverrides, applyPriorityL2GasLimitBuffer, buildFeeBreakdown, buildIndirectBundle, preflightIndirect, buildDirectBundle, preflightDirect, derivePriorityTxGasBreakdown, quoteL2Gas, quoteL2BaseCost, quoteL1Gas, derivePriorityBodyGasEstimateCap, quoteL2Gas2, assertProtocolVersion } from './chunk-K2UVKMLN.js';
|
|
3
|
+
import { findL1MessageSentLog, messengerLogIndex, pickWithdrawRoute } from './chunk-3HHUZXSV.js';
|
|
4
|
+
import { isHash66, IL1Nullifier_default, OP_WITHDRAWALS, createError, normalizeL1Token, isAddressEq, hexEq, OP_DEPOSITS, IERC20_default, isZKsyncError, isReceiptNotFound, OP_INTEROP, IInteropHandler_default, IERC7786Attributes_default, IInteropCenter_default, sleep, isETH, normalizeAddrEq, IInteropRootStorage_default, IL2AssetRouter_default, L2NativeTokenVault_default, assertNever } from './chunk-JXR5V5YK.js';
|
|
5
|
+
import { ETH_ADDRESS, TOPIC_CANONICAL_ASSIGNED, TOPIC_CANONICAL_SUCCESS, L1_MESSENGER_ADDRESS, L2_BASE_TOKEN_ADDRESS, L2_NATIVE_TOKEN_VAULT_ADDRESS, BUFFER, L2_INTEROP_ROOT_STORAGE_ADDRESS, SAFE_L1_BRIDGE_GAS, L2_ASSET_ROUTER_ADDRESS, FORMAL_ETH_ADDRESS } from './chunk-MT4X5FEO.js';
|
|
6
|
+
import { Interface, keccak256, AbiCoder, ethers, getBytes, Contract, NonceManager, JsonRpcProvider, getAddress, concat, hexlify, toBeArray, toBeHex, isError } from 'ethers';
|
|
7
7
|
|
|
8
8
|
var I_BRIDGEHUB = new Interface([
|
|
9
9
|
"event NewPriorityRequest(uint256 indexed chainId, address indexed sender, bytes32 txHash, uint256 txId, bytes data)"
|
|
@@ -279,8 +279,22 @@ async function determineNonBaseL2Gas(input) {
|
|
|
279
279
|
try {
|
|
280
280
|
const l2TokenAddress = input.knownL2Token ?? (ctx.tokens ? await ctx.tokens.toL2Address(l1Token) : await (await ctx.contracts.l2NativeTokenVault()).l2TokenAddress(l1Token));
|
|
281
281
|
if (l2TokenAddress === ZERO_L2_TOKEN_ADDRESS) {
|
|
282
|
+
if (input.undeployedGasLimit != null) {
|
|
283
|
+
return quoteL2Gas3({
|
|
284
|
+
ctx,
|
|
285
|
+
route,
|
|
286
|
+
overrideGasLimit: input.undeployedGasLimit
|
|
287
|
+
});
|
|
288
|
+
}
|
|
282
289
|
return fallbackQuote();
|
|
283
290
|
}
|
|
291
|
+
if (input.priorityFloorGasLimit != null) {
|
|
292
|
+
return quoteL2Gas3({
|
|
293
|
+
ctx,
|
|
294
|
+
route,
|
|
295
|
+
overrideGasLimit: input.priorityFloorGasLimit
|
|
296
|
+
});
|
|
297
|
+
}
|
|
284
298
|
const modelTx = {
|
|
285
299
|
to: input.modelTx?.to ?? ctx.sender,
|
|
286
300
|
from: input.modelTx?.from ?? ctx.sender,
|
|
@@ -296,8 +310,7 @@ async function determineNonBaseL2Gas(input) {
|
|
|
296
310
|
return fallbackQuote();
|
|
297
311
|
}
|
|
298
312
|
return gas;
|
|
299
|
-
} catch
|
|
300
|
-
console.warn("Failed to determine non-base deposit L2 gas; defaulting to safe gas limit.", err);
|
|
313
|
+
} catch {
|
|
301
314
|
return fallbackQuote();
|
|
302
315
|
}
|
|
303
316
|
}
|
|
@@ -314,45 +327,89 @@ async function determineEthNonBaseL2Gas(input) {
|
|
|
314
327
|
route: "eth-nonbase",
|
|
315
328
|
l1Token: input.ctx.resolvedToken?.l1 ?? FORMAL_ETH_ADDRESS,
|
|
316
329
|
knownL2Token: input.ctx.resolvedToken?.l2,
|
|
317
|
-
modelTx: input.modelTx
|
|
330
|
+
modelTx: input.modelTx,
|
|
331
|
+
priorityFloorGasLimit: input.priorityFloorGasLimit,
|
|
332
|
+
undeployedGasLimit: input.undeployedGasLimit
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
var EMPTY_BYTES = "0x";
|
|
336
|
+
var ZERO_RESERVED_WORDS = [0n, 0n, 0n, 0n];
|
|
337
|
+
var L2_CANONICAL_TRANSACTION_TUPLE = "tuple(uint256 txType,uint256 from,uint256 to,uint256 gasLimit,uint256 gasPerPubdataByteLimit,uint256 maxFeePerGas,uint256 maxPriorityFeePerGas,uint256 paymaster,uint256 nonce,uint256 value,uint256[4] reserved,bytes data,bytes signature,uint256[] factoryDeps,bytes paymasterInput,bytes reservedDynamic)";
|
|
338
|
+
function hexByteLength(hex) {
|
|
339
|
+
return BigInt(Math.max(hex.length - 2, 0) / 2);
|
|
340
|
+
}
|
|
341
|
+
function getPriorityTxEncodedLength(input) {
|
|
342
|
+
const encoded = AbiCoder.defaultAbiCoder().encode(
|
|
343
|
+
[L2_CANONICAL_TRANSACTION_TUPLE],
|
|
344
|
+
[
|
|
345
|
+
[
|
|
346
|
+
0n,
|
|
347
|
+
BigInt(input.sender),
|
|
348
|
+
BigInt(input.l2Contract),
|
|
349
|
+
0n,
|
|
350
|
+
input.gasPerPubdata,
|
|
351
|
+
0n,
|
|
352
|
+
0n,
|
|
353
|
+
0n,
|
|
354
|
+
0n,
|
|
355
|
+
input.l2Value,
|
|
356
|
+
ZERO_RESERVED_WORDS,
|
|
357
|
+
input.l2Calldata,
|
|
358
|
+
EMPTY_BYTES,
|
|
359
|
+
input.factoryDepsHashes ?? [],
|
|
360
|
+
EMPTY_BYTES,
|
|
361
|
+
EMPTY_BYTES
|
|
362
|
+
]
|
|
363
|
+
]
|
|
364
|
+
);
|
|
365
|
+
return hexByteLength(encoded);
|
|
366
|
+
}
|
|
367
|
+
function getPriorityTxGasBreakdown(input) {
|
|
368
|
+
return derivePriorityTxGasBreakdown({
|
|
369
|
+
encodedLength: getPriorityTxEncodedLength(input),
|
|
370
|
+
gasPerPubdata: input.gasPerPubdata,
|
|
371
|
+
factoryDepsCount: BigInt(input.factoryDepsHashes?.length ?? 0)
|
|
318
372
|
});
|
|
319
373
|
}
|
|
320
374
|
|
|
321
375
|
// src/adapters/ethers/resources/deposits/routes/eth.ts
|
|
376
|
+
var EMPTY_BYTES2 = "0x";
|
|
322
377
|
function routeEthDirect() {
|
|
323
378
|
return {
|
|
324
379
|
async build(p, ctx) {
|
|
325
380
|
const bh = await ctx.contracts.bridgehub();
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
381
|
+
const l2Contract = p.to ?? ctx.sender;
|
|
382
|
+
const l2Value = p.amount;
|
|
383
|
+
const l2Calldata = EMPTY_BYTES2;
|
|
384
|
+
const priorityFloorBreakdown = getPriorityTxGasBreakdown({
|
|
385
|
+
sender: ctx.sender,
|
|
386
|
+
l2Contract,
|
|
387
|
+
l2Value,
|
|
388
|
+
l2Calldata,
|
|
389
|
+
gasPerPubdata: ctx.gasPerPubdata
|
|
390
|
+
});
|
|
391
|
+
const quotedL2GasLimit = ctx.l2GasLimit ?? applyPriorityL2GasLimitBuffer({
|
|
392
|
+
chainIdL2: ctx.chainIdL2,
|
|
393
|
+
gasLimit: priorityFloorBreakdown.derivedL2GasLimit
|
|
394
|
+
});
|
|
332
395
|
const l2GasParams = await quoteL2Gas3({
|
|
333
396
|
ctx,
|
|
334
397
|
route: "eth-base",
|
|
335
|
-
|
|
336
|
-
overrideGasLimit: ctx.l2GasLimit,
|
|
337
|
-
stateOverrides: {
|
|
338
|
-
[ctx.sender]: {
|
|
339
|
-
balance: "0xffffffffffffffffffff"
|
|
340
|
-
}
|
|
341
|
-
}
|
|
398
|
+
overrideGasLimit: quotedL2GasLimit
|
|
342
399
|
});
|
|
343
400
|
if (!l2GasParams) {
|
|
344
401
|
throw new Error("Failed to estimate L2 gas for deposit.");
|
|
345
402
|
}
|
|
346
403
|
const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
347
|
-
const mintValue = baseCost + ctx.operatorTip +
|
|
404
|
+
const mintValue = baseCost + ctx.operatorTip + l2Value;
|
|
348
405
|
const req = buildDirectRequestStruct({
|
|
349
406
|
chainId: ctx.chainIdL2,
|
|
350
407
|
mintValue,
|
|
351
408
|
l2GasLimit: l2GasParams.gasLimit,
|
|
352
409
|
gasPerPubdata: ctx.gasPerPubdata,
|
|
353
410
|
refundRecipient: ctx.refundRecipient,
|
|
354
|
-
l2Contract
|
|
355
|
-
l2Value
|
|
411
|
+
l2Contract,
|
|
412
|
+
l2Value
|
|
356
413
|
});
|
|
357
414
|
const data = bh.interface.encodeFunctionData("requestL2TransactionDirect", [req]);
|
|
358
415
|
const l1TxCandidate = {
|
|
@@ -396,12 +453,57 @@ function routeEthDirect() {
|
|
|
396
453
|
}
|
|
397
454
|
};
|
|
398
455
|
}
|
|
399
|
-
|
|
400
|
-
// src/core/types/primitives.ts
|
|
401
|
-
var ZERO_HASH = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
402
|
-
|
|
403
|
-
// src/adapters/ethers/resources/deposits/routes/erc20-nonbase.ts
|
|
404
456
|
var { wrapAs: wrapAs2 } = createErrorHandlers("deposits");
|
|
457
|
+
var ZERO_L2_TOKEN_ADDRESS2 = "0x0000000000000000000000000000000000000000";
|
|
458
|
+
var ZERO_ASSET_ID = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
459
|
+
async function getPriorityGasModel(input) {
|
|
460
|
+
try {
|
|
461
|
+
const l1NativeTokenVault = await input.ctx.contracts.l1NativeTokenVault();
|
|
462
|
+
const l1AssetRouter = await input.ctx.contracts.l1AssetRouter();
|
|
463
|
+
const { chainId: l1ChainId } = await input.ctx.client.l1.getNetwork();
|
|
464
|
+
const isFirstBridge = input.ctx.resolvedToken.assetId.toLowerCase() === ZERO_ASSET_ID || input.ctx.resolvedToken.originChainId === 0n;
|
|
465
|
+
const erc20MetadataOriginChainId = isFirstBridge ? BigInt(l1ChainId) : input.ctx.resolvedToken.originChainId;
|
|
466
|
+
const erc20Metadata = await l1NativeTokenVault.getERC20Getters(
|
|
467
|
+
input.token,
|
|
468
|
+
erc20MetadataOriginChainId
|
|
469
|
+
);
|
|
470
|
+
const bridgeMintCalldata = AbiCoder.defaultAbiCoder().encode(
|
|
471
|
+
["address", "address", "address", "uint256", "bytes"],
|
|
472
|
+
[input.ctx.sender, input.receiver, input.token, input.amount, erc20Metadata]
|
|
473
|
+
);
|
|
474
|
+
const l2Calldata = isFirstBridge ? new Interface(IL2AssetRouter_default).encodeFunctionData(
|
|
475
|
+
"finalizeDeposit(address,address,address,uint256,bytes)",
|
|
476
|
+
[input.ctx.sender, input.receiver, input.token, input.amount, erc20Metadata]
|
|
477
|
+
) : await (() => {
|
|
478
|
+
return l1AssetRouter.getDepositCalldata(
|
|
479
|
+
input.ctx.sender,
|
|
480
|
+
input.ctx.resolvedToken.assetId,
|
|
481
|
+
bridgeMintCalldata
|
|
482
|
+
);
|
|
483
|
+
})();
|
|
484
|
+
const priorityFloorBreakdown = getPriorityTxGasBreakdown({
|
|
485
|
+
sender: input.ctx.l1AssetRouter,
|
|
486
|
+
l2Contract: L2_ASSET_ROUTER_ADDRESS,
|
|
487
|
+
l2Value: 0n,
|
|
488
|
+
l2Calldata,
|
|
489
|
+
gasPerPubdata: input.ctx.gasPerPubdata
|
|
490
|
+
});
|
|
491
|
+
const model = {
|
|
492
|
+
priorityFloorGasLimit: applyPriorityL2GasLimitBuffer({
|
|
493
|
+
chainIdL2: input.ctx.chainIdL2,
|
|
494
|
+
gasLimit: priorityFloorBreakdown.derivedL2GasLimit
|
|
495
|
+
})
|
|
496
|
+
};
|
|
497
|
+
if (isFirstBridge || input.ctx.resolvedToken.l2.toLowerCase() === ZERO_L2_TOKEN_ADDRESS2) {
|
|
498
|
+
model.undeployedGasLimit = derivePriorityBodyGasEstimateCap({
|
|
499
|
+
minBodyGas: priorityFloorBreakdown.minBodyGas
|
|
500
|
+
}) + priorityFloorBreakdown.overhead;
|
|
501
|
+
}
|
|
502
|
+
return model;
|
|
503
|
+
} catch {
|
|
504
|
+
return {};
|
|
505
|
+
}
|
|
506
|
+
}
|
|
405
507
|
function routeErc20NonBase() {
|
|
406
508
|
return {
|
|
407
509
|
async preflight(p, ctx) {
|
|
@@ -422,11 +524,29 @@ function routeErc20NonBase() {
|
|
|
422
524
|
const l1Signer = ctx.client.getL1Signer();
|
|
423
525
|
const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
|
|
424
526
|
const baseIsEth = ctx.baseIsEth ?? isETH(baseToken);
|
|
527
|
+
const receiver = p.to ?? ctx.sender;
|
|
528
|
+
const secondBridgeCalldata = await wrapAs2(
|
|
529
|
+
"INTERNAL",
|
|
530
|
+
OP_DEPOSITS.nonbase.encodeCalldata,
|
|
531
|
+
() => Promise.resolve(encodeSecondBridgeErc20Args(p.token, p.amount, receiver)),
|
|
532
|
+
{
|
|
533
|
+
ctx: { where: "encodeSecondBridgeErc20Args" },
|
|
534
|
+
message: "Failed to encode bridging calldata."
|
|
535
|
+
}
|
|
536
|
+
);
|
|
537
|
+
const priorityGasModel = await getPriorityGasModel({
|
|
538
|
+
ctx,
|
|
539
|
+
token: p.token,
|
|
540
|
+
amount: p.amount,
|
|
541
|
+
receiver
|
|
542
|
+
});
|
|
425
543
|
const l2GasParams = await determineErc20L2Gas({
|
|
426
544
|
ctx,
|
|
427
545
|
l1Token: p.token,
|
|
546
|
+
priorityFloorGasLimit: priorityGasModel.priorityFloorGasLimit,
|
|
547
|
+
undeployedGasLimit: priorityGasModel.undeployedGasLimit,
|
|
428
548
|
modelTx: {
|
|
429
|
-
to:
|
|
549
|
+
to: receiver,
|
|
430
550
|
from: ctx.sender,
|
|
431
551
|
data: "0x",
|
|
432
552
|
value: 0n
|
|
@@ -488,15 +608,6 @@ function routeErc20NonBase() {
|
|
|
488
608
|
});
|
|
489
609
|
}
|
|
490
610
|
}
|
|
491
|
-
const secondBridgeCalldata = await wrapAs2(
|
|
492
|
-
"INTERNAL",
|
|
493
|
-
OP_DEPOSITS.nonbase.encodeCalldata,
|
|
494
|
-
() => Promise.resolve(encodeSecondBridgeErc20Args(p.token, p.amount, p.to ?? ctx.sender)),
|
|
495
|
-
{
|
|
496
|
-
ctx: { where: "encodeSecondBridgeErc20Args" },
|
|
497
|
-
message: "Failed to encode bridging calldata."
|
|
498
|
-
}
|
|
499
|
-
);
|
|
500
611
|
const requestStruct = {
|
|
501
612
|
chainId: ctx.chainIdL2,
|
|
502
613
|
mintValue,
|
|
@@ -554,6 +665,54 @@ function routeErc20NonBase() {
|
|
|
554
665
|
};
|
|
555
666
|
}
|
|
556
667
|
var { wrapAs: wrapAs3 } = createErrorHandlers("deposits");
|
|
668
|
+
var ZERO_L2_TOKEN_ADDRESS3 = "0x0000000000000000000000000000000000000000";
|
|
669
|
+
var ZERO_ASSET_ID2 = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
670
|
+
var ntvCodec = createNTVCodec({
|
|
671
|
+
encode: (types, values) => AbiCoder.defaultAbiCoder().encode(types, values),
|
|
672
|
+
keccak256: (data) => keccak256(data)
|
|
673
|
+
});
|
|
674
|
+
async function getPriorityGasModel2(input) {
|
|
675
|
+
try {
|
|
676
|
+
const l1AssetRouter = await input.ctx.contracts.l1AssetRouter();
|
|
677
|
+
const l1NativeTokenVault = await input.ctx.contracts.l1NativeTokenVault();
|
|
678
|
+
const originChainId = input.ctx.resolvedToken.originChainId !== 0n ? input.ctx.resolvedToken.originChainId : BigInt((await input.ctx.client.l1.getNetwork()).chainId);
|
|
679
|
+
const resolvedAssetId = input.ctx.resolvedToken.assetId.toLowerCase() === ZERO_ASSET_ID2 ? ntvCodec.encodeAssetId(originChainId, L2_NATIVE_TOKEN_VAULT_ADDRESS, ETH_ADDRESS) : input.ctx.resolvedToken.assetId;
|
|
680
|
+
const erc20Metadata = await l1NativeTokenVault.getERC20Getters(
|
|
681
|
+
ETH_ADDRESS,
|
|
682
|
+
originChainId
|
|
683
|
+
);
|
|
684
|
+
const bridgeMintCalldata = AbiCoder.defaultAbiCoder().encode(
|
|
685
|
+
["address", "address", "address", "uint256", "bytes"],
|
|
686
|
+
[input.ctx.sender, input.receiver, ETH_ADDRESS, input.amount, erc20Metadata]
|
|
687
|
+
);
|
|
688
|
+
const l2Calldata = await l1AssetRouter.getDepositCalldata(
|
|
689
|
+
input.ctx.sender,
|
|
690
|
+
resolvedAssetId,
|
|
691
|
+
bridgeMintCalldata
|
|
692
|
+
);
|
|
693
|
+
const priorityFloorBreakdown = getPriorityTxGasBreakdown({
|
|
694
|
+
sender: input.ctx.l1AssetRouter,
|
|
695
|
+
l2Contract: L2_ASSET_ROUTER_ADDRESS,
|
|
696
|
+
l2Value: 0n,
|
|
697
|
+
l2Calldata,
|
|
698
|
+
gasPerPubdata: input.ctx.gasPerPubdata
|
|
699
|
+
});
|
|
700
|
+
const model = {
|
|
701
|
+
priorityFloorGasLimit: applyPriorityL2GasLimitBuffer({
|
|
702
|
+
chainIdL2: input.ctx.chainIdL2,
|
|
703
|
+
gasLimit: priorityFloorBreakdown.derivedL2GasLimit
|
|
704
|
+
})
|
|
705
|
+
};
|
|
706
|
+
if (input.ctx.resolvedToken.l2.toLowerCase() === ZERO_L2_TOKEN_ADDRESS3) {
|
|
707
|
+
model.undeployedGasLimit = derivePriorityBodyGasEstimateCap({
|
|
708
|
+
minBodyGas: priorityFloorBreakdown.minBodyGas
|
|
709
|
+
}) + priorityFloorBreakdown.overhead;
|
|
710
|
+
}
|
|
711
|
+
return model;
|
|
712
|
+
} catch {
|
|
713
|
+
return {};
|
|
714
|
+
}
|
|
715
|
+
}
|
|
557
716
|
function routeEthNonBase() {
|
|
558
717
|
return {
|
|
559
718
|
async preflight(p, ctx) {
|
|
@@ -602,15 +761,23 @@ function routeEthNonBase() {
|
|
|
602
761
|
async build(p, ctx) {
|
|
603
762
|
const l1Signer = ctx.client.getL1Signer();
|
|
604
763
|
const baseToken = ctx.baseTokenL1;
|
|
764
|
+
const receiver = p.to ?? ctx.sender;
|
|
765
|
+
const priorityGasModel = await getPriorityGasModel2({
|
|
766
|
+
ctx,
|
|
767
|
+
amount: p.amount,
|
|
768
|
+
receiver
|
|
769
|
+
});
|
|
605
770
|
const l2TxModel = {
|
|
606
|
-
to:
|
|
771
|
+
to: receiver,
|
|
607
772
|
from: ctx.sender,
|
|
608
773
|
data: "0x",
|
|
609
774
|
value: 0n
|
|
610
775
|
};
|
|
611
776
|
const l2GasParams = await determineEthNonBaseL2Gas({
|
|
612
777
|
ctx,
|
|
613
|
-
modelTx: l2TxModel
|
|
778
|
+
modelTx: l2TxModel,
|
|
779
|
+
priorityFloorGasLimit: priorityGasModel.priorityFloorGasLimit,
|
|
780
|
+
undeployedGasLimit: priorityGasModel.undeployedGasLimit
|
|
614
781
|
});
|
|
615
782
|
if (!l2GasParams) throw new Error("Failed to estimate L2 gas parameters.");
|
|
616
783
|
const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
@@ -644,12 +811,12 @@ function routeEthNonBase() {
|
|
|
644
811
|
const secondBridgeCalldata = await wrapAs3(
|
|
645
812
|
"INTERNAL",
|
|
646
813
|
OP_DEPOSITS.ethNonBase.encodeCalldata,
|
|
647
|
-
() => Promise.resolve(encodeSecondBridgeEthArgs(p.amount,
|
|
814
|
+
() => Promise.resolve(encodeSecondBridgeEthArgs(p.amount, receiver)),
|
|
648
815
|
{
|
|
649
816
|
ctx: {
|
|
650
817
|
where: "encodeSecondBridgeEthArgs",
|
|
651
818
|
amount: p.amount.toString(),
|
|
652
|
-
to:
|
|
819
|
+
to: receiver
|
|
653
820
|
}
|
|
654
821
|
}
|
|
655
822
|
);
|
|
@@ -710,6 +877,7 @@ function routeEthNonBase() {
|
|
|
710
877
|
};
|
|
711
878
|
}
|
|
712
879
|
var { wrapAs: wrapAs4 } = createErrorHandlers("deposits");
|
|
880
|
+
var EMPTY_BYTES3 = "0x";
|
|
713
881
|
function routeErc20Base() {
|
|
714
882
|
return {
|
|
715
883
|
async preflight(p, ctx) {
|
|
@@ -740,17 +908,24 @@ function routeErc20Base() {
|
|
|
740
908
|
async build(p, ctx) {
|
|
741
909
|
const l1Signer = ctx.client.getL1Signer();
|
|
742
910
|
const baseToken = ctx.baseTokenL1 ?? await ctx.client.baseToken(ctx.chainIdL2);
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
911
|
+
const l2Contract = p.to ?? ctx.sender;
|
|
912
|
+
const l2Value = p.amount;
|
|
913
|
+
const l2Calldata = EMPTY_BYTES3;
|
|
914
|
+
const priorityFloorBreakdown = getPriorityTxGasBreakdown({
|
|
915
|
+
sender: ctx.sender,
|
|
916
|
+
l2Contract,
|
|
917
|
+
l2Value,
|
|
918
|
+
l2Calldata,
|
|
919
|
+
gasPerPubdata: ctx.gasPerPubdata
|
|
920
|
+
});
|
|
921
|
+
const quotedL2GasLimit = ctx.l2GasLimit ?? applyPriorityL2GasLimitBuffer({
|
|
922
|
+
chainIdL2: ctx.chainIdL2,
|
|
923
|
+
gasLimit: priorityFloorBreakdown.derivedL2GasLimit
|
|
924
|
+
});
|
|
749
925
|
const l2GasParams = await quoteL2Gas3({
|
|
750
926
|
ctx,
|
|
751
927
|
route: "erc20-base",
|
|
752
|
-
|
|
753
|
-
overrideGasLimit: ctx.l2GasLimit
|
|
928
|
+
overrideGasLimit: quotedL2GasLimit
|
|
754
929
|
});
|
|
755
930
|
if (!l2GasParams) throw new Error("Failed to estimate L2 gas parameters.");
|
|
756
931
|
const baseCost = await quoteL2BaseCost2({ ctx, l2GasLimit: l2GasParams.gasLimit });
|
|
@@ -789,8 +964,8 @@ function routeErc20Base() {
|
|
|
789
964
|
l2GasLimit: l2GasParams.gasLimit,
|
|
790
965
|
gasPerPubdata: ctx.gasPerPubdata,
|
|
791
966
|
refundRecipient: ctx.refundRecipient,
|
|
792
|
-
l2Contract
|
|
793
|
-
l2Value
|
|
967
|
+
l2Contract,
|
|
968
|
+
l2Value
|
|
794
969
|
});
|
|
795
970
|
const bridgehub = await ctx.contracts.bridgehub();
|
|
796
971
|
const data = bridgehub.interface.encodeFunctionData("requestL2TransactionDirect", [
|
|
@@ -839,7 +1014,7 @@ function routeErc20Base() {
|
|
|
839
1014
|
}
|
|
840
1015
|
var { wrapAs: wrapAs5 } = createErrorHandlers("tokens");
|
|
841
1016
|
var abi = AbiCoder.defaultAbiCoder();
|
|
842
|
-
var
|
|
1017
|
+
var ntvCodec2 = createNTVCodec({
|
|
843
1018
|
encode: (types, values) => abi.encode(types, values),
|
|
844
1019
|
keccak256: (data) => ethers.keccak256(data)
|
|
845
1020
|
});
|
|
@@ -958,7 +1133,7 @@ function createTokensResource(client) {
|
|
|
958
1133
|
return wrapAs5("CONTRACT", "tokens.isChainEthBased", async () => {
|
|
959
1134
|
const baseAssetId = await getBaseTokenAssetId();
|
|
960
1135
|
const l1ChainId = await getL1ChainId();
|
|
961
|
-
const ethAssetId =
|
|
1136
|
+
const ethAssetId = ntvCodec2.encodeAssetId(
|
|
962
1137
|
l1ChainId,
|
|
963
1138
|
L2_NATIVE_TOKEN_VAULT_ADDRESS,
|
|
964
1139
|
ETH_ADDRESS
|
|
@@ -1172,6 +1347,8 @@ function createDepositsResource(client, tokens, contracts) {
|
|
|
1172
1347
|
async () => {
|
|
1173
1348
|
const plan = await prepare(p);
|
|
1174
1349
|
const stepHashes = {};
|
|
1350
|
+
const { chainId } = await client.l2.getNetwork();
|
|
1351
|
+
const chainIdL2 = BigInt(chainId);
|
|
1175
1352
|
const managed = new NonceManager(client.signer);
|
|
1176
1353
|
const from = await managed.getAddress();
|
|
1177
1354
|
let next;
|
|
@@ -1217,8 +1394,14 @@ function createDepositsResource(client, tokens, contracts) {
|
|
|
1217
1394
|
}
|
|
1218
1395
|
if (!p.l1TxOverrides?.gasLimit) {
|
|
1219
1396
|
try {
|
|
1397
|
+
const preparedGasLimit = step.tx.gasLimit != null ? BigInt(step.tx.gasLimit.toString()) : void 0;
|
|
1220
1398
|
const est = await client.l1.estimateGas(step.tx);
|
|
1221
|
-
step.tx.gasLimit =
|
|
1399
|
+
step.tx.gasLimit = resolveCreateDepositL1GasLimit({
|
|
1400
|
+
chainIdL2,
|
|
1401
|
+
stepKey: step.key,
|
|
1402
|
+
preparedGasLimit,
|
|
1403
|
+
estimatedGasLimit: BigInt(est)
|
|
1404
|
+
});
|
|
1222
1405
|
} catch {
|
|
1223
1406
|
}
|
|
1224
1407
|
}
|
|
@@ -1853,7 +2036,7 @@ var ROUTES2 = {
|
|
|
1853
2036
|
};
|
|
1854
2037
|
function createWithdrawalsResource(client, tokens, contracts) {
|
|
1855
2038
|
const svc = createFinalizationServices(client);
|
|
1856
|
-
const { wrap:
|
|
2039
|
+
const { wrap: wrap7, toResult: toResult3 } = createErrorHandlers("withdrawals");
|
|
1857
2040
|
const tokensResource = tokens ?? createTokensResource(client);
|
|
1858
2041
|
const contractsResource = contracts ?? createContractsResource(client);
|
|
1859
2042
|
async function buildPlan(p) {
|
|
@@ -1874,7 +2057,7 @@ function createWithdrawalsResource(client, tokens, contracts) {
|
|
|
1874
2057
|
};
|
|
1875
2058
|
}
|
|
1876
2059
|
const finalizeCache = /* @__PURE__ */ new Map();
|
|
1877
|
-
const quote = (p) =>
|
|
2060
|
+
const quote = (p) => wrap7(
|
|
1878
2061
|
OP_WITHDRAWALS.quote,
|
|
1879
2062
|
async () => {
|
|
1880
2063
|
const plan = await buildPlan(p);
|
|
@@ -1896,7 +2079,7 @@ function createWithdrawalsResource(client, tokens, contracts) {
|
|
|
1896
2079
|
ctx: { token: p.token, where: "withdrawals.tryQuote" }
|
|
1897
2080
|
}
|
|
1898
2081
|
);
|
|
1899
|
-
const prepare = (p) =>
|
|
2082
|
+
const prepare = (p) => wrap7(OP_WITHDRAWALS.prepare, () => buildPlan(p), {
|
|
1900
2083
|
message: "Internal error while preparing a withdrawal plan.",
|
|
1901
2084
|
ctx: { token: p.token, where: "withdrawals.prepare" }
|
|
1902
2085
|
});
|
|
@@ -1904,7 +2087,7 @@ function createWithdrawalsResource(client, tokens, contracts) {
|
|
|
1904
2087
|
message: "Internal error while preparing a withdrawal plan.",
|
|
1905
2088
|
ctx: { token: p.token, where: "withdrawals.tryPrepare" }
|
|
1906
2089
|
});
|
|
1907
|
-
const create = (p) =>
|
|
2090
|
+
const create = (p) => wrap7(
|
|
1908
2091
|
OP_WITHDRAWALS.create,
|
|
1909
2092
|
async () => {
|
|
1910
2093
|
const plan = await prepare(p);
|
|
@@ -1975,7 +2158,7 @@ function createWithdrawalsResource(client, tokens, contracts) {
|
|
|
1975
2158
|
message: "Internal error while creating withdrawal transactions.",
|
|
1976
2159
|
ctx: { token: p.token, amount: p.amount, to: p.to, where: "withdrawals.tryCreate" }
|
|
1977
2160
|
});
|
|
1978
|
-
const status = (h) =>
|
|
2161
|
+
const status = (h) => wrap7(
|
|
1979
2162
|
OP_WITHDRAWALS.status,
|
|
1980
2163
|
async () => {
|
|
1981
2164
|
const l2TxHash = typeof h === "string" ? h : "l2TxHash" in h && h.l2TxHash ? h.l2TxHash : "0x";
|
|
@@ -2030,7 +2213,7 @@ function createWithdrawalsResource(client, tokens, contracts) {
|
|
|
2030
2213
|
const wait = (h, opts = {
|
|
2031
2214
|
for: "l2",
|
|
2032
2215
|
pollMs: 5500
|
|
2033
|
-
}) =>
|
|
2216
|
+
}) => wrap7(
|
|
2034
2217
|
OP_WITHDRAWALS.wait,
|
|
2035
2218
|
async () => {
|
|
2036
2219
|
const l2Hash = typeof h === "string" ? h : "l2TxHash" in h && h.l2TxHash ? h.l2TxHash : "0x";
|
|
@@ -2095,7 +2278,7 @@ function createWithdrawalsResource(client, tokens, contracts) {
|
|
|
2095
2278
|
}
|
|
2096
2279
|
}
|
|
2097
2280
|
);
|
|
2098
|
-
const finalize = (l2TxHash) =>
|
|
2281
|
+
const finalize = (l2TxHash) => wrap7(
|
|
2099
2282
|
OP_WITHDRAWALS.finalize.send,
|
|
2100
2283
|
async () => {
|
|
2101
2284
|
const pack = await (async () => {
|
|
@@ -2206,36 +2389,6 @@ function createWithdrawalsResource(client, tokens, contracts) {
|
|
|
2206
2389
|
tryWait
|
|
2207
2390
|
};
|
|
2208
2391
|
}
|
|
2209
|
-
|
|
2210
|
-
// src/core/resources/interop/attributes/call.ts
|
|
2211
|
-
function createCallAttributes(codec) {
|
|
2212
|
-
const indirectCall = (messageValue) => codec.encode("indirectCall", [messageValue]);
|
|
2213
|
-
const interopCallValue = (bridgedAmount) => codec.encode("interopCallValue", [bridgedAmount]);
|
|
2214
|
-
return {
|
|
2215
|
-
indirectCall,
|
|
2216
|
-
interopCallValue
|
|
2217
|
-
};
|
|
2218
|
-
}
|
|
2219
|
-
|
|
2220
|
-
// src/core/resources/interop/attributes/bundle.ts
|
|
2221
|
-
function createBundleAttributes(codec) {
|
|
2222
|
-
const executionAddress = (executor) => codec.encode("executionAddress", [executor]);
|
|
2223
|
-
const unbundlerAddress = (addr) => codec.encode("unbundlerAddress", [addr]);
|
|
2224
|
-
return {
|
|
2225
|
-
executionAddress,
|
|
2226
|
-
unbundlerAddress
|
|
2227
|
-
};
|
|
2228
|
-
}
|
|
2229
|
-
|
|
2230
|
-
// src/core/resources/interop/attributes/resource.ts
|
|
2231
|
-
function createAttributesResource(codec) {
|
|
2232
|
-
return {
|
|
2233
|
-
call: createCallAttributes(codec),
|
|
2234
|
-
bundle: createBundleAttributes(codec)
|
|
2235
|
-
};
|
|
2236
|
-
}
|
|
2237
|
-
|
|
2238
|
-
// src/adapters/ethers/resources/interop/attributes/resource.ts
|
|
2239
2392
|
function getInteropAttributes(params, ctx) {
|
|
2240
2393
|
const bundleAttributes = [];
|
|
2241
2394
|
if (params.execution?.only) {
|
|
@@ -2244,6 +2397,7 @@ function getInteropAttributes(params, ctx) {
|
|
|
2244
2397
|
if (params.unbundling?.by) {
|
|
2245
2398
|
bundleAttributes.push(ctx.attributes.bundle.unbundlerAddress(params.unbundling.by));
|
|
2246
2399
|
}
|
|
2400
|
+
bundleAttributes.push(ctx.attributes.bundle.useFixedFee(params.fee?.useFixed ?? false));
|
|
2247
2401
|
const callAttributes = params.actions.map((action) => {
|
|
2248
2402
|
switch (action.type) {
|
|
2249
2403
|
case "sendNative": {
|
|
@@ -2271,185 +2425,6 @@ function createEthersAttributesResource(opts = {}) {
|
|
|
2271
2425
|
const encode2 = (fn, args) => iface.encodeFunctionData(fn, args);
|
|
2272
2426
|
return createAttributesResource({ encode: encode2 });
|
|
2273
2427
|
}
|
|
2274
|
-
|
|
2275
|
-
// src/core/types/flows/interop.ts
|
|
2276
|
-
function isInteropExpectedRoot(obj) {
|
|
2277
|
-
if (typeof obj !== "object" || obj === null) return false;
|
|
2278
|
-
const root = obj;
|
|
2279
|
-
return isBigint(root.rootChainId) && isBigint(root.batchNumber) && isHash(root.expectedRoot);
|
|
2280
|
-
}
|
|
2281
|
-
function isInteropMessageProof(obj) {
|
|
2282
|
-
if (typeof obj !== "object" || obj === null) return false;
|
|
2283
|
-
const proof = obj;
|
|
2284
|
-
return isBigint(proof.chainId) && isBigint(proof.l1BatchNumber) && isBigint(proof.l2MessageIndex) && typeof proof.message === "object" && proof.message !== null && isNumber(proof.message.txNumberInBatch) && isAddress(proof.message.sender) && isHash(proof.message.data) && isHash66Array(proof.proof);
|
|
2285
|
-
}
|
|
2286
|
-
function isInteropFinalizationInfo(obj) {
|
|
2287
|
-
if (typeof obj !== "object" || obj === null) return false;
|
|
2288
|
-
const info = obj;
|
|
2289
|
-
return isHash66(info.l2SrcTxHash) && isHash66(info.bundleHash) && isBigint(info.dstChainId) && isHash(info.encodedData) && isInteropExpectedRoot(info.expectedRoot) && isInteropMessageProof(info.proof);
|
|
2290
|
-
}
|
|
2291
|
-
|
|
2292
|
-
// src/core/resources/interop/route.ts
|
|
2293
|
-
function sumActionMsgValue(actions) {
|
|
2294
|
-
let sum = 0n;
|
|
2295
|
-
for (const a of actions) {
|
|
2296
|
-
if (a.type === "sendNative") sum += a.amount;
|
|
2297
|
-
else if (a.type === "call" && a.value) sum += a.value;
|
|
2298
|
-
}
|
|
2299
|
-
return sum;
|
|
2300
|
-
}
|
|
2301
|
-
function sumErc20Amounts(actions) {
|
|
2302
|
-
let sum = 0n;
|
|
2303
|
-
for (const a of actions) if (a.type === "sendErc20") sum += a.amount;
|
|
2304
|
-
return sum;
|
|
2305
|
-
}
|
|
2306
|
-
function pickInteropRoute(args) {
|
|
2307
|
-
const hasErc20 = args.actions.some((a) => a.type === "sendErc20");
|
|
2308
|
-
const baseMatches = args.ctx.baseTokenSrc.toLowerCase() === args.ctx.baseTokenDst.toLowerCase();
|
|
2309
|
-
if (hasErc20) return "indirect";
|
|
2310
|
-
if (!baseMatches) return "indirect";
|
|
2311
|
-
return "direct";
|
|
2312
|
-
}
|
|
2313
|
-
|
|
2314
|
-
// src/core/resources/interop/plan.ts
|
|
2315
|
-
function preflightDirect(params, ctx) {
|
|
2316
|
-
if (!params.actions?.length) {
|
|
2317
|
-
throw new Error('route "direct" requires at least one action.');
|
|
2318
|
-
}
|
|
2319
|
-
const baseMatch = ctx.baseTokens.src.toLowerCase() === ctx.baseTokens.dst.toLowerCase();
|
|
2320
|
-
if (!baseMatch) {
|
|
2321
|
-
throw new Error('route "direct" requires matching base tokens between source and destination.');
|
|
2322
|
-
}
|
|
2323
|
-
for (const action of params.actions) {
|
|
2324
|
-
switch (action.type) {
|
|
2325
|
-
case "sendNative":
|
|
2326
|
-
if (action.amount < 0n) {
|
|
2327
|
-
throw new Error("sendNative.amount must be >= 0.");
|
|
2328
|
-
}
|
|
2329
|
-
break;
|
|
2330
|
-
case "call":
|
|
2331
|
-
if (action.value != null && action.value < 0n) {
|
|
2332
|
-
throw new Error("call.value must be >= 0 when provided.");
|
|
2333
|
-
}
|
|
2334
|
-
break;
|
|
2335
|
-
default:
|
|
2336
|
-
throw new Error(
|
|
2337
|
-
`route "direct" does not support ${action.type} actions; use the indirect route.`
|
|
2338
|
-
);
|
|
2339
|
-
}
|
|
2340
|
-
}
|
|
2341
|
-
}
|
|
2342
|
-
function buildDirectBundle(params, ctx, attrs) {
|
|
2343
|
-
const totalActionValue = sumActionMsgValue(params.actions);
|
|
2344
|
-
const starters = params.actions.map((action, index) => {
|
|
2345
|
-
const to = ctx.codec.formatAddress(action.to);
|
|
2346
|
-
const callAttributes = attrs.callAttributes[index] ?? [];
|
|
2347
|
-
switch (action.type) {
|
|
2348
|
-
case "sendNative":
|
|
2349
|
-
return [to, "0x", callAttributes];
|
|
2350
|
-
case "call":
|
|
2351
|
-
return [to, action.data ?? "0x", callAttributes];
|
|
2352
|
-
default:
|
|
2353
|
-
throw new Error(`buildDirectBundle: unsupported action type "${action.type}".`);
|
|
2354
|
-
}
|
|
2355
|
-
});
|
|
2356
|
-
return {
|
|
2357
|
-
dstChain: ctx.codec.formatChain(ctx.dstChainId),
|
|
2358
|
-
starters,
|
|
2359
|
-
bundleAttributes: attrs.bundleAttributes,
|
|
2360
|
-
approvals: [],
|
|
2361
|
-
quoteExtras: {
|
|
2362
|
-
totalActionValue,
|
|
2363
|
-
bridgedTokenTotal: 0n
|
|
2364
|
-
}
|
|
2365
|
-
};
|
|
2366
|
-
}
|
|
2367
|
-
function preflightIndirect(params, ctx) {
|
|
2368
|
-
if (!params.actions?.length) {
|
|
2369
|
-
throw new Error('route "indirect" requires at least one action.');
|
|
2370
|
-
}
|
|
2371
|
-
const hasErc20 = params.actions.some((a) => a.type === "sendErc20");
|
|
2372
|
-
const baseMatches = ctx.baseTokens.src.toLowerCase() === ctx.baseTokens.dst.toLowerCase();
|
|
2373
|
-
if (!hasErc20 && baseMatches) {
|
|
2374
|
-
throw new Error(
|
|
2375
|
-
'route "indirect" requires ERC-20 actions or mismatched base tokens; use the direct route instead.'
|
|
2376
|
-
);
|
|
2377
|
-
}
|
|
2378
|
-
for (const action of params.actions) {
|
|
2379
|
-
switch (action.type) {
|
|
2380
|
-
case "sendNative":
|
|
2381
|
-
if (action.amount < 0n) {
|
|
2382
|
-
throw new Error("sendNative.amount must be >= 0.");
|
|
2383
|
-
}
|
|
2384
|
-
break;
|
|
2385
|
-
case "sendErc20":
|
|
2386
|
-
if (action.amount < 0n) {
|
|
2387
|
-
throw new Error("sendErc20.amount must be >= 0.");
|
|
2388
|
-
}
|
|
2389
|
-
break;
|
|
2390
|
-
case "call":
|
|
2391
|
-
if (action.value != null) {
|
|
2392
|
-
if (action.value < 0n) {
|
|
2393
|
-
throw new Error("call.value must be >= 0 when provided.");
|
|
2394
|
-
}
|
|
2395
|
-
if (action.value > 0n && !baseMatches) {
|
|
2396
|
-
throw new Error("indirect route does not support call.value when base tokens differ.");
|
|
2397
|
-
}
|
|
2398
|
-
}
|
|
2399
|
-
break;
|
|
2400
|
-
default:
|
|
2401
|
-
assertNever(action);
|
|
2402
|
-
}
|
|
2403
|
-
}
|
|
2404
|
-
}
|
|
2405
|
-
function buildIndirectBundle(params, ctx, attrs, starterData) {
|
|
2406
|
-
const totalActionValue = sumActionMsgValue(params.actions);
|
|
2407
|
-
const bridgedTokenTotal = sumErc20Amounts(params.actions);
|
|
2408
|
-
const approvalMap = /* @__PURE__ */ new Map();
|
|
2409
|
-
for (const action of params.actions) {
|
|
2410
|
-
if (action.type !== "sendErc20") continue;
|
|
2411
|
-
const key = action.token.toLowerCase();
|
|
2412
|
-
const existing = approvalMap.get(key);
|
|
2413
|
-
if (existing) {
|
|
2414
|
-
existing.amount += action.amount;
|
|
2415
|
-
} else {
|
|
2416
|
-
approvalMap.set(key, {
|
|
2417
|
-
token: action.token,
|
|
2418
|
-
spender: ctx.l2NativeTokenVault,
|
|
2419
|
-
amount: action.amount
|
|
2420
|
-
});
|
|
2421
|
-
}
|
|
2422
|
-
}
|
|
2423
|
-
const approvals = Array.from(approvalMap.values());
|
|
2424
|
-
const starters = params.actions.map((action, index) => {
|
|
2425
|
-
const callAttributes = attrs.callAttributes[index] ?? [];
|
|
2426
|
-
if (starterData[index]?.assetRouterPayload) {
|
|
2427
|
-
const l2AssetRouter = ctx.codec.formatAddress(ctx.l2AssetRouter);
|
|
2428
|
-
return [l2AssetRouter, starterData[index].assetRouterPayload, callAttributes];
|
|
2429
|
-
}
|
|
2430
|
-
const directTo = ctx.codec.formatAddress(action.to);
|
|
2431
|
-
switch (action.type) {
|
|
2432
|
-
case "sendNative":
|
|
2433
|
-
return [directTo, "0x", callAttributes];
|
|
2434
|
-
case "call":
|
|
2435
|
-
return [directTo, action.data ?? "0x", callAttributes];
|
|
2436
|
-
case "sendErc20":
|
|
2437
|
-
throw new Error("buildIndirectBundle: missing assetRouterPayload for sendErc20 action.");
|
|
2438
|
-
default:
|
|
2439
|
-
return assertNever(action);
|
|
2440
|
-
}
|
|
2441
|
-
});
|
|
2442
|
-
return {
|
|
2443
|
-
dstChain: ctx.codec.formatChain(ctx.dstChainId),
|
|
2444
|
-
starters,
|
|
2445
|
-
bundleAttributes: attrs.bundleAttributes,
|
|
2446
|
-
approvals,
|
|
2447
|
-
quoteExtras: {
|
|
2448
|
-
totalActionValue,
|
|
2449
|
-
bridgedTokenTotal
|
|
2450
|
-
}
|
|
2451
|
-
};
|
|
2452
|
-
}
|
|
2453
2428
|
var PREFIX_EVM_CHAIN = getBytes("0x00010000");
|
|
2454
2429
|
var PREFIX_EVM_ADDRESS = getBytes("0x000100000014");
|
|
2455
2430
|
function formatInteropEvmChain(chainId) {
|
|
@@ -2490,6 +2465,29 @@ function buildEnsureTokenSteps(erc20Tokens, ctx) {
|
|
|
2490
2465
|
}
|
|
2491
2466
|
}));
|
|
2492
2467
|
}
|
|
2468
|
+
async function buildApproveSteps(approvals, ctx) {
|
|
2469
|
+
const steps = [];
|
|
2470
|
+
for (const approval of approvals) {
|
|
2471
|
+
const erc20 = new Contract(approval.token, IERC20_default, ctx.client.l2);
|
|
2472
|
+
const currentAllowance = await erc20.allowance(ctx.sender, approval.spender);
|
|
2473
|
+
if (currentAllowance < approval.amount) {
|
|
2474
|
+
steps.push({
|
|
2475
|
+
key: `approve:${approval.token}:${approval.spender}`,
|
|
2476
|
+
kind: "approve",
|
|
2477
|
+
description: `Approve ${approval.spender} to spend ${approval.amount} of ${approval.token}`,
|
|
2478
|
+
tx: {
|
|
2479
|
+
to: approval.token,
|
|
2480
|
+
data: erc20.interface.encodeFunctionData("approve", [
|
|
2481
|
+
approval.spender,
|
|
2482
|
+
approval.amount
|
|
2483
|
+
]),
|
|
2484
|
+
...ctx.gasOverrides
|
|
2485
|
+
}
|
|
2486
|
+
});
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
return steps;
|
|
2490
|
+
}
|
|
2493
2491
|
async function resolveErc20AssetIds(erc20Tokens, ctx) {
|
|
2494
2492
|
const assetIds = /* @__PURE__ */ new Map();
|
|
2495
2493
|
if (erc20Tokens.length === 0) return assetIds;
|
|
@@ -2543,6 +2541,44 @@ async function getStarterData(params, ctx, erc20AssetIds) {
|
|
|
2543
2541
|
}
|
|
2544
2542
|
return starterData;
|
|
2545
2543
|
}
|
|
2544
|
+
var { wrap: wrap2 } = createErrorHandlers("interop");
|
|
2545
|
+
async function buildFeeInfo(params, ctx, numStarters) {
|
|
2546
|
+
const useFixed = params.fee?.useFixed ?? false;
|
|
2547
|
+
const interopCenter = new Contract(ctx.interopCenter, IInteropCenter_default, ctx.client.l2);
|
|
2548
|
+
if (useFixed) {
|
|
2549
|
+
const zkFeePerCall = await wrap2(
|
|
2550
|
+
OP_INTEROP.svc.fees.zkInteropFee,
|
|
2551
|
+
() => interopCenter.ZK_INTEROP_FEE(),
|
|
2552
|
+
{ message: "Failed to fetch ZK interop fee from InteropCenter." }
|
|
2553
|
+
);
|
|
2554
|
+
const zkFeeTotal = zkFeePerCall * BigInt(numStarters);
|
|
2555
|
+
const zkTokenAddress = await wrap2(
|
|
2556
|
+
OP_INTEROP.svc.fees.zkToken,
|
|
2557
|
+
() => interopCenter.zkToken(),
|
|
2558
|
+
{ message: "Failed to fetch ZK token address from InteropCenter." }
|
|
2559
|
+
);
|
|
2560
|
+
const approval = {
|
|
2561
|
+
token: zkTokenAddress,
|
|
2562
|
+
spender: ctx.interopCenter,
|
|
2563
|
+
amount: zkFeeTotal
|
|
2564
|
+
};
|
|
2565
|
+
return {
|
|
2566
|
+
approval,
|
|
2567
|
+
fee: { token: zkTokenAddress, amount: zkFeeTotal }
|
|
2568
|
+
};
|
|
2569
|
+
} else {
|
|
2570
|
+
const protocolFeePerCall = await wrap2(
|
|
2571
|
+
OP_INTEROP.svc.fees.protocolFee,
|
|
2572
|
+
() => interopCenter.interopProtocolFee(),
|
|
2573
|
+
{ message: "Failed to fetch interop protocol fee from InteropCenter." }
|
|
2574
|
+
);
|
|
2575
|
+
const totalFee = protocolFeePerCall * BigInt(numStarters);
|
|
2576
|
+
return {
|
|
2577
|
+
approval: null,
|
|
2578
|
+
fee: { token: ctx.baseTokens.src, amount: totalFee }
|
|
2579
|
+
};
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2546
2582
|
|
|
2547
2583
|
// src/adapters/ethers/resources/interop/routes/indirect.ts
|
|
2548
2584
|
function routeIndirect() {
|
|
@@ -2553,12 +2589,17 @@ function routeIndirect() {
|
|
|
2553
2589
|
dstChainId: ctx.dstChainId,
|
|
2554
2590
|
baseTokens: ctx.baseTokens,
|
|
2555
2591
|
l2AssetRouter: ctx.l2AssetRouter,
|
|
2556
|
-
l2NativeTokenVault: ctx.l2NativeTokenVault
|
|
2592
|
+
l2NativeTokenVault: ctx.l2NativeTokenVault,
|
|
2593
|
+
codec: interopCodec
|
|
2594
|
+
});
|
|
2557
2595
|
},
|
|
2558
2596
|
async build(params, ctx) {
|
|
2559
2597
|
const steps = [];
|
|
2560
2598
|
const erc20Tokens = getErc20Tokens(params);
|
|
2561
|
-
const erc20AssetIds = await
|
|
2599
|
+
const [erc20AssetIds, feeInfo] = await Promise.all([
|
|
2600
|
+
resolveErc20AssetIds(erc20Tokens, ctx),
|
|
2601
|
+
buildFeeInfo(params, ctx, params.actions.length)
|
|
2602
|
+
]);
|
|
2562
2603
|
const attributes = getInteropAttributes(params, ctx);
|
|
2563
2604
|
const starterData = await getStarterData(params, ctx, erc20AssetIds);
|
|
2564
2605
|
const bundle = buildIndirectBundle(
|
|
@@ -2571,32 +2612,11 @@ function routeIndirect() {
|
|
|
2571
2612
|
codec: interopCodec
|
|
2572
2613
|
},
|
|
2573
2614
|
attributes,
|
|
2574
|
-
starterData
|
|
2615
|
+
starterData,
|
|
2616
|
+
feeInfo
|
|
2575
2617
|
);
|
|
2576
2618
|
steps.push(...buildEnsureTokenSteps(erc20Tokens, ctx));
|
|
2577
|
-
|
|
2578
|
-
const erc20 = new Contract(approval.token, IERC20_default, ctx.client.l2);
|
|
2579
|
-
const currentAllowance = await erc20.allowance(
|
|
2580
|
-
ctx.sender,
|
|
2581
|
-
ctx.l2NativeTokenVault
|
|
2582
|
-
);
|
|
2583
|
-
if (currentAllowance < approval.amount) {
|
|
2584
|
-
const approveData = erc20.interface.encodeFunctionData("approve", [
|
|
2585
|
-
ctx.l2NativeTokenVault,
|
|
2586
|
-
approval.amount
|
|
2587
|
-
]);
|
|
2588
|
-
steps.push({
|
|
2589
|
-
key: `approve:${approval.token}:${ctx.l2NativeTokenVault}`,
|
|
2590
|
-
kind: "approve",
|
|
2591
|
-
description: `Approve ${ctx.l2NativeTokenVault} to spend ${approval.amount} of ${approval.token}`,
|
|
2592
|
-
tx: {
|
|
2593
|
-
to: approval.token,
|
|
2594
|
-
data: approveData,
|
|
2595
|
-
...ctx.gasOverrides
|
|
2596
|
-
}
|
|
2597
|
-
});
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2619
|
+
steps.push(...await buildApproveSteps(bundle.approvals, ctx));
|
|
2600
2620
|
const data = ctx.ifaces.interopCenter.encodeFunctionData("sendBundle", [
|
|
2601
2621
|
bundle.dstChain,
|
|
2602
2622
|
bundle.starters,
|
|
@@ -2609,14 +2629,15 @@ function routeIndirect() {
|
|
|
2609
2629
|
tx: {
|
|
2610
2630
|
to: ctx.interopCenter,
|
|
2611
2631
|
data,
|
|
2612
|
-
value: bundle.quoteExtras.totalActionValue,
|
|
2632
|
+
value: bundle.quoteExtras.totalActionValue + feeInfo.fee.amount,
|
|
2613
2633
|
...ctx.gasOverrides
|
|
2614
2634
|
}
|
|
2615
2635
|
});
|
|
2616
2636
|
return {
|
|
2617
2637
|
steps,
|
|
2618
2638
|
approvals: bundle.approvals,
|
|
2619
|
-
quoteExtras: bundle.quoteExtras
|
|
2639
|
+
quoteExtras: bundle.quoteExtras,
|
|
2640
|
+
interopFee: feeInfo.fee
|
|
2620
2641
|
};
|
|
2621
2642
|
}
|
|
2622
2643
|
};
|
|
@@ -2631,12 +2652,14 @@ function routeDirect() {
|
|
|
2631
2652
|
dstChainId: ctx.dstChainId,
|
|
2632
2653
|
baseTokens: ctx.baseTokens,
|
|
2633
2654
|
l2AssetRouter: ctx.l2AssetRouter,
|
|
2634
|
-
l2NativeTokenVault: ctx.l2NativeTokenVault
|
|
2655
|
+
l2NativeTokenVault: ctx.l2NativeTokenVault,
|
|
2656
|
+
codec: interopCodec
|
|
2657
|
+
});
|
|
2635
2658
|
},
|
|
2636
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
2637
2659
|
async build(params, ctx) {
|
|
2638
2660
|
const steps = [];
|
|
2639
2661
|
const attrs = getInteropAttributes(params, ctx);
|
|
2662
|
+
const feeInfo = await buildFeeInfo(params, ctx, params.actions.length);
|
|
2640
2663
|
const built = buildDirectBundle(
|
|
2641
2664
|
params,
|
|
2642
2665
|
{
|
|
@@ -2646,8 +2669,10 @@ function routeDirect() {
|
|
|
2646
2669
|
l2NativeTokenVault: ctx.l2NativeTokenVault,
|
|
2647
2670
|
codec: interopCodec
|
|
2648
2671
|
},
|
|
2649
|
-
attrs
|
|
2672
|
+
attrs,
|
|
2673
|
+
feeInfo
|
|
2650
2674
|
);
|
|
2675
|
+
steps.push(...await buildApproveSteps(built.approvals, ctx));
|
|
2651
2676
|
const data = ctx.ifaces.interopCenter.encodeFunctionData("sendBundle", [
|
|
2652
2677
|
built.dstChain,
|
|
2653
2678
|
built.starters,
|
|
@@ -2657,43 +2682,28 @@ function routeDirect() {
|
|
|
2657
2682
|
key: "sendBundle",
|
|
2658
2683
|
kind: "interop.center",
|
|
2659
2684
|
description: `Send interop bundle (direct route; ${params.actions.length} actions)`,
|
|
2660
|
-
//
|
|
2661
|
-
// all calls (sendNative.amount + call.value).
|
|
2685
|
+
// msg.value = forwarded action value + protocol fee.
|
|
2662
2686
|
tx: {
|
|
2663
2687
|
to: ctx.interopCenter,
|
|
2664
2688
|
data,
|
|
2665
|
-
value: built.quoteExtras.totalActionValue,
|
|
2689
|
+
value: built.quoteExtras.totalActionValue + feeInfo.fee.amount,
|
|
2666
2690
|
...ctx.gasOverrides
|
|
2667
2691
|
}
|
|
2668
2692
|
});
|
|
2669
2693
|
return {
|
|
2670
2694
|
steps,
|
|
2671
2695
|
approvals: built.approvals,
|
|
2672
|
-
quoteExtras: built.quoteExtras
|
|
2696
|
+
quoteExtras: built.quoteExtras,
|
|
2697
|
+
interopFee: feeInfo.fee
|
|
2673
2698
|
};
|
|
2674
2699
|
}
|
|
2675
2700
|
};
|
|
2676
2701
|
}
|
|
2677
|
-
var MIN_INTEROP_PROTOCOL = 31;
|
|
2678
2702
|
async function assertInteropProtocolVersion(client, srcChainId, dstChainId) {
|
|
2679
2703
|
const [srcProtocolVersion, dstProtocolVersion] = await Promise.all([
|
|
2680
2704
|
client.getProtocolVersion(srcChainId),
|
|
2681
2705
|
client.getProtocolVersion(dstChainId)
|
|
2682
2706
|
]);
|
|
2683
|
-
const assertProtocolVersion = (chainId, protocolVersion) => {
|
|
2684
|
-
if (protocolVersion[1] < MIN_INTEROP_PROTOCOL) {
|
|
2685
|
-
throw createError("VALIDATION", {
|
|
2686
|
-
resource: "interop",
|
|
2687
|
-
operation: OP_INTEROP.context.protocolVersion,
|
|
2688
|
-
message: `Interop requires protocol version 31.0+. Found: ${protocolVersion[1]}.${protocolVersion[2]} for chain: ${chainId}.`,
|
|
2689
|
-
context: {
|
|
2690
|
-
chainId,
|
|
2691
|
-
requiredMinor: MIN_INTEROP_PROTOCOL,
|
|
2692
|
-
semver: protocolVersion
|
|
2693
|
-
}
|
|
2694
|
-
});
|
|
2695
|
-
}
|
|
2696
|
-
};
|
|
2697
2707
|
assertProtocolVersion(srcChainId, srcProtocolVersion);
|
|
2698
2708
|
assertProtocolVersion(dstChainId, dstProtocolVersion);
|
|
2699
2709
|
}
|
|
@@ -2749,7 +2759,7 @@ function getTopics() {
|
|
|
2749
2759
|
};
|
|
2750
2760
|
return { topics, centerIface };
|
|
2751
2761
|
}
|
|
2752
|
-
var { wrap:
|
|
2762
|
+
var { wrap: wrap3 } = createErrorHandlers("interop");
|
|
2753
2763
|
var DEFAULT_BLOCKS_RANGE_SIZE = 1e4;
|
|
2754
2764
|
var DEFAULT_MAX_BLOCKS_BACK = 2e4;
|
|
2755
2765
|
var SAFE_BLOCKS_RANGE_SIZE = 1e3;
|
|
@@ -2762,9 +2772,16 @@ function parseMaxBlockRangeLimit(error) {
|
|
|
2762
2772
|
return Number.isInteger(limit) && limit > 0 ? limit : null;
|
|
2763
2773
|
}
|
|
2764
2774
|
async function getTxReceipt(provider, txHash) {
|
|
2765
|
-
const receipt = await
|
|
2775
|
+
const receipt = await wrap3(
|
|
2766
2776
|
OP_INTEROP.svc.status.sourceReceipt,
|
|
2767
|
-
() =>
|
|
2777
|
+
async () => {
|
|
2778
|
+
try {
|
|
2779
|
+
return await provider.getTransactionReceipt(txHash);
|
|
2780
|
+
} catch (error) {
|
|
2781
|
+
if (isReceiptNotFound(error)) return null;
|
|
2782
|
+
throw error;
|
|
2783
|
+
}
|
|
2784
|
+
},
|
|
2768
2785
|
{
|
|
2769
2786
|
ctx: { where: "l2.getTransactionReceipt", l2SrcTxHash: txHash },
|
|
2770
2787
|
message: "Failed to fetch source L2 receipt for interop tx."
|
|
@@ -2783,7 +2800,7 @@ async function getTxReceipt(provider, txHash) {
|
|
|
2783
2800
|
async function getLogs(provider, address, topics, opts) {
|
|
2784
2801
|
const maxBlocksBack = opts?.maxBlocksBack ?? DEFAULT_MAX_BLOCKS_BACK;
|
|
2785
2802
|
const initialChunkSize = opts?.logChunkSize ?? DEFAULT_BLOCKS_RANGE_SIZE;
|
|
2786
|
-
return await
|
|
2803
|
+
return await wrap3(
|
|
2787
2804
|
OP_INTEROP.svc.status.dstLogs,
|
|
2788
2805
|
async () => {
|
|
2789
2806
|
const currentBlock = await provider.getBlockNumber();
|
|
@@ -2830,7 +2847,7 @@ async function getLogs(provider, address, topics, opts) {
|
|
|
2830
2847
|
);
|
|
2831
2848
|
}
|
|
2832
2849
|
async function getInteropRoot(provider, rootChainId, batchNumber) {
|
|
2833
|
-
return await
|
|
2850
|
+
return await wrap3(
|
|
2834
2851
|
OP_INTEROP.svc.status.getRoot,
|
|
2835
2852
|
async () => {
|
|
2836
2853
|
const rootStorage = new Contract(
|
|
@@ -2848,7 +2865,7 @@ async function getInteropRoot(provider, rootChainId, batchNumber) {
|
|
|
2848
2865
|
}
|
|
2849
2866
|
|
|
2850
2867
|
// src/adapters/ethers/resources/interop/services/finalization/bundle.ts
|
|
2851
|
-
var { wrap:
|
|
2868
|
+
var { wrap: wrap4 } = createErrorHandlers("interop");
|
|
2852
2869
|
async function getBundleStatus(client, dstProvider, topics, bundleHash, opts) {
|
|
2853
2870
|
const { interopHandler } = await client.ensureAddresses();
|
|
2854
2871
|
const bundleLogs = await getLogs(dstProvider, interopHandler, [null, bundleHash], opts);
|
|
@@ -2880,7 +2897,7 @@ async function executeBundle(client, dstProvider, info, opts) {
|
|
|
2880
2897
|
context: { bundleHash }
|
|
2881
2898
|
});
|
|
2882
2899
|
}
|
|
2883
|
-
const signer = await
|
|
2900
|
+
const signer = await wrap4(OP_INTEROP.exec.sendStep, () => client.signerFor(dstProvider), {
|
|
2884
2901
|
message: "Failed to resolve destination signer."
|
|
2885
2902
|
});
|
|
2886
2903
|
const { interopHandler } = await client.ensureAddresses();
|
|
@@ -2929,144 +2946,6 @@ async function executeBundle(client, dstProvider, info, opts) {
|
|
|
2929
2946
|
);
|
|
2930
2947
|
}
|
|
2931
2948
|
}
|
|
2932
|
-
|
|
2933
|
-
// src/core/resources/interop/finalization.ts
|
|
2934
|
-
var DEFAULT_POLL_MS = 1e3;
|
|
2935
|
-
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
2936
|
-
function resolveIdsFromWaitable(input) {
|
|
2937
|
-
if (typeof input === "string") {
|
|
2938
|
-
return { l2SrcTxHash: input };
|
|
2939
|
-
}
|
|
2940
|
-
return {
|
|
2941
|
-
l2SrcTxHash: input.l2SrcTxHash,
|
|
2942
|
-
bundleHash: input.bundleHash,
|
|
2943
|
-
dstExecTxHash: input.dstExecTxHash
|
|
2944
|
-
};
|
|
2945
|
-
}
|
|
2946
|
-
function parseBundleSentFromReceipt(input) {
|
|
2947
|
-
const { receipt, interopCenter, interopBundleSentTopic, decodeInteropBundleSent: decodeInteropBundleSent2 } = input;
|
|
2948
|
-
const bundleSentLog = receipt.logs.find(
|
|
2949
|
-
(log) => log.address.toLowerCase() === interopCenter.toLowerCase() && log.topics[0].toLowerCase() === interopBundleSentTopic.toLowerCase()
|
|
2950
|
-
);
|
|
2951
|
-
if (!bundleSentLog) {
|
|
2952
|
-
throw createError("STATE", {
|
|
2953
|
-
resource: "interop",
|
|
2954
|
-
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
2955
|
-
message: "Failed to locate InteropBundleSent event in source receipt.",
|
|
2956
|
-
context: { receipt, interopCenter }
|
|
2957
|
-
});
|
|
2958
|
-
}
|
|
2959
|
-
const decoded = decodeInteropBundleSent2({
|
|
2960
|
-
data: bundleSentLog.data,
|
|
2961
|
-
topics: bundleSentLog.topics
|
|
2962
|
-
});
|
|
2963
|
-
return { bundleHash: decoded.bundleHash, dstChainId: decoded.destinationChainId };
|
|
2964
|
-
}
|
|
2965
|
-
function parseBundleReceiptInfo(params) {
|
|
2966
|
-
const {
|
|
2967
|
-
rawReceipt,
|
|
2968
|
-
interopCenter,
|
|
2969
|
-
interopBundleSentTopic,
|
|
2970
|
-
decodeInteropBundleSent: decodeInteropBundleSent2,
|
|
2971
|
-
decodeL1MessageData: decodeL1MessageData2,
|
|
2972
|
-
l2SrcTxHash
|
|
2973
|
-
} = params;
|
|
2974
|
-
let l2ToL1LogIndex = -1;
|
|
2975
|
-
let l1MessageData = null;
|
|
2976
|
-
let found;
|
|
2977
|
-
for (const log of rawReceipt.logs) {
|
|
2978
|
-
if (isL1MessageSentLog(log)) {
|
|
2979
|
-
l2ToL1LogIndex += 1;
|
|
2980
|
-
try {
|
|
2981
|
-
l1MessageData = decodeL1MessageData2(log);
|
|
2982
|
-
} catch (e) {
|
|
2983
|
-
throw createError("STATE", {
|
|
2984
|
-
resource: "interop",
|
|
2985
|
-
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
2986
|
-
message: "Failed to decode L1MessageSent log data for interop bundle.",
|
|
2987
|
-
context: { l2SrcTxHash, l2ToL1LogIndex },
|
|
2988
|
-
cause: e
|
|
2989
|
-
});
|
|
2990
|
-
}
|
|
2991
|
-
continue;
|
|
2992
|
-
}
|
|
2993
|
-
if (log.address.toLowerCase() !== interopCenter.toLowerCase() || log.topics[0].toLowerCase() !== interopBundleSentTopic.toLowerCase())
|
|
2994
|
-
continue;
|
|
2995
|
-
const decoded = decodeInteropBundleSent2({
|
|
2996
|
-
data: log.data,
|
|
2997
|
-
topics: log.topics
|
|
2998
|
-
});
|
|
2999
|
-
found = {
|
|
3000
|
-
bundleHash: decoded.bundleHash,
|
|
3001
|
-
dstChainId: decoded.destinationChainId,
|
|
3002
|
-
sourceChainId: decoded.sourceChainId
|
|
3003
|
-
};
|
|
3004
|
-
break;
|
|
3005
|
-
}
|
|
3006
|
-
if (!found) {
|
|
3007
|
-
throw createError("STATE", {
|
|
3008
|
-
resource: "interop",
|
|
3009
|
-
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
3010
|
-
message: "Failed to locate InteropBundleSent event in source receipt.",
|
|
3011
|
-
context: { l2SrcTxHash, interopCenter }
|
|
3012
|
-
});
|
|
3013
|
-
}
|
|
3014
|
-
if (!l1MessageData) {
|
|
3015
|
-
throw createError("STATE", {
|
|
3016
|
-
resource: "interop",
|
|
3017
|
-
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
3018
|
-
message: "Failed to locate L1MessageSent log data for interop bundle.",
|
|
3019
|
-
context: { l2SrcTxHash, interopCenter }
|
|
3020
|
-
});
|
|
3021
|
-
}
|
|
3022
|
-
return {
|
|
3023
|
-
bundleHash: found.bundleHash,
|
|
3024
|
-
dstChainId: found.dstChainId,
|
|
3025
|
-
sourceChainId: found.sourceChainId,
|
|
3026
|
-
l1MessageData,
|
|
3027
|
-
l2ToL1LogIndex,
|
|
3028
|
-
txNumberInBatch: Number(rawReceipt.transactionIndex),
|
|
3029
|
-
rawReceipt
|
|
3030
|
-
};
|
|
3031
|
-
}
|
|
3032
|
-
function getBundleEncodedData(messageData) {
|
|
3033
|
-
const prefix = `0x${messageData.slice(2, 4)}`;
|
|
3034
|
-
if (prefix !== BUNDLE_IDENTIFIER) {
|
|
3035
|
-
throw createError("STATE", {
|
|
3036
|
-
resource: "interop",
|
|
3037
|
-
operation: OP_INTEROP.wait,
|
|
3038
|
-
message: "Unexpected bundle prefix in L1MessageSent data.",
|
|
3039
|
-
context: { prefix, expected: BUNDLE_IDENTIFIER }
|
|
3040
|
-
});
|
|
3041
|
-
}
|
|
3042
|
-
return `0x${messageData.slice(4)}`;
|
|
3043
|
-
}
|
|
3044
|
-
function buildFinalizationInfo(ids, bundleInfo, proof, messageData) {
|
|
3045
|
-
const expectedRoot = {
|
|
3046
|
-
rootChainId: bundleInfo.sourceChainId,
|
|
3047
|
-
batchNumber: proof.batchNumber,
|
|
3048
|
-
expectedRoot: proof.root
|
|
3049
|
-
};
|
|
3050
|
-
const messageProof = {
|
|
3051
|
-
chainId: bundleInfo.sourceChainId,
|
|
3052
|
-
l1BatchNumber: proof.batchNumber,
|
|
3053
|
-
l2MessageIndex: proof.id,
|
|
3054
|
-
message: {
|
|
3055
|
-
txNumberInBatch: bundleInfo.txNumberInBatch,
|
|
3056
|
-
sender: L2_INTEROP_CENTER_ADDRESS,
|
|
3057
|
-
data: messageData
|
|
3058
|
-
},
|
|
3059
|
-
proof: proof.proof
|
|
3060
|
-
};
|
|
3061
|
-
return {
|
|
3062
|
-
l2SrcTxHash: ids.l2SrcTxHash,
|
|
3063
|
-
bundleHash: bundleInfo.bundleHash,
|
|
3064
|
-
dstChainId: bundleInfo.dstChainId,
|
|
3065
|
-
expectedRoot,
|
|
3066
|
-
proof: messageProof,
|
|
3067
|
-
encodedData: getBundleEncodedData(messageData)
|
|
3068
|
-
};
|
|
3069
|
-
}
|
|
3070
2949
|
function decodeInteropBundleSent(centerIface, log) {
|
|
3071
2950
|
const decoded = centerIface.decodeEventLog(
|
|
3072
2951
|
"InteropBundleSent",
|
|
@@ -3085,7 +2964,7 @@ function decodeL1MessageData(log) {
|
|
|
3085
2964
|
}
|
|
3086
2965
|
|
|
3087
2966
|
// src/adapters/ethers/resources/interop/services/finalization/polling.ts
|
|
3088
|
-
var { wrap:
|
|
2967
|
+
var { wrap: wrap5 } = createErrorHandlers("interop");
|
|
3089
2968
|
function isProofNotReadyError(error) {
|
|
3090
2969
|
return isZKsyncError(error, {
|
|
3091
2970
|
operation: "zksrpc.getL2ToL1LogProof",
|
|
@@ -3122,30 +3001,26 @@ async function waitForProof(client, l2SrcTxHash, logIndex, blockNumber, pollMs,
|
|
|
3122
3001
|
});
|
|
3123
3002
|
}
|
|
3124
3003
|
try {
|
|
3125
|
-
return await client.zks.getL2ToL1LogProof(l2SrcTxHash, logIndex);
|
|
3004
|
+
return await client.zks.getL2ToL1LogProof(l2SrcTxHash, logIndex, "messageRoot" /* MessageRoot */);
|
|
3126
3005
|
} catch (error) {
|
|
3127
3006
|
if (!isProofNotReadyError(error)) throw error;
|
|
3128
3007
|
}
|
|
3129
3008
|
await sleep(pollMs);
|
|
3130
3009
|
}
|
|
3131
3010
|
}
|
|
3132
|
-
async function waitForRoot(provider,
|
|
3011
|
+
async function waitForRoot(provider, chainId, batchNumber, pollMs, deadline) {
|
|
3133
3012
|
while (true) {
|
|
3134
3013
|
if (Date.now() > deadline) {
|
|
3135
3014
|
throw createError("TIMEOUT", {
|
|
3136
3015
|
resource: "interop",
|
|
3137
3016
|
operation: OP_INTEROP.svc.wait.timeout,
|
|
3138
3017
|
message: "Timed out waiting for interop root to become available.",
|
|
3139
|
-
context: {
|
|
3018
|
+
context: { chainId, batchNumber }
|
|
3140
3019
|
});
|
|
3141
3020
|
}
|
|
3142
3021
|
let interopRoot = null;
|
|
3143
3022
|
try {
|
|
3144
|
-
const root = await getInteropRoot(
|
|
3145
|
-
provider,
|
|
3146
|
-
expectedRoot.rootChainId,
|
|
3147
|
-
expectedRoot.batchNumber
|
|
3148
|
-
);
|
|
3023
|
+
const root = await getInteropRoot(provider, chainId, batchNumber);
|
|
3149
3024
|
if (root !== ZERO_HASH) {
|
|
3150
3025
|
interopRoot = root;
|
|
3151
3026
|
}
|
|
@@ -3154,18 +3029,7 @@ async function waitForRoot(provider, expectedRoot, pollMs, deadline) {
|
|
|
3154
3029
|
interopRoot = null;
|
|
3155
3030
|
}
|
|
3156
3031
|
if (interopRoot) {
|
|
3157
|
-
|
|
3158
|
-
return;
|
|
3159
|
-
}
|
|
3160
|
-
throw createError("STATE", {
|
|
3161
|
-
resource: "interop",
|
|
3162
|
-
operation: OP_INTEROP.wait,
|
|
3163
|
-
message: "Interop root mismatch.",
|
|
3164
|
-
context: {
|
|
3165
|
-
expected: expectedRoot.expectedRoot,
|
|
3166
|
-
got: interopRoot
|
|
3167
|
-
}
|
|
3168
|
-
});
|
|
3032
|
+
return interopRoot;
|
|
3169
3033
|
}
|
|
3170
3034
|
await sleep(pollMs);
|
|
3171
3035
|
}
|
|
@@ -3180,7 +3044,7 @@ async function waitForTxReceipt(client, txHash, pollMs, deadline) {
|
|
|
3180
3044
|
context: { txHash }
|
|
3181
3045
|
});
|
|
3182
3046
|
}
|
|
3183
|
-
const receipt = await
|
|
3047
|
+
const receipt = await wrap5(
|
|
3184
3048
|
OP_INTEROP.svc.status.sourceReceipt,
|
|
3185
3049
|
() => client.zks.getReceiptWithL2ToL1(txHash),
|
|
3186
3050
|
{
|
|
@@ -3194,7 +3058,7 @@ async function waitForTxReceipt(client, txHash, pollMs, deadline) {
|
|
|
3194
3058
|
await sleep(pollMs);
|
|
3195
3059
|
}
|
|
3196
3060
|
}
|
|
3197
|
-
async function waitForFinalization(client, dstProvider, input, opts) {
|
|
3061
|
+
async function waitForFinalization(client, dstProvider, gwProvider, input, opts) {
|
|
3198
3062
|
const { topics, centerIface } = getTopics();
|
|
3199
3063
|
const pollMs = opts?.pollMs ?? DEFAULT_POLL_MS;
|
|
3200
3064
|
const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
@@ -3243,7 +3107,16 @@ async function waitForFinalization(client, dstProvider, input, opts) {
|
|
|
3243
3107
|
proof,
|
|
3244
3108
|
bundleInfo.l1MessageData
|
|
3245
3109
|
);
|
|
3246
|
-
|
|
3110
|
+
if (proof.gatewayBlockNumber == null) {
|
|
3111
|
+
throw createError("STATE", {
|
|
3112
|
+
resource: "interop",
|
|
3113
|
+
operation: OP_INTEROP.svc.wait.timeout,
|
|
3114
|
+
message: "Proof missing gatewayBlockNumber required for interop finalization.",
|
|
3115
|
+
context: { l2SrcTxHash: ids.l2SrcTxHash }
|
|
3116
|
+
});
|
|
3117
|
+
}
|
|
3118
|
+
const { chainId: gwChainId } = await gwProvider.getNetwork();
|
|
3119
|
+
await waitForRoot(dstProvider, gwChainId, proof.gatewayBlockNumber, pollMs, deadline);
|
|
3247
3120
|
return finalizationInfo;
|
|
3248
3121
|
}
|
|
3249
3122
|
|
|
@@ -3289,8 +3162,8 @@ function createInteropFinalizationServices(client) {
|
|
|
3289
3162
|
status(dstProvider, input, opts) {
|
|
3290
3163
|
return getStatus(client, dstProvider, input, opts);
|
|
3291
3164
|
},
|
|
3292
|
-
wait(dstProvider, input, opts) {
|
|
3293
|
-
return waitForFinalization(client, dstProvider, input, opts);
|
|
3165
|
+
wait(dstProvider, gwProvider, input, opts) {
|
|
3166
|
+
return waitForFinalization(client, dstProvider, gwProvider, input, opts);
|
|
3294
3167
|
},
|
|
3295
3168
|
async finalize(dstProvider, info, opts) {
|
|
3296
3169
|
const execResult = await executeBundle(client, dstProvider, info, opts);
|
|
@@ -3302,24 +3175,56 @@ function createInteropFinalizationServices(client) {
|
|
|
3302
3175
|
}
|
|
3303
3176
|
};
|
|
3304
3177
|
}
|
|
3305
|
-
function
|
|
3306
|
-
return typeof
|
|
3178
|
+
function resolveChainRef(ref) {
|
|
3179
|
+
return typeof ref === "string" ? new JsonRpcProvider(ref) : ref;
|
|
3307
3180
|
}
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3181
|
+
|
|
3182
|
+
// src/adapters/ethers/resources/interop/services/gas.ts
|
|
3183
|
+
async function quoteStepsL2Fee(steps, ctx) {
|
|
3184
|
+
if (steps.length === 0) return 0n;
|
|
3185
|
+
const estimator = ethersToGasEstimator(ctx.client.l2);
|
|
3186
|
+
let maxFeePerGas;
|
|
3187
|
+
try {
|
|
3188
|
+
const fees = await estimator.estimateFeesPerGas();
|
|
3189
|
+
maxFeePerGas = fees.maxFeePerGas ?? fees.gasPrice ?? await estimator.getGasPrice();
|
|
3190
|
+
} catch {
|
|
3191
|
+
return void 0;
|
|
3192
|
+
}
|
|
3193
|
+
let total = 0n;
|
|
3194
|
+
for (const step of steps) {
|
|
3195
|
+
try {
|
|
3196
|
+
const coreTx = toCoreTx({ ...step.tx, from: ctx.sender });
|
|
3197
|
+
const est = await estimator.estimateGas(coreTx);
|
|
3198
|
+
const buffered = BigInt(est) * (100n + BUFFER) / 100n;
|
|
3199
|
+
total += buffered * maxFeePerGas;
|
|
3200
|
+
} catch {
|
|
3201
|
+
return void 0;
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
return total;
|
|
3314
3205
|
}
|
|
3315
3206
|
|
|
3316
3207
|
// src/adapters/ethers/resources/interop/index.ts
|
|
3317
|
-
var { wrap:
|
|
3208
|
+
var { wrap: wrap6, toResult: toResult2 } = createErrorHandlers("interop");
|
|
3318
3209
|
var ROUTES3 = {
|
|
3319
3210
|
direct: routeDirect(),
|
|
3320
3211
|
indirect: routeIndirect()
|
|
3321
3212
|
};
|
|
3322
|
-
function createInteropResource(client, tokens, contracts, attributes) {
|
|
3213
|
+
function createInteropResource(client, config, tokens, contracts, attributes) {
|
|
3214
|
+
let gwProviderCache;
|
|
3215
|
+
function requireConfig() {
|
|
3216
|
+
if (!config)
|
|
3217
|
+
throw createError("STATE", {
|
|
3218
|
+
resource: "interop",
|
|
3219
|
+
operation: "interop.init",
|
|
3220
|
+
message: "Interop is not configured. Pass gwChain in createEthersSdk options."
|
|
3221
|
+
});
|
|
3222
|
+
return config;
|
|
3223
|
+
}
|
|
3224
|
+
function getGwProvider() {
|
|
3225
|
+
if (!gwProviderCache) gwProviderCache = resolveChainRef(requireConfig().gwChain);
|
|
3226
|
+
return gwProviderCache;
|
|
3227
|
+
}
|
|
3323
3228
|
const svc = createInteropFinalizationServices(client);
|
|
3324
3229
|
const tokensResource = tokens ?? createTokensResource(client);
|
|
3325
3230
|
const contractsResource = contracts ?? createContractsResource(client);
|
|
@@ -3343,11 +3248,11 @@ function createInteropResource(client, tokens, contracts, attributes) {
|
|
|
3343
3248
|
baseTokenDst: ctx.baseTokens.dst
|
|
3344
3249
|
}
|
|
3345
3250
|
});
|
|
3346
|
-
await
|
|
3251
|
+
await wrap6(OP_INTEROP.routes[route].preflight, () => ROUTES3[route].preflight?.(params, ctx), {
|
|
3347
3252
|
message: "Interop preflight failed.",
|
|
3348
3253
|
ctx: { where: `routes.${route}.preflight` }
|
|
3349
3254
|
});
|
|
3350
|
-
const { steps, approvals, quoteExtras } = await
|
|
3255
|
+
const { steps, approvals, quoteExtras, interopFee } = await wrap6(
|
|
3351
3256
|
OP_INTEROP.routes[route].build,
|
|
3352
3257
|
() => ROUTES3[route].build(params, ctx),
|
|
3353
3258
|
{
|
|
@@ -3355,11 +3260,14 @@ function createInteropResource(client, tokens, contracts, attributes) {
|
|
|
3355
3260
|
ctx: { where: `routes.${route}.build` }
|
|
3356
3261
|
}
|
|
3357
3262
|
);
|
|
3263
|
+
const l2Fee = await quoteStepsL2Fee(steps, ctx).catch(() => void 0);
|
|
3358
3264
|
const summary = {
|
|
3359
3265
|
route,
|
|
3360
3266
|
approvalsNeeded: approvals,
|
|
3361
3267
|
totalActionValue: quoteExtras.totalActionValue,
|
|
3362
|
-
bridgedTokenTotal: quoteExtras.bridgedTokenTotal
|
|
3268
|
+
bridgedTokenTotal: quoteExtras.bridgedTokenTotal,
|
|
3269
|
+
interopFee,
|
|
3270
|
+
l2Fee
|
|
3363
3271
|
};
|
|
3364
3272
|
return { plan: { route, summary, steps }, ctx };
|
|
3365
3273
|
}
|
|
@@ -3367,20 +3275,23 @@ function createInteropResource(client, tokens, contracts, attributes) {
|
|
|
3367
3275
|
const { plan } = await buildPlanWithCtx(dstProvider, params);
|
|
3368
3276
|
return plan;
|
|
3369
3277
|
}
|
|
3370
|
-
const quote = (params) =>
|
|
3371
|
-
const plan = await buildPlan(
|
|
3278
|
+
const quote = (dstChain, params) => wrap6(OP_INTEROP.quote, async () => {
|
|
3279
|
+
const plan = await buildPlan(resolveChainRef(dstChain), params);
|
|
3372
3280
|
return plan.summary;
|
|
3373
3281
|
});
|
|
3374
|
-
const tryQuote = (params) => toResult2(OP_INTEROP.tryQuote, () => quote(params));
|
|
3375
|
-
const prepare = (params) =>
|
|
3282
|
+
const tryQuote = (dstChain, params) => toResult2(OP_INTEROP.tryQuote, () => quote(dstChain, params));
|
|
3283
|
+
const prepare = (dstChain, params) => wrap6(OP_INTEROP.prepare, () => buildPlan(resolveChainRef(dstChain), params), {
|
|
3376
3284
|
message: "Internal error while preparing an interop plan.",
|
|
3377
3285
|
ctx: { where: "interop.prepare" }
|
|
3378
3286
|
});
|
|
3379
|
-
const tryPrepare = (params) => toResult2(
|
|
3380
|
-
|
|
3287
|
+
const tryPrepare = (dstChain, params) => toResult2(
|
|
3288
|
+
OP_INTEROP.tryPrepare,
|
|
3289
|
+
() => prepare(dstChain, params)
|
|
3290
|
+
);
|
|
3291
|
+
const create = (dstChain, params) => wrap6(
|
|
3381
3292
|
OP_INTEROP.create,
|
|
3382
3293
|
async () => {
|
|
3383
|
-
const { plan, ctx } = await buildPlanWithCtx(
|
|
3294
|
+
const { plan, ctx } = await buildPlanWithCtx(resolveChainRef(dstChain), params);
|
|
3384
3295
|
const signer = ctx.client.signerFor(ctx.client.l2);
|
|
3385
3296
|
const srcProvider = ctx.client.l2;
|
|
3386
3297
|
const from = await signer.getAddress();
|
|
@@ -3442,7 +3353,6 @@ function createInteropResource(client, tokens, contracts, attributes) {
|
|
|
3442
3353
|
const last = Object.values(stepHashes).pop();
|
|
3443
3354
|
return {
|
|
3444
3355
|
kind: "interop",
|
|
3445
|
-
dstChain: params.dstChain,
|
|
3446
3356
|
stepHashes,
|
|
3447
3357
|
plan,
|
|
3448
3358
|
l2SrcTxHash: last ?? "0x"
|
|
@@ -3453,46 +3363,27 @@ function createInteropResource(client, tokens, contracts, attributes) {
|
|
|
3453
3363
|
ctx: { where: "interop.create" }
|
|
3454
3364
|
}
|
|
3455
3365
|
);
|
|
3456
|
-
const tryCreate = (params) => toResult2(
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
}
|
|
3463
|
-
};
|
|
3464
|
-
const wait = (h, opts) => {
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
return { ...info, dstChain: h.dstChain };
|
|
3471
|
-
},
|
|
3472
|
-
{
|
|
3473
|
-
message: "Internal error while waiting for interop finalization.",
|
|
3474
|
-
ctx: { where: "interop.wait" }
|
|
3475
|
-
}
|
|
3476
|
-
);
|
|
3477
|
-
};
|
|
3478
|
-
const tryWait = (h, opts) => toResult2(OP_INTEROP.tryWait, () => wait(h, opts));
|
|
3479
|
-
const finalize = (h, opts) => wrap5(
|
|
3366
|
+
const tryCreate = (dstChain, params) => toResult2(
|
|
3367
|
+
OP_INTEROP.tryCreate,
|
|
3368
|
+
() => create(dstChain, params)
|
|
3369
|
+
);
|
|
3370
|
+
const status = (dstChain, h, opts) => wrap6(OP_INTEROP.status, () => svc.status(resolveChainRef(dstChain), h, opts), {
|
|
3371
|
+
message: "Internal error while checking interop status.",
|
|
3372
|
+
ctx: { where: "interop.status" }
|
|
3373
|
+
});
|
|
3374
|
+
const wait = (dstChain, h, opts) => wrap6(OP_INTEROP.wait, () => svc.wait(resolveChainRef(dstChain), getGwProvider(), h, opts), {
|
|
3375
|
+
message: "Internal error while waiting for interop finalization.",
|
|
3376
|
+
ctx: { where: "interop.wait" }
|
|
3377
|
+
});
|
|
3378
|
+
const tryWait = (dstChain, h, opts) => toResult2(OP_INTEROP.tryWait, () => wait(dstChain, h, opts));
|
|
3379
|
+
const finalize = (dstChain, h, opts) => wrap6(
|
|
3480
3380
|
OP_INTEROP.finalize,
|
|
3481
3381
|
async () => {
|
|
3382
|
+
const dstProvider = resolveChainRef(dstChain);
|
|
3482
3383
|
if (isInteropFinalizationInfo(h)) {
|
|
3483
|
-
|
|
3484
|
-
throw createError("STATE", {
|
|
3485
|
-
resource: "interop",
|
|
3486
|
-
operation: OP_INTEROP.finalize,
|
|
3487
|
-
message: "Missing dstChain in interop finalization info.",
|
|
3488
|
-
context: { input: h }
|
|
3489
|
-
});
|
|
3490
|
-
}
|
|
3491
|
-
const dstProvider2 = resolveDstProvider(h.dstChain);
|
|
3492
|
-
return svc.finalize(dstProvider2, h, opts);
|
|
3384
|
+
return svc.finalize(dstProvider, h, opts);
|
|
3493
3385
|
}
|
|
3494
|
-
const
|
|
3495
|
-
const info = await svc.wait(dstProvider, waitable);
|
|
3386
|
+
const info = await svc.wait(dstProvider, getGwProvider(), h);
|
|
3496
3387
|
return svc.finalize(dstProvider, info, opts);
|
|
3497
3388
|
},
|
|
3498
3389
|
{
|
|
@@ -3500,7 +3391,7 @@ function createInteropResource(client, tokens, contracts, attributes) {
|
|
|
3500
3391
|
ctx: { where: "interop.finalize" }
|
|
3501
3392
|
}
|
|
3502
3393
|
);
|
|
3503
|
-
const tryFinalize = (h, opts) => toResult2(OP_INTEROP.tryFinalize, () => finalize(h, opts));
|
|
3394
|
+
const tryFinalize = (dstChain, h, opts) => toResult2(OP_INTEROP.tryFinalize, () => finalize(dstChain, h, opts));
|
|
3504
3395
|
return {
|
|
3505
3396
|
quote,
|
|
3506
3397
|
tryQuote,
|
|
@@ -3517,10 +3408,10 @@ function createInteropResource(client, tokens, contracts, attributes) {
|
|
|
3517
3408
|
}
|
|
3518
3409
|
|
|
3519
3410
|
// src/adapters/ethers/sdk.ts
|
|
3520
|
-
function createEthersSdk(client) {
|
|
3411
|
+
function createEthersSdk(client, options) {
|
|
3521
3412
|
const tokens = createTokensResource(client);
|
|
3522
3413
|
const contracts = createContractsResource(client);
|
|
3523
|
-
const interop = createInteropResource(client);
|
|
3414
|
+
const interop = createInteropResource(client, options?.interop, tokens, contracts);
|
|
3524
3415
|
return {
|
|
3525
3416
|
deposits: createDepositsResource(client, tokens, contracts),
|
|
3526
3417
|
withdrawals: createWithdrawalsResource(client, tokens, contracts),
|