Skip to content

Commit

Permalink
Merge pull request #15 from immutable/proxies-on-deployment
Browse files Browse the repository at this point in the history
[SMR-1772] Proxies on deployment
  • Loading branch information
Benjimmutable authored Nov 1, 2023
2 parents 57cb487 + ef30f6c commit 0b76195
Show file tree
Hide file tree
Showing 16 changed files with 218 additions and 137 deletions.
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
Expand All @@ -13,3 +10,6 @@
[submodule "lib/axelar-gmp-sdk-solidity"]
path = lib/axelar-gmp-sdk-solidity
url = https://github.com/axelarnetwork/axelar-gmp-sdk-solidity
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,4 @@ yarn run execute evm/call-contract local Ethereum Polygon deposit
source .env
cast call --rpc-url $CHILD_RPC_URL "0x3b39f73D7De57Ed2Fe85C0F30374D839dc625b93" "balanceOf(address)(uint256)" "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
```
(Note: This assumed your address if the one associated with the above-specified private key)
(Note: This assumes your address is the one associated with the above-specified private key)
6 changes: 3 additions & 3 deletions axelar-local-dev/chain-config/local.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"function mapToken(address rootToken) external payable returns (address)",
"function deposit(address rootToken, uint256 amount) external payable"
],
"address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"
"address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707"
},
"usdc": {
"abi": [
Expand Down Expand Up @@ -46,13 +46,13 @@
"rpc": "http://localhost:8500/1",
"contract": {
"abi": [],
"address": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9"
"address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853"
},
"contract2": {
"abi": [
"function rootTokenToChildToken(address rootToken) external view returns (address)"
],
"address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"
"address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707"
},
"usdc": {
"abi": [
Expand Down
6 changes: 3 additions & 3 deletions axelar-local-dev/chain-config/local.template.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"function mapToken(address rootToken) external payable returns (address)",
"function deposit(address rootToken, uint256 amount) external payable"
],
"address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"
"address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707"
},
"usdc": {
"abi": [
Expand Down Expand Up @@ -46,13 +46,13 @@
"rpc": "http://localhost:8500/1",
"contract": {
"abi": [],
"address": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9"
"address": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853"
},
"contract2": {
"abi": [
"function rootTokenToChildToken(address rootToken) external view returns (address)"
],
"address": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"
"address": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707"
},
"usdc": {
"abi": [
Expand Down
57 changes: 45 additions & 12 deletions deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,52 @@ function main() {
child_filename="broadcast/DeployChildContracts.s.sol/$CHILD_CHAIN_ID/run-latest.json"

# Extract smart contract addresses from deployments JSON
root_erc20_bridge=$( get_deployed_contract "$root_filename" "RootERC20Bridge" )
root_bridge_adaptor=$( get_deployed_contract "$root_filename" "RootAxelarBridgeAdaptor" )
root_proxies=$( get_deployed_contract "$root_filename" "TransparentUpgradeableProxy" )
root_erc20_bridge_implementation=$( get_deployed_contract "$root_filename" "RootERC20Bridge" )
root_bridge_adaptor_implementation=$( get_deployed_contract "$root_filename" "RootAxelarBridgeAdaptor" )
root_chain_child_token_template=$( get_deployed_contract "$root_filename" "ChildERC20" )
root_proxy_admin=$( get_deployed_contract "$root_filename" "ProxyAdmin" )

if [ "$ENVIRONMENT" = "local" ]; then
root_weth_contract=$( get_deployed_contract "$root_filename" "WETH" )
export ROOT_WETH_ADDRESS=$root_weth_contract
fi

child_erc20_bridge=$( get_deployed_contract "$child_filename" "ChildERC20Bridge" )
child_bridge_adaptor=$( get_deployed_contract "$child_filename" "ChildAxelarBridgeAdaptor" )
child_proxies=$( get_deployed_contract "$child_filename" "TransparentUpgradeableProxy" )
child_erc20_bridge_implementation=$( get_deployed_contract "$child_filename" "ChildERC20Bridge" )
child_bridge_adaptor_implementation=$( get_deployed_contract "$child_filename" "ChildAxelarBridgeAdaptor" )
child_chain_child_token_template=$( get_deployed_contract "$child_filename" "ChildERC20" )
child_proxy_admin=$( get_deployed_contract "$child_filename" "ProxyAdmin" )

export ROOT_ERC20_BRIDGE=$root_erc20_bridge
export ROOT_BRIDGE_ADAPTOR=$root_bridge_adaptor
# In the TransparentUpgradeableProxy contract, you have to query the storage slot directly.
implementation_storage_slot="0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"

while IFS= read -r proxy_address; do
implementation_slot_value=$(cast storage --rpc-url "$CHILD_RPC_URL" "$proxy_address" "$implementation_storage_slot")
implementation_address=$(cast parse-bytes32-address "$implementation_slot_value")
if [ "$implementation_address" = "$child_erc20_bridge_implementation" ]; then
child_erc20_bridge_proxy=$proxy_address
elif [ "$implementation_address" = "$child_bridge_adaptor_implementation" ]; then
child_bridge_adaptor_proxy=$proxy_address
fi
done <<< "$child_proxies"

while IFS= read -r proxy_address; do
implementation_slot_value=$(cast storage --rpc-url "$ROOT_RPC_URL" "$proxy_address" "$implementation_storage_slot")
implementation_address=$(cast parse-bytes32-address "$implementation_slot_value")
if [ "$implementation_address" = "$root_erc20_bridge_implementation" ]; then
root_erc20_bridge_proxy=$proxy_address
elif [ "$implementation_address" = "$root_bridge_adaptor_implementation" ]; then
root_bridge_adaptor_proxy=$proxy_address
fi
done <<< "$root_proxies"

export ROOT_ERC20_BRIDGE=$root_erc20_bridge_proxy
export ROOT_BRIDGE_ADAPTOR=$root_bridge_adaptor_proxy
export ROOTCHAIN_CHILD_TOKEN_TEMPLATE=$root_chain_child_token_template

export CHILD_BRIDGE_ADAPTOR=$child_bridge_adaptor
export CHILD_ERC20_BRIDGE=$child_erc20_bridge
export CHILD_BRIDGE_ADAPTOR=$child_bridge_adaptor_proxy
export CHILD_ERC20_BRIDGE=$child_erc20_bridge_proxy
export CHILDCHAIN_CHILD_TOKEN_TEMPLATE=$child_chain_child_token_template

forge script script/InitializeRootContracts.s.sol:InitializeRootContracts --broadcast --ffi
Expand All @@ -48,12 +75,18 @@ function main() {
# Write JSON file with contract addresses
echo "{
\"root_chain_id\": \"$ROOT_CHAIN_ID\",
\"root_bridge\": \"$root_erc20_bridge\",
\"root_bridge_adaptor\": \"$root_bridge_adaptor\",
\"root_proxy_admin_address\": \"$root_proxy_admin\",
\"root_bridge_proxy_address\": \"$root_erc20_bridge_proxy\",
\"root_bridge_implementation_address\": \"$root_erc20_bridge_implementation\",
\"root_bridge_adaptor_proxy_address\": \"$root_bridge_adaptor_proxy\",
\"root_bridge_adaptor_implementation_address\": \"$root_bridge_adaptor_implementation\",
\"root_chain_child_token_template\": \"$root_chain_child_token_template\",
\"child_chain_id\": \"$CHILD_CHAIN_ID\",
\"child_bridge_address\": \"$child_erc20_bridge\",
\"child_bridge_adaptor\": \"$child_bridge_adaptor\",
\"child_proxy_admin_address\": \"$child_proxy_admin\",
\"child_bridge_proxy_address\": \"$child_erc20_bridge_proxy\",
\"child_bridge_implementation_address\": \"$child_erc20_bridge_implementation\",
\"child_bridge_proxy_adaptor\": \"$child_bridge_adaptor_proxy\",
\"child_bridge_adaptor_implementation_address\": \"$child_bridge_adaptor_implementation\",
\"child_chain_child_token_template\": \"$child_chain_child_token_template\"
}" | jq . > addresses.json

Expand Down
35 changes: 27 additions & 8 deletions script/DeployChildContracts.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ pragma solidity ^0.8.21;

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 {ChildAxelarBridgeAdaptor} from "../src/child/ChildAxelarBridgeAdaptor.sol";
import {ChildERC20} from "../src/child/ChildERC20.sol";
Expand All @@ -14,29 +17,45 @@ contract DeployChildContracts is Script {
function run() public {
uint256 deployerPrivateKey = vm.envUint("CHILD_PRIVATE_KEY");
address childGateway = vm.envAddress("CHILD_GATEWAY_ADDRESS");
//address childGasService = vm.envAddress("CHILD_GAS_SERVICE_ADDRESS"); // Not yet used.
string memory childRpcUrl = vm.envString("CHILD_RPC_URL");

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

ProxyAdmin proxyAdmin = new ProxyAdmin();

ChildERC20 childTokenTemplate = new ChildERC20();
childTokenTemplate.initialize(address(123), "TEMPLATE", "TPT", 18);

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

TransparentUpgradeableProxy childERC20BridgeProxy = new TransparentUpgradeableProxy(
address(childERC20BridgeImplementation),
address(proxyAdmin),
""
);

ChildAxelarBridgeAdaptor childBridgeAdaptorImplementation = new ChildAxelarBridgeAdaptor(
childGateway
);

ChildAxelarBridgeAdaptor childBridgeAdaptor = new ChildAxelarBridgeAdaptor(
childGateway, // child gateway
address(childBridge) // child bridge
TransparentUpgradeableProxy childBridgeAdaptorProxy = new TransparentUpgradeableProxy(
address(childBridgeAdaptorImplementation),
address(proxyAdmin),
""
);

WIMX wrappedIMX = new WIMX();

vm.stopBroadcast();

console2.log("====ADDRESSES====");
console2.log("Child ERC20 Bridge: %s", address(childBridge));
console2.log("Child Axelar Bridge Adaptor: %s", address(childBridgeAdaptor));
console2.log("====CHILD ADDRESSES====");
console2.log("ProxyAdmin: %", address(proxyAdmin));
console2.log("Child ERC20 Bridge Proxy: %s", address(childERC20BridgeProxy));
console2.log("Child ERC20 Bridge Implementation: %s", address(childERC20BridgeImplementation));
console2.log("Child Axelar Bridge Adaptor Proxy: %s", address(childBridgeAdaptorProxy));
console2.log("Child Axelar Bridge Adaptor Implementation: %s", address(childBridgeAdaptorImplementation));
console2.log("childTokenTemplate: %s", address(childTokenTemplate));
console2.log("Wrapped IMX: %s", address(wrappedIMX));
}
Expand Down
38 changes: 27 additions & 11 deletions script/DeployRootContracts.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ pragma solidity ^0.8.21;

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 {RootAxelarBridgeAdaptor} from "../src/root/RootAxelarBridgeAdaptor.sol";
Expand All @@ -17,9 +20,6 @@ contract DeployRootContracts is Script {
function run() public {
uint256 rootPrivateKey = vm.envUint("ROOT_PRIVATE_KEY");
string memory rootRpcUrl = vm.envString("ROOT_RPC_URL");
address rootGateway = vm.envAddress("ROOT_GATEWAY_ADDRESS");
address rootGasService = vm.envAddress("ROOT_GAS_SERVICE_ADDRESS");
string memory childChainName = vm.envString("CHILD_CHAIN_NAME");
string memory deployEnvironment = vm.envString("ENVIRONMENT");

/**
Expand All @@ -28,17 +28,30 @@ contract DeployRootContracts is Script {
vm.createSelectFork(rootRpcUrl);
vm.startBroadcast(rootPrivateKey);

ProxyAdmin proxyAdmin = new ProxyAdmin();

// The ChildERC20 deployment on the root chain.
ChildERC20 rootChainChildTokenTemplate = new ChildERC20();
rootChainChildTokenTemplate.initialize(address(123), "TEMPLATE", "TPT", 18);

RootERC20Bridge rootERC20Bridge = new RootERC20Bridge();
RootERC20Bridge rootERC20BridgeImplementation = new RootERC20Bridge();
rootERC20BridgeImplementation.initialize(address(1), address(1), "filler", address(1), address(1), address(1));
TransparentUpgradeableProxy rootERC20BridgeProxy = new TransparentUpgradeableProxy(
address(rootERC20BridgeImplementation),
address(proxyAdmin),
""
);

RootAxelarBridgeAdaptor rootBridgeAdaptor = new RootAxelarBridgeAdaptor(
address(rootERC20Bridge), // root bridge
childChainName, // child chain name
rootGateway, // axelar gateway
rootGasService // axelar gas service
// TODO add dummy initialize of implementation contracts!

RootAxelarBridgeAdaptor rootBridgeAdaptorImplementation = new RootAxelarBridgeAdaptor();
rootBridgeAdaptorImplementation.initialize(
address(rootERC20BridgeImplementation), "Filler", address(1), address(1)
);
TransparentUpgradeableProxy rootBridgeAdaptorProxy = new TransparentUpgradeableProxy(
address(rootBridgeAdaptorImplementation),
address(proxyAdmin),
""
);

if (Strings.equal(deployEnvironment, "local")) {
Expand All @@ -48,8 +61,11 @@ contract DeployRootContracts is Script {
vm.stopBroadcast();

console2.log("====ROOT ADDRESSES====");
console2.log("Root ERC20 Bridge: %s", address(rootERC20Bridge));
console2.log("Root Axelar Bridge Adaptor: %s", address(rootBridgeAdaptor));
console2.log("ProxyAdmin: %", address(proxyAdmin));
console2.log("Root ERC20 Bridge Proxy: %s", address(rootERC20BridgeProxy));
console2.log("Root ERC20 Bridge Implementation: %s", address(rootERC20BridgeImplementation));
console2.log("Root Axelar Bridge Adaptor Proxy: %s", address(rootBridgeAdaptorProxy));
console2.log("Root Axelar Bridge Adaptor Implementation: %s", address(rootBridgeAdaptorImplementation));
console2.log("ROOT CHAIN childTokenTemplate: %s", address(rootChainChildTokenTemplate));
}
}
2 changes: 1 addition & 1 deletion script/InitializeChildContracts.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ contract InitializeChildContracts is Script {
address(childAxelarBridgeAdaptor), rootBridgeAdaptorString, childTokenTemplate, rootChainName, rootIMXToken
);

childAxelarBridgeAdaptor.setRootBridgeAdaptor();
childAxelarBridgeAdaptor.initialize(address(childERC20Bridge));

vm.stopBroadcast();
}
Expand Down
66 changes: 45 additions & 21 deletions script/InitializeRootContracts.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,63 @@ 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 {
RootERC20Bridge rootERC20Bridge;
RootAxelarBridgeAdaptor rootBridgeAdaptor;
address rootChainChildTokenTemplate;
address childBridgeAdaptor;
address childERC20Bridge;
string rootRpcUrl;
uint256 rootPrivateKey;
address rootIMXToken;
address rootWETHToken;
string childChainName;
address rootGateway;
address rootGasService;
}

contract InitializeRootContracts is Script {
function run() public {
RootERC20Bridge rootERC20Bridge = RootERC20Bridge(payable(vm.envAddress("ROOT_ERC20_BRIDGE")));
RootAxelarBridgeAdaptor rootBridgeAdaptor = RootAxelarBridgeAdaptor(vm.envAddress("ROOT_BRIDGE_ADAPTOR"));
address rootChainChildTokenTemplate = vm.envAddress("ROOTCHAIN_CHILD_TOKEN_TEMPLATE");
address childBridgeAdaptor = vm.envAddress("CHILD_BRIDGE_ADAPTOR");
address childERC20Bridge = vm.envAddress("CHILD_ERC20_BRIDGE");
string memory rootRpcUrl = vm.envString("ROOT_RPC_URL");
uint256 rootPrivateKey = vm.envUint("ROOT_PRIVATE_KEY");
address rootIMXToken = vm.envAddress("ROOT_IMX_ADDRESS");
address rootWETHToken = vm.envAddress("ROOT_WETH_ADDRESS");

string[] memory checksumInputs = Utils.getChecksumInputs(childBridgeAdaptor);
InitializeRootContractsParams memory params = InitializeRootContractsParams({
rootERC20Bridge: RootERC20Bridge(payable(vm.envAddress("ROOT_ERC20_BRIDGE"))),
rootBridgeAdaptor: RootAxelarBridgeAdaptor(vm.envAddress("ROOT_BRIDGE_ADAPTOR")),
rootChainChildTokenTemplate: vm.envAddress("ROOTCHAIN_CHILD_TOKEN_TEMPLATE"),
childBridgeAdaptor: vm.envAddress("CHILD_BRIDGE_ADAPTOR"),
childERC20Bridge: vm.envAddress("CHILD_ERC20_BRIDGE"),
rootRpcUrl: vm.envString("ROOT_RPC_URL"),
rootPrivateKey: vm.envUint("ROOT_PRIVATE_KEY"),
rootIMXToken: vm.envAddress("ROOT_IMX_ADDRESS"),
rootWETHToken: vm.envAddress("ROOT_WETH_ADDRESS"),
childChainName: vm.envString("CHILD_CHAIN_NAME"),
rootGateway: vm.envAddress("ROOT_GATEWAY_ADDRESS"),
rootGasService: vm.envAddress("ROOT_GAS_SERVICE_ADDRESS")
});

string[] memory checksumInputs = Utils.getChecksumInputs(params.childBridgeAdaptor);
bytes memory checksumOutput = vm.ffi(checksumInputs);
string memory childBridgeAdaptorChecksum = string(Utils.removeZeroByteValues(checksumOutput));
/**
* INITIALIZE ROOT CHAIN CONTRACTS
*/
vm.createSelectFork(rootRpcUrl);
vm.startBroadcast(rootPrivateKey);
vm.createSelectFork(params.rootRpcUrl);
vm.startBroadcast(params.rootPrivateKey);

rootERC20Bridge.initialize(
address(rootBridgeAdaptor),
childERC20Bridge,
params.rootERC20Bridge.initialize(
address(params.rootBridgeAdaptor),
params.childERC20Bridge,
childBridgeAdaptorChecksum,
rootChainChildTokenTemplate,
rootIMXToken,
rootWETHToken
params.rootChainChildTokenTemplate,
params.rootIMXToken,
params.rootWETHToken
);

rootBridgeAdaptor.setChildBridgeAdaptor();
params.rootBridgeAdaptor.initialize(
address(params.rootERC20Bridge), // root bridge
params.childChainName, // child chain name
params.rootGateway, // axelar gateway
params.rootGasService // axelar gas service
);

vm.stopBroadcast();
console2.log(rootERC20Bridge.childBridgeAdaptor());
}
}
Loading

0 comments on commit 0b76195

Please sign in to comment.