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

feat: QoL changes Create3 + foundry.toml #138

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 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
9 changes: 5 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# anvil --port 8646 or via docker compose up in eth-pos-devnet
CLIENT_CHAIN_RPC=http://localhost:8646
EXOCORE_TESETNET_RPC=http://localhost:8545
EXOCORE_TESTNET_RPC=http://localhost:8545
EXOCORE_LOCAL_RPC=http://localhost:8545
# The following are default Anvil keys - not real keys!
TEST_ACCOUNT_ONE_PRIVATE_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
Expand All @@ -10,13 +10,14 @@ TEST_ACCOUNT_FOUR_PRIVATE_KEY=0x7c852118294e51e653712a81e05800f419141751be58f605
# Use 'exocored keys unsafe-export-eth-key "dev0" --home ~/.tmp-exocored' to get the privatekey
EXOCORE_GENESIS_PRIVATE_KEY=0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a

USE_ENDPOINT_MOCK=true
USE_EXOCORE_PRECOMPILE_MOCK=true
USE_ENDPOINT_MOCK=false
USE_EXOCORE_PRECOMPILE_MOCK=false

# For contract verification
ETHERSCAN_API_KEY=
EXOCORE_TESTNET_EXPLORER=

# These are used for integration testing the Bootstrap contract, in addition to
# These are used for integration testing the Bootstrap contract, in addition to
# CLIENT_CHAIN_RPC and BEACON_CHAIN_ENDPOINT above.
INTEGRATION_VALIDATOR_KEYS=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80,0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d,0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
INTEGRATION_STAKERS=0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6,0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a,0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba,0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e,0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356,0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97,0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6
Expand Down
13 changes: 10 additions & 3 deletions .github/workflows/forge-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,17 @@ jobs:
./cache
./broadcast
key: build-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}
- name: Test
run: forge test -vvv
- name: Clear out the `etherscan` section in `foundry.toml` for missing env vars
run: sed -i '/\[etherscan\]/,/^\[/ s/^/#/' foundry.toml
- name: Run tests
env:
FOUNDRY_PROFILE: test
run: forge test
- name: Set test snapshot as summary
run: NO_COLOR=1 forge snapshot >> $GITHUB_STEP_SUMMARY
env:
FOUNDRY_PROFILE: test
NO_COLOR: 1
run: forge snapshot >> "$GITHUB_STEP_SUMMARY"

format:
# Takes less than 30s
Expand Down
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Makefile for Foundry commands

# Variables
FOUNDRY_PROFILE=test

# Targets
.PHONY: test build fmt

test:
FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) forge test -vvv

build:
forge build

fmt:
forge fmt
33 changes: 28 additions & 5 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,40 @@ ignored_warnings_from = ["script", "test"]
# fail compilation if the warnings are not fixed.
# this is super useful for the code size warning.
deny_warnings = true
# for tests, use the mainnet chain_id for NetworkConstants to work.
chain_id = 1

[rpc_endpoints]
ethereum_local_rpc = "${ETHEREUM_LOCAL_RPC}"
exocore_local_rpc = "${EXOCORE_LOCAL_RPC}"
[profile.test]
# for tests, use the Eth mainnet chain_id for NetworkConstants to work.
# do not specify this in the default profile to pacify forge script
# running on non-Eth mainnet chains.
chain_id = 1

[fmt]
number_underscore = "thousands"
sort_imports = true
wrap_comments = true
single_line_statement_blocks = "multi"
contract_new_lines = true

[rpc_endpoints]
# We do not distinguish between Holesky / Sepolia / mainnet here, since that is
# handled within the scripts as an environment variable. This is more of a convenience
# mechanism to specify the chain name via command line; for example:
# cast balance $ADDRESS --rpc-url client
client = "${CLIENT_CHAIN_RPC}"
exocore_local = "${EXOCORE_LOCAL_RPC}"
exocore_testnet = "${EXOCORE_TESTNET_RPC}"

