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

fix: blockscout verification #59

Merged
merged 5 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,39 @@ jobs:

- name: Test Storage Layouts
run: yarn run test:storage

test-e2e:
name: Test e2e
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- uses: OffchainLabs/actions/run-nitro-test-node@main
with:
nitro-testnode-ref: bump-nitro
l3-node: true
no-token-bridge: true

- name: Setup node/yarn
uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'
cache-dependency-path: '**/yarn.lock'

- name: Install packages
run: yarn

- name: Compile contracts
run: yarn build

- name: Deploy creator and create token bridge
run: yarn deploy:local:token-bridge

- name: Verify deployed token bridge
run: yarn test:tokenbridge:deployment

- name: Verify creation code generation
run: yarn test:creation-code
59 changes: 28 additions & 31 deletions contracts/tokenbridge/arbitrum/L2AtomicTokenBridgeFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {L2CustomGateway} from "./gateway/L2CustomGateway.sol";
import {L2WethGateway} from "./gateway/L2WethGateway.sol";
import {StandardArbERC20} from "./StandardArbERC20.sol";
import {IUpgradeExecutor} from "@offchainlabs/upgrade-executor/src/IUpgradeExecutor.sol";
import {CreationCodeHelper} from "../libraries/CreationCodeHelper.sol";
import {BeaconProxyFactory} from "../libraries/ClonableBeaconProxy.sol";
import {aeWETH} from "../libraries/aeWETH.sol";
import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
Expand Down Expand Up @@ -75,7 +76,11 @@ contract L2AtomicTokenBridgeFactory {
}

// deploy multicall
Create2.deploy(0, _getL2Salt(OrbitSalts.L2_MULTICALL), _creationCodeFor(l2Code.multicall));
Create2.deploy(
0,
_getL2Salt(OrbitSalts.L2_MULTICALL),
CreationCodeHelper.getCreationCodeFor(l2Code.multicall)
);

// transfer ownership to L2 upgradeExecutor
ProxyAdmin(proxyAdmin).transferOwnership(upgradeExecutor);
Expand All @@ -93,14 +98,19 @@ contract L2AtomicTokenBridgeFactory {
);

// Create UpgradeExecutor logic and upgrade to it.
// Note: UpgradeExecutor logic has initializer disabled so no need to call it.
address upExecutorLogic = Create2.deploy(
0, _getL2Salt(OrbitSalts.L2_EXECUTOR_LOGIC), _creationCodeFor(runtimeCode)
0,
_getL2Salt(OrbitSalts.L2_EXECUTOR_LOGIC),
CreationCodeHelper.getCreationCodeFor(runtimeCode)
);
ProxyAdmin(proxyAdmin).upgrade(
ITransparentUpgradeableProxy(canonicalUpgradeExecutor), upExecutorLogic
);

// init logic contract with dummy values
address[] memory empty = new address[](0);
IUpgradeExecutor(upExecutorLogic).initialize(ADDRESS_DEAD, empty);

// init upgrade executor
address[] memory executors = new address[](2);
executors[0] = rollupOwner;
Expand All @@ -122,8 +132,11 @@ contract L2AtomicTokenBridgeFactory {
);

// create L2 router logic and upgrade
address routerLogic =
Create2.deploy(0, _getL2Salt(OrbitSalts.L2_ROUTER_LOGIC), _creationCodeFor(runtimeCode));
address routerLogic = Create2.deploy(
0,
_getL2Salt(OrbitSalts.L2_ROUTER_LOGIC),
CreationCodeHelper.getCreationCodeFor(runtimeCode)
);
ProxyAdmin(proxyAdmin).upgrade(ITransparentUpgradeableProxy(canonicalRouter), routerLogic);

