Skip to content

Commit

Permalink
Merge pull request #23 from immutable/smr-1910-rbac
Browse files Browse the repository at this point in the history
Smr 1910 rbac
  • Loading branch information
wcgcyx authored Nov 13, 2023
2 parents 95ddd11 + 7695c60 commit 81697c0
Show file tree
Hide file tree
Showing 53 changed files with 763 additions and 165 deletions.
20 changes: 14 additions & 6 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
ROOT_ADMIN_ADDRESS=
ROOT_PAUSER_ADDRESS=
ROOT_UNPAUSER_ADDRESS=
ROOT_RPC_URL=
CHILD_RPC_URL=
ROOT_CHAIN_ID=
CHILD_CHAIN_ID=
ROOT_PRIVATE_KEY=
CHILD_PRIVATE_KEY=
ROOT_GATEWAY_ADDRESS=
CHILD_GATEWAY_ADDRESS=
ROOT_GAS_SERVICE_ADDRESS=
CHILD_GAS_SERVICE_ADDRESS=
ROOT_CHAIN_NAME=
CHILD_CHAIN_NAME=
ROOT_IMX_ADDRESS=
ROOT_WETH_ADDRESS=
INITIAL_IMX_CUMULATIVE_DEPOSIT_LIMIT= # 0 for unlimited

CHILD_ADMIN_ADDRESS=
CHILD_PAUSER_ADDRESS=
CHILD_UNPAUSER_ADDRESS=
CHILD_RPC_URL=
CHILD_CHAIN_ID=
CHILD_PRIVATE_KEY=
CHILD_GATEWAY_ADDRESS=
CHILD_GAS_SERVICE_ADDRESS=
CHILD_CHAIN_NAME=
ENVIRONMENT=
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ yarn run execute evm/call-contract local Ethereum Polygon map
5. (OPTIONAL) Check the token mapping has been populated using `cast`
```shell
source .env
cast call --rpc-url $CHILD_RPC_URL "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" "rootTokenToChildToken(address)(address)" "0x38Aa1Cb12E5263eC0c6e9febC25B01116D346CD4"
cast call --rpc-url $CHILD_RPC_URL "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" "rootTokenToChildToken(address)(address)" "0x38Aa1Cb12E5263eC0c6e9febC25B01116D346CD4"
```

6. Run the script that will send a `DEPOSIT` message
Expand All @@ -172,6 +172,6 @@ yarn run execute evm/call-contract local Ethereum Polygon deposit
7. (OPTIONAL) Check the tokens have been deposited using `cast`
```shell
source .env
cast call --rpc-url $CHILD_RPC_URL "0x3b39f73D7De57Ed2Fe85C0F30374D839dc625b93" "balanceOf(address)(uint256)" "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
cast call --rpc-url $CHILD_RPC_URL "0xa03647137120b00cae83751A82280A67df027F04" "balanceOf(address)(uint256)" "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
```
(Note: This assumes your address is the one associated with the above-specified private key)
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
src = "src"
out = "out"
libs = ["lib"]
solc-version = "0.8.19"

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
14 changes: 11 additions & 3 deletions script/DeployChildContracts.s.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.21;
pragma solidity 0.8.19;

import {Script, console2} from "forge-std/Script.sol";

import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

