Compare commits

..

13 Commits

Author SHA1 Message Date
f4dec3520f Add op-node --log.level 2024-09-06 20:01:17 +08:00
96d05aee9c Enable granite 2024-09-06 20:01:17 +08:00
c91620421d Configure rpc kind from env 2024-09-06 20:01:15 +08:00
defe41869f Update readme 2024-09-06 20:00:14 +08:00
14642b1174 Config L1, L2 block time, set poll intervals 2024-09-06 20:00:12 +08:00
e9131dc98f Fix docs 2024-09-06 19:59:14 +08:00
114963d57c Script clean up 2024-09-06 19:59:12 +08:00
189ae577c4 Exec services in containers
allows forwarding of signals
2024-09-06 19:58:08 +08:00
846655837f op-geth needs state.scheme=hash for archive 2024-09-06 19:58:08 +08:00
5ac0518c27 Fix L2 alloc state dump
runWithStateDump instead of runWithAllUpgrades
2024-09-06 19:58:08 +08:00
2939d549cd Use optimism contracts image 2024-09-06 19:58:08 +08:00
44ed6708d0 Optimism script update 2024-09-06 19:58:08 +08:00
2ba7045792 Add missing packages to images
op-plasma => op-alt-da
2024-09-06 19:58:08 +08:00
14 changed files with 124 additions and 136 deletions

View File

@ -1,5 +1,3 @@
version: '3.7'
services:
# Generates and funds the accounts required when setting up the L2 chain (outputs to volume l2_accounts)
# Creates / updates the configuration for L1 contracts deployment
@ -10,6 +8,7 @@ services:
hostname: fixturenet-optimism-contracts
env_file:
- ../config/fixturenet-optimism/l1-params.env
- ../config/fixturenet-optimism/l2-params.env
environment:
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
CERC_L1_CHAIN_ID: ${CERC_L1_CHAIN_ID}
@ -17,17 +16,20 @@ services:
CERC_L1_ACCOUNTS_CSV_URL: ${CERC_L1_ACCOUNTS_CSV_URL}
CERC_L1_ADDRESS: ${CERC_L1_ADDRESS}
CERC_L1_PRIV_KEY: ${CERC_L1_PRIV_KEY}
CERC_L1_BLOCK_TIME: ${CERC_L1_BLOCK_TIME}
CERC_L2_BLOCK_TIME: ${CERC_L2_BLOCK_TIME}
CERC_PROPOSER_AMOUNT: ${CERC_PROPOSER_AMOUNT}
CERC_BATCHER_AMOUNT: ${CERC_BATCHER_AMOUNT}
volumes:
- ../config/network/wait-for-it.sh:/app/packages/contracts-bedrock/wait-for-it.sh
- ../config/fixturenet-optimism/optimism-contracts/deploy-contracts.sh:/app/packages/contracts-bedrock/deploy-contracts.sh
- ../config/network/wait-for-it.sh:/wait-for-it.sh
- ../config/fixturenet-optimism/optimism-contracts/deploy-contracts.sh:/deploy-contracts.sh
- l2_accounts:/l2-accounts
- l1_deployment:/l1-deployment
- l2_config:/l2-config
entrypoint: ["sh", "-c"]
# Waits for L1 endpoint to be up before running the contract deploy script
command: |
"./wait-for-it.sh -h ${CERC_L1_HOST:-$${DEFAULT_CERC_L1_HOST}} -p ${CERC_L1_PORT:-$${DEFAULT_CERC_L1_PORT}} -s -t 60 -- ./deploy-contracts.sh"
"/wait-for-it.sh -h ${CERC_L1_HOST:-$${DEFAULT_CERC_L1_HOST}} -p ${CERC_L1_PORT:-$${DEFAULT_CERC_L1_PORT}} -s -t 60 -- /deploy-contracts.sh"
extra_hosts:
- "host.docker.internal:host-gateway"
@ -93,6 +95,8 @@ services:
environment:
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
CERC_L1_RPC: ${CERC_L1_RPC}
CERC_L1_RPC_KIND: ${CERC_L1_RPC_KIND}
CERC_L1_BLOCK_TIME: ${CERC_L1_BLOCK_TIME}
CERC_L1_BEACON: ${CERC_L1_BEACON}
volumes:
- ../config/fixturenet-optimism/run-op-node.sh:/run-op-node.sh
@ -156,6 +160,7 @@ services:
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
CERC_L1_RPC: ${CERC_L1_RPC}
CERC_L1_CHAIN_ID: ${CERC_L1_CHAIN_ID}
CERC_L1_BLOCK_TIME: ${CERC_L1_BLOCK_TIME}
volumes:
- ../config/network/wait-for-it.sh:/wait-for-it.sh
- ../config/fixturenet-optimism/run-op-proposer.sh:/run-op-proposer.sh

