Skip to content

Commit

Permalink
Merge pull request #59 from OffchainLabs/fix-verification
Browse files Browse the repository at this point in the history
fix: blockscout verification
  • Loading branch information
gzeoneth authored Dec 5, 2023
2 parents 280d518 + bf9ad3d commit f03619e
Show file tree
Hide file tree
Showing 11 changed files with 542 additions and 69 deletions.
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

0 comments on commit f03619e

Please sign in to comment.