diff --git a/README.md b/README.md
index 6c09098..0e968fa 100644
--- a/README.md
+++ b/README.md
@@ -70,6 +70,7 @@ Using public testnet RPCs can be slow because many tutorials wait for transactio
- 🌉 [Bridging a custom token through the generic-custom gateway](./packages/custom-token-bridging/)
- 🌉 [Bridging a custom token through a custom gateway](./packages/custom-gateway-bridging/)
- ✈️ [Send a signed transaction from the parent chain](./packages/delayedInbox-l2msg/)
+- 🛡️ [Force inclusion end-to-end test](./packages/force-inclusion/)
- 🎁 [Redeem pending retryable ticket](./packages/redeem-pending-retryable/)
- 🧮 [Gas estimation](./packages/gas-estimation/)
- 🌀 [Deposit Ether or Tokens from L1 to L3](./packages/l1-l3-teleport/)
diff --git a/packages/force-inclusion/.env-sample b/packages/force-inclusion/.env-sample
new file mode 100644
index 0000000..b77b1f6
--- /dev/null
+++ b/packages/force-inclusion/.env-sample
@@ -0,0 +1,18 @@
+# This is a sample .env file for use in local development.
+# Duplicate this file as .env here
+
+# Private key of the deployer (must have ETH on the parent chain)
+DEPLOYER_PRIVATE_KEY="0x your key here"
+
+# The parent chain's RPC
+# (default: Arbitrum Sepolia)
+PARENT_CHAIN_RPC="https://sepolia-rollup.arbitrum.io/rpc"
+
+# (Optional) Parent chain ID
+# Defaults to Arbitrum Sepolia (421614) if not set
+# PARENT_CHAIN_ID=421614
+
+# (Optional) Batch poster and validator keys
+# Auto-generated if not set (only needed for --with-node)
+# BATCH_POSTER_PRIVATE_KEY="0x..."
+# VALIDATOR_PRIVATE_KEY="0x..."
diff --git a/packages/force-inclusion/README.md b/packages/force-inclusion/README.md
new file mode 100644
index 0000000..02322e7
--- /dev/null
+++ b/packages/force-inclusion/README.md
@@ -0,0 +1,92 @@
+# Tutorial: Force Inclusion End-to-End Test
+
+`force-inclusion` demonstrates Arbitrum's **censorship resistance** mechanism end-to-end. It deploys a fresh Orbit rollup with a short force inclusion delay (90 seconds), deposits ETH via the delayed inbox, waits for the delay window to pass, and then force includes the deposit — all without a running sequencer.
+
+## What is force inclusion?
+
+Arbitrum's [Sequencer](https://docs.arbitrum.io/how-arbitrum-works/sequencer) normally orders transactions. But what if the sequencer goes offline or starts censoring? Arbitrum guarantees that any message sent to the **delayed inbox** on the parent chain can be **force included** into the chain's inbox after a time delay, bypassing the sequencer entirely.
+
+This tutorial runs the full cycle in a single command:
+
+1. **Deploy** a new Orbit rollup with `maxTimeVariation.delaySeconds = 90` (instead of the default 24 hours)
+2. **Deposit** ETH via `Inbox.depositEth()` on the parent chain (goes into the delayed inbox)
+3. **Force include** the deposit by calling `SequencerInbox.forceInclusion()` after the delay window passes
+4. _(Optional)_ **Start a fullnode** (no sequencer) to verify the deposit appears on the child chain
+
+## Prerequisites
+
+- Node.js 18+
+- A deployer account with ETH on the parent chain (Arbitrum Sepolia or a custom parent chain)
+- Docker (only needed for the `--with-node` option)
+
+## Set environment variables
+
+Copy the sample env file and fill in your values:
+
+```bash
+cp .env-sample .env
+```
+
+Required variables:
+
+| Variable | Description |
+| ---------------------- | --------------------------------------------------------------- |
+| `DEPLOYER_PRIVATE_KEY` | Private key of the deployer (must have ETH on the parent chain) |
+| `PARENT_CHAIN_RPC` | RPC URL of the parent chain |
+
+Optional variables:
+
+| Variable | Description |
+| -------------------------- | ----------------------------------------------------- |
+| `PARENT_CHAIN_ID` | Parent chain ID (defaults to Arbitrum Sepolia 421614) |
+| `BATCH_POSTER_PRIVATE_KEY` | Batch poster key (auto-generated if not set) |
+| `VALIDATOR_PRIVATE_KEY` | Validator key (auto-generated if not set) |
+
+## Run
+
+Run steps 1–3 (deploy, deposit, force include):
+
+```bash
+yarn test
+```
+
+Run all 4 steps including fullnode verification (requires Docker):
+
+```bash
+yarn test:withNode
+```
+
+## How it works
+
+### Rollup deployment
+
+The script uses `@arbitrum/chain-sdk` (Orbit SDK) to deploy a new rollup. The key configuration is `sequencerInboxMaxTimeVariation`, which controls how long a delayed message must wait before it can be force included:
+
+```js
+sequencerInboxMaxTimeVariation: {
+ delayBlocks: 6n,
+ futureBlocks: 12n,
+ delaySeconds: 90n,
+ futureSeconds: 3600n,
+}
+```
+
+### Delayed inbox deposit
+
+ETH is deposited using `@arbitrum/sdk`'s `EthBridger.deposit()`. Under the hood, this calls `Inbox.depositEth()` on the parent chain, which routes through `bridge.enqueueDelayedMessage()`. Without a running sequencer, this message stays in the delayed inbox.
+
+### Force inclusion
+
+After the delay window passes (90 seconds + 6 blocks), `InboxTools.forceInclude()` calls `SequencerInbox.forceInclusion()` on the parent chain. This emits the same `SequencerBatchDelivered` event as a normal sequencer batch, making the deposit part of the canonical chain.
+
+### Fullnode verification (--with-node)
+
+When `--with-node` is passed, the script starts a Nitro fullnode via Docker with the sequencer disabled (`node.sequencer = false`, `execution.forwarding-target = "null"`). The fullnode reads from the parent chain and processes the force-included batch, allowing you to verify that the deposited ETH appears on the child chain.
+
+## Related tutorials
+
+- [Send a signed transaction from the parent chain](../delayedInbox-l2msg/) — demonstrates sending transactions via the delayed inbox with a running sequencer
+
+
+
+
diff --git a/packages/force-inclusion/package.json b/packages/force-inclusion/package.json
new file mode 100644
index 0000000..0225bba
--- /dev/null
+++ b/packages/force-inclusion/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "force-inclusion",
+ "version": "1.0.0",
+ "description": "End-to-end force inclusion test: deploy a rollup with a short delay, deposit ETH via delayed inbox, and force include — all without a sequencer.",
+ "scripts": {
+ "test": "node scripts/force-inclusion-test.js",
+ "test:withNode": "node scripts/force-inclusion-test.js --with-node"
+ },
+ "author": "Offchain Labs, Inc.",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@arbitrum/sdk": "^4.0.5",
+ "@arbitrum/chain-sdk": "^0.25.0",
+ "viem": "^1.20.0"
+ }
+}
diff --git a/packages/force-inclusion/scripts/force-inclusion-test.js b/packages/force-inclusion/scripts/force-inclusion-test.js
new file mode 100644
index 0000000..390d25c
--- /dev/null
+++ b/packages/force-inclusion/scripts/force-inclusion-test.js
@@ -0,0 +1,489 @@
+/**
+ * Force Inclusion End-to-End Test
+ *
+ * This script runs the full force inclusion cycle in one command:
+ * 1. Deploy a new Orbit rollup with a short force inclusion delay (90s)
+ * 2. Deposit ETH via the delayed inbox on the parent chain
+ * 3. Wait for the delay window, then force include the deposit
+ * 4. (Optional, --with-node) Start a fullnode to verify the L2 state
+ *
+ * Usage:
+ * node scripts/force-inclusion-test.js # Steps 1-3
+ * node scripts/force-inclusion-test.js --with-node # Steps 1-4 (requires docker)
+ *
+ * Required environment variables:
+ * DEPLOYER_PRIVATE_KEY - Private key of the deployer (must have ETH on parent chain)
+ * PARENT_CHAIN_RPC - RPC URL of the parent chain
+ *
+ * Optional:
+ * PARENT_CHAIN_ID - Parent chain ID (default: Arbitrum Sepolia)
+ */
+
+const { createPublicClient, http, defineChain } = require('viem');
+const { privateKeyToAccount, generatePrivateKey } = require('viem/accounts');
+const { arbitrumSepolia } = require('viem/chains');
+const {
+ createRollupPrepareDeploymentParamsConfig,
+ prepareChainConfig,
+ createRollupPrepareTransactionRequest,
+ createRollupPrepareTransactionReceipt,
+ prepareNodeConfig,
+} = require('@arbitrum/chain-sdk');
+const { generateChainId, sanitizePrivateKey } = require('@arbitrum/chain-sdk/utils');
+const {
+ SequencerInbox__factory,
+} = require('@arbitrum/sdk/dist/lib/abi/factories/SequencerInbox__factory');
+const { utils, providers, Wallet } = require('ethers');
+const { EthBridger, InboxTools, registerCustomArbitrumNetwork } = require('@arbitrum/sdk');
+const { execSync, execFileSync } = require('child_process');
+const fs = require('fs');
+const path = require('path');
+require('dotenv').config();
+
+// ============================================================
+// Config
+// ============================================================
+
+const WITH_NODE = process.argv.includes('--with-node');
+
+const FORCE_INCLUSION_DELAY_SECONDS = 72n;
+const FORCE_INCLUSION_DELAY_BLOCKS = 6n;
+const FUTURE_SECONDS = 3600n;
+const FUTURE_BLOCKS = 12n;
+
+const DEPOSIT_AMOUNT = utils.parseEther('0.01');
+const POLL_INTERVAL_SECONDS = 10;
+const FULLNODE_RPC = 'http://localhost:8449';
+const SYNC_TIMEOUT_MS = 180_000;
+const BALANCE_TIMEOUT_MS = 60_000;
+
+// ============================================================
+// Helpers
+// ============================================================
+
+function requireEnv(name) {
+ if (!process.env[name]) {
+ throw new Error(`Please provide the "${name}" environment variable`);
+ }
+ return process.env[name];
+}
+
+function getParentChain(parentChainRpc) {
+ if (process.env.PARENT_CHAIN_ID) {
+ const id = Number(process.env.PARENT_CHAIN_ID);
+ if (id === arbitrumSepolia.id) return { chain: arbitrumSepolia, isCustom: false };
+ return {
+ chain: defineChain({
+ id,
+ name: 'Custom Parent Chain',
+ nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
+ rpcUrls: { default: { http: [parentChainRpc] } },
+ }),
+ isCustom: true,
+ };
+ }
+ return { chain: arbitrumSepolia, isCustom: false };
+}
+
+// ============================================================
+// Step 1: Deploy Rollup
+// ============================================================
+
+async function deployRollup() {
+ console.log('\n========================================');
+ console.log(' Step 1: Deploy Orbit Rollup');
+ console.log('========================================\n');
+
+ const deployerPrivateKey = sanitizePrivateKey(requireEnv('DEPLOYER_PRIVATE_KEY'));
+ const deployer = privateKeyToAccount(deployerPrivateKey);
+ const parentChainRpc = requireEnv('PARENT_CHAIN_RPC');
+
+ console.log(`Deployer: ${deployer.address}`);
+
+ // Generate batch poster and validator keys (required for deployment but not used)
+ const batchPosterPrivateKey = process.env.BATCH_POSTER_PRIVATE_KEY
+ ? sanitizePrivateKey(process.env.BATCH_POSTER_PRIVATE_KEY)
+ : generatePrivateKey();
+ const batchPoster = privateKeyToAccount(batchPosterPrivateKey).address;
+
+ const validatorPrivateKey = process.env.VALIDATOR_PRIVATE_KEY
+ ? sanitizePrivateKey(process.env.VALIDATOR_PRIVATE_KEY)
+ : generatePrivateKey();
+ const validator = privateKeyToAccount(validatorPrivateKey).address;
+
+ const { chain: parentChain, isCustom: parentChainIsCustom } = getParentChain(parentChainRpc);
+ const parentChainPublicClient = createPublicClient({
+ chain: parentChain,
+ transport: http(parentChainRpc),
+ });
+
+ const chainId = generateChainId();
+ console.log(`New rollup chain ID: ${chainId}`);
+ console.log(
+ `Force inclusion delay: ${FORCE_INCLUSION_DELAY_SECONDS}s / ${FORCE_INCLUSION_DELAY_BLOCKS} blocks`,
+ );
+
+ const chainConfig = prepareChainConfig({
+ chainId,
+ arbitrum: {
+ InitialChainOwner: deployer.address,
+ DataAvailabilityCommittee: false,
+ },
+ });
+
+ const deploymentParamsConfig = {
+ chainId: BigInt(chainId),
+ owner: deployer.address,
+ chainConfig,
+ sequencerInboxMaxTimeVariation: {
+ delayBlocks: FORCE_INCLUSION_DELAY_BLOCKS,
+ futureBlocks: FUTURE_BLOCKS,
+ delaySeconds: FORCE_INCLUSION_DELAY_SECONDS,
+ futureSeconds: FUTURE_SECONDS,
+ },
+ };
+
+ if (parentChainIsCustom) {
+ deploymentParamsConfig.confirmPeriodBlocks = 150n;
+ }
+
+ const createRollupConfig = createRollupPrepareDeploymentParamsConfig(
+ parentChainPublicClient,
+ deploymentParamsConfig,
+ );
+
+ console.log('\nPreparing deployment transaction...');
+ const request = await createRollupPrepareTransactionRequest({
+ params: {
+ config: createRollupConfig,
+ batchPosters: [batchPoster],
+ validators: [validator],
+ },
+ account: deployer.address,
+ publicClient: parentChainPublicClient,
+ });
+
+ console.log('Sending deployment transaction...');
+ const txHash = await parentChainPublicClient.sendRawTransaction({
+ serializedTransaction: await deployer.signTransaction(request),
+ });
+ console.log(`Transaction hash: ${txHash}`);
+
+ console.log('Waiting for confirmation...');
+ const txReceipt = createRollupPrepareTransactionReceipt(
+ await parentChainPublicClient.waitForTransactionReceipt({ hash: txHash }),
+ );
+
+ const coreContracts = txReceipt.getCoreContracts();
+ console.log('\nRollup deployed!');
+ console.log(` Rollup: ${coreContracts.rollup}`);
+ console.log(` Inbox: ${coreContracts.inbox}`);
+ console.log(` SequencerInbox: ${coreContracts.sequencerInbox}`);
+ console.log(` Bridge: ${coreContracts.bridge}`);
+
+ // Generate fullnode config (for optional --with-node step)
+ const nodeConfig = prepareNodeConfig({
+ chainName: 'ForceInclusionTestChain',
+ chainConfig,
+ coreContracts,
+ batchPosterPrivateKey,
+ validatorPrivateKey,
+ stakeToken: '0x0000000000000000000000000000000000000000',
+ parentChainId: parentChain.id,
+ parentChainRpcUrl: parentChainRpc,
+ });
+ nodeConfig.node.sequencer = false;
+ nodeConfig.node['delayed-sequencer'] = { enable: false };
+ nodeConfig.node['batch-poster'] = { enable: false };
+ nodeConfig.node.staker = { enable: false };
+ nodeConfig.execution.sequencer = { enable: false };
+ nodeConfig.execution['forwarding-target'] = 'null';
+ nodeConfig['ensure-rollup-deployment'] = false;
+
+ const nodeConfigPath = path.join(__dirname, '..', 'fullnode-config.json');
+ fs.writeFileSync(nodeConfigPath, JSON.stringify(nodeConfig, null, 2));
+
+ return {
+ chainId,
+ parentChainId: parentChain.id,
+ coreContracts,
+ chainConfig,
+ nodeConfigPath,
+ };
+}
+
+// ============================================================
+// Step 2: Deposit ETH via Delayed Inbox
+// ============================================================
+
+async function depositEth(chainId, coreContracts, parentChainId) {
+ console.log('\n========================================');
+ console.log(' Step 2: Deposit ETH via Delayed Inbox');
+ console.log('========================================\n');
+
+ const parentChainProvider = new providers.JsonRpcProvider(requireEnv('PARENT_CHAIN_RPC'));
+ const parentChainWallet = new Wallet(requireEnv('DEPLOYER_PRIVATE_KEY'), parentChainProvider);
+
+ // Register the custom network with Arbitrum SDK (v4 API)
+ const childChainNetwork = registerCustomArbitrumNetwork({
+ chainId,
+ parentChainId,
+ confirmPeriodBlocks: 150,
+ ethBridge: {
+ bridge: coreContracts.bridge,
+ inbox: coreContracts.inbox,
+ outbox: coreContracts.outbox,
+ rollup: coreContracts.rollup,
+ sequencerInbox: coreContracts.sequencerInbox,
+ },
+ isCustom: true,
+ isTestnet: true,
+ name: 'ForceInclusionTestChain',
+ });
+ const ethBridger = new EthBridger(childChainNetwork);
+
+ console.log(`Depositing ${utils.formatEther(DEPOSIT_AMOUNT)} ETH to the delayed inbox...`);
+ console.log(`Depositor: ${parentChainWallet.address}`);
+
+ const depositTx = await ethBridger.deposit({
+ amount: DEPOSIT_AMOUNT,
+ parentSigner: parentChainWallet,
+ childProvider: parentChainProvider,
+ });
+
+ const depositReceipt = await depositTx.wait();
+ console.log(`\nDeposit confirmed! TX: ${depositReceipt.transactionHash}`);
+ console.log('The deposit is now in the delayed inbox. No sequencer will pick it up.');
+
+ return childChainNetwork;
+}
+
+// ============================================================
+// Step 3: Force Include
+// ============================================================
+
+async function forceInclude(childChainNetwork) {
+ console.log('\n========================================');
+ console.log(' Step 3: Force Include');
+ console.log('========================================\n');
+
+ const parentChainProvider = new providers.JsonRpcProvider(requireEnv('PARENT_CHAIN_RPC'));
+ const parentChainWallet = new Wallet(requireEnv('DEPLOYER_PRIVATE_KEY'), parentChainProvider);
+
+ const inboxTools = new InboxTools(parentChainWallet, childChainNetwork);
+
+ console.log(`Waiting for force inclusion delay (~${FORCE_INCLUSION_DELAY_SECONDS}s) to pass...`);
+ console.log('Polling for force-includable events...\n');
+
+ let forceIncludableEvent = null;
+ while (!forceIncludableEvent) {
+ try {
+ // eslint-disable-next-line no-await-in-loop
+ forceIncludableEvent = await inboxTools.getForceIncludableEvent();
+ } catch (e) {
+ console.log(
+ ` Query failed (likely L1 block not yet mapped). Retrying in ${POLL_INTERVAL_SECONDS}s...`,
+ );
+ }
+ if (!forceIncludableEvent) {
+ console.log(` No eligible messages yet. Retrying in ${POLL_INTERVAL_SECONDS}s...`);
+ // eslint-disable-next-line no-await-in-loop
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_SECONDS * 1000));
+ }
+ }
+
+ console.log('Found force-includable event!');
+ console.log(` Message index: ${forceIncludableEvent.event.messageIndex.toString()}`);
+
+ console.log('\nCalling forceInclude()...');
+ const tx = await inboxTools.forceInclude(forceIncludableEvent);
+ const receipt = await tx.wait();
+
+ console.log(`\nForce inclusion successful!`);
+ console.log(` TX: ${receipt.transactionHash}`);
+
+ // Verify totalDelayedMessagesRead
+
+ const sequencerInbox = SequencerInbox__factory.connect(
+ childChainNetwork.ethBridge.sequencerInbox,
+ parentChainProvider,
+ );
+ const totalRead = await sequencerInbox.totalDelayedMessagesRead();
+ console.log(` totalDelayedMessagesRead: ${totalRead.toString()}`);
+}
+
+// ============================================================
+// Step 4 (Optional): Verify on Fullnode
+// ============================================================
+
+async function verifyOnFullnode(nodeConfigPath) {
+ console.log('\n========================================');
+ console.log(' Step 4: Verify on Fullnode (--with-node)');
+ console.log('========================================\n');
+
+ if (!fs.existsSync(nodeConfigPath)) {
+ console.error('fullnode-config.json not found.');
+ return;
+ }
+
+ console.log('Starting fullnode via docker (sequencer disabled)...');
+ let dockerContainerId;
+ try {
+ dockerContainerId = execFileSync(
+ 'docker',
+ [
+ 'run',
+ '-d',
+ '-v',
+ `${nodeConfigPath}:/config/nodeConfig.json`,
+ '-p',
+ '8449:8449',
+ 'offchainlabs/nitro-node:v3.10.0-b1cf6db',
+ '--conf.file',
+ '/config/nodeConfig.json',
+ ],
+ { encoding: 'utf8' },
+ ).trim();
+ console.log(`Container started: ${dockerContainerId.substring(0, 12)}`);
+
+ // Wait briefly then verify the container is still running
+ await new Promise((r) => setTimeout(r, 3000));
+ const running = execFileSync('docker', ['ps', '-q', '--filter', `id=${dockerContainerId}`], {
+ encoding: 'utf8',
+ }).trim();
+ if (!running) {
+ console.error('Container exited immediately. Logs:');
+ try {
+ console.error(execFileSync('docker', ['logs', dockerContainerId], { encoding: 'utf8' }));
+ } catch (_) {
+ /* ignore */
+ }
+ try {
+ execFileSync('docker', ['rm', dockerContainerId], { encoding: 'utf8' });
+ } catch (_) {
+ /* ignore */
+ }
+ return;
+ }
+
+ console.log('Waiting for node to initialize...\n');
+ } catch (error) {
+ console.error('Failed to start docker container. Is docker running?');
+ console.error(error.message);
+ return;
+ }
+
+ try {
+ console.log(`Connecting to fullnode RPC: ${FULLNODE_RPC}`);
+ let childChainProvider;
+ let connected = false;
+ const connectStart = Date.now();
+ while (Date.now() - connectStart < SYNC_TIMEOUT_MS) {
+ try {
+ childChainProvider = new providers.JsonRpcProvider(FULLNODE_RPC);
+ // eslint-disable-next-line no-await-in-loop
+ const network = await childChainProvider.getNetwork();
+ console.log(`Connected! Chain ID: ${network.chainId}\n`);
+ connected = true;
+ break;
+ } catch (e) {
+ console.log(' Node not ready yet, retrying in 5s...');
+ // eslint-disable-next-line no-await-in-loop
+ await new Promise((r) => setTimeout(r, 5_000));
+ }
+ }
+ if (!connected) {
+ console.error('\nTimeout: could not connect to fullnode RPC.');
+ return;
+ }
+ const wallet = new Wallet(requireEnv('DEPLOYER_PRIVATE_KEY'), childChainProvider);
+
+ console.log('Waiting for fullnode to sync...');
+ const startTime = Date.now();
+ let latestBlock;
+ while (Date.now() - startTime < SYNC_TIMEOUT_MS) {
+ // eslint-disable-next-line no-await-in-loop
+ latestBlock = await childChainProvider.getBlock('latest');
+ if (latestBlock.number > 0) break;
+ console.log(` Block: ${latestBlock.number}, waiting...`);
+ // eslint-disable-next-line no-await-in-loop
+ await new Promise((r) => setTimeout(r, 5_000));
+ }
+
+ if (!latestBlock || latestBlock.number === 0) {
+ console.error('\nTimeout: fullnode did not produce blocks.');
+ return;
+ }
+
+ console.log(`Fullnode synced! Latest block: ${latestBlock.number}`);
+ console.log(`\nWallet: ${wallet.address}`);
+ console.log('Waiting for force-included deposit to settle in state...');
+
+ const balanceStartTime = Date.now();
+ let balance;
+ while (Date.now() - balanceStartTime < BALANCE_TIMEOUT_MS) {
+ // eslint-disable-next-line no-await-in-loop
+ balance = await wallet.getBalance();
+ if (balance.gt(0)) break;
+ console.log(' Balance still 0, retrying in 5s...');
+ // eslint-disable-next-line no-await-in-loop
+ await new Promise((r) => setTimeout(r, 5_000));
+ }
+
+ console.log(`Balance on child chain: ${utils.formatEther(balance)} ETH`);
+
+ if (balance.gt(0)) {
+ console.log('\nETH deposit verified on child chain! Force inclusion works end-to-end.');
+ } else {
+ console.log('\nBalance is still 0 after timeout. Fullnode may need more time to process.');
+ }
+ } finally {
+ console.log(`\nStopping container ${dockerContainerId.substring(0, 12)}...`);
+ try {
+ execSync(`docker stop ${dockerContainerId}`, { encoding: 'utf8' });
+ } catch (e) {
+ /* container may have already stopped */
+ }
+ try {
+ execSync(`docker rm ${dockerContainerId}`, { encoding: 'utf8' });
+ } catch (e) {
+ /* container may have already been removed */
+ }
+ }
+}
+
+// ============================================================
+// Main
+// ============================================================
+
+async function main() {
+ console.log('=== Force Inclusion End-to-End Test ===');
+ console.log(
+ `Mode: ${
+ WITH_NODE ? 'full (with fullnode verification)' : 'deploy + deposit + forceInclude'
+ }\n`,
+ );
+
+ // Step 1: Deploy
+ const { chainId, parentChainId, coreContracts, nodeConfigPath } = await deployRollup();
+
+ // Step 2: Deposit
+ const childChainNetwork = await depositEth(chainId, coreContracts, parentChainId);
+
+ // Step 3: Force Include
+ await forceInclude(childChainNetwork);
+
+ // Step 4: (Optional) Verify on fullnode
+ if (WITH_NODE) {
+ await verifyOnFullnode(nodeConfigPath);
+ }
+
+ console.log('\n=== Done ===');
+}
+
+main()
+ .then(() => process.exit(0))
+ .catch((error) => {
+ console.error(error);
+ process.exit(1);
+ });
diff --git a/yarn.lock b/yarn.lock
index 2039192..4e2b107 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,27 @@
# yarn lockfile v1
+"@adraffy/ens-normalize@1.10.0":
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7"
+ integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==
+
+"@adraffy/ens-normalize@1.10.1":
+ version "1.10.1"
+ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069"
+ integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==
+
+"@arbitrum/chain-sdk@^0.25.0":
+ version "0.25.3"
+ resolved "https://registry.yarnpkg.com/@arbitrum/chain-sdk/-/chain-sdk-0.25.3.tgz#73191c568f5252f4881fd16f4dac4b417a2a044b"
+ integrity sha512-K2xBtOlBS8mk47QozIq8cLAYmb40ONoUwrqDb8vSfF4pn+g5BNntx/my2MWi+YASbDG377w49J0iK44L7khljA==
+ dependencies:
+ "@arbitrum/sdk" "^4.0.4"
+ "@arbitrum/token-bridge-contracts" "^1.2.2"
+ "@offchainlabs/fund-distribution-contracts" "^1.0.1"
+ "@safe-global/protocol-kit" "^4.1.7"
+ ethers "^5.7.2"
+
"@arbitrum/nitro-contracts@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@arbitrum/nitro-contracts/-/nitro-contracts-1.1.1.tgz#2d8a2f9ab757bb7654562aebe435bff833c4b98d"
@@ -34,10 +55,10 @@
async-mutex "^0.4.0"
ethers "^5.1.0"
-"@arbitrum/sdk@^v4.0.4":
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/@arbitrum/sdk/-/sdk-4.0.4.tgz#32f3cfa75d2b3f9ab0be01eb807112e0001f428d"
- integrity sha512-GscwlkHYmPzRKs9huDHntbqx1xMRhTraTUvTC9exu+prjndKxHe9ZORuIcqmtEqwLwma/l8nqxI+k+pEEdIO6Q==
+"@arbitrum/sdk@^4.0.4", "@arbitrum/sdk@^4.0.5":
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/@arbitrum/sdk/-/sdk-4.0.5.tgz#c7abf6fcec72b36faee7af704245a7e14c49ad7f"
+ integrity sha512-bADi4kVzSBUAV+GkxuKMx7zrkCVahIE4+fkBi0Ee18EPqGt1Wiub+yQCGTh+llApn1RpRtwwtYeZXhz9XelqGQ==
dependencies:
"@ethersproject/address" "^5.0.8"
"@ethersproject/bignumber" "^5.1.1"
@@ -45,6 +66,19 @@
async-mutex "^0.4.0"
ethers "^5.1.0"
+"@arbitrum/token-bridge-contracts@^1.2.2":
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/@arbitrum/token-bridge-contracts/-/token-bridge-contracts-1.2.5.tgz#ca954e75383c8d4b1baacdc004043fc2dd5adce5"
+ integrity sha512-wIekHs2hNGt0uxlKN8NiEcAoiN1Y4rN9jhbx/BX8T6E1B6XsabrLNVRs0lbsn7uLhV5Z61OaRTy9HirGmTs5+A==
+ dependencies:
+ "@arbitrum/nitro-contracts" "1.1.1"
+ "@offchainlabs/stablecoin-evm" "1.0.0-orbit-alpha.2"
+ "@offchainlabs/upgrade-executor" "1.1.0-beta.0"
+ "@openzeppelin/contracts" "4.8.3"
+ "@openzeppelin/contracts-upgradeable" "4.8.3"
+ optionalDependencies:
+ "@openzeppelin/upgrades-core" "^1.24.1"
+
"@arbitrum/token-bridge-contracts@^1.2.3":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@arbitrum/token-bridge-contracts/-/token-bridge-contracts-1.2.3.tgz#b08b22b5dcac255149a10bd8b66b0b55be7f3329"
@@ -487,11 +521,33 @@
tweetnacl "^1.0.3"
tweetnacl-util "^0.15.1"
+"@noble/curves@1.2.0", "@noble/curves@~1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35"
+ integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==
+ dependencies:
+ "@noble/hashes" "1.3.2"
+
"@noble/hashes@1.2.0", "@noble/hashes@~1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12"
integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==
+"@noble/hashes@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39"
+ integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==
+
+"@noble/hashes@^1.3.3":
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a"
+ integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==
+
+"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.2":
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699"
+ integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==
+
"@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c"
@@ -672,6 +728,15 @@
resolved "https://registry.yarnpkg.com/@offchainlabs/eslint-config-typescript/-/eslint-config-typescript-0.2.2.tgz#0bb6f1dcde70bbf54683e243a4a7c4923a6a3c8e"
integrity sha512-kyDX+8dgHSWgWVe+K0BmeVRz8k52wjWLC2THM8a6zlnPJXXY0zcccciHc0kRFJZYmiFEiH13YGsFraaS9hJMfA==
+"@offchainlabs/fund-distribution-contracts@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@offchainlabs/fund-distribution-contracts/-/fund-distribution-contracts-1.0.1.tgz#3d7c05cb5ad0d5057e74286a8db8a72bf0571da6"
+ integrity sha512-ig1aAmfWPpq9474td6M/f/ltseipM2c5xs3nAsv9JX6YBhRF4OlNBczfdtjTgEh069rCnu4DcFSdoNzuaHDxBg==
+ dependencies:
+ "@types/yargs" "^17.0.32"
+ dotenv "^16.3.1"
+ yargs "^17.7.2"
+
"@offchainlabs/prettier-config@0.2.1":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@offchainlabs/prettier-config/-/prettier-config-0.2.1.tgz#e3b57e013935269d84bf6379cdc529b3bbca9ae5"
@@ -739,11 +804,49 @@
proper-lockfile "^4.1.1"
solidity-ast "^0.4.51"
+"@safe-global/protocol-kit@^4.1.7":
+ version "4.1.7"
+ resolved "https://registry.yarnpkg.com/@safe-global/protocol-kit/-/protocol-kit-4.1.7.tgz#b0b93c894a783aee2daaef71afd9cdbcc5321f7c"
+ integrity sha512-4VMqbezB91JasxhOB2HhRjsCeuxBMnPdUMXh5eKEs59xE86Ys2GhQ7+xk78qaB9SKUe74wKaQAeKE+hC7nHffA==
+ dependencies:
+ "@noble/hashes" "^1.3.3"
+ "@safe-global/safe-core-sdk-types" "^5.1.0"
+ "@safe-global/safe-deployments" "^1.37.31"
+ "@safe-global/safe-modules-deployments" "^2.2.1"
+ abitype "^1.0.2"
+ ethereumjs-util "^7.1.5"
+ ethers "^6.13.1"
+ semver "^7.6.2"
+
+"@safe-global/safe-core-sdk-types@^5.1.0":
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/@safe-global/safe-core-sdk-types/-/safe-core-sdk-types-5.1.0.tgz#af8d877b9af231242d023c7182f78ff4223bc3f4"
+ integrity sha512-UzXR4zWmVzux25FcIm4H049QhZZpVpIBL5HE+V0p5gHpArZROL+t24fZmsKUf403CtBxIJM5zZSVQL0nFJi+IQ==
+ dependencies:
+ abitype "^1.0.2"
+
+"@safe-global/safe-deployments@^1.37.31":
+ version "1.37.56"
+ resolved "https://registry.yarnpkg.com/@safe-global/safe-deployments/-/safe-deployments-1.37.56.tgz#8a13d2aed4d8bfb5ab8fcc105fec3025b45114e5"
+ integrity sha512-HF3ETre/KSP3nCOZ72XEbq5U56gOGgYLJ22LxOAnR8+YzMjzZ8cpnHpx5Z31Zt1xkUTGSCMi9XF950lJt6WbsQ==
+ dependencies:
+ semver "^7.6.2"
+
+"@safe-global/safe-modules-deployments@^2.2.1":
+ version "2.2.25"
+ resolved "https://registry.yarnpkg.com/@safe-global/safe-modules-deployments/-/safe-modules-deployments-2.2.25.tgz#d0942c5d4f854a7221bcbf82bc13e15269c6822a"
+ integrity sha512-KjgenKhBRyFHEfo8xlBgNzKAy25vrmGyCGZwTjIuA81yOSRJRe85GE5Yfg/FBKeeyHqR2dD1WPZr6c2Uqd6C/g==
+
"@scure/base@~1.1.0":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==
+"@scure/base@~1.1.2":
+ version "1.1.9"
+ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1"
+ integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==
+
"@scure/bip32@1.1.5":
version "1.1.5"
resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300"
@@ -753,6 +856,15 @@
"@noble/secp256k1" "~1.7.0"
"@scure/base" "~1.1.0"
+"@scure/bip32@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.2.tgz#90e78c027d5e30f0b22c1f8d50ff12f3fb7559f8"
+ integrity sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==
+ dependencies:
+ "@noble/curves" "~1.2.0"
+ "@noble/hashes" "~1.3.2"
+ "@scure/base" "~1.1.2"
+
"@scure/bip39@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5"
@@ -761,6 +873,14 @@
"@noble/hashes" "~1.2.0"
"@scure/base" "~1.1.0"
+"@scure/bip39@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.1.tgz#5cee8978656b272a917b7871c981e0541ad6ac2a"
+ integrity sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==
+ dependencies:
+ "@noble/hashes" "~1.3.0"
+ "@scure/base" "~1.1.0"
+
"@sentry/core@5.30.0":
version "5.30.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3"
@@ -883,6 +1003,13 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.1.tgz#e8a83f1aa8b649377bb1fb5d7bac5cb90e784dfe"
integrity sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==
+"@types/node@22.7.5":
+ version "22.7.5"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b"
+ integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==
+ dependencies:
+ undici-types "~6.19.2"
+
"@types/pbkdf2@^3.0.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1"
@@ -907,6 +1034,13 @@
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b"
integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==
+"@types/yargs@^17.0.32":
+ version "17.0.35"
+ resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.35.tgz#07013e46aa4d7d7d50a49e15604c1c5340d4eb24"
+ integrity sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==
+ dependencies:
+ "@types/yargs-parser" "*"
+
"@types/yargs@^17.0.33":
version "17.0.33"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d"
@@ -1008,6 +1142,16 @@
resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
+abitype@0.9.8:
+ version "0.9.8"
+ resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.8.tgz#1f120b6b717459deafd213dfbf3a3dd1bf10ae8c"
+ integrity sha512-puLifILdm+8sjyss4S+fsUN09obiT1g2YW6CtcQF+QDzxR0euzgEB29MZujC6zMk2a6SVmtttq1fc6+YFA7WYQ==
+
+abitype@^1.0.2:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.2.4.tgz#8aab72949bcad4107031862ae998e5bd20eec76e"
+ integrity sha512-dpKH+N27vRjarMVTFFkeY445VTKftzGWpL0FiT7xmVmzQRKazZexzC5uHG0f6XKsVLAuUlndnbGau6lRejClxg==
+
acorn-jsx@^5.3.2:
version "5.3.2"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
@@ -1038,6 +1182,11 @@ aes-js@3.0.0:
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d"
integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==
+aes-js@4.0.0-beta.5:
+ version "4.0.0-beta.5"
+ resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873"
+ integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==
+
agent-base@6:
version "6.0.2"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
@@ -1645,6 +1794,11 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
+dotenv@^16.3.1:
+ version "16.6.1"
+ resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020"
+ integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==
+
dotenv@^16.4.5:
version "16.4.5"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
@@ -1985,7 +2139,7 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1:
ethjs-util "0.1.6"
rlp "^2.2.3"
-ethereumjs-util@^7.0.3:
+ethereumjs-util@^7.0.3, ethereumjs-util@^7.1.5:
version "7.1.5"
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181"
integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==
@@ -2032,6 +2186,19 @@ ethers@^5.1.0, ethers@^5.7.2:
"@ethersproject/web" "5.7.1"
"@ethersproject/wordlists" "5.7.0"
+ethers@^6.13.1:
+ version "6.16.0"
+ resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.16.0.tgz#fff9b4f05d7a359c774ad6e91085a800f7fccf65"
+ integrity sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==
+ dependencies:
+ "@adraffy/ens-normalize" "1.10.1"
+ "@noble/curves" "1.2.0"
+ "@noble/hashes" "1.3.2"
+ "@types/node" "22.7.5"
+ aes-js "4.0.0-beta.5"
+ tslib "2.7.0"
+ ws "8.17.1"
+
ethjs-util@0.1.6, ethjs-util@^0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536"
@@ -2755,6 +2922,11 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+isows@1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.3.tgz#93c1cf0575daf56e7120bab5c8c448b0809d0d74"
+ integrity sha512-2cKei4vlmg2cxEjm3wVSqn8pcoRF/LX/wpifuuNquFO4SQmPwarClT+SUCA2lt+l581tTeZIPIZuIDo2jWN1fg==
+
js-sha3@0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
@@ -3406,6 +3578,11 @@ semver@^7.3.7, semver@^7.6.3:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
+semver@^7.6.2:
+ version "7.8.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.0.tgz#ed0661039fcbcda2ce71f01fa6adbefaa77040df"
+ integrity sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==
+
serialize-javascript@6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
@@ -3684,6 +3861,11 @@ ts-node@^10.9.2:
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"
+tslib@2.7.0:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01"
+ integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==
+
tslib@^1.8.1, tslib@^1.9.3:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
@@ -3802,6 +3984,11 @@ unbox-primitive@^1.0.2:
has-symbols "^1.0.3"
which-boxed-primitive "^1.0.2"
+undici-types@~6.19.2:
+ version "6.19.8"
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02"
+ integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==
+
undici@^5.14.0:
version "5.22.1"
resolved "https://registry.yarnpkg.com/undici/-/undici-5.22.1.tgz#877d512effef2ac8be65e695f3586922e1a57d7b"
@@ -3846,6 +4033,20 @@ v8-compile-cache-lib@^3.0.1:
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
+viem@^1.20.0:
+ version "1.21.4"
+ resolved "https://registry.yarnpkg.com/viem/-/viem-1.21.4.tgz#883760e9222540a5a7e0339809202b45fe6a842d"
+ integrity sha512-BNVYdSaUjeS2zKQgPs+49e5JKocfo60Ib2yiXOWBT6LuVxY1I/6fFX3waEtpXvL1Xn4qu+BVitVtMh9lyThyhQ==
+ dependencies:
+ "@adraffy/ens-normalize" "1.10.0"
+ "@noble/curves" "1.2.0"
+ "@noble/hashes" "1.3.2"
+ "@scure/bip32" "1.3.2"
+ "@scure/bip39" "1.2.1"
+ abitype "0.9.8"
+ isows "1.0.3"
+ ws "8.13.0"
+
which-boxed-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
@@ -3918,6 +4119,16 @@ ws@7.4.6:
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
+ws@8.13.0:
+ version "8.13.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0"
+ integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==
+
+ws@8.17.1:
+ version "8.17.1"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b"
+ integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==
+
ws@^7.4.6:
version "7.5.9"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"