View File

@ -6,6 +6,12 @@ DEFAULT_CERC_L1_RPC="http://fixturenet-eth-geth-1:8545"
DEFAULT_CERC_L1_HOST="fixturenet-eth-geth-1"
DEFAULT_CERC_L1_PORT=8545
# Default block time matches L1 fixturenet config.
DEFAULT_CERC_L1_BLOCK_TIME=3
# This can optionally be set to a preset for common node providers like Infura, Alchemy, etc.
# Or, set to "any" to try all available methods.
DEFAULT_CERC_L1_RPC_KIND=standard
# URL to get CSV with credentials for accounts on L1
# that are used to send balance to Optimism Proxy contract
# (enables them to do transactions on L2)

View File

@ -0,0 +1,2 @@
# Default L2 block time. Must be <= L1 block time.
DEFAULT_CERC_L2_BLOCK_TIME=1

View File

@ -50,28 +50,9 @@ wait_for_block() {
}
# We need four accounts and their private keys for the deployment: Admin, Proposer, Batcher, and Sequencer
# Check if accounts file already exists
l2_accounts_file="/l2-accounts/accounts.json"
if [ -f $l2_accounts_file ]; then
echo "Using existing accounts from $l2_accounts_file."
ADMIN=$(jq -r .Admin $l2_accounts_file)
ADMIN_KEY=$(jq -r .AdminKey $l2_accounts_file)
# Proposer
PROPOSER=$(jq -r .Proposer $l2_accounts_file)
PROPOSER_KEY=$(jq -r .ProposerKey $l2_accounts_file)
# Batcher
BATCHER=$(jq -r .Batcher $l2_accounts_file)
BATCHER_KEY=$(jq -r .BatcherKey $l2_accounts_file)
# Sequencer
SEQ=$(jq -r .Seq $l2_accounts_file)
SEQ_KEY=$(jq -r .SeqKey $l2_accounts_file)
else
# If $CERC_L1_ADDRESS and $CERC_L1_PRIV_KEY have been set, we'll assign it to Admin and generate/fund the remaining three accounts from it
# If not, we'll assume the L1 is the stack's own fixturenet-eth and use the pre-funded accounts/keys from $CERC_L1_ACCOUNTS_CSV_URL
if [ -n "$CERC_L1_ADDRESS" ] && [ -n "$CERC_L1_PRIV_KEY" ]; then
echo "Creating new accounts for Optimism deployment."
wallet1=$(cast wallet new)
wallet2=$(cast wallet new)
wallet3=$(cast wallet new)
@ -88,7 +69,7 @@ else
SEQ=$(echo "$wallet3" | awk '/Address:/{print $2}')
SEQ_KEY=$(echo "$wallet3" | awk '/Private key:/{print $3}')
echo "Funding accounts..."
echo "Funding accounts."
wait_for_block 1 300
cast send --from $ADMIN --rpc-url $CERC_L1_RPC --value $CERC_PROPOSER_AMOUNT $PROPOSER --private-key $ADMIN_KEY
cast send --from $ADMIN --rpc-url $CERC_L1_RPC --value $CERC_BATCHER_AMOUNT $BATCHER --private-key $ADMIN_KEY
@ -108,6 +89,9 @@ else
SEQ_KEY=$(awk -F ',' 'NR == 4 {print $3}' accounts.csv)
fi
echo "Using accounts:"
echo -e "Admin: $ADMIN\nProposer: $PROPOSER\nBatcher: $BATCHER\nSequencer: $SEQ"
# These accounts will be needed by other containers, so write them to a shared volume
echo "Writing accounts/private keys to volume l2_accounts."
accounts_json=$(jq -n \
@ -116,11 +100,7 @@ else
--arg Batcher "$BATCHER" --arg BatcherKey "$BATCHER_KEY" \
--arg Seq "$SEQ" --arg SeqKey "$SEQ_KEY" \
'{Admin: $Admin, AdminKey: $AdminKey, Proposer: $Proposer, ProposerKey: $ProposerKey, Batcher: $Batcher, BatcherKey: $BatcherKey, Seq: $Seq, SeqKey: $SeqKey}')
echo "$accounts_json" > $l2_accounts_file
fi
echo "Using accounts:"
echo -e "Admin: $ADMIN\nProposer: $PROPOSER\nBatcher: $BATCHER\nSequencer: $SEQ"
echo "$accounts_json" > "/l2-accounts/accounts.json"
# Get a finalized L1 block to set as the starting point for the L2 deployment
# If the chain is a freshly created fixturenet-eth, a finalized block won't be available for many minutes; rather than wait, we can use block 1
@ -146,8 +126,9 @@ GS_SEQUENCER_ADDRESS=$SEQ \
L1_RPC_URL=$CERC_L1_RPC \
L1_CHAIN_ID=$CERC_L1_CHAIN_ID \
L2_CHAIN_ID=42069 \
L1_BLOCK_TIME=12 \
L2_BLOCK_TIME=2 \
L1_BLOCK_TIME=${CERC_L1_BLOCK_TIME:-$DEFAULT_CERC_L1_BLOCK_TIME} \
L2_BLOCK_TIME=${CERC_L2_BLOCK_TIME:-$DEFAULT_CERC_L2_BLOCK_TIME} \
GRANITE_TIME_OFFSET=None \
$config_build_script
echo "Writing deployment config."
@ -177,25 +158,25 @@ if [ "$create2CodeSize" -eq 0 ]; then
fi
# Create the L2 deployment
# Writes out artifact to /app/packages/contracts-bedrock/deployments/$DEPLOYMENT_CONTEXT-deploy.json
# Writes out artifact to $OPTIMISM_ROOT/packages/contracts-bedrock/deployments/$DEPLOYMENT_CONTEXT-deploy.json
echo "Deploying L1 Optimism contracts..."
DEPLOY_CONFIG_PATH=$deploy_config_file forge script scripts/Deploy.s.sol:Deploy --private-key $ADMIN_KEY --broadcast --rpc-url $CERC_L1_RPC
DEPLOY_CONFIG_PATH=$deploy_config_file forge script scripts/deploy/Deploy.s.sol:Deploy --private-key $ADMIN_KEY --broadcast --rpc-url $CERC_L1_RPC
echo "Done deploying contracts."
echo "Generating L2 genesis allocs..."
L2_CHAIN_ID=$(jq ".l2ChainID" $deploy_config_file)
DEPLOY_CONFIG_PATH=$deploy_config_file \
CONTRACT_ADDRESSES_PATH="deployments/$DEPLOYMENT_CONTEXT-deploy.json" \
forge script --chain-id $L2_CHAIN_ID scripts/L2Genesis.s.sol:L2Genesis --sig 'runWithAllUpgrades()' --private-key $ADMIN_KEY
CONTRACT_ADDRESSES_PATH=deployments/$DEPLOYMENT_CONTEXT-deploy.json \
STATE_DUMP_PATH=allocs-l2.json \
forge script --chain-id $L2_CHAIN_ID scripts/L2Genesis.s.sol:L2Genesis --sig 'runWithStateDump()' --private-key $ADMIN_KEY
cp /app/packages/contracts-bedrock/state-dump-$L2_CHAIN_ID.json allocs-l2.json
echo "Done."
echo "*************************************"
# Copy files needed by other containers to the appropriate shared volumes
echo "Copying deployment artifacts to volume l1_deployment and deploy-config to volume l2_config"
cp /app/packages/contracts-bedrock/deployments/$DEPLOYMENT_CONTEXT-deploy.json /l1-deployment
cp /app/packages/contracts-bedrock/deploy-config/$DEPLOYMENT_CONTEXT.json /l2-config
echo "Copying deployment artifacts volume l1_deployment and deploy-config to volume l2_config"
cp /opt/optimism/packages/contracts-bedrock/deployments/$DEPLOYMENT_CONTEXT-deploy.json /l1-deployment
cp /opt/optimism/packages/contracts-bedrock/deploy-config/$DEPLOYMENT_CONTEXT.json /l2-config
cp allocs-l2.json /l2-config
echo "Deployment successful. Exiting"
echo "Deployment successful, exiting."