[etherscan]
# Similar shortcut as `rpc_endpoints` to verify contracts by name and not URL.
# Example:
# forge verify-contract --etherscan-api-key exocore_testnet <...usual args...>
# However, defining this section with these env vars makes `forge test` complain
# if they are missing. It is because it tries to fetch debugging context from
# the block explorer. To avoid this, either ensure these vars are set, or comment
# out this section.
mainnet = { key = "${ETHERSCAN_API_KEY}" }
sepolia = { key = "${ETHERSCAN_API_KEY}" }
holesky = { key = "${ETHERSCAN_API_KEY}" }
exocore_testnet = { key = "${ETHERSCAN_API_KEY}", chain = 233, url = "${EXOCORE_TESTNET_EXPLORER_API}" }

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
3 changes: 1 addition & 2 deletions script/12_RedeployClientChainGateway.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,8 @@ contract RedeployClientChainGateway is BaseScript {
new ClientChainGateway(address(clientChainLzEndpoint), config, address(rewardVaultBeacon));

// then the client chain initialization
address[] memory emptyList;
bytes memory initialization =
abi.encodeWithSelector(clientGatewayLogic.initialize.selector, exocoreValidatorSet.addr, emptyList);
abi.encodeWithSelector(clientGatewayLogic.initialize.selector, exocoreValidatorSet.addr);
bootstrap.setClientChainGatewayLogic(address(clientGatewayLogic), initialization);
vm.stopBroadcast();

Expand Down
81 changes: 81 additions & 0 deletions script/20_DeployCreate3.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "forge-std/Script.sol";

/// @title DeployCreate3
/// @author ExocoreNetwork
/// @notice This script is used to deploy the deterministic Create2 and Create3 factories to any network.
/// The Create2 factory is deployed using a raw transaction and the Create3 factory is deployed using a Create2 call.
/// @dev The advantage of using the Create3 factory over the Create2 factory for further deployments is that the
/// contract address for Create3-deployments is only dependent on the salt and the sender and not the code. This allows
/// for omni-chain deployments at the same address regardless of the contract code version that is deployed.
contract DeployCreate3 is Script {

// Unfortunately this is a pre-EIP155 transaction, so it will not work on most chains (which have blocked them).
// In that case, such a chain should add the contract as a predeploy.
bytes public constant CREATE2_RAW_TRANSACTION =
// solhint-disable-next-line
hex"f8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222";
address public constant CREATE2_DEPLOYER = address(0x3fAB184622Dc19b6109349B94811493BF2a45362);
// this param is contained in the signed transaction already
uint256 public constant CREATE2_BALANCE = 100 gwei * 100_000;
address public constant CREATE2_DESTINATION = address(0x4e59b44847b379578588920cA78FbF26c0B4956C);
bytes public constant CREATE2_RUNTIME_CODE =
// solhint-disable-next-line
hex"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3";
// https://github.com/ZeframLou/create3-factory
bytes public constant CREATE3_INIT_CODE =
// solhint-disable-next-line
hex"608060405234801561001057600080fd5b5061063b806100206000396000f3fe6080604052600436106100295760003560e01c806350f1c4641461002e578063cdcb760a14610077575b600080fd5b34801561003a57600080fd5b5061004e610049366004610489565b61008a565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61004e6100853660046104fd565b6100ee565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b166020820152603481018290526000906054016040516020818303038152906040528051906020012091506100e78261014c565b9392505050565b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b166020820152603481018390526000906054016040516020818303038152906040528051906020012092506100e78383346102b2565b604080518082018252601081527f67363d3d37363d34f03d5260086018f30000000000000000000000000000000060209182015290517fff00000000000000000000000000000000000000000000000000000000000000918101919091527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b166021820152603581018290527f21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f60558201526000908190610228906075015b6040516020818303038152906040528051906020012090565b6040517fd69400000000000000000000000000000000000000000000000000000000000060208201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606083901b1660228201527f010000000000000000000000000000000000000000000000000000000000000060368201529091506100e79060370161020f565b6000806040518060400160405280601081526020017f67363d3d37363d34f03d5260086018f30000000000000000000000000000000081525090506000858251602084016000f5905073ffffffffffffffffffffffffffffffffffffffff811661037d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4445504c4f594d454e545f4641494c454400000000000000000000000000000060448201526064015b60405180910390fd5b6103868661014c565b925060008173ffffffffffffffffffffffffffffffffffffffff1685876040516103b091906105d6565b60006040518083038185875af1925050503d80600081146103ed576040519150601f19603f3d011682016040523d82523d6000602084013e6103f2565b606091505b50509050808015610419575073ffffffffffffffffffffffffffffffffffffffff84163b15155b61047f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f494e495449414c495a4154494f4e5f4641494c454400000000000000000000006044820152606401610374565b5050509392505050565b6000806040838503121561049c57600080fd5b823573ffffffffffffffffffffffffffffffffffffffff811681146104c057600080fd5b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561051057600080fd5b82359150602083013567ffffffffffffffff8082111561052f57600080fd5b818501915085601f83011261054357600080fd5b813581811115610555576105556104ce565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561059b5761059b6104ce565b816040528281528860208487010111156105b457600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000825160005b818110156105f757602081860181015185830152016105dd565b50600092019182525091905056fea2646970667358221220fd377c185926b3110b7e8a544f897646caf36a0e82b2629de851045e2a5f937764736f6c63430008100033";
bytes32 public constant CREATE3_SALT = bytes32(0);
address public constant CREATE3_DESTINATION = address(0x6aA3D87e99286946161dCA02B97C5806fC5eD46F);
bytes public constant CREATE3_RUNTIME_CODE =
// solhint-disable-next-line
hex"6080604052600436106100295760003560e01c806350f1c4641461002e578063cdcb760a14610077575b600080fd5b34801561003a57600080fd5b5061004e610049366004610489565b61008a565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61004e6100853660046104fd565b6100ee565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b166020820152603481018290526000906054016040516020818303038152906040528051906020012091506100e78261014c565b9392505050565b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b166020820152603481018390526000906054016040516020818303038152906040528051906020012092506100e78383346102b2565b604080518082018252601081527f67363d3d37363d34f03d5260086018f30000000000000000000000000000000060209182015290517fff00000000000000000000000000000000000000000000000000000000000000918101919091527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b166021820152603581018290527f21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f60558201526000908190610228906075015b6040516020818303038152906040528051906020012090565b6040517fd69400000000000000000000000000000000000000000000000000000000000060208201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606083901b1660228201527f010000000000000000000000000000000000000000000000000000000000000060368201529091506100e79060370161020f565b6000806040518060400160405280601081526020017f67363d3d37363d34f03d5260086018f30000000000000000000000000000000081525090506000858251602084016000f5905073ffffffffffffffffffffffffffffffffffffffff811661037d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4445504c4f594d454e545f4641494c454400000000000000000000000000000060448201526064015b60405180910390fd5b6103868661014c565b925060008173ffffffffffffffffffffffffffffffffffffffff1685876040516103b091906105d6565b60006040518083038185875af1925050503d80600081146103ed576040519150601f19603f3d011682016040523d82523d6000602084013e6103f2565b606091505b50509050808015610419575073ffffffffffffffffffffffffffffffffffffffff84163b15155b61047f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f494e495449414c495a4154494f4e5f4641494c454400000000000000000000006044820152606401610374565b5050509392505050565b6000806040838503121561049c57600080fd5b823573ffffffffffffffffffffffffffffffffffffffff811681146104c057600080fd5b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561051057600080fd5b82359150602083013567ffffffffffffffff8082111561052f57600080fd5b818501915085601f83011261054357600080fd5b813581811115610555576105556104ce565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561059b5761059b6104ce565b816040528281528860208487010111156105b457600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000825160005b818110156105f757602081860181015185830152016105dd565b50600092019182525091905056fea2646970667358221220fd377c185926b3110b7e8a544f897646caf36a0e82b2629de851045e2a5f937764736f6c63430008100033";

function setUp() public virtual {
// do nothing
}

function run() public {
vm.startBroadcast();
// only deploy if the destination is not already deployed
// with Anvil, pass `--disable-default-create2-deployer` to test this case
if (CREATE2_DESTINATION.code.length == 0) {
deployCreate2Factory();
console.log("Deployed create2 factory");
} else {
vm.assertEq(CREATE2_DESTINATION.code, CREATE2_RUNTIME_CODE);
console.log("Create2 factory already deployed");
}
// only deploy if the destination i1s not already deployed
if (CREATE3_DESTINATION.code.length == 0) {
deployCreate3Factory();
console.log("Deployed create3 factory");
} else {
vm.assertEq(CREATE3_DESTINATION.code, CREATE3_RUNTIME_CODE);
console.log("Create3 factory already deployed");
}
vm.stopBroadcast();
}

function deployCreate2Factory() public {
// provide gas funds to the deployer
uint256 currentBalance = CREATE2_DEPLOYER.balance;
if (currentBalance < CREATE2_BALANCE) {
payable(CREATE2_DEPLOYER).transfer(CREATE2_BALANCE - currentBalance);
}
// forge-std lib added this function in newer versions
vm.broadcastRawTransaction(CREATE2_RAW_TRANSACTION);
}

function deployCreate3Factory() public {
// any sender can deploy the create3 factory because it is deployed via create2
// the address will be the same across all chains as long as the code and
// the salt are the same. that is why we use a constant code instead of compilation.
(bool success,) = CREATE2_DESTINATION.call(abi.encodePacked(CREATE3_SALT, CREATE3_INIT_CODE));
require(success, "DeployCreate3: failed to deploy create3 factory");
}
MaxMustermann2 marked this conversation as resolved.
Show resolved Hide resolved

}
3 changes: 1 addition & 2 deletions script/7_DeployBootstrap.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,8 @@ contract DeployBootstrapOnly is BaseScript {
new ClientChainGateway(address(clientChainLzEndpoint), config, address(rewardVaultBeacon));

// then the client chain initialization
address[] memory emptyList;
bytes memory initialization =
abi.encodeWithSelector(clientGatewayLogic.initialize.selector, exocoreValidatorSet.addr, emptyList);
abi.encodeWithSelector(clientGatewayLogic.initialize.selector, exocoreValidatorSet.addr);

// bootstrap implementation
Bootstrap bootstrap = Bootstrap(
Expand Down
2 changes: 1 addition & 1 deletion script/BaseScript.sol
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ contract BaseScript is Script, StdCheats {
console.log("NOTICE: using exocore precompiles mock", useExocorePrecompileMock);

clientChainRPCURL = vm.envString("CLIENT_CHAIN_RPC");
exocoreRPCURL = vm.envString("EXOCORE_TESETNET_RPC");
exocoreRPCURL = vm.envString("EXOCORE_TESTNET_RPC");
}

function _bindPrecompileMocks() internal {
Expand Down
2 changes: 1 addition & 1 deletion script/TokenTransfer.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ contract DeployScript is Script {
relayer.addr = vm.addr(relayer.privateKey);

clientChainRPCURL = vm.envString("CLIENT_CHAIN_RPC");
exocoreRPCURL = vm.envString("EXOCORE_TESETNET_RPC");
exocoreRPCURL = vm.envString("EXOCORE_TESTNET_RPC");

string memory deployedContracts = vm.readFile("script/deployedContracts.json");

Expand Down
3 changes: 1 addition & 2 deletions script/integration/1_DeployBootstrap.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,8 @@ contract DeployContracts is Script {
ClientChainGateway clientGatewayLogic =
new ClientChainGateway(address(clientChainLzEndpoint), config, address(rewardVaultBeacon));

address[] memory emptyList;
bytes memory initialization =
abi.encodeWithSelector(clientGatewayLogic.initialize.selector, vm.addr(contractDeployer), emptyList);
abi.encodeWithSelector(clientGatewayLogic.initialize.selector, vm.addr(contractDeployer));

bootstrap.setClientChainGatewayLogic(address(clientGatewayLogic), initialization);

Expand Down
7 changes: 5 additions & 2 deletions test/foundry/BootstrapDepositNST.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,11 @@ contract BootstrapDepositNSTTest is Test {
address capsuleAddress = _getCapsuleFromWithdrawalCredentials(_getWithdrawalCredentials(validatorContainer));
vm.etch(capsuleAddress, address(createdCapsule).code);
capsule = ExoCapsule(payable(capsuleAddress));
stdstore.target(capsuleAddress).sig("_beacon()").checked_write(address(capsuleBeacon));
assertEq(stdstore.target(capsuleAddress).sig("_beacon()").read_address(), address(capsuleBeacon));
// TODO: load this dynamically somehow instead of hardcoding it
bytes32 beaconSlotInCapsule = bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1);
bytes32 beaconAddress = bytes32(uint256(uint160(address(capsuleBeacon))));
vm.store(capsuleAddress, beaconSlotInCapsule, beaconAddress);
assertEq(vm.load(capsuleAddress, beaconSlotInCapsule), beaconAddress);

/// replace expectedCapsule with capsule
bytes32 capsuleSlotInGateway =
Expand Down
2 changes: 0 additions & 2 deletions test/foundry/Delegation.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import "@layerzero-v2/protocol/contracts/libs/AddressCast.sol";
import "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/GUID.sol";
import "forge-std/Test.sol";

import "forge-std/console.sol";

contract DelegateTest is ExocoreDeployer {

using AddressCast for address;
Expand Down
2 changes: 0 additions & 2 deletions test/foundry/DepositThenDelegateTo.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/GUID.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "forge-std/Test.sol";

import "forge-std/console.sol";

contract DepositThenDelegateToTest is ExocoreDeployer {

using AddressCast for address;
Expand Down
Loading
Loading