diff --git a/scripts/ethcommands.ts b/scripts/ethcommands.ts index 7442fb47..3d782333 100644 --- a/scripts/ethcommands.ts +++ b/scripts/ethcommands.ts @@ -3,6 +3,7 @@ import { ContractFactory, ethers, Wallet } from "ethers"; import * as consts from "./consts"; import { namedAccount, namedAddress } from "./accounts"; import * as ERC20PresetFixedSupplyArtifact from "@openzeppelin/contracts/build/contracts/ERC20PresetFixedSupply.json"; +import * as ERC20 from "@openzeppelin/contracts/build/contracts/ERC20.json"; import * as fs from "fs"; const path = require("path"); @@ -52,6 +53,38 @@ async function bridgeFunds(argv: any, parentChainUrl: string, chainUrl: string, } } +async function bridgeNativeToken(argv: any, parentChainUrl: string, chainUrl: string, inboxAddr: string, token: string) { + argv.provider = new ethers.providers.WebSocketProvider(parentChainUrl); + + argv.to = "address_" + inboxAddr; + + /// approve inbox to use fee token + const bridgerParentChain = namedAccount(argv.from, argv.threadId).connect(argv.provider) + const nativeTokenContract = new ethers.Contract(token, ERC20.abi, bridgerParentChain) + await nativeTokenContract.approve(inboxAddr, ethers.utils.parseEther(argv.amount)) + + /// deposit fee token + const iface = new ethers.utils.Interface(["function depositERC20(uint256 amount)"]) + argv.data = iface.encodeFunctionData("depositERC20", [ethers.utils.parseEther(argv.amount)]); + + await runStress(argv, sendTransaction); + + argv.provider.destroy(); + if (argv.wait) { + const childProvider = new ethers.providers.WebSocketProvider(chainUrl); + const bridger = namedAccount(argv.from, argv.threadId).connect(childProvider) + const sleep = (ms: number) => new Promise(r => setTimeout(r, ms)); + while (true) { + const balance = await bridger.getBalance() + if (balance.gte(ethers.utils.parseEther(argv.amount))) { + return + } + await sleep(100) + } + } +} + + export const bridgeFundsCommand = { command: "bridge-funds", describe: "sends funds from l1 to l2", @@ -84,7 +117,6 @@ export const bridgeFundsCommand = { }, }; - export const bridgeToL3Command = { command: "bridge-to-l3", describe: "sends funds from l2 to l3", @@ -117,6 +149,40 @@ export const bridgeToL3Command = { }, }; +export const bridgeNativeTokenToL3Command = { + command: "bridge-native-token-to-l3", + describe: "bridge native token from l2 to l3", + builder: { + amount: { + string: true, + describe: "amount to transfer", + default: "10", + }, + from: { + string: true, + describe: "account (see general help)", + default: "funnel", + }, + wait: { + boolean: true, + describe: "wait till l3 has balance of amount", + default: false, + }, + }, + handler: async (argv: any) => { + const deploydata = JSON.parse( + fs + .readFileSync(path.join(consts.configpath, "l3deployment.json")) + .toString() + ); + const inboxAddr = ethers.utils.hexlify(deploydata.inbox); + const nativeTokenAddr = ethers.utils.hexlify(deploydata["native-token"]); + + argv.ethamount = "0" + await bridgeNativeToken(argv, argv.l2url, argv.l3url, inboxAddr, nativeTokenAddr) + }, +}; + export const createERC20Command = { command: "create-erc20", describe: "creates simple ERC20 on L2", @@ -228,7 +294,7 @@ export const sendL2Command = { export const sendL3Command = { command: "send-l3", - describe: "sends funds between l2 accounts", + describe: "sends funds between l3 accounts", builder: { ethamount: { string: true, diff --git a/scripts/index.ts b/scripts/index.ts index ee27b9e1..c39406ed 100644 --- a/scripts/index.ts +++ b/scripts/index.ts @@ -10,6 +10,7 @@ import { } from "./accounts"; import { bridgeFundsCommand, + bridgeNativeTokenToL3Command, bridgeToL3Command, createERC20Command, sendL1Command, @@ -31,6 +32,7 @@ async function main() { .options(stressOptions) .command(bridgeFundsCommand) .command(bridgeToL3Command) + .command(bridgeNativeTokenToL3Command) .command(createERC20Command) .command(sendL1Command) .command(sendL2Command) diff --git a/test-node.bash b/test-node.bash index 66b6edc1..407d03bc 100755 --- a/test-node.bash +++ b/test-node.bash @@ -2,22 +2,15 @@ set -e -NITRO_NODE_VERSION=offchainlabs/nitro-node:v2.2.0-alpha.1-fdd098e-dev +NITRO_NODE_VERSION=offchainlabs/nitro-node:v2.2.2-8f33fea-dev BLOCKSCOUT_VERSION=offchainlabs/blockscout:v1.0.0-c8db5b1 mydir=`dirname $0` cd "$mydir" -if ! which docker-compose > /dev/null; then - echo == Error! docker-compose not installed - echo please install docker-compose and have it in PATH - echo see https://docs.docker.com/compose/install/ - exit 1 -fi - if [[ $# -gt 0 ]] && [[ $1 == "script" ]]; then shift - docker-compose run scripts "$@" + docker compose run scripts "$@" exit $? fi @@ -40,7 +33,8 @@ consensusclient=false redundantsequencers=0 dev_build_nitro=false dev_build_blockscout=false -l3CustomFeeToken=false +l3_custom_fee_token=false +l3_token_bridge=false batchposters=1 devprivkey=b6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659 l1chainid=1337 @@ -131,7 +125,15 @@ while [[ $# -gt 0 ]]; do echo "Error: --l3-fee-token requires --l3node to be provided." exit 1 fi - l3CustomFeeToken=true + l3_custom_fee_token=true + shift + ;; + --l3-token-bridge) + if ! $l3node; then + echo "Error: --l3-token-bridge requires --l3node to be provided." + exit 1 + fi + l3_token_bridge=true shift ;; --redundantsequencers) @@ -163,6 +165,7 @@ while [[ $# -gt 0 ]]; do echo --pos l1 is a proof-of-stake chain \(using prysm for consensus\) echo --validate heavy computation, validating all blocks in WASM echo --l3-fee-token L3 chain is set up to use custom fee token. Only valid if also '--l3node' is provided + echo --l3-token-bridge Deploy L2-L3 token bridge. Only valid if also '--l3node' is provided echo --batchposters batch posters [0-3] echo --redundantsequencers redundant sequencers [0-3] echo --detach detach from nodes after running them @@ -251,10 +254,10 @@ if $force_build; then fi fi LOCAL_BUILD_NODES=scripts - if $tokenbridge; then + if $tokenbridge || $l3_token_bridge; then LOCAL_BUILD_NODES="$LOCAL_BUILD_NODES tokenbridge" fi - docker-compose build --no-rm $LOCAL_BUILD_NODES + docker compose build --no-rm $LOCAL_BUILD_NODES fi if $dev_build_nitro; then @@ -276,12 +279,12 @@ else fi if $force_build; then - docker-compose build --no-rm $NODES scripts + docker compose build --no-rm $NODES scripts fi if $force_init; then echo == Removing old data.. - docker-compose down + docker compose down leftoverContainers=`docker container ls -a --filter label=com.docker.compose.project=nitro-testnode -q | xargs echo` if [ `echo $leftoverContainers | wc -w` -gt 0 ]; then docker rm $leftoverContainers @@ -293,108 +296,123 @@ if $force_init; then fi echo == Generating l1 keys - docker-compose run scripts write-accounts - docker-compose run --entrypoint sh geth -c "echo passphrase > /datadir/passphrase" - docker-compose run --entrypoint sh geth -c "chown -R 1000:1000 /keystore" - docker-compose run --entrypoint sh geth -c "chown -R 1000:1000 /config" + docker compose run scripts write-accounts + docker compose run --entrypoint sh geth -c "echo passphrase > /datadir/passphrase" + docker compose run --entrypoint sh geth -c "chown -R 1000:1000 /keystore" + docker compose run --entrypoint sh geth -c "chown -R 1000:1000 /config" if $consensusclient; then echo == Writing configs - docker-compose run scripts write-geth-genesis-config + docker compose run scripts write-geth-genesis-config echo == Writing configs - docker-compose run scripts write-prysm-config + docker compose run scripts write-prysm-config echo == Initializing go-ethereum genesis configuration - docker-compose run geth init --datadir /datadir/ /config/geth_genesis.json + docker compose run geth init --datadir /datadir/ /config/geth_genesis.json echo == Starting geth - docker-compose up --wait geth + docker compose up --wait geth echo == Creating prysm genesis - docker-compose up create_beacon_chain_genesis + docker compose up create_beacon_chain_genesis echo == Running prysm - docker-compose up --wait prysm_beacon_chain - docker-compose up --wait prysm_validator + docker compose up --wait prysm_beacon_chain + docker compose up --wait prysm_validator else - docker-compose up --wait geth + docker compose up --wait geth fi echo == Funding validator and sequencer - docker-compose run scripts send-l1 --ethamount 1000 --to validator --wait - docker-compose run scripts send-l1 --ethamount 1000 --to sequencer --wait + docker compose run scripts send-l1 --ethamount 1000 --to validator --wait + docker compose run scripts send-l1 --ethamount 1000 --to sequencer --wait echo == create l1 traffic - docker-compose run scripts send-l1 --ethamount 1000 --to user_l1user --wait - docker-compose run scripts send-l1 --ethamount 0.0001 --from user_l1user --to user_l1user_b --wait --delay 500 --times 1000000 > /dev/null & + docker compose run scripts send-l1 --ethamount 1000 --to user_l1user --wait + docker compose run scripts send-l1 --ethamount 0.0001 --from user_l1user --to user_l1user_b --wait --delay 500 --times 1000000 > /dev/null & echo == Writing l2 chain config - docker-compose run scripts write-l2-chain-config + docker compose run scripts write-l2-chain-config - sequenceraddress=`docker-compose run scripts print-address --account sequencer | tail -n 1 | tr -d '\r\n'` + sequenceraddress=`docker compose run scripts print-address --account sequencer | tail -n 1 | tr -d '\r\n'` - docker-compose run --entrypoint /usr/local/bin/deploy sequencer --l1conn ws://geth:8546 --l1keystore /home/user/l1keystore --sequencerAddress $sequenceraddress --ownerAddress $sequenceraddress --l1DeployAccount $sequenceraddress --l1deployment /config/deployment.json --authorizevalidators 10 --wasmrootpath /home/user/target/machines --l1chainid=$l1chainid --l2chainconfig /config/l2_chain_config.json --l2chainname arb-dev-test --l2chaininfo /config/deployed_chain_info.json - docker-compose run --entrypoint sh sequencer -c "jq [.[]] /config/deployed_chain_info.json > /config/l2_chain_info.json" + docker compose run --entrypoint /usr/local/bin/deploy sequencer --l1conn ws://geth:8546 --l1keystore /home/user/l1keystore --sequencerAddress $sequenceraddress --ownerAddress $sequenceraddress --l1DeployAccount $sequenceraddress --l1deployment /config/deployment.json --authorizevalidators 10 --wasmrootpath /home/user/target/machines --l1chainid=$l1chainid --l2chainconfig /config/l2_chain_config.json --l2chainname arb-dev-test --l2chaininfo /config/deployed_chain_info.json + docker compose run --entrypoint sh sequencer -c "jq [.[]] /config/deployed_chain_info.json > /config/l2_chain_info.json" if $simple; then echo == Writing configs - docker-compose run scripts write-config --simple + docker compose run scripts write-config --simple else echo == Writing configs - docker-compose run scripts write-config + docker compose run scripts write-config echo == Initializing redis - docker-compose up --wait redis - docker-compose run scripts redis-init --redundancy $redundantsequencers + docker compose up --wait redis + docker compose run scripts redis-init --redundancy $redundantsequencers fi echo == Funding l2 funnel and dev key - docker-compose up --wait $INITIAL_SEQ_NODES - docker-compose run scripts bridge-funds --ethamount 100000 --wait - docker-compose run scripts bridge-funds --ethamount 1000 --wait --from "key_0x$devprivkey" + docker compose up --wait $INITIAL_SEQ_NODES + docker compose run scripts bridge-funds --ethamount 100000 --wait + docker compose run scripts bridge-funds --ethamount 1000 --wait --from "key_0x$devprivkey" if $tokenbridge; then - echo == Deploying token bridge - docker-compose run -e ARB_KEY=$devprivkey -e ETH_KEY=$devprivkey tokenbridge gen:network - docker-compose run --entrypoint sh tokenbridge -c "cat localNetwork.json" + echo == Deploying L1-L2 token bridge + 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=$sequenceraddress -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" echo fi if $l3node; then echo == Funding l3 users - docker-compose run scripts send-l2 --ethamount 1000 --to l3owner --wait - docker-compose run scripts send-l2 --ethamount 1000 --to l3sequencer --wait + docker compose run scripts send-l2 --ethamount 1000 --to l3owner --wait + docker compose run scripts send-l2 --ethamount 1000 --to l3sequencer --wait echo == Funding l2 deployers - docker-compose run scripts send-l2 --ethamount 100 --to user_token_bridge_deployer --wait - docker-compose run scripts send-l2 --ethamount 100 --to user_fee_token_deployer --wait + docker compose run scripts send-l2 --ethamount 100 --to user_token_bridge_deployer --wait + docker compose run scripts send-l2 --ethamount 100 --to user_fee_token_deployer --wait echo == create l2 traffic - docker-compose run scripts send-l2 --ethamount 100 --to user_traffic_generator --wait - docker-compose run scripts send-l2 --ethamount 0.0001 --from user_traffic_generator --to user_fee_token_deployer --wait --delay 500 --times 1000000 > /dev/null & + docker compose run scripts send-l2 --ethamount 100 --to user_traffic_generator --wait + docker compose run scripts send-l2 --ethamount 0.0001 --from user_traffic_generator --to user_fee_token_deployer --wait --delay 500 --times 1000000 > /dev/null & echo == Writing l3 chain config - docker-compose run scripts write-l3-chain-config + docker compose run scripts write-l3-chain-config - if $l3CustomFeeToken; then + if $l3_custom_fee_token; then echo == Deploying custom fee token - nativeTokenAddress=`docker-compose run scripts create-erc20 --deployer user_fee_token_deployer --mintTo user_token_bridge_deployer | tail -n 1 | awk '{ print $NF }'` + nativeTokenAddress=`docker compose run scripts create-erc20 --deployer user_fee_token_deployer --mintTo user_token_bridge_deployer | tail -n 1 | awk '{ print $NF }'` EXTRA_L3_DEPLOY_FLAG="--nativeTokenAddress $nativeTokenAddress" fi echo == Deploying L3 - l3owneraddress=`docker-compose run scripts print-address --account l3owner | tail -n 1 | tr -d '\r\n'` - l3sequenceraddress=`docker-compose run scripts print-address --account l3sequencer | tail -n 1 | tr -d '\r\n'` - docker-compose run --entrypoint /usr/local/bin/deploy sequencer --l1conn ws://sequencer:8548 --l1keystore /home/user/l1keystore --sequencerAddress $l3sequenceraddress --ownerAddress $l3owneraddress --l1DeployAccount $l3owneraddress --l1deployment /config/l3deployment.json --authorizevalidators 10 --wasmrootpath /home/user/target/machines --l1chainid=412346 --l2chainconfig /config/l3_chain_config.json --l2chainname orbit-dev-test --l2chaininfo /config/deployed_l3_chain_info.json --maxDataSize 104857 $EXTRA_L3_DEPLOY_FLAG - docker-compose run --entrypoint sh sequencer -c "jq [.[]] /config/deployed_l3_chain_info.json > /config/l3_chain_info.json" + l3owneraddress=`docker compose run scripts print-address --account l3owner | tail -n 1 | tr -d '\r\n'` + l3sequenceraddress=`docker compose run scripts print-address --account l3sequencer | tail -n 1 | tr -d '\r\n'` + docker compose run --entrypoint /usr/local/bin/deploy sequencer --l1conn ws://sequencer:8548 --l1keystore /home/user/l1keystore --sequencerAddress $l3sequenceraddress --ownerAddress $l3owneraddress --l1DeployAccount $l3owneraddress --l1deployment /config/l3deployment.json --authorizevalidators 10 --wasmrootpath /home/user/target/machines --l1chainid=412346 --l2chainconfig /config/l3_chain_config.json --l2chainname orbit-dev-test --l2chaininfo /config/deployed_l3_chain_info.json --maxDataSize 104857 $EXTRA_L3_DEPLOY_FLAG + docker compose run --entrypoint sh sequencer -c "jq [.[]] /config/deployed_l3_chain_info.json > /config/l3_chain_info.json" echo == Funding l3 funnel and dev key - docker-compose up --wait l3node sequencer + docker compose up --wait l3node sequencer + + if $l3_token_bridge; then + echo == Deploying L2-L3 token bridge + deployer_key=`printf "%s" "user_token_bridge_deployer" | openssl dgst -sha256 | sed 's/^.*= //'` + rollupAddress=`docker compose run --entrypoint sh poster -c "jq -r '.[0].rollup.rollup' /config/deployed_l3_chain_info.json | tail -n 1 | tr -d '\r\n'"` + docker compose run -e ROLLUP_OWNER=$l3owneraddress -e ROLLUP_ADDRESS=$rollupAddress -e PARENT_RPC=http://sequencer:8547 -e PARENT_KEY=$deployer_key -e CHILD_RPC=http://l3node:3347 -e CHILD_KEY=$deployer_key tokenbridge deploy:local:token-bridge + docker compose run --entrypoint sh tokenbridge -c "cat network.json" + echo + fi - if ! $l3CustomFeeToken; then - docker-compose run scripts bridge-to-l3 --ethamount 50000 --wait - docker-compose run scripts bridge-to-l3 --ethamount 500 --wait --from "key_0x$devprivkey" + echo == Fund L3 accounts + if $l3_custom_fee_token; then + docker compose run scripts bridge-native-token-to-l3 --amount 50000 --from user_token_bridge_deployer --wait + docker compose run scripts send-l3 --ethamount 500 --from user_token_bridge_deployer --wait + docker compose run scripts send-l3 --ethamount 500 --from user_token_bridge_deployer --to "key_0x$devprivkey" --wait + else + docker compose run scripts bridge-to-l3 --ethamount 50000 --wait + docker compose run scripts bridge-to-l3 --ethamount 500 --wait --from "key_0x$devprivkey" fi fi @@ -410,5 +428,5 @@ if $run; then echo if things go wrong - use --init to create a new chain echo - docker-compose up $UP_FLAG $NODES + docker compose up $UP_FLAG $NODES fi diff --git a/tokenbridge/Dockerfile b/tokenbridge/Dockerfile index 09156556..2b952168 100644 --- a/tokenbridge/Dockerfile +++ b/tokenbridge/Dockerfile @@ -1,7 +1,8 @@ FROM node:16-bullseye-slim RUN apt-get update && \ - apt-get install -y git docker.io + apt-get install -y git docker.io python3 chromium build-essential WORKDIR /workspace -RUN git clone --depth 1 -b v3.1.4 https://github.com/OffchainLabs/arbitrum-sdk.git ./ +RUN git clone -b feat-registry https://github.com/OffchainLabs/token-bridge-contracts.git ./ RUN yarn install +RUN yarn build ENTRYPOINT ["yarn"]