View File

@ -11,7 +11,7 @@ L2_RPC="http://op-geth:8545"
ROLLUP_RPC="http://op-node:8547"
BATCHER_KEY=$(cat /l2-accounts/accounts.json | jq -r .BatcherKey)
op-batcher \
exec op-batcher \
--l2-eth-rpc=$L2_RPC \
--rollup-rpc=$ROLLUP_RPC \
--poll-interval=1s \

View File

@ -26,13 +26,13 @@ fi
# Initialize geth from our generated L2 genesis file (if not already initialized)
data_dir="/datadir"
if [ ! -d "$datadir/geth" ]; then
geth init --datadir=$data_dir $l2_genesis_file
geth init --datadir=$data_dir --state.scheme=hash $l2_genesis_file
fi
# Start op-geth
jwt_file="/l2-config/l2-jwt.txt"
geth \
exec geth \
--datadir=$data_dir \
--http \
--http.corsdomain="*" \
@ -45,6 +45,7 @@ geth \
--ws.origins="*" \
--ws.api=debug,eth,txpool,net,engine \
--syncmode=full \
--state.scheme=hash \
--gcmode=archive \
--nodiscover \
--maxpeers=0 \

View File

@ -4,35 +4,37 @@ if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
CERC_L1_CHAIN_ID="${CERC_L1_CHAIN_ID:-${DEFAULT_CERC_L1_CHAIN_ID}}"
CERC_L1_RPC="${CERC_L1_RPC:-${DEFAULT_CERC_L1_RPC}}"
DEPLOYMENT_CONTEXT="$CERC_L1_CHAIN_ID"
CERC_L1_RPC_KIND="${CERC_L1_RPC_KIND:-${DEFAULT_CERC_L1_RPC_KIND}}"
CERC_L1_BLOCK_TIME="${CERC_L1_BLOCK_TIME:-$DEFAULT_CERC_L1_BLOCK_TIME}"
CERC_L1_BEACON="${CERC_L1_BEACON:-${DEFAULT_CERC_L1_BEACON}}"
deploy_config_file="/l2-config/$DEPLOYMENT_CONTEXT.json"
l1_deployment_file="/l1-deployment/$DEPLOYMENT_CONTEXT-deploy.json"
l2_allocs_file="/l2-config/allocs-l2.json"
genesis_outfile="/l2-config/genesis.json"
rollup_outfile="/l2-config/rollup.json"
log_level=INFO
if [ -n "$CERC_LOG_LEVEL" ]; then
log_level="$CERC_LOG_LEVEL"
fi
# Start op-node
SEQ_KEY=$(cat /l2-accounts/accounts.json | jq -r .SeqKey)
rollup_config=/l2-config/rollup.json
seq_key=$(cat /l2-accounts/accounts.json | jq -r .SeqKey)
jwt_file=/l2-config/l2-jwt.txt
L2_AUTH="http://op-geth:8551"
RPC_KIND=any # this can optionally be set to a preset for common node providers like Infura, Alchemy, etc.
l2_auth="http://op-geth:8551"
op-node \
--l2=$L2_AUTH \
exec op-node \
--l2=$l2_auth \
--l2.jwt-secret=$jwt_file \
--sequencer.enabled \
--sequencer.l1-confs=5 \
--verifier.l1-confs=4 \
--rollup.config=$rollup_outfile \
--rollup.config=$rollup_config \
--rpc.addr=0.0.0.0 \
--rpc.port=8547 \
--p2p.disable \
--rpc.enable-admin \
--p2p.sequencer.key="${SEQ_KEY#0x}" \
--l1=$CERC_L1_RPC \
--l1.rpckind=$RPC_KIND \
--l1.beacon=$CERC_L1_BEACON
--l1.rpckind=$CERC_L1_RPC_KIND \
--l1.beacon=$CERC_L1_BEACON \
--l1.http-poll-interval="${CERC_L1_BLOCK_TIME}s" \
--l1.epoch-poll-interval="$((CERC_L1_BLOCK_TIME * 32))s" \
--log.level="$log_level"

