@matterlabs/zksync-js 0.0.14 → 0.0.16
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.map +1 -1
- package/dist/adapters/ethers/client.d.ts +1 -2
- package/dist/adapters/ethers/client.js +4 -5
- package/dist/adapters/ethers/index.cjs +200 -32
- package/dist/adapters/ethers/index.cjs.map +1 -1
- package/dist/adapters/ethers/index.js +6 -7
- package/dist/adapters/ethers/resources/interop/index.d.ts +4 -1
- package/dist/adapters/ethers/resources/interop/services/finalization/bundle.d.ts +4 -0
- package/dist/adapters/ethers/resources/interop/services/gas.d.ts +12 -0
- package/dist/adapters/ethers/sdk.cjs +200 -32
- package/dist/adapters/ethers/sdk.cjs.map +1 -1
- package/dist/adapters/ethers/sdk.js +5 -6
- package/dist/adapters/viem/client.cjs +787 -3
- package/dist/adapters/viem/client.cjs.map +1 -1
- package/dist/adapters/viem/client.d.ts +6 -1
- package/dist/adapters/viem/client.js +4 -5
- package/dist/adapters/viem/index.cjs +6502 -2966
- package/dist/adapters/viem/index.cjs.map +1 -1
- package/dist/adapters/viem/index.d.ts +5 -0
- package/dist/adapters/viem/index.js +6 -7
- 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 +65 -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 +19 -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 +6665 -3173
- package/dist/adapters/viem/sdk.cjs.map +1 -1
- package/dist/adapters/viem/sdk.d.ts +8 -1
- package/dist/adapters/viem/sdk.js +5 -5
- package/dist/{chunk-7CAVFIMW.js → chunk-24TE2NNJ.js} +2 -3
- package/dist/{chunk-75IOOODG.js → chunk-3KH5PCD6.js} +1233 -31
- package/dist/{chunk-XKRNLFET.js → chunk-5HG2DUYW.js} +150 -375
- package/dist/{chunk-OTXPSNNC.js → chunk-CK5UFAZK.js} +64 -7
- package/dist/{chunk-HP3EWKJL.js → chunk-JSBMIT4S.js} +1 -1
- package/dist/{chunk-5RRJDPAJ.js → chunk-NJK325XV.js} +2 -2
- package/dist/chunk-NLUCYVMX.js +658 -0
- package/dist/{chunk-XDRCN4FC.js → chunk-SBGBYZJM.js} +10 -2
- package/dist/{chunk-J47RI3G7.js → chunk-TYYUG5GA.js} +1 -1
- package/dist/{chunk-JY62QO3W.js → chunk-UEKFQAOS.js} +420 -6
- package/dist/core/index.js +2 -3
- 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 +4 -0
- package/dist/core/resources/interop/protocol.d.ts +3 -0
- package/dist/core/types/errors.d.ts +1 -0
- package/dist/core/types/flows/interop.d.ts +0 -2
- package/dist/core/types/primitives.d.ts +2 -0
- package/dist/index.js +2 -3
- package/package.json +1 -1
- package/dist/chunk-DYJKK5FW.js +0 -417
- package/dist/chunk-EOBXYHTZ.js +0 -265
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { createErrorHandlers, toZKsyncError, classifyReadinessFromRevert } from './chunk-
|
|
2
|
-
import { createNTVCodec, toGasOverrides, buildFeeBreakdown, derivePriorityTxGasBreakdown, quoteL2Gas, quoteL2BaseCost, quoteL1Gas, derivePriorityBodyGasEstimateCap, 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, keccak256, AbiCoder, ethers, getBytes, Contract, NonceManager, JsonRpcProvider,
|
|
1
|
+
import { createErrorHandlers, toZKsyncError, classifyReadinessFromRevert } from './chunk-NJK325XV.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-NLUCYVMX.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, IInteropRootStorage_default, IInteropCenter_default, sleep, isETH, normalizeAddrEq, IL2AssetRouter_default, L2NativeTokenVault_default, assertNever } from './chunk-UEKFQAOS.js';
|
|
5
|
+
import { ETH_ADDRESS, TOPIC_CANONICAL_ASSIGNED, TOPIC_CANONICAL_SUCCESS, L1_MESSENGER_ADDRESS, L2_BASE_TOKEN_ADDRESS, L2_NATIVE_TOKEN_VAULT_ADDRESS, L2_INTEROP_ROOT_STORAGE_ADDRESS, BUFFER, 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)"
|
|
@@ -388,7 +388,10 @@ function routeEthDirect() {
|
|
|
388
388
|
l2Calldata,
|
|
389
389
|
gasPerPubdata: ctx.gasPerPubdata
|
|
390
390
|
});
|
|
391
|
-
const quotedL2GasLimit = ctx.l2GasLimit ??
|
|
391
|
+
const quotedL2GasLimit = ctx.l2GasLimit ?? applyPriorityL2GasLimitBuffer({
|
|
392
|
+
chainIdL2: ctx.chainIdL2,
|
|
393
|
+
gasLimit: priorityFloorBreakdown.derivedL2GasLimit
|
|
394
|
+
});
|
|
392
395
|
const l2GasParams = await quoteL2Gas3({
|
|
393
396
|
ctx,
|
|
394
397
|
route: "eth-base",
|
|
@@ -450,11 +453,6 @@ function routeEthDirect() {
|
|
|
450
453
|
}
|
|
451
454
|
};
|
|
452
455
|
}
|
|
453
|
-
|
|
454
|
-
// src/core/types/primitives.ts
|
|
455
|
-
var ZERO_HASH = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
456
|
-
|
|
457
|
-
// src/adapters/ethers/resources/deposits/routes/erc20-nonbase.ts
|
|
458
456
|
var { wrapAs: wrapAs2 } = createErrorHandlers("deposits");
|
|
459
457
|
var ZERO_L2_TOKEN_ADDRESS2 = "0x0000000000000000000000000000000000000000";
|
|
460
458
|
var ZERO_ASSET_ID = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
@@ -491,7 +489,10 @@ async function getPriorityGasModel(input) {
|
|
|
491
489
|
gasPerPubdata: input.ctx.gasPerPubdata
|
|
492
490
|
});
|
|
493
491
|
const model = {
|
|
494
|
-
priorityFloorGasLimit:
|
|
492
|
+
priorityFloorGasLimit: applyPriorityL2GasLimitBuffer({
|
|
493
|
+
chainIdL2: input.ctx.chainIdL2,
|
|
494
|
+
gasLimit: priorityFloorBreakdown.derivedL2GasLimit
|
|
495
|
+
})
|
|
495
496
|
};
|
|
496
497
|
if (isFirstBridge || input.ctx.resolvedToken.l2.toLowerCase() === ZERO_L2_TOKEN_ADDRESS2) {
|
|
497
498
|
model.undeployedGasLimit = derivePriorityBodyGasEstimateCap({
|
|
@@ -697,7 +698,10 @@ async function getPriorityGasModel2(input) {
|
|
|
697
698
|
gasPerPubdata: input.ctx.gasPerPubdata
|
|
698
699
|
});
|
|
699
700
|
const model = {
|
|
700
|
-
priorityFloorGasLimit:
|
|
701
|
+
priorityFloorGasLimit: applyPriorityL2GasLimitBuffer({
|
|
702
|
+
chainIdL2: input.ctx.chainIdL2,
|
|
703
|
+
gasLimit: priorityFloorBreakdown.derivedL2GasLimit
|
|
704
|
+
})
|
|
701
705
|
};
|
|
702
706
|
if (input.ctx.resolvedToken.l2.toLowerCase() === ZERO_L2_TOKEN_ADDRESS3) {
|
|
703
707
|
model.undeployedGasLimit = derivePriorityBodyGasEstimateCap({
|
|
@@ -819,7 +823,7 @@ function routeEthNonBase() {
|
|
|
819
823
|
const requestStruct = {
|
|
820
824
|
chainId: ctx.chainIdL2,
|
|
821
825
|
mintValue,
|
|
822
|
-
l2Value:
|
|
826
|
+
l2Value: 0n,
|
|
823
827
|
l2GasLimit: l2GasParams.gasLimit,
|
|
824
828
|
l2GasPerPubdataByteLimit: ctx.gasPerPubdata,
|
|
825
829
|
refundRecipient: ctx.refundRecipient,
|
|
@@ -827,6 +831,7 @@ function routeEthNonBase() {
|
|
|
827
831
|
secondBridgeValue: p.amount,
|
|
828
832
|
secondBridgeCalldata
|
|
829
833
|
};
|
|
834
|
+
const bridgehubValue = p.amount;
|
|
830
835
|
const bridgehub = await ctx.contracts.bridgehub();
|
|
831
836
|
const data = bridgehub.interface.encodeFunctionData("requestL2TransactionTwoBridges", [
|
|
832
837
|
requestStruct
|
|
@@ -834,8 +839,7 @@ function routeEthNonBase() {
|
|
|
834
839
|
const l1TxCandidate = {
|
|
835
840
|
to: ctx.bridgehub,
|
|
836
841
|
data,
|
|
837
|
-
value:
|
|
838
|
-
// base ≠ ETH ⇒ msg.value == secondBridgeValue
|
|
842
|
+
value: bridgehubValue,
|
|
839
843
|
from: ctx.sender,
|
|
840
844
|
...ctx.gasOverrides
|
|
841
845
|
};
|
|
@@ -914,7 +918,10 @@ function routeErc20Base() {
|
|
|
914
918
|
l2Calldata,
|
|
915
919
|
gasPerPubdata: ctx.gasPerPubdata
|
|
916
920
|
});
|
|
917
|
-
const quotedL2GasLimit = ctx.l2GasLimit ??
|
|
921
|
+
const quotedL2GasLimit = ctx.l2GasLimit ?? applyPriorityL2GasLimitBuffer({
|
|
922
|
+
chainIdL2: ctx.chainIdL2,
|
|
923
|
+
gasLimit: priorityFloorBreakdown.derivedL2GasLimit
|
|
924
|
+
});
|
|
918
925
|
const l2GasParams = await quoteL2Gas3({
|
|
919
926
|
ctx,
|
|
920
927
|
route: "erc20-base",
|
|
@@ -1340,6 +1347,8 @@ function createDepositsResource(client, tokens, contracts) {
|
|
|
1340
1347
|
async () => {
|
|
1341
1348
|
const plan = await prepare(p);
|
|
1342
1349
|
const stepHashes = {};
|
|
1350
|
+
const { chainId } = await client.l2.getNetwork();
|
|
1351
|
+
const chainIdL2 = BigInt(chainId);
|
|
1343
1352
|
const managed = new NonceManager(client.signer);
|
|
1344
1353
|
const from = await managed.getAddress();
|
|
1345
1354
|
let next;
|
|
@@ -1385,8 +1394,14 @@ function createDepositsResource(client, tokens, contracts) {
|
|
|
1385
1394
|
}
|
|
1386
1395
|
if (!p.l1TxOverrides?.gasLimit) {
|
|
1387
1396
|
try {
|
|
1397
|
+
const preparedGasLimit = step.tx.gasLimit != null ? BigInt(step.tx.gasLimit.toString()) : void 0;
|
|
1388
1398
|
const est = await client.l1.estimateGas(step.tx);
|
|
1389
|
-
step.tx.gasLimit =
|
|
1399
|
+
step.tx.gasLimit = resolveCreateDepositL1GasLimit({
|
|
1400
|
+
chainIdL2,
|
|
1401
|
+
stepKey: step.key,
|
|
1402
|
+
preparedGasLimit,
|
|
1403
|
+
estimatedGasLimit: BigInt(est)
|
|
1404
|
+
});
|
|
1390
1405
|
} catch {
|
|
1391
1406
|
}
|
|
1392
1407
|
}
|
|
@@ -2374,38 +2389,6 @@ function createWithdrawalsResource(client, tokens, contracts) {
|
|
|
2374
2389
|
tryWait
|
|
2375
2390
|
};
|
|
2376
2391
|
}
|
|
2377
|
-
|
|
2378
|
-
// src/core/resources/interop/attributes/call.ts
|
|
2379
|
-
function createCallAttributes(codec) {
|
|
2380
|
-
const indirectCall = (messageValue) => codec.encode("indirectCall", [messageValue]);
|
|
2381
|
-
const interopCallValue = (bridgedAmount) => codec.encode("interopCallValue", [bridgedAmount]);
|
|
2382
|
-
return {
|
|
2383
|
-
indirectCall,
|
|
2384
|
-
interopCallValue
|
|
2385
|
-
};
|
|
2386
|
-
}
|
|
2387
|
-
|
|
2388
|
-
// src/core/resources/interop/attributes/bundle.ts
|
|
2389
|
-
function createBundleAttributes(codec) {
|
|
2390
|
-
const executionAddress = (executor) => codec.encode("executionAddress", [executor]);
|
|
2391
|
-
const unbundlerAddress = (addr) => codec.encode("unbundlerAddress", [addr]);
|
|
2392
|
-
const useFixedFee = (enabled) => codec.encode("useFixedFee", [enabled]);
|
|
2393
|
-
return {
|
|
2394
|
-
executionAddress,
|
|
2395
|
-
unbundlerAddress,
|
|
2396
|
-
useFixedFee
|
|
2397
|
-
};
|
|
2398
|
-
}
|
|
2399
|
-
|
|
2400
|
-
// src/core/resources/interop/attributes/resource.ts
|
|
2401
|
-
function createAttributesResource(codec) {
|
|
2402
|
-
return {
|
|
2403
|
-
call: createCallAttributes(codec),
|
|
2404
|
-
bundle: createBundleAttributes(codec)
|
|
2405
|
-
};
|
|
2406
|
-
}
|
|
2407
|
-
|
|
2408
|
-
// src/adapters/ethers/resources/interop/attributes/resource.ts
|
|
2409
2392
|
function getInteropAttributes(params, ctx) {
|
|
2410
2393
|
const bundleAttributes = [];
|
|
2411
2394
|
if (params.execution?.only) {
|
|
@@ -2442,183 +2425,6 @@ function createEthersAttributesResource(opts = {}) {
|
|
|
2442
2425
|
const encode2 = (fn, args) => iface.encodeFunctionData(fn, args);
|
|
2443
2426
|
return createAttributesResource({ encode: encode2 });
|
|
2444
2427
|
}
|
|
2445
|
-
|
|
2446
|
-
// src/core/types/flows/interop.ts
|
|
2447
|
-
function isInteropMessageProof(obj) {
|
|
2448
|
-
if (typeof obj !== "object" || obj === null) return false;
|
|
2449
|
-
const proof = obj;
|
|
2450
|
-
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);
|
|
2451
|
-
}
|
|
2452
|
-
function isInteropFinalizationInfo(obj) {
|
|
2453
|
-
if (typeof obj !== "object" || obj === null) return false;
|
|
2454
|
-
const info = obj;
|
|
2455
|
-
return isHash66(info.l2SrcTxHash) && isHash66(info.bundleHash) && isBigint(info.dstChainId) && isHash(info.encodedData) && isInteropMessageProof(info.proof);
|
|
2456
|
-
}
|
|
2457
|
-
|
|
2458
|
-
// src/core/resources/interop/route.ts
|
|
2459
|
-
function sumActionMsgValue(actions) {
|
|
2460
|
-
let sum = 0n;
|
|
2461
|
-
for (const a of actions) {
|
|
2462
|
-
if (a.type === "sendNative") sum += a.amount;
|
|
2463
|
-
else if (a.type === "call" && a.value) sum += a.value;
|
|
2464
|
-
}
|
|
2465
|
-
return sum;
|
|
2466
|
-
}
|
|
2467
|
-
function sumErc20Amounts(actions) {
|
|
2468
|
-
let sum = 0n;
|
|
2469
|
-
for (const a of actions) if (a.type === "sendErc20") sum += a.amount;
|
|
2470
|
-
return sum;
|
|
2471
|
-
}
|
|
2472
|
-
function pickInteropRoute(args) {
|
|
2473
|
-
const hasErc20 = args.actions.some((a) => a.type === "sendErc20");
|
|
2474
|
-
const baseMatches = args.ctx.baseTokenSrc.toLowerCase() === args.ctx.baseTokenDst.toLowerCase();
|
|
2475
|
-
if (hasErc20) return "indirect";
|
|
2476
|
-
if (!baseMatches) return "indirect";
|
|
2477
|
-
return "direct";
|
|
2478
|
-
}
|
|
2479
|
-
|
|
2480
|
-
// src/core/resources/interop/plan.ts
|
|
2481
|
-
function preflightDirect(params, ctx) {
|
|
2482
|
-
if (!params.actions?.length) {
|
|
2483
|
-
throw new Error('route "direct" requires at least one action.');
|
|
2484
|
-
}
|
|
2485
|
-
const baseMatch = ctx.baseTokens.src.toLowerCase() === ctx.baseTokens.dst.toLowerCase();
|
|
2486
|
-
if (!baseMatch) {
|
|
2487
|
-
throw new Error('route "direct" requires matching base tokens between source and destination.');
|
|
2488
|
-
}
|
|
2489
|
-
for (const action of params.actions) {
|
|
2490
|
-
switch (action.type) {
|
|
2491
|
-
case "sendNative":
|
|
2492
|
-
if (action.amount < 0n) {
|
|
2493
|
-
throw new Error("sendNative.amount must be >= 0.");
|
|
2494
|
-
}
|
|
2495
|
-
break;
|
|
2496
|
-
case "call":
|
|
2497
|
-
if (action.value != null && action.value < 0n) {
|
|
2498
|
-
throw new Error("call.value must be >= 0 when provided.");
|
|
2499
|
-
}
|
|
2500
|
-
break;
|
|
2501
|
-
default:
|
|
2502
|
-
throw new Error(
|
|
2503
|
-
`route "direct" does not support ${action.type} actions; use the indirect route.`
|
|
2504
|
-
);
|
|
2505
|
-
}
|
|
2506
|
-
}
|
|
2507
|
-
}
|
|
2508
|
-
function buildDirectBundle(params, ctx, attrs, interopFeeInfo) {
|
|
2509
|
-
const totalActionValue = sumActionMsgValue(params.actions);
|
|
2510
|
-
const starters = params.actions.map((action, index) => {
|
|
2511
|
-
const to = ctx.codec.formatAddress(action.to);
|
|
2512
|
-
const callAttributes = attrs.callAttributes[index] ?? [];
|
|
2513
|
-
switch (action.type) {
|
|
2514
|
-
case "sendNative":
|
|
2515
|
-
return [to, "0x", callAttributes];
|
|
2516
|
-
case "call":
|
|
2517
|
-
return [to, action.data ?? "0x", callAttributes];
|
|
2518
|
-
default:
|
|
2519
|
-
throw new Error(`buildDirectBundle: unsupported action type "${action.type}".`);
|
|
2520
|
-
}
|
|
2521
|
-
});
|
|
2522
|
-
return {
|
|
2523
|
-
dstChain: ctx.codec.formatChain(ctx.dstChainId),
|
|
2524
|
-
starters,
|
|
2525
|
-
bundleAttributes: attrs.bundleAttributes,
|
|
2526
|
-
approvals: interopFeeInfo.approval ? [interopFeeInfo.approval] : [],
|
|
2527
|
-
interopFee: interopFeeInfo.fee,
|
|
2528
|
-
quoteExtras: {
|
|
2529
|
-
totalActionValue,
|
|
2530
|
-
bridgedTokenTotal: 0n
|
|
2531
|
-
}
|
|
2532
|
-
};
|
|
2533
|
-
}
|
|
2534
|
-
function preflightIndirect(params, ctx) {
|
|
2535
|
-
if (!params.actions?.length) {
|
|
2536
|
-
throw new Error('route "indirect" requires at least one action.');
|
|
2537
|
-
}
|
|
2538
|
-
const hasErc20 = params.actions.some((a) => a.type === "sendErc20");
|
|
2539
|
-
const baseMatches = ctx.baseTokens.src.toLowerCase() === ctx.baseTokens.dst.toLowerCase();
|
|
2540
|
-
if (!hasErc20 && baseMatches) {
|
|
2541
|
-
throw new Error(
|
|
2542
|
-
'route "indirect" requires ERC-20 actions or mismatched base tokens; use the direct route instead.'
|
|
2543
|
-
);
|
|
2544
|
-
}
|
|
2545
|
-
for (const action of params.actions) {
|
|
2546
|
-
switch (action.type) {
|
|
2547
|
-
case "sendNative":
|
|
2548
|
-
if (action.amount < 0n) {
|
|
2549
|
-
throw new Error("sendNative.amount must be >= 0.");
|
|
2550
|
-
}
|
|
2551
|
-
break;
|
|
2552
|
-
case "sendErc20":
|
|
2553
|
-
if (action.amount < 0n) {
|
|
2554
|
-
throw new Error("sendErc20.amount must be >= 0.");
|
|
2555
|
-
}
|
|
2556
|
-
break;
|
|
2557
|
-
case "call":
|
|
2558
|
-
if (action.value != null) {
|
|
2559
|
-
if (action.value < 0n) {
|
|
2560
|
-
throw new Error("call.value must be >= 0 when provided.");
|
|
2561
|
-
}
|
|
2562
|
-
if (action.value > 0n && !baseMatches) {
|
|
2563
|
-
throw new Error("indirect route does not support call.value when base tokens differ.");
|
|
2564
|
-
}
|
|
2565
|
-
}
|
|
2566
|
-
break;
|
|
2567
|
-
default:
|
|
2568
|
-
assertNever(action);
|
|
2569
|
-
}
|
|
2570
|
-
}
|
|
2571
|
-
}
|
|
2572
|
-
function buildIndirectBundle(params, ctx, attrs, starterData, interopFeeInfo) {
|
|
2573
|
-
const totalActionValue = sumActionMsgValue(params.actions);
|
|
2574
|
-
const bridgedTokenTotal = sumErc20Amounts(params.actions);
|
|
2575
|
-
const approvalMap = /* @__PURE__ */ new Map();
|
|
2576
|
-
for (const action of params.actions) {
|
|
2577
|
-
if (action.type !== "sendErc20") continue;
|
|
2578
|
-
const key = action.token.toLowerCase();
|
|
2579
|
-
const existing = approvalMap.get(key);
|
|
2580
|
-
if (existing) {
|
|
2581
|
-
existing.amount += action.amount;
|
|
2582
|
-
} else {
|
|
2583
|
-
approvalMap.set(key, {
|
|
2584
|
-
token: action.token,
|
|
2585
|
-
spender: ctx.l2NativeTokenVault,
|
|
2586
|
-
amount: action.amount
|
|
2587
|
-
});
|
|
2588
|
-
}
|
|
2589
|
-
}
|
|
2590
|
-
const approvals = Array.from(approvalMap.values());
|
|
2591
|
-
if (interopFeeInfo.approval) approvals.push(interopFeeInfo.approval);
|
|
2592
|
-
const starters = params.actions.map((action, index) => {
|
|
2593
|
-
const callAttributes = attrs.callAttributes[index] ?? [];
|
|
2594
|
-
if (starterData[index]?.assetRouterPayload) {
|
|
2595
|
-
const l2AssetRouter = ctx.codec.formatAddress(ctx.l2AssetRouter);
|
|
2596
|
-
return [l2AssetRouter, starterData[index].assetRouterPayload, callAttributes];
|
|
2597
|
-
}
|
|
2598
|
-
const directTo = ctx.codec.formatAddress(action.to);
|
|
2599
|
-
switch (action.type) {
|
|
2600
|
-
case "sendNative":
|
|
2601
|
-
return [directTo, "0x", callAttributes];
|
|
2602
|
-
case "call":
|
|
2603
|
-
return [directTo, action.data ?? "0x", callAttributes];
|
|
2604
|
-
case "sendErc20":
|
|
2605
|
-
throw new Error("buildIndirectBundle: missing assetRouterPayload for sendErc20 action.");
|
|
2606
|
-
default:
|
|
2607
|
-
return assertNever(action);
|
|
2608
|
-
}
|
|
2609
|
-
});
|
|
2610
|
-
return {
|
|
2611
|
-
dstChain: ctx.codec.formatChain(ctx.dstChainId),
|
|
2612
|
-
starters,
|
|
2613
|
-
bundleAttributes: attrs.bundleAttributes,
|
|
2614
|
-
approvals,
|
|
2615
|
-
interopFee: interopFeeInfo.fee,
|
|
2616
|
-
quoteExtras: {
|
|
2617
|
-
totalActionValue,
|
|
2618
|
-
bridgedTokenTotal
|
|
2619
|
-
}
|
|
2620
|
-
};
|
|
2621
|
-
}
|
|
2622
2428
|
var PREFIX_EVM_CHAIN = getBytes("0x00010000");
|
|
2623
2429
|
var PREFIX_EVM_ADDRESS = getBytes("0x000100000014");
|
|
2624
2430
|
function formatInteropEvmChain(chainId) {
|
|
@@ -2783,7 +2589,9 @@ function routeIndirect() {
|
|
|
2783
2589
|
dstChainId: ctx.dstChainId,
|
|
2784
2590
|
baseTokens: ctx.baseTokens,
|
|
2785
2591
|
l2AssetRouter: ctx.l2AssetRouter,
|
|
2786
|
-
l2NativeTokenVault: ctx.l2NativeTokenVault
|
|
2592
|
+
l2NativeTokenVault: ctx.l2NativeTokenVault,
|
|
2593
|
+
codec: interopCodec
|
|
2594
|
+
});
|
|
2787
2595
|
},
|
|
2788
2596
|
async build(params, ctx) {
|
|
2789
2597
|
const steps = [];
|
|
@@ -2844,7 +2652,9 @@ function routeDirect() {
|
|
|
2844
2652
|
dstChainId: ctx.dstChainId,
|
|
2845
2653
|
baseTokens: ctx.baseTokens,
|
|
2846
2654
|
l2AssetRouter: ctx.l2AssetRouter,
|
|
2847
|
-
l2NativeTokenVault: ctx.l2NativeTokenVault
|
|
2655
|
+
l2NativeTokenVault: ctx.l2NativeTokenVault,
|
|
2656
|
+
codec: interopCodec
|
|
2657
|
+
});
|
|
2848
2658
|
},
|
|
2849
2659
|
async build(params, ctx) {
|
|
2850
2660
|
const steps = [];
|
|
@@ -2889,26 +2699,11 @@ function routeDirect() {
|
|
|
2889
2699
|
}
|
|
2890
2700
|
};
|
|
2891
2701
|
}
|
|
2892
|
-
var MIN_INTEROP_PROTOCOL = 31;
|
|
2893
2702
|
async function assertInteropProtocolVersion(client, srcChainId, dstChainId) {
|
|
2894
2703
|
const [srcProtocolVersion, dstProtocolVersion] = await Promise.all([
|
|
2895
2704
|
client.getProtocolVersion(srcChainId),
|
|
2896
2705
|
client.getProtocolVersion(dstChainId)
|
|
2897
2706
|
]);
|
|
2898
|
-
const assertProtocolVersion = (chainId, protocolVersion) => {
|
|
2899
|
-
if (protocolVersion[1] < MIN_INTEROP_PROTOCOL) {
|
|
2900
|
-
throw createError("VALIDATION", {
|
|
2901
|
-
resource: "interop",
|
|
2902
|
-
operation: OP_INTEROP.context.protocolVersion,
|
|
2903
|
-
message: `Interop requires protocol version 31.0+. Found: ${protocolVersion[1]}.${protocolVersion[2]} for chain: ${chainId}.`,
|
|
2904
|
-
context: {
|
|
2905
|
-
chainId,
|
|
2906
|
-
requiredMinor: MIN_INTEROP_PROTOCOL,
|
|
2907
|
-
semver: protocolVersion
|
|
2908
|
-
}
|
|
2909
|
-
});
|
|
2910
|
-
}
|
|
2911
|
-
};
|
|
2912
2707
|
assertProtocolVersion(srcChainId, srcProtocolVersion);
|
|
2913
2708
|
assertProtocolVersion(dstChainId, dstProtocolVersion);
|
|
2914
2709
|
}
|
|
@@ -2979,7 +2774,14 @@ function parseMaxBlockRangeLimit(error) {
|
|
|
2979
2774
|
async function getTxReceipt(provider, txHash) {
|
|
2980
2775
|
const receipt = await wrap3(
|
|
2981
2776
|
OP_INTEROP.svc.status.sourceReceipt,
|
|
2982
|
-
() =>
|
|
2777
|
+
async () => {
|
|
2778
|
+
try {
|
|
2779
|
+
return await provider.getTransactionReceipt(txHash);
|
|
2780
|
+
} catch (error) {
|
|
2781
|
+
if (isReceiptNotFound(error)) return null;
|
|
2782
|
+
throw error;
|
|
2783
|
+
}
|
|
2784
|
+
},
|
|
2983
2785
|
{
|
|
2984
2786
|
ctx: { where: "l2.getTransactionReceipt", l2SrcTxHash: txHash },
|
|
2985
2787
|
message: "Failed to fetch source L2 receipt for interop tx."
|
|
@@ -3144,137 +2946,59 @@ async function executeBundle(client, dstProvider, info, opts) {
|
|
|
3144
2946
|
);
|
|
3145
2947
|
}
|
|
3146
2948
|
}
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
3151
|
-
function resolveIdsFromWaitable(input) {
|
|
3152
|
-
if (typeof input === "string") {
|
|
3153
|
-
return { l2SrcTxHash: input };
|
|
3154
|
-
}
|
|
3155
|
-
return {
|
|
3156
|
-
l2SrcTxHash: input.l2SrcTxHash,
|
|
3157
|
-
bundleHash: input.bundleHash,
|
|
3158
|
-
dstExecTxHash: input.dstExecTxHash
|
|
3159
|
-
};
|
|
3160
|
-
}
|
|
3161
|
-
function parseBundleSentFromReceipt(input) {
|
|
3162
|
-
const { receipt, interopCenter, interopBundleSentTopic, decodeInteropBundleSent: decodeInteropBundleSent2 } = input;
|
|
3163
|
-
const bundleSentLog = receipt.logs.find(
|
|
3164
|
-
(log) => log.address.toLowerCase() === interopCenter.toLowerCase() && log.topics[0].toLowerCase() === interopBundleSentTopic.toLowerCase()
|
|
3165
|
-
);
|
|
3166
|
-
if (!bundleSentLog) {
|
|
3167
|
-
throw createError("STATE", {
|
|
3168
|
-
resource: "interop",
|
|
3169
|
-
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
3170
|
-
message: "Failed to locate InteropBundleSent event in source receipt.",
|
|
3171
|
-
context: { receipt, interopCenter }
|
|
3172
|
-
});
|
|
3173
|
-
}
|
|
3174
|
-
const decoded = decodeInteropBundleSent2({
|
|
3175
|
-
data: bundleSentLog.data,
|
|
3176
|
-
topics: bundleSentLog.topics
|
|
2949
|
+
async function verifyBundle(client, dstProvider, info) {
|
|
2950
|
+
const signer = await wrap4(OP_INTEROP.verify, () => client.signerFor(dstProvider), {
|
|
2951
|
+
message: "Failed to resolve destination signer for verifyBundle."
|
|
3177
2952
|
});
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
2953
|
+
const { interopHandler } = await client.ensureAddresses();
|
|
2954
|
+
const handler = new Contract(interopHandler, IInteropHandler_default, signer);
|
|
2955
|
+
try {
|
|
2956
|
+
const txResponse = await handler.verifyBundle(
|
|
2957
|
+
info.encodedData,
|
|
2958
|
+
info.proof
|
|
2959
|
+
);
|
|
2960
|
+
const hash = txResponse.hash;
|
|
2961
|
+
return {
|
|
2962
|
+
hash,
|
|
2963
|
+
wait: async () => {
|
|
2964
|
+
try {
|
|
2965
|
+
const receipt = await txResponse.wait();
|
|
2966
|
+
if (!receipt || receipt.status !== 1) {
|
|
2967
|
+
throw createError("EXECUTION", {
|
|
2968
|
+
resource: "interop",
|
|
2969
|
+
operation: OP_INTEROP.verify,
|
|
2970
|
+
message: "Interop bundle verification reverted on destination.",
|
|
2971
|
+
context: { txHash: hash }
|
|
2972
|
+
});
|
|
2973
|
+
}
|
|
2974
|
+
return receipt;
|
|
2975
|
+
} catch (e) {
|
|
2976
|
+
if (isZKsyncError(e)) throw e;
|
|
2977
|
+
throw toZKsyncError(
|
|
2978
|
+
"EXECUTION",
|
|
2979
|
+
{
|
|
2980
|
+
resource: "interop",
|
|
2981
|
+
operation: OP_INTEROP.verify,
|
|
2982
|
+
message: "Failed while waiting for verifyBundle transaction on destination.",
|
|
2983
|
+
context: { txHash: hash }
|
|
2984
|
+
},
|
|
2985
|
+
e
|
|
2986
|
+
);
|
|
2987
|
+
}
|
|
3205
2988
|
}
|
|
3206
|
-
continue;
|
|
3207
|
-
}
|
|
3208
|
-
if (log.address.toLowerCase() !== interopCenter.toLowerCase() || log.topics[0].toLowerCase() !== interopBundleSentTopic.toLowerCase())
|
|
3209
|
-
continue;
|
|
3210
|
-
const decoded = decodeInteropBundleSent2({
|
|
3211
|
-
data: log.data,
|
|
3212
|
-
topics: log.topics
|
|
3213
|
-
});
|
|
3214
|
-
found = {
|
|
3215
|
-
bundleHash: decoded.bundleHash,
|
|
3216
|
-
dstChainId: decoded.destinationChainId,
|
|
3217
|
-
sourceChainId: decoded.sourceChainId
|
|
3218
2989
|
};
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
throw createError("STATE", {
|
|
3231
|
-
resource: "interop",
|
|
3232
|
-
operation: OP_INTEROP.svc.status.parseSentLog,
|
|
3233
|
-
message: "Failed to locate L1MessageSent log data for interop bundle.",
|
|
3234
|
-
context: { l2SrcTxHash, interopCenter }
|
|
3235
|
-
});
|
|
2990
|
+
} catch (e) {
|
|
2991
|
+
if (isZKsyncError(e)) throw e;
|
|
2992
|
+
throw toZKsyncError(
|
|
2993
|
+
"EXECUTION",
|
|
2994
|
+
{
|
|
2995
|
+
resource: "interop",
|
|
2996
|
+
operation: OP_INTEROP.verify,
|
|
2997
|
+
message: "Failed to send verifyBundle transaction on destination chain."
|
|
2998
|
+
},
|
|
2999
|
+
e
|
|
3000
|
+
);
|
|
3236
3001
|
}
|
|
3237
|
-
return {
|
|
3238
|
-
bundleHash: found.bundleHash,
|
|
3239
|
-
dstChainId: found.dstChainId,
|
|
3240
|
-
sourceChainId: found.sourceChainId,
|
|
3241
|
-
l1MessageData,
|
|
3242
|
-
l2ToL1LogIndex,
|
|
3243
|
-
txNumberInBatch: Number(rawReceipt.transactionIndex),
|
|
3244
|
-
rawReceipt
|
|
3245
|
-
};
|
|
3246
|
-
}
|
|
3247
|
-
function getBundleEncodedData(messageData) {
|
|
3248
|
-
const prefix = `0x${messageData.slice(2, 4)}`;
|
|
3249
|
-
if (prefix !== BUNDLE_IDENTIFIER) {
|
|
3250
|
-
throw createError("STATE", {
|
|
3251
|
-
resource: "interop",
|
|
3252
|
-
operation: OP_INTEROP.wait,
|
|
3253
|
-
message: "Unexpected bundle prefix in L1MessageSent data.",
|
|
3254
|
-
context: { prefix, expected: BUNDLE_IDENTIFIER }
|
|
3255
|
-
});
|
|
3256
|
-
}
|
|
3257
|
-
return `0x${messageData.slice(4)}`;
|
|
3258
|
-
}
|
|
3259
|
-
function buildFinalizationInfo(ids, bundleInfo, proof, messageData) {
|
|
3260
|
-
const messageProof = {
|
|
3261
|
-
chainId: bundleInfo.sourceChainId,
|
|
3262
|
-
l1BatchNumber: proof.batchNumber,
|
|
3263
|
-
l2MessageIndex: proof.id,
|
|
3264
|
-
message: {
|
|
3265
|
-
txNumberInBatch: bundleInfo.txNumberInBatch,
|
|
3266
|
-
sender: L2_INTEROP_CENTER_ADDRESS,
|
|
3267
|
-
data: messageData
|
|
3268
|
-
},
|
|
3269
|
-
proof: proof.proof
|
|
3270
|
-
};
|
|
3271
|
-
return {
|
|
3272
|
-
l2SrcTxHash: ids.l2SrcTxHash,
|
|
3273
|
-
bundleHash: bundleInfo.bundleHash,
|
|
3274
|
-
dstChainId: bundleInfo.dstChainId,
|
|
3275
|
-
proof: messageProof,
|
|
3276
|
-
encodedData: getBundleEncodedData(messageData)
|
|
3277
|
-
};
|
|
3278
3002
|
}
|
|
3279
3003
|
function decodeInteropBundleSent(centerIface, log) {
|
|
3280
3004
|
const decoded = centerIface.decodeEventLog(
|
|
@@ -3509,6 +3233,31 @@ function resolveChainRef(ref) {
|
|
|
3509
3233
|
return typeof ref === "string" ? new JsonRpcProvider(ref) : ref;
|
|
3510
3234
|
}
|
|
3511
3235
|
|
|
3236
|
+
// src/adapters/ethers/resources/interop/services/gas.ts
|
|
3237
|
+
async function quoteStepsL2Fee(steps, ctx) {
|
|
3238
|
+
if (steps.length === 0) return 0n;
|
|
3239
|
+
const estimator = ethersToGasEstimator(ctx.client.l2);
|
|
3240
|
+
let maxFeePerGas;
|
|
3241
|
+
try {
|
|
3242
|
+
const fees = await estimator.estimateFeesPerGas();
|
|
3243
|
+
maxFeePerGas = fees.maxFeePerGas ?? fees.gasPrice ?? await estimator.getGasPrice();
|
|
3244
|
+
} catch {
|
|
3245
|
+
return void 0;
|
|
3246
|
+
}
|
|
3247
|
+
let total = 0n;
|
|
3248
|
+
for (const step of steps) {
|
|
3249
|
+
try {
|
|
3250
|
+
const coreTx = toCoreTx({ ...step.tx, from: ctx.sender });
|
|
3251
|
+
const est = await estimator.estimateGas(coreTx);
|
|
3252
|
+
const buffered = BigInt(est) * (100n + BUFFER) / 100n;
|
|
3253
|
+
total += buffered * maxFeePerGas;
|
|
3254
|
+
} catch {
|
|
3255
|
+
return void 0;
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
return total;
|
|
3259
|
+
}
|
|
3260
|
+
|
|
3512
3261
|
// src/adapters/ethers/resources/interop/index.ts
|
|
3513
3262
|
var { wrap: wrap6, toResult: toResult2 } = createErrorHandlers("interop");
|
|
3514
3263
|
var ROUTES3 = {
|
|
@@ -3565,12 +3314,14 @@ function createInteropResource(client, config, tokens, contracts, attributes) {
|
|
|
3565
3314
|
ctx: { where: `routes.${route}.build` }
|
|
3566
3315
|
}
|
|
3567
3316
|
);
|
|
3317
|
+
const l2Fee = await quoteStepsL2Fee(steps, ctx).catch(() => void 0);
|
|
3568
3318
|
const summary = {
|
|
3569
3319
|
route,
|
|
3570
3320
|
approvalsNeeded: approvals,
|
|
3571
3321
|
totalActionValue: quoteExtras.totalActionValue,
|
|
3572
3322
|
bridgedTokenTotal: quoteExtras.bridgedTokenTotal,
|
|
3573
|
-
interopFee
|
|
3323
|
+
interopFee,
|
|
3324
|
+
l2Fee
|
|
3574
3325
|
};
|
|
3575
3326
|
return { plan: { route, summary, steps }, ctx };
|
|
3576
3327
|
}
|
|
@@ -3695,6 +3446,28 @@ function createInteropResource(client, config, tokens, contracts, attributes) {
|
|
|
3695
3446
|
}
|
|
3696
3447
|
);
|
|
3697
3448
|
const tryFinalize = (dstChain, h, opts) => toResult2(OP_INTEROP.tryFinalize, () => finalize(dstChain, h, opts));
|
|
3449
|
+
const interopGetRoot = (dstChain, rootChainId, batchNumber) => wrap6(
|
|
3450
|
+
OP_INTEROP.svc.status.getRoot,
|
|
3451
|
+
() => getInteropRoot(resolveChainRef(dstChain), rootChainId, batchNumber),
|
|
3452
|
+
{
|
|
3453
|
+
message: "Failed to get interop root from the destination chain.",
|
|
3454
|
+
ctx: { where: "interop.getInteropRoot" }
|
|
3455
|
+
}
|
|
3456
|
+
);
|
|
3457
|
+
const verifyBundle2 = (dstChain, h) => wrap6(
|
|
3458
|
+
OP_INTEROP.verify,
|
|
3459
|
+
async () => {
|
|
3460
|
+
const dstProvider = resolveChainRef(dstChain);
|
|
3461
|
+
const info = isInteropFinalizationInfo(h) ? h : await svc.wait(dstProvider, getGwProvider(), h);
|
|
3462
|
+
const result = await verifyBundle(client, dstProvider, info);
|
|
3463
|
+
await result.wait();
|
|
3464
|
+
return { bundleHash: info.bundleHash, dstExecTxHash: result.hash };
|
|
3465
|
+
},
|
|
3466
|
+
{
|
|
3467
|
+
message: "Failed to verify interop bundle on destination.",
|
|
3468
|
+
ctx: { where: "interop.verifyBundle" }
|
|
3469
|
+
}
|
|
3470
|
+
);
|
|
3698
3471
|
return {
|
|
3699
3472
|
quote,
|
|
3700
3473
|
tryQuote,
|
|
@@ -3706,7 +3479,9 @@ function createInteropResource(client, config, tokens, contracts, attributes) {
|
|
|
3706
3479
|
wait,
|
|
3707
3480
|
tryWait,
|
|
3708
3481
|
finalize,
|
|
3709
|
-
tryFinalize
|
|
3482
|
+
tryFinalize,
|
|
3483
|
+
getInteropRoot: interopGetRoot,
|
|
3484
|
+
verifyBundle: verifyBundle2
|
|
3710
3485
|
};
|
|
3711
3486
|
}
|
|
3712
3487
|
|