// init logic contract with dummy values.
Expand Down Expand Up @@ -151,7 +164,9 @@ contract L2AtomicTokenBridgeFactory {

// create L2 standard gateway logic and upgrade
address stdGatewayLogic = Create2.deploy(
0, _getL2Salt(OrbitSalts.L2_STANDARD_GATEWAY_LOGIC), _creationCodeFor(runtimeCode)
0,
_getL2Salt(OrbitSalts.L2_STANDARD_GATEWAY_LOGIC),
CreationCodeHelper.getCreationCodeFor(runtimeCode)
);
ProxyAdmin(proxyAdmin).upgrade(
ITransparentUpgradeableProxy(canonicalStdGateway), stdGatewayLogic
Expand Down Expand Up @@ -196,7 +211,9 @@ contract L2AtomicTokenBridgeFactory {

// create L2 custom gateway logic and upgrade
address customGatewayLogicAddress = Create2.deploy(
0, _getL2Salt(OrbitSalts.L2_CUSTOM_GATEWAY_LOGIC), _creationCodeFor(runtimeCode)
0,
_getL2Salt(OrbitSalts.L2_CUSTOM_GATEWAY_LOGIC),
CreationCodeHelper.getCreationCodeFor(runtimeCode)
);
ProxyAdmin(proxyAdmin).upgrade(
ITransparentUpgradeableProxy(canonicalCustomGateway), customGatewayLogicAddress
Expand Down Expand Up @@ -224,7 +241,9 @@ contract L2AtomicTokenBridgeFactory {

// Create L2WETH logic and upgrade
address l2WethLogic = Create2.deploy(
0, _getL2Salt(OrbitSalts.L2_WETH_LOGIC), _creationCodeFor(aeWethRuntimeCode)
0,
_getL2Salt(OrbitSalts.L2_WETH_LOGIC),
CreationCodeHelper.getCreationCodeFor(aeWethRuntimeCode)
);
ProxyAdmin(proxyAdmin).upgrade(ITransparentUpgradeableProxy(canonicalL2Weth), l2WethLogic);

Expand All @@ -239,7 +258,7 @@ contract L2AtomicTokenBridgeFactory {
address l2WethGatewayLogic = Create2.deploy(
0,
_getL2Salt(OrbitSalts.L2_WETH_GATEWAY_LOGIC),
_creationCodeFor(wethGatewayRuntimeCode)
CreationCodeHelper.getCreationCodeFor(wethGatewayRuntimeCode)
);
ProxyAdmin(proxyAdmin).upgrade(
ITransparentUpgradeableProxy(canonicalL2WethGateway), l2WethGatewayLogic
Expand Down Expand Up @@ -288,27 +307,6 @@ contract L2AtomicTokenBridgeFactory {
)
);
}

/**
* @notice Generate a creation code that results on a contract with `code` as bytecode.
* Source - https://github.com/0xsequence/sstore2/blob/master/contracts/utils/Bytecode.sol
* @param code The returning value of the resulting `creationCode`
* @return creationCode (constructor) for new contract
*/
function _creationCodeFor(bytes memory code) internal pure returns (bytes memory) {
/*
0x00 0x63 0x63XXXXXX PUSH4 _code.length size
0x01 0x80 0x80 DUP1 size size
0x02 0x60 0x600e PUSH1 14 14 size size
0x03 0x60 0x6000 PUSH1 00 0 14 size size
0x04 0x39 0x39 CODECOPY size
0x05 0x60 0x6000 PUSH1 00 0 size
0x06 0xf3 0xf3 RETURN
<CODE>
*/

return abi.encodePacked(hex"63", uint32(code.length), hex"80600E6000396000F3", code);
}
}

/**
Expand All @@ -333,7 +331,6 @@ struct L2RuntimeCode {
* Collection of salts used in CREATE2 deployment of L2 token bridge contracts.
*/
library OrbitSalts {
bytes public constant L1_PROXY_ADMIN = bytes("OrbitL1ProxyAdmin");
bytes public constant L1_ROUTER = bytes("OrbitL1GatewayRouterProxy");
bytes public constant L1_STANDARD_GATEWAY = bytes("OrbitL1StandardGatewayProxy");
bytes public constant L1_CUSTOM_GATEWAY = bytes("OrbitL1CustomGatewayProxy");
Expand Down
43 changes: 14 additions & 29 deletions contracts/tokenbridge/ethereum/L1AtomicTokenBridgeCreator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
L2RuntimeCode,
ProxyAdmin
} from "../arbitrum/L2AtomicTokenBridgeFactory.sol";
import {CreationCodeHelper} from "../libraries/CreationCodeHelper.sol";
import {BytesLib} from "../libraries/BytesLib.sol";
import {
IUpgradeExecutor,
Expand Down Expand Up @@ -57,6 +58,7 @@ contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable {
error L1AtomicTokenBridgeCreator_TemplatesNotSet();
error L1AtomicTokenBridgeCreator_RollupOwnershipMisconfig();
error L1AtomicTokenBridgeCreator_ProxyAdminNotFound();
error L1AtomicTokenBridgeCreator_L2FactoryCannotBeChanged();

event OrbitTokenBridgeCreated(
address indexed inbox,
Expand Down Expand Up @@ -122,7 +124,8 @@ contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable {

constructor(address _l2MulticallTemplate) {
l2MulticallTemplate = _l2MulticallTemplate;
ARB_MULTICALL_CODE_HASH = keccak256(_creationCodeFor(l2MulticallTemplate.code));
ARB_MULTICALL_CODE_HASH =
keccak256(CreationCodeHelper.getCreationCodeFor(l2MulticallTemplate.code));
_disableInitializers();
}

Expand Down Expand Up @@ -156,6 +159,12 @@ contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable {
) external onlyOwner {
l1Templates = _l1Templates;

if (
l2TokenBridgeFactoryTemplate != address(0)
&& l2TokenBridgeFactoryTemplate != _l2TokenBridgeFactoryTemplate
) {
revert L1AtomicTokenBridgeCreator_L2FactoryCannotBeChanged();
}
l2TokenBridgeFactoryTemplate = _l2TokenBridgeFactoryTemplate;
l2RouterTemplate = _l2RouterTemplate;
l2StandardGatewayTemplate = _l2StandardGatewayTemplate;
Expand Down Expand Up @@ -413,7 +422,8 @@ contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable {
returns (uint256)
{
// encode L2 factory bytecode
bytes memory deploymentData = _creationCodeFor(l2TokenBridgeFactoryTemplate.code);
bytes memory deploymentData =
CreationCodeHelper.getCreationCodeFor(l2TokenBridgeFactoryTemplate.code);

if (isUsingFeeToken) {
// transfer fee tokens to inbox to pay for 1st retryable
Expand Down Expand Up @@ -518,11 +528,7 @@ contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable {
}

function getCanonicalL1RouterAddress(address inbox) public view returns (address) {
address expectedL1ProxyAdminAddress = Create2.computeAddress(
_getL1Salt(OrbitSalts.L1_PROXY_ADMIN, inbox),
keccak256(type(ProxyAdmin).creationCode),
address(this)
);
address proxyAdminAddress = IInbox_ProxyAdmin(inbox).getProxyAdmin();

bool isUsingFeeToken = _getFeeToken(inbox) != address(0);
address template = isUsingFeeToken
Expand All @@ -534,7 +540,7 @@ contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable {
keccak256(
abi.encodePacked(
type(TransparentUpgradeableProxy).creationCode,
abi.encode(template, expectedL1ProxyAdminAddress, bytes(""))
abi.encode(template, proxyAdminAddress, bytes(""))
)
),
address(this)
Expand Down Expand Up @@ -661,27 +667,6 @@ contract L1AtomicTokenBridgeCreator is Initializable, OwnableUpgradeable {
return address(uint160(uint256(keccak256(data))));
}

/**
* @notice Generate a creation code that results on a contract with `code` as bytecode.
* Source - https://github.com/0xsequence/sstore2/blob/master/contracts/utils/Bytecode.sol
* @param code The returning value of the resulting `creationCode`
* @return creationCode (constructor) for new contract
*/
function _creationCodeFor(bytes memory code) internal pure returns (bytes memory) {
/*
0x00 0x63 0x63XXXXXX PUSH4 _code.length size
0x01 0x80 0x80 DUP1 size size
0x02 0x60 0x600e PUSH1 14 14 size size
0x03 0x60 0x6000 PUSH1 00 0 14 size size
0x04 0x39 0x39 CODECOPY size
0x05 0x60 0x6000 PUSH1 00 0 size
0x06 0xf3 0xf3 RETURN
<CODE>
*/

return abi.encodePacked(hex"63", uint32(code.length), hex"80600E6000396000F3", code);
}

/**
* @notice L2 contracts are deployed as proxy with dummy seed logic contracts using CREATE2. That enables
* us to upfront calculate the expected canonical addresses.
Expand Down
24 changes: 24 additions & 0 deletions contracts/tokenbridge/libraries/CreationCodeHelper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

library CreationCodeHelper {
/**
* @notice Generate a creation code that results with a contract with `code` as deployed code.
* Generated creation code shall match the one generated by Solidity compiler with an empty constructor.
* @dev Prepended constructor bytecode consists of:
* - 608060405234801561001057600080fd5b50 - store free memory pointer, then check no callvalue is provided
* - 61xxxx - push 2 bytes of `code` length
* - 806100206000396000f3fe - copy deployed code to memory and return the location of it
* @param runtimeCode Deployed bytecode to which constructor bytecode will be prepended
* @return Creation code of a new contract
*/
function getCreationCodeFor(bytes memory runtimeCode) internal pure returns (bytes memory) {
return abi.encodePacked(
hex"608060405234801561001057600080fd5b50",
hex"61",
uint16(runtimeCode.length),
hex"806100206000396000f3fe",
runtimeCode
);
}
}
13 changes: 13 additions & 0 deletions contracts/tokenbridge/test/CreationCodeTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import {CreationCodeHelper} from "../libraries/CreationCodeHelper.sol";

contract CreationCodeTest {
/**
* @dev Wrapper function around CreationCodeHelper.getCreationCodeFor used for testing convenience.
*/
function creationCodeFor(bytes memory code) external pure returns (bytes memory) {
return CreationCodeHelper.getCreationCodeFor(code);
}
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@arbitrum/token-bridge-contracts",
"version": "1.1.0",
"version": "1.1.2",
"license": "Apache-2.0",
"scripts": {
"prepublishOnly": "hardhat clean && hardhat compile",
Expand All @@ -24,6 +24,7 @@
"deploy:token-bridge-creator": "ts-node ./scripts/deployment/deployTokenBridgeCreator.ts",
"create:token-bridge": "ts-node ./scripts/deployment/createTokenBridge.ts",
"test:tokenbridge:deployment": "hardhat test test-e2e/tokenBridgeDeploymentTest.ts",
"test:creation-code": "hardhat test test-e2e/creationCodeTest.ts",
"typechain": "hardhat typechain",
"deploy:tokenbridge": "hardhat run scripts/deploy_token_bridge_l1.ts --network mainnet",
"gen:uml": "sol2uml ./contracts/tokenbridge/arbitrum,./contracts/tokenbridge/ethereum,./contracts/tokenbridge/libraries -o ./gatewayUML.svg",
Expand Down
6 changes: 3 additions & 3 deletions scripts/local-deployment/deployCreatorAndCreateTokenBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,14 @@ export const setupTokenBridgeInLocalEnv = async () => {

//// run retryable estimate for deploying L2 factory
const deployFactoryGasParams = await getEstimateForDeployingFactory(
l1Deployer,
l2Deployer.provider!
parentDeployer,
childDeployer.provider!
)
const gasLimitForL2FactoryDeployment = deployFactoryGasParams.gasLimit

const { l1TokenBridgeCreator, retryableSender } =
await deployL1TokenBridgeCreator(
l1Deployer,
parentDeployer,
l1Weth,
gasLimitForL2FactoryDeployment
)
Expand Down
33 changes: 33 additions & 0 deletions scripts/upgradeTemplate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { JsonRpcProvider } from '@ethersproject/providers'
import { L2AtomicTokenBridgeFactory__factory } from '../build/types'
import dotenv from 'dotenv'
import { Wallet } from 'ethers'

dotenv.config()

async function main() {
const deployRpc = process.env['BASECHAIN_RPC'] as string
if (deployRpc == undefined) {
throw new Error("Env var 'BASECHAIN_RPC' not set")
}
const rpc = new JsonRpcProvider(deployRpc)

const deployKey = process.env['BASECHAIN_DEPLOYER_KEY'] as string
if (deployKey == undefined) {
throw new Error("Env var 'BASECHAIN_DEPLOYER_KEY' not set")
}
const deployer = new Wallet(deployKey).connect(rpc)

console.log(
'Deploying L2AtomicTokenBridgeFactory to chain',
await deployer.getChainId()
)
const l2TokenBridgeFactory = await new L2AtomicTokenBridgeFactory__factory(
deployer
).deploy()
await l2TokenBridgeFactory.deployed()

console.log('l2TokenBridgeFactory:', l2TokenBridgeFactory.address)
}

main().then(() => console.log('Done.'))
Loading