View File

@ -6,6 +6,7 @@ fi
CERC_L1_RPC="${CERC_L1_RPC:-${DEFAULT_CERC_L1_RPC}}"
CERC_L1_CHAIN_ID="${CERC_L1_CHAIN_ID:-${DEFAULT_CERC_L1_CHAIN_ID}}"
CERC_L1_BLOCK_TIME="${CERC_L1_BLOCK_TIME:-${DEFAULT_CERC_L1_BLOCK_TIME}}"
DEPLOYMENT_CONTEXT="$CERC_L1_CHAIN_ID"
# Start op-proposer
@ -13,8 +14,8 @@ ROLLUP_RPC="http://op-node:8547"
PROPOSER_KEY=$(cat /l2-accounts/accounts.json | jq -r .ProposerKey)
L2OO_ADDR=$(cat /l1-deployment/$DEPLOYMENT_CONTEXT-deploy.json | jq -r .L2OutputOracleProxy)
op-proposer \
--poll-interval=12s \
exec op-proposer \
--poll-interval="${CERC_L1_BLOCK_TIME}s" \
--rpc.port=8560 \
--rollup-rpc=$ROLLUP_RPC \
--l2oo-address="${L2OO_ADDR#0x}" \

View File

@ -1,24 +0,0 @@
# TODO: Make work for arm64/Apple Silicon
FROM ghcr.io/foundry-rs/foundry:nightly-c4a984fbf2c48b793c8cd53af84f56009dd1070c
RUN apk update
# Install node (use edge repo to get latest version)
RUN apk add --update --no-cache curl wget bash git busybox jq openssl \
&& apk add nodejs --update-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/main --allow-untrusted \
&& apk add npm \
&& node -v
# Add corepack for yarn and pnpm
RUN npm install -g corepack && corepack enable \
&& yarn --version
WORKDIR /app
# Copy optimism repo contents
COPY . .
RUN echo "Building optimism" && \
pnpm install && pnpm build
WORKDIR /app/packages/contracts-bedrock

