diff --git a/scripts/consts.ts b/scripts/consts.ts index ff322260..06f40f90 100644 --- a/scripts/consts.ts +++ b/scripts/consts.ts @@ -5,3 +5,5 @@ export const tokenbridgedatapath = "/tokenbridge-data"; // Not secure. Do not use for production purposes export const l1mnemonic = "indoor dish desk flag debris potato excuse depart ticket judge file exit"; + +export const ARB_OWNER = "0x0000000000000000000000000000000000000070"; diff --git a/scripts/ethcommands.ts b/scripts/ethcommands.ts index 00fdbb15..a4f5e13b 100644 --- a/scripts/ethcommands.ts +++ b/scripts/ethcommands.ts @@ -3,9 +3,11 @@ import { ContractFactory, ethers, Wallet } from "ethers"; import * as consts from "./consts"; 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 ERC20PresetFixedSupplyArtifact from "@openzeppelin/contracts/build/contracts/ERC20PresetFixedSupply.json"; import * as ERC20 from "@openzeppelin/contracts/build/contracts/ERC20.json"; import * as fs from "fs"; +import { ARB_OWNER } from "./consts"; const path = require("path"); async function sendTransaction(argv: any, threadId: number) { @@ -184,6 +186,56 @@ export const bridgeNativeTokenToL3Command = { }, }; +export const transferL3ChainOwnershipCommand = { + command: "transfer-l3-chain-ownership", + describe: "transfer L3 chain ownership to upgrade executor", + builder: { + creator: { + string: true, + describe: "address of the token bridge creator", + }, + wait: { + boolean: true, + describe: "wait till ownership is transferred", + default: false, + }, + }, + handler: async (argv: any) => { + // get inbox address from config file + const deploydata = JSON.parse( + fs + .readFileSync(path.join(consts.configpath, "l3deployment.json")) + .toString() + ); + const inboxAddr = ethers.utils.hexlify(deploydata.inbox); + + // get L3 upgrade executor address from token bridge creator + const l2provider = new ethers.providers.WebSocketProvider(argv.l2url); + const tokenBridgeCreator = new ethers.Contract(argv.creator, L1AtomicTokenBridgeCreator.abi, l2provider); + const [,,,,,,,l3UpgradeExecutorAddress,] = await tokenBridgeCreator.inboxToL2Deployment(inboxAddr); + + // set TX params + argv.provider = new ethers.providers.WebSocketProvider(argv.l3url); + argv.to = "address_" + ARB_OWNER; + argv.from = "l3owner"; + argv.ethamount = "0"; + + // add L3 UpgradeExecutor to chain owners + const arbOwnerIface = new ethers.utils.Interface([ + "function addChainOwner(address newOwner) external", + "function removeChainOwner(address ownerToRemove) external" + ]) + argv.data = arbOwnerIface.encodeFunctionData("addChainOwner", [l3UpgradeExecutorAddress]); + await runStress(argv, sendTransaction); + + // remove L3 owner from chain owners + argv.data = arbOwnerIface.encodeFunctionData("removeChainOwner", [namedAccount("l3owner").address]); + await runStress(argv, sendTransaction); + + argv.provider.destroy(); + } +}; + export const createERC20Command = { command: "create-erc20", describe: "creates simple ERC20 on L2", @@ -279,7 +331,6 @@ export const createERC20Command = { }, }; - export const sendL1Command = { command: "send-l1", describe: "sends funds between l1 accounts", diff --git a/scripts/index.ts b/scripts/index.ts index 4db38538..a1b47220 100644 --- a/scripts/index.ts +++ b/scripts/index.ts @@ -18,6 +18,7 @@ import { sendL2Command, sendL3Command, sendRPCCommand, + transferL3ChainOwnershipCommand } from "./ethcommands"; async function main() { @@ -40,6 +41,7 @@ async function main() { .command(sendL2Command) .command(sendL3Command) .command(sendRPCCommand) + .command(transferL3ChainOwnershipCommand) .command(writeConfigCommand) .command(writeGethGenesisCommand) .command(writeL2ChainConfigCommand) diff --git a/test-node.bash b/test-node.bash index e79652ca..48825d3a 100755 --- a/test-node.bash +++ b/test-node.bash @@ -426,6 +426,10 @@ if $force_init; then fi docker compose run -e PARENT_WETH_OVERRIDE=$l2Weth -e ROLLUP_OWNER_KEY=$l3ownerkey -e ROLLUP_ADDRESS=$rollupAddress -e PARENT_RPC=http://sequencer:8547 -e PARENT_KEY=$l3_token_bridge_deployer_key -e CHILD_RPC=http://l3node:3347 -e CHILD_KEY=$l3_token_bridge_deployer_key tokenbridge deploy:local:token-bridge docker compose run --entrypoint sh tokenbridge -c "cat network.json && cp network.json l2l3_network.json" + + # set L3 UpgradeExecutor, deployed by token bridge creator in previous step, to be the L3 chain owner. L3owner (EOA) and alias of L2 UpgradeExectuor have the executor role on the L3 UpgradeExecutor + tokenBridgeCreator=`docker compose run --entrypoint sh tokenbridge -c "cat l2l3_network.json" | jq -r '.l1TokenBridgeCreator'` + docker compose run scripts transfer-l3-chain-ownership --creator $tokenBridgeCreator echo fi