import {ChildERC20Bridge} from "../src/child/ChildERC20Bridge.sol";
import {ChildERC20Bridge, IChildERC20Bridge} from "../src/child/ChildERC20Bridge.sol";
import {ChildAxelarBridgeAdaptor} from "../src/child/ChildAxelarBridgeAdaptor.sol";
import {ChildERC20} from "../src/child/ChildERC20.sol";
import {WIMX} from "../src/child/WIMX.sol";
Expand All @@ -27,8 +27,16 @@ contract DeployChildContracts is Script {
ChildERC20 childTokenTemplate = new ChildERC20();
childTokenTemplate.initialize(address(123), "TEMPLATE", "TPT", 18);

IChildERC20Bridge.InitializationRoles memory roles = IChildERC20Bridge.InitializationRoles({
defaultAdmin: address(0x1111),
pauser: address(0x2222),
unpauser: address(0x3333),
variableManager: address(0x4444),
adaptorManager: address(0x5555)
});

ChildERC20Bridge childERC20BridgeImplementation = new ChildERC20Bridge();
childERC20BridgeImplementation.initialize(address(1), "0x123", address(1), "root", address(1));
childERC20BridgeImplementation.initialize(roles, address(1), "0x123", address(1), "root", address(1));

TransparentUpgradeableProxy childERC20BridgeProxy = new TransparentUpgradeableProxy(
address(childERC20BridgeImplementation),
Expand Down
9 changes: 6 additions & 3 deletions script/DeployRootContracts.s.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.21;
pragma solidity 0.8.19;

import {Script, console2} from "forge-std/Script.sol";

import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

import {ChildERC20} from "../src/child/ChildERC20.sol";
import {RootERC20Bridge} from "../src/root/RootERC20Bridge.sol";
import {RootERC20Bridge, IRootERC20Bridge} from "../src/root/RootERC20Bridge.sol";
import {RootAxelarBridgeAdaptor} from "../src/root/RootAxelarBridgeAdaptor.sol";
import {ChildERC20Bridge} from "../src/child/ChildERC20Bridge.sol";
import {ChildAxelarBridgeAdaptor} from "../src/child/ChildAxelarBridgeAdaptor.sol";
Expand Down Expand Up @@ -35,9 +35,12 @@ contract DeployRootContracts is Script {
ChildERC20 rootChainChildTokenTemplate = new ChildERC20();
rootChainChildTokenTemplate.initialize(address(123), "TEMPLATE", "TPT", 18);

IRootERC20Bridge.InitializationRoles memory fillerRoles =
IRootERC20Bridge.InitializationRoles(address(1), address(1), address(1), address(1), address(1));

RootERC20Bridge rootERC20BridgeImplementation = new RootERC20Bridge();
rootERC20BridgeImplementation.initialize(
address(1), address(1), "filler", address(1), address(1), address(1), "filler_child_name", 1
fillerRoles, address(1), address(1), "filler", address(1), address(1), address(1), "filler_child_name", 1
);
TransparentUpgradeableProxy rootERC20BridgeProxy = new TransparentUpgradeableProxy(
address(rootERC20BridgeImplementation),
Expand Down
70 changes: 52 additions & 18 deletions script/InitializeChildContracts.s.sol
Original file line number Diff line number Diff line change
@@ -1,42 +1,76 @@
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.21;
pragma solidity 0.8.19;

import {Script, console2} from "forge-std/Script.sol";

import {ChildERC20Bridge} from "../src/child/ChildERC20Bridge.sol";
import {ChildERC20Bridge, IChildERC20Bridge} from "../src/child/ChildERC20Bridge.sol";
import {ChildAxelarBridgeAdaptor} from "../src/child/ChildAxelarBridgeAdaptor.sol";
import {Utils} from "./Utils.sol";

// TODO update private key usage to be more secure: https://book.getfoundry.sh/reference/forge/forge-script#wallet-options---raw

struct InitializeChildContractsParams {
address childAdminAddress;
address childPauserAddress;
address childUnpauserAddress;
ChildERC20Bridge childERC20Bridge;
ChildAxelarBridgeAdaptor childAxelarBridgeAdaptor;
address childTokenTemplate;
address rootERC20BridgeAdaptor;
string rootChainName;
address rootIMXToken;
string childRpcUrl;
uint256 deployerPrivateKey;
address childGasService;
}

contract InitializeChildContracts is Script {
function run() public {
uint256 deployerPrivateKey = vm.envUint("CHILD_PRIVATE_KEY");
ChildERC20Bridge childERC20Bridge = ChildERC20Bridge(vm.envAddress("CHILD_ERC20_BRIDGE"));
ChildAxelarBridgeAdaptor childAxelarBridgeAdaptor =
ChildAxelarBridgeAdaptor(vm.envAddress("CHILD_BRIDGE_ADAPTOR"));
address childTokenTemplate = vm.envAddress("CHILDCHAIN_CHILD_TOKEN_TEMPLATE");
address rootERC20BridgeAdaptor = vm.envAddress("ROOT_BRIDGE_ADAPTOR");
string memory childRpcUrl = vm.envString("CHILD_RPC_URL");
string memory rootChainName = vm.envString("ROOT_CHAIN_NAME");
address rootIMXToken = vm.envAddress("ROOT_IMX_ADDRESS");
address childGasService = vm.envAddress("CHILD_GAS_SERVICE_ADDRESS"); // Not yet used.
InitializeChildContractsParams memory params = InitializeChildContractsParams({
childAdminAddress: vm.envAddress("CHILD_ADMIN_ADDRESS"),
childPauserAddress: vm.envAddress("CHILD_PAUSER_ADDRESS"),
childUnpauserAddress: vm.envAddress("CHILD_UNPAUSER_ADDRESS"),
childERC20Bridge: ChildERC20Bridge(vm.envAddress("CHILD_ERC20_BRIDGE")),
childAxelarBridgeAdaptor: ChildAxelarBridgeAdaptor(vm.envAddress("CHILD_BRIDGE_ADAPTOR")),
childTokenTemplate: vm.envAddress("CHILDCHAIN_CHILD_TOKEN_TEMPLATE"),
rootERC20BridgeAdaptor: vm.envAddress("ROOT_BRIDGE_ADAPTOR"),
rootChainName: vm.envString("ROOT_CHAIN_NAME"),
rootIMXToken: vm.envAddress("ROOT_IMX_ADDRESS"),
childRpcUrl: vm.envString("CHILD_RPC_URL"),
deployerPrivateKey: vm.envUint("CHILD_PRIVATE_KEY"),
childGasService: vm.envAddress("CHILD_GAS_SERVICE_ADDRESS")
});

/**
* INITIALIZE CHILD CONTRACTS
*/
string[] memory checksumInputs = Utils.getChecksumInputs(rootERC20BridgeAdaptor);
string[] memory checksumInputs = Utils.getChecksumInputs(params.rootERC20BridgeAdaptor);
bytes memory checksumOutput = vm.ffi(checksumInputs);
string memory rootBridgeAdaptorString = string(Utils.removeZeroByteValues(checksumOutput));

vm.createSelectFork(childRpcUrl);
vm.startBroadcast(deployerPrivateKey);
vm.createSelectFork(params.childRpcUrl);
vm.startBroadcast(params.deployerPrivateKey);

childERC20Bridge.initialize(
address(childAxelarBridgeAdaptor), rootBridgeAdaptorString, childTokenTemplate, rootChainName, rootIMXToken
// TODO update
IChildERC20Bridge.InitializationRoles memory roles = IChildERC20Bridge.InitializationRoles({
defaultAdmin: params.childAdminAddress,
pauser: params.childPauserAddress,
unpauser: params.childUnpauserAddress,
variableManager: params.childAdminAddress,
adaptorManager: params.childAdminAddress
});
params.childERC20Bridge.initialize(
roles,
address(params.childAxelarBridgeAdaptor),
rootBridgeAdaptorString,
params.childTokenTemplate,
params.rootChainName,
params.rootIMXToken
);

childAxelarBridgeAdaptor.initialize(rootChainName, address(childERC20Bridge), childGasService);
params.childAxelarBridgeAdaptor.initialize(
params.rootChainName, address(params.childERC20Bridge), params.childGasService
);

vm.stopBroadcast();
}
Expand Down
21 changes: 19 additions & 2 deletions script/InitializeRootContracts.s.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.21;
pragma solidity 0.8.19;

import {Script, console2} from "forge-std/Script.sol";

import {ChildERC20} from "../src/child/ChildERC20.sol";
import {RootERC20Bridge} from "../src/root/RootERC20Bridge.sol";
import {RootERC20Bridge, IRootERC20Bridge} from "../src/root/RootERC20Bridge.sol";
import {RootAxelarBridgeAdaptor} from "../src/root/RootAxelarBridgeAdaptor.sol";
import {ChildERC20Bridge} from "../src/child/ChildERC20Bridge.sol";
import {ChildAxelarBridgeAdaptor} from "../src/child/ChildAxelarBridgeAdaptor.sol";
Expand All @@ -14,6 +14,9 @@ import {Utils} from "./Utils.sol";
// TODO update private key usage to be more secure: https://book.getfoundry.sh/reference/forge/forge-script#wallet-options---raw

struct InitializeRootContractsParams {
address rootAdminAddress;
address rootPauserAddress;
address rootUnpauserAddress;
RootERC20Bridge rootERC20Bridge;
RootAxelarBridgeAdaptor rootBridgeAdaptor;
address rootChainChildTokenTemplate;
Expand All @@ -31,6 +34,9 @@ struct InitializeRootContractsParams {
contract InitializeRootContracts is Script {
function run() public {
InitializeRootContractsParams memory params = InitializeRootContractsParams({
rootAdminAddress: vm.envAddress("ROOT_ADMIN_ADDRESS"),
rootPauserAddress: vm.envAddress("ROOT_PAUSER_ADDRESS"),
rootUnpauserAddress: vm.envAddress("ROOT_UNPAUSER_ADDRESS"),
rootERC20Bridge: RootERC20Bridge(payable(vm.envAddress("ROOT_ERC20_BRIDGE"))),
rootBridgeAdaptor: RootAxelarBridgeAdaptor(vm.envAddress("ROOT_BRIDGE_ADAPTOR")),
rootChainChildTokenTemplate: vm.envAddress("ROOTCHAIN_CHILD_TOKEN_TEMPLATE"),
Expand All @@ -54,7 +60,18 @@ contract InitializeRootContracts is Script {
vm.createSelectFork(params.rootRpcUrl);
vm.startBroadcast(params.rootPrivateKey);

// TODO add pauser, unpauser roles. variable manager and Adaptor manager will be privileged transaction multisg

IRootERC20Bridge.InitializationRoles memory roles = IRootERC20Bridge.InitializationRoles({
defaultAdmin: params.rootAdminAddress,
pauser: params.rootPauserAddress,
unpauser: params.rootUnpauserAddress,
variableManager: params.rootAdminAddress,
adaptorManager: params.rootAdminAddress
});

params.rootERC20Bridge.initialize(
roles,
address(params.rootBridgeAdaptor),
params.childERC20Bridge,
childBridgeAdaptorChecksum,
Expand Down
2 changes: 1 addition & 1 deletion script/Utils.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.21;
pragma solidity 0.8.19;

import {AddressToString} from "@axelar-gmp-sdk-solidity/contracts/libs/AddressString.sol";

Expand Down
2 changes: 1 addition & 1 deletion src/child/ChildAxelarBridgeAdaptor.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.21;
pragma solidity 0.8.19;

import {AxelarExecutable} from "@axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol";
import {IAxelarGasService} from "@axelar-cgp-solidity/contracts/interfaces/IAxelarGasService.sol";
Expand Down
2 changes: 1 addition & 1 deletion src/child/ChildERC20.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache 2.0
// Adapted from OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.21;
pragma solidity 0.8.19;

import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "../lib/EIP712MetaTransaction.sol";
Expand Down
42 changes: 34 additions & 8 deletions src/child/ChildERC20Bridge.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.21;
pragma solidity 0.8.19;

import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {
IChildERC20BridgeEvents,
IChildERC20BridgeErrors,
Expand All @@ -25,8 +24,7 @@ import {IChildERC20} from "../interfaces/child/IChildERC20.sol";
* @dev Any checks or logic that is specific to the underlying messaging protocol should be done in the bridge adaptor.
*/
contract ChildERC20Bridge is
Ownable2Step,
Initializable,
AccessControlUpgradeable, // AccessControlUpgradeable inherits Initializable
IChildERC20BridgeErrors,
IChildERC20Bridge,
IChildERC20BridgeEvents
Expand All @@ -36,6 +34,14 @@ contract ChildERC20Bridge is
/// @dev leave this as the first param for the integration tests
mapping(address => address) public rootTokenToChildToken;

/**
* ROLES
*/
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant UNPAUSER_ROLE = keccak256("UNPAUSER_ROLE");
bytes32 public constant VARIABLE_MANAGER_ROLE = keccak256("VARIABLE_MANAGER_ROLE");
bytes32 public constant ADAPTOR_MANAGER_ROLE = keccak256("ADAPTOR_MANAGER_ROLE");

bytes32 public constant MAP_TOKEN_SIG = keccak256("MAP_TOKEN");
bytes32 public constant DEPOSIT_SIG = keccak256("DEPOSIT");
bytes32 public constant WITHDRAW_SIG = keccak256("WITHDRAW");
Expand All @@ -56,7 +62,8 @@ contract ChildERC20Bridge is
address public childETHToken;

/**
* @notice Initilization function for RootERC20Bridge.
* @notice Initialization function for ChildERC20Bridge.
* @param newRoles Struct containing addresses of roles.
* @param newBridgeAdaptor Address of StateSender to send deposit information to.
* @param newRootERC20BridgeAdaptor Stringified address of root ERC20 bridge adaptor to communicate with.
* @param newChildTokenTemplate Address of child token template to clone.
Expand All @@ -65,13 +72,18 @@ contract ChildERC20Bridge is
* @dev Can only be called once.
*/
function initialize(
InitializationRoles memory newRoles,
address newBridgeAdaptor,
string memory newRootERC20BridgeAdaptor,
address newChildTokenTemplate,
string memory newRootChain,
address newRootIMXToken
) public initializer {
if (newBridgeAdaptor == address(0) || newChildTokenTemplate == address(0) || newRootIMXToken == address(0)) {
if (
newBridgeAdaptor == address(0) || newChildTokenTemplate == address(0) || newRootIMXToken == address(0)
|| newRoles.defaultAdmin == address(0) || newRoles.pauser == address(0) || newRoles.unpauser == address(0)
|| newRoles.variableManager == address(0) || newRoles.adaptorManager == address(0)
) {
revert ZeroAddress();
}

Expand All @@ -83,6 +95,14 @@ contract ChildERC20Bridge is
revert InvalidRootChain();
}

__AccessControl_init();

_grantRole(DEFAULT_ADMIN_ROLE, newRoles.defaultAdmin);
_grantRole(PAUSER_ROLE, newRoles.pauser);
_grantRole(UNPAUSER_ROLE, newRoles.unpauser);
_grantRole(VARIABLE_MANAGER_ROLE, newRoles.variableManager);
_grantRole(ADAPTOR_MANAGER_ROLE, newRoles.adaptorManager);

rootERC20BridgeAdaptor = newRootERC20BridgeAdaptor;
childTokenTemplate = newChildTokenTemplate;
bridgeAdaptor = IChildERC20BridgeAdaptor(newBridgeAdaptor);
Expand Down Expand Up @@ -281,7 +301,13 @@ contract ChildERC20Bridge is
}
}

function updateBridgeAdaptor(address newBridgeAdaptor) external override onlyOwner {
/**
* @inheritdoc IChildERC20Bridge
*/
function updateBridgeAdaptor(address newBridgeAdaptor) external override {
if (!(hasRole(ADAPTOR_MANAGER_ROLE, msg.sender))) {
revert NotVariableManager(msg.sender);
}
if (newBridgeAdaptor == address(0)) {
revert ZeroAddress();
}
Expand Down
2 changes: 1 addition & 1 deletion src/child/WIMX.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.21;
pragma solidity 0.8.19;

import {IWIMX} from "../interfaces/child/IWIMX.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/child/IChildAxelarBridgeAdaptor.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.21;
pragma solidity 0.8.19;

interface IChildAxelarBridgeAdaptorErrors {
/// @notice Error when a zero address is given when not valid.
Expand Down
Loading

0 comments on commit 81697c0

Please sign in to comment.