View File

@ -6,4 +6,10 @@ source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
# See: https://stackoverflow.com/a/246128/1701505
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
docker build -t cerc/optimism-contracts:local -f ${SCRIPT_DIR}/Dockerfile ${build_command_args} ${CERC_REPO_BASE_DIR}/optimism
# The optimism contracts image has dependencies with no aarch64 support, so on aarch64 use an
# emulated amd64 image
if [[ $(docker info --format='{{ .Architecture }}') == "aarch64" ]]; then
PLATFORM_ARG="--platform linux/amd64"
fi
docker build -t cerc/optimism-contracts:local -f ${CERC_REPO_BASE_DIR}/optimism/ops/docker/Dockerfile.packages ${build_command_args} ${CERC_REPO_BASE_DIR}/optimism $PLATFORM_ARG

View File

@ -8,7 +8,7 @@ RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash
COPY ./op-batcher /app/op-batcher
COPY ./op-node /app/op-node
COPY ./op-service /app/op-service
COPY ./op-plasma /app/op-plasma
COPY ./op-alt-da /app/op-alt-da
COPY ./go.mod /app/go.mod
COPY ./go.sum /app/go.sum

View File

@ -8,8 +8,9 @@ RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash
COPY ./op-node /app/op-node
COPY ./op-chain-ops /app/op-chain-ops
COPY ./op-service /app/op-service
COPY ./op-plasma /app/op-plasma
COPY ./op-alt-da /app/op-alt-da
COPY ./op-conductor /app/op-conductor
COPY ./packages /app/packages
COPY ./go.mod /app/go.mod
COPY ./go.sum /app/go.sum
COPY ./.git /app/.git

View File

@ -8,7 +8,8 @@ RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash
COPY ./op-proposer /app/op-proposer
COPY ./op-node /app/op-node
COPY ./op-service /app/op-service
COPY ./op-plasma /app/op-plasma
COPY ./op-alt-da /app/op-alt-da
COPY ./packages /app/packages
COPY ./go.mod /app/go.mod
COPY ./go.sum /app/go.sum
COPY ./.git /app/.git

