Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: bold upgrader #98

Merged
merged 16 commits into from
Dec 6, 2024
Merged
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,20 @@ jobs:

- name: Startup Nitro testnode
run: ${{ github.workspace }}/.github/workflows/testnode.bash --init-force ${{ (matrix.l3node == 'l3node' && '--l3node') || (matrix.l3node == 'l3node-token-6' && '--l3node --l3-fee-token --l3-token-bridge --l3-fee-token-decimals 6') || '' }} ${{ matrix.tokenbridge == 'tokenbridge' && '--tokenbridge' || '--no-tokenbridge' }} --detach ${{ matrix.pos == 'pos' && '--pos' || '' }} --simple ${{ (matrix.simple == 'simple' && '--simple') || (matrix.simple == 'no-simple' && '--no-simple') || '' }}

bold_upgrade:
runs-on: ubuntu-8

steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: network=host

- name: Startup Nitro testnode
run: ${{ github.workspace }}/.github/workflows/testnode.bash --init-force --bold-upgrade --simple --detach
14 changes: 14 additions & 0 deletions boldupgrader/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM node:18-bullseye-slim
RUN apt-get update && \
apt-get install -y git docker.io python3 make gcc g++ curl jq
ARG BOLD_CONTRACTS_BRANCH=bold-merge-script
WORKDIR /workspace
RUN git clone --no-checkout https://github.com/OffchainLabs/nitro-contracts.git ./
RUN git checkout ${BOLD_CONTRACTS_BRANCH}
RUN yarn install && yarn cache clean
RUN curl -L https://foundry.paradigm.xyz | bash
ENV PATH="${PATH}:/root/.foundry/bin"
RUN foundryup
RUN touch scripts/config.ts
RUN yarn build:all
ENTRYPOINT ["yarn"]
11 changes: 11 additions & 0 deletions docker-compose-ci-cache.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@
"type=docker"
]
},
"boldupgrader": {
"cache-from": [
"type=local,src=/tmp/.buildx-cache"
],
"cache-to": [
"type=local,dest=/tmp/.buildx-cache,mode=max"
],
"output": [
"type=docker"
]
},
"tokenbridge": {
"cache-from": [
"type=local,src=/tmp/.buildx-cache"
Expand Down
21 changes: 21 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,26 @@ services:
- "tokenbridge-data:/workspace"
- /var/run/docker.sock:/var/run/docker.sock

boldupgrader:
depends_on:
- geth
- sequencer
pid: host
build:
context: boldupgrader/
args:
BOLD_CONTRACTS_BRANCH: ${BOLD_CONTRACTS_BRANCH:-}
environment:
- L1_RPC_URL=http://geth:8545
- L1_PRIV_KEY=0xdc04c5399f82306ec4b4d654a342f40e2e0620fe39950d967e1e574b32d4dd36
- CONFIG_NETWORK_NAME=local
- DEPLOYED_CONTRACTS_DIR=./scripts/files/
- DISABLE_VERIFICATION=true
volumes:
- "config:/config"
- "boldupgrader-data:/workspace"
- /var/run/docker.sock:/var/run/docker.sock

rollupcreator:
depends_on:
- geth
Expand Down Expand Up @@ -383,3 +403,4 @@ volumes:
config:
postgres-data:
tokenbridge-data:
boldupgrader-data:
86 changes: 68 additions & 18 deletions scripts/ethcommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { namedAccount, namedAddress } from "./accounts";
import * as L1GatewayRouter from "@arbitrum/token-bridge-contracts/build/contracts/contracts/tokenbridge/ethereum/gateway/L1GatewayRouter.sol/L1GatewayRouter.json";
import * as L1AtomicTokenBridgeCreator from "@arbitrum/token-bridge-contracts/build/contracts/contracts/tokenbridge/ethereum/L1AtomicTokenBridgeCreator.sol/L1AtomicTokenBridgeCreator.json";
import * as ERC20 from "@openzeppelin/contracts/build/contracts/ERC20.json";
import * as TestWETH9 from "@arbitrum/token-bridge-contracts/build/contracts/contracts/tokenbridge/test/TestWETH9.sol/TestWETH9.json";
import * as fs from "fs";
import { ARB_OWNER } from "./consts";
const path = require("path");
Expand Down Expand Up @@ -139,6 +140,14 @@ async function deployERC20Contract(deployerWallet: Wallet, decimals: number): Pr
return token.address;
}

async function deployWETHContract(deployerWallet: Wallet): Promise<string> {
const wethFactory = new ContractFactory(TestWETH9.abi, TestWETH9.bytecode, deployerWallet);
const weth = await wethFactory.deploy("Wrapped Ether", "WETH");
await weth.deployTransaction.wait();

return weth.address;
}

export const bridgeFundsCommand = {
command: "bridge-funds",
describe: "sends funds from l1 to l2",
Expand Down Expand Up @@ -299,6 +308,10 @@ export const createERC20Command = {
boolean: true,
describe: "if true, deploy on L1 and bridge to L2",
},
l1: {
boolean: true,
describe: "if true, deploy on L1 only",
},
decimals: {
string: true,
describe: "number of decimals for token",
Expand All @@ -308,26 +321,26 @@ export const createERC20Command = {
handler: async (argv: any) => {
console.log("create-erc20");

if (argv.bridgeable) {
// deploy token on l1 and bridge to l2
const l1l2tokenbridge = JSON.parse(
fs
.readFileSync(path.join(consts.tokenbridgedatapath, "l1l2_network.json"))
.toString()
);
if (argv.bridgeable || argv.l1) {

// deploy token on l1
const l1provider = new ethers.providers.WebSocketProvider(argv.l1url);
const l2provider = new ethers.providers.WebSocketProvider(argv.l2url);

const deployerWallet = new Wallet(
ethers.utils.sha256(ethers.utils.toUtf8Bytes(argv.deployer)),
l1provider
);
const deployerWallet = namedAccount(argv.deployer).connect(l1provider);

const tokenAddress = await deployERC20Contract(deployerWallet, argv.decimals);
const token = new ethers.Contract(tokenAddress, ERC20.abi, deployerWallet);
console.log("Contract deployed at L1 address:", token.address);

if (!argv.bridgeable) return;

// bridge to l2
const l2provider = new ethers.providers.WebSocketProvider(argv.l2url);
const l1l2tokenbridge = JSON.parse(
fs
.readFileSync(path.join(consts.tokenbridgedatapath, "l1l2_network.json"))
.toString()
);

const l1GatewayRouter = new ethers.Contract(l1l2tokenbridge.l2Network.tokenBridge.l1GatewayRouter, L1GatewayRouter.abi, deployerWallet);
await (await token.functions.approve(l1l2tokenbridge.l2Network.tokenBridge.l1ERC20Gateway, ethers.constants.MaxUint256)).wait();
const supply = await token.totalSupply();
Expand Down Expand Up @@ -361,10 +374,7 @@ export const createERC20Command = {

// no l1-l2 token bridge, deploy token on l2 directly
argv.provider = new ethers.providers.WebSocketProvider(argv.l2url);
const deployerWallet = new Wallet(
ethers.utils.sha256(ethers.utils.toUtf8Bytes(argv.deployer)),
argv.provider
);
const deployerWallet = namedAccount(argv.deployer).connect(argv.provider);
const tokenAddress = await deployERC20Contract(deployerWallet, argv.decimals);
console.log("Contract deployed at address:", tokenAddress);

Expand Down Expand Up @@ -392,11 +402,19 @@ export const transferERC20Command = {
string: true,
describe: "address (see general help)",
},
l1: {
boolean: true,
describe: "if true, transfer on L1",
},
},
handler: async (argv: any) => {
console.log("transfer-erc20");

argv.provider = new ethers.providers.WebSocketProvider(argv.l2url);
if (argv.l1) {
argv.provider = new ethers.providers.WebSocketProvider(argv.l1url);
} else {
argv.provider = new ethers.providers.WebSocketProvider(argv.l2url);
}
const account = namedAccount(argv.from).connect(argv.provider);
const tokenContract = new ethers.Contract(argv.token, ERC20.abi, account);
const tokenDecimals = await tokenContract.decimals();
Expand All @@ -406,6 +424,38 @@ export const transferERC20Command = {
},
};

export const createWETHCommand = {
command: "create-weth",
describe: "creates WETH on L1",
builder: {
deployer: {
string: true,
describe: "account (see general help)"
},
deposit: {
number: true,
describe: "amount of weth to deposit",
default: 100,
}
},
handler: async (argv: any) => {
console.log("create-weth");

const l1provider = new ethers.providers.WebSocketProvider(argv.l1url);
const deployerWallet = namedAccount(argv.deployer).connect(l1provider);

const wethAddress = await deployWETHContract(deployerWallet);
const weth = new ethers.Contract(wethAddress, TestWETH9.abi, deployerWallet);
console.log("WETH deployed at L1 address:", weth.address);

if (argv.deposit > 0) {
const amount = ethers.utils.parseEther(argv.deposit.toString());
const depositTx = await deployerWallet.sendTransaction({ to: wethAddress, value: amount, data:"0xd0e30db0" }); // deposit()
await depositTx.wait();
}
},
};

export const sendL1Command = {
command: "send-l1",
describe: "sends funds between l1 accounts",
Expand Down
2 changes: 2 additions & 0 deletions scripts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
bridgeNativeTokenToL3Command,
bridgeToL3Command,
createERC20Command,
createWETHCommand,
transferERC20Command,
sendL1Command,
sendL2Command,
Expand All @@ -38,6 +39,7 @@ async function main() {
.command(bridgeToL3Command)
.command(bridgeNativeTokenToL3Command)
.command(createERC20Command)
.command(createWETHCommand)
.command(transferERC20Command)
.command(sendL1Command)
.command(sendL2Command)
Expand Down
37 changes: 31 additions & 6 deletions test-node.bash
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,22 @@ set -eu
NITRO_NODE_VERSION=offchainlabs/nitro-node:v3.2.1-d81324d-dev
BLOCKSCOUT_VERSION=offchainlabs/blockscout:v1.1.0-0e716c8

# This commit matches v2.1.0 release of nitro-contracts, with additional support to set arb owner through upgrade executor
DEFAULT_NITRO_CONTRACTS_VERSION="99c07a7db2fcce75b751c5a2bd4936e898cda065"
DEFAULT_NITRO_CONTRACTS_VERSION="v2.1.1-beta.0"
DEFAULT_TOKEN_BRIDGE_VERSION="v1.2.2"

# The is the latest bold-merge commit in nitro-contracts at the time
DEFAULT_BOLD_CONTRACTS_VERSION="42d80e40"

# Set default versions if not overriden by provided env vars
: ${NITRO_CONTRACTS_BRANCH:=$DEFAULT_NITRO_CONTRACTS_VERSION}
: ${BOLD_CONTRACTS_BRANCH:=$DEFAULT_BOLD_CONTRACTS_VERSION}
: ${TOKEN_BRIDGE_BRANCH:=$DEFAULT_TOKEN_BRIDGE_VERSION}
export NITRO_CONTRACTS_BRANCH
export BOLD_CONTRACTS_BRANCH
export TOKEN_BRIDGE_BRANCH

echo "Using NITRO_CONTRACTS_BRANCH: $NITRO_CONTRACTS_BRANCH"
echo "Using BOLD_CONTRACTS_BRANCH: $BOLD_CONTRACTS_BRANCH"
echo "Using TOKEN_BRIDGE_BRANCH: $TOKEN_BRIDGE_BRANCH"

mydir=`dirname $0`
Expand Down Expand Up @@ -44,6 +49,7 @@ blockscout=false
tokenbridge=false
l3node=false
consensusclient=false
boldupgrade=false
redundantsequencers=0
l3_custom_fee_token=false
l3_token_bridge=false
Expand Down Expand Up @@ -203,6 +209,10 @@ while [[ $# -gt 0 ]]; do
l1chainid=1337
shift
;;
--bold-upgrade)
boldupgrade=true
shift
;;
--l3node)
l3node=true
shift
Expand Down Expand Up @@ -282,8 +292,8 @@ while [[ $# -gt 0 ]]; do
echo --no-build-dev-nitro don\'t rebuild dev nitro docker image
echo --build-dev-blockscout rebuild dev blockscout docker image
echo --no-build-dev-blockscout don\'t rebuild dev blockscout docker image
echo --build-utils rebuild scripts, rollupcreator, token bridge docker images
echo --no-build-utils don\'t rebuild scripts, rollupcreator, token bridge docker images
echo --build-utils rebuild scripts, rollupcreator, boldupgrader, token bridge docker images
echo --no-build-utils don\'t rebuild scripts, rollupcreator, boldupgrader, token bridge docker images
echo --force-build-utils force rebuilding utils, useful if NITRO_CONTRACTS_ or TOKEN_BRIDGE_BRANCH changes
echo
echo script runs inside a separate docker. For SCRIPT-ARGS, run $0 script --help
Expand Down Expand Up @@ -352,7 +362,7 @@ if $dev_blockscout && $build_dev_blockscout; then
fi

if $build_utils; then
LOCAL_BUILD_NODES="scripts rollupcreator"
LOCAL_BUILD_NODES="scripts rollupcreator boldupgrader"
# always build tokenbridge in CI mode to avoid caching issues
if $tokenbridge || $l3_token_bridge || $ci; then
LOCAL_BUILD_NODES="$LOCAL_BUILD_NODES tokenbridge"
Expand Down Expand Up @@ -473,11 +483,11 @@ if $force_init; then
docker compose up --wait $INITIAL_SEQ_NODES
docker compose run scripts bridge-funds --ethamount 100000 --wait
docker compose run scripts send-l2 --ethamount 100 --to l2owner --wait
rollupAddress=`docker compose run --entrypoint sh poster -c "jq -r '.[0].rollup.rollup' /config/deployed_chain_info.json | tail -n 1 | tr -d '\r\n'"`

if $tokenbridge; then
echo == Deploying L1-L2 token bridge
sleep 10 # no idea why this sleep is needed but without it the deploy fails randomly
rollupAddress=`docker compose run --entrypoint sh poster -c "jq -r '.[0].rollup.rollup' /config/deployed_chain_info.json | tail -n 1 | tr -d '\r\n'"`
docker compose run -e ROLLUP_OWNER_KEY=$l2ownerKey -e ROLLUP_ADDRESS=$rollupAddress -e PARENT_KEY=$devprivkey -e PARENT_RPC=http://geth:8545 -e CHILD_KEY=$devprivkey -e CHILD_RPC=http://sequencer:8547 tokenbridge deploy:local:token-bridge
docker compose run --entrypoint sh tokenbridge -c "cat network.json && cp network.json l1l2_network.json && cp network.json localNetwork.json"
echo
Expand All @@ -486,6 +496,21 @@ if $force_init; then
echo == Deploy CacheManager on L2
docker compose run -e CHILD_CHAIN_RPC="http://sequencer:8547" -e CHAIN_OWNER_PRIVKEY=$l2ownerKey rollupcreator deploy-cachemanager-testnode

if $boldupgrade; then
echo == Deploying WETH as BOLD stake token
stakeTokenAddress=`docker compose run scripts create-weth --deployer l2owner --deposit 100 | tail -n 1 | awk '{ print $NF }'`
echo BOLD stake token address: $stakeTokenAddress
docker compose run scripts transfer-erc20 --token $stakeTokenAddress --l1 --amount 100 --from l2owner --to validator
echo == Preparing BOLD upgrade
docker compose run -e TESTNODE_MODE=true -e ROLLUP_ADDRESS=$rollupAddress -e STAKE_TOKEN=$stakeTokenAddress boldupgrader script:bold-prepare
# retry this 10 times because the staker might not have made a node yet
for i in {1..10}; do
docker compose run -e TESTNODE_MODE=true -e ROLLUP_ADDRESS=$rollupAddress -e STAKE_TOKEN=$stakeTokenAddress boldupgrader script:bold-populate-lookup && break || true
echo "Failed to populate lookup table, retrying..."
sleep 10
done
docker compose run -e TESTNODE_MODE=true -e ROLLUP_ADDRESS=$rollupAddress -e STAKE_TOKEN=$stakeTokenAddress boldupgrader script:bold-local-execute
fi

if $l3node; then
echo == Funding l3 users
Expand Down
Loading