View File

@ -68,7 +68,7 @@ laconic-so --stack ~/cerc/fixturenet-optimism-stack/stack/fixturenet-optimism de
### Ports
It is usually necessary to expose certain container ports on one or more the host's addresses to allow incoming connections.
It is usually necessary to expose certain container ports on one or more of the host's addresses to allow incoming connections.
Any ports defined in the Docker compose file are exposed by default with random port assignments, bound to "any" interface (IP address 0.0.0.0), but the port mappings can be customized by editing the "spec" file generated by `laconic-so deploy init`.
In addition, a stack-wide port mapping "recipe" can be applied at the time the
@ -154,7 +154,7 @@ docker logs -f <CONTAINER_ID>
Send some ETH from the desired account to the `L1StandardBridgeProxy` contract on L1 to test bridging to L2.
We can use the testing account `0xe6CE22afe802CAf5fF7d3845cec8c736ecc8d61F` which is pre-funded and unlocked, and the `cerc/foundry:local` container to make use of the `cast` cli.
We can use the testing account `0xe6CE22afe802CAf5fF7d3845cec8c736ecc8d61F` which is pre-funded and unlocked, and the `cerc/optimism-contracts:local` container to make use of the `cast` cli.
1. Note the docker network the stack is running on:
@ -173,16 +173,22 @@ We can use the testing account `0xe6CE22afe802CAf5fF7d3845cec8c736ecc8d61F` whic
ACCOUNT=0xe6CE22afe802CAf5fF7d3845cec8c736ecc8d61F
```
You can create an alias for running `cast` on the network:
```bash
alias op-cast="docker run --rm --network $NETWORK --entrypoint cast cerc/optimism-contracts:local"
```
If you need to check the L1 chain-id, you can use:
```bash
docker run --rm --network $NETWORK cerc/optimism-contracts:local "cast chain-id --rpc-url $L1_RPC"
op-cast chain-id --rpc-url $L1_RPC
```
3. Check the account starting balance on L2 (it should be 0):
```bash
docker run --rm --network $NETWORK cerc/optimism-contracts:local "cast balance $ACCOUNT --rpc-url $L2_RPC"
op-cast balance $ACCOUNT --rpc-url $L2_RPC
# 0
```
@ -191,8 +197,8 @@ We can use the testing account `0xe6CE22afe802CAf5fF7d3845cec8c736ecc8d61F` whic
```bash
# get the container id for op-node
NODE_CONTAINER=$(docker ps --filter "name=op-node" -q)
BRIDGE=$(docker exec $NODE_CONTAINER cat /l1-deployment/$DEPLOYMENT_CONTEXT/.deploy | jq -r .L1StandardBridgeProxy)
# get the bridge contract address
BRIDGE=$(docker exec $NODE_CONTAINER cat /l1-deployment/$DEPLOYMENT_CONTEXT-deploy.json | jq -r .L1StandardBridgeProxy)
# get the funded account's pk
ACCOUNT_PK=$(docker exec $NODE_CONTAINER jq -r '.AdminKey' /l2-accounts/accounts.json)
```
@ -200,15 +206,15 @@ We can use the testing account `0xe6CE22afe802CAf5fF7d3845cec8c736ecc8d61F` whic
5. Use cast to send some ETH to the bridge contract:
```bash
docker run --rm --network $NETWORK cerc/optimism-contracts:local "cast send --from $ACCOUNT --value 1ether $BRIDGE --rpc-url $L1_RPC --private-key $ACCOUNT_PK"
op-cast send --from $ACCOUNT --value 1ether $BRIDGE --rpc-url $L1_RPC --private-key $ACCOUNT_PK
```
6. Allow a couple minutes for the bridge to complete
6. Allow a couple minutes for the bridge to complete.
7. Check the L2 balance again (it should show the bridged funds):
```bash
docker run --rm --network $NETWORK cerc/optimism-contracts:local "cast balance $ACCOUNT --rpc-url $L2_RPC"
op-cast balance $ACCOUNT --rpc-url $L2_RPC
# 1000000000000000000
```