diff --git a/.github/workflows/forge-ci.yml b/.github/workflows/forge-ci.yml new file mode 100644 index 00000000..9e9bb68e --- /dev/null +++ b/.github/workflows/forge-ci.yml @@ -0,0 +1,132 @@ +--- +name: Forge CI to build, test and format + +on: + pull_request: + push: + branches: + - main + - release/** + tags: + - "*" + +jobs: + setup: + uses: ./.github/workflows/foundry-setup.yml + with: + foundry-version: nightly-f625d0fa7c51e65b4bf1e8f7931cd1c6e2e285e9 + + build: + runs-on: ubuntu-latest + needs: setup + outputs: + installation-dir: ${{ needs.setup.outputs.installation-dir }} + cache-key: ${{ needs.setup.outputs.cache-key }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Restore cached Foundry toolchain + uses: actions/cache/restore@v3 + with: + path: ${{ needs.setup.outputs.installation-dir }} + key: ${{ needs.setup.outputs.cache-key }} + - name: Add Foundry to PATH + run: echo "${{ needs.setup.outputs.installation-dir }}" >> $GITHUB_PATH + - name: Build + run: forge build + - name: Add comment for build failure + if: failure() + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'The build has failed. Please check the logs.' + }) + - name: Cache build artifacts + uses: actions/cache/save@v3 + with: + path: | + ./lib + ./out + ./cache + ./broadcast + key: ${{ runner.os }}-build-${{ github.sha }} + + test: + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/checkout@v4 + - name: Restore cached Foundry toolchain + uses: actions/cache/restore@v3 + with: + path: ${{ needs.build.outputs.installation-dir }} + key: ${{ needs.build.outputs.cache-key }} + - name: Add Foundry to PATH + run: echo "${{ needs.build.outputs.installation-dir }}" >> $GITHUB_PATH + - name: Restore build artifacts + uses: actions/cache/restore@v3 + with: + path: | + ./lib + ./out + ./cache + ./broadcast + key: ${{ runner.os }}-build-${{ github.sha }} + - name: Run tests + run: forge test -vvv + - name: Run test snapshot + run: NO_COLOR=1 forge snapshot >> $GITHUB_STEP_SUMMARY + - name: Add comment for test failure + if: failure() + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'The tests have failed. Please check the logs.' + }) + + fmt: + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/checkout@v4 + - name: Restore cached Foundry toolchain + uses: actions/cache/restore@v3 + with: + path: ${{ needs.build.outputs.installation-dir }} + key: ${{ needs.build.outputs.cache-key }} + - name: Add Foundry to PATH + run: echo "${{ needs.build.outputs.installation-dir }}" >> $GITHUB_PATH + - name: Restore build artifacts + uses: actions/cache/restore@v3 + with: + path: | + ./lib + ./out + ./cache + ./broadcast + key: ${{ runner.os }}-build-${{ github.sha }} + - name: Check formatting + run: forge fmt --check + - name: Add comment for format failure + if: failure() + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'The code is not formatted correctly. Please run `forge fmt` and push the changes.' + }) diff --git a/.github/workflows/foundry-setup.yml b/.github/workflows/foundry-setup.yml new file mode 100644 index 00000000..dfd5688c --- /dev/null +++ b/.github/workflows/foundry-setup.yml @@ -0,0 +1,47 @@ +--- +name: Foundry Setup + +on: + workflow_call: + inputs: + foundry-version: + required: true + type: string + outputs: + installation-dir: + description: "The installation directory of Foundry toolchain" + value: ${{ jobs.setup.outputs.installation-dir }} + cache-key: + description: "The cache key for Foundry toolchain" + value: ${{ jobs.setup.outputs.cache-key }} + +jobs: + setup: + runs-on: ubuntu-latest + outputs: + cache-key: ${{ steps.set-cache-key.outputs.cache-key }} + installation-dir: ${{ steps.find-path.outputs.installation-dir }} + steps: + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: ${{ inputs.foundry-version }} + - name: Print forge version + run: forge --version + # Unfortunately, the `foundry-toolchain` action installs it in a + # randomly generated location, so we must determine it ourselves + - name: Determine Foundry installation path + id: find-path + run: | + installation_path=$(which forge) + installation_dir=$(dirname $installation_path) + echo "installation-dir=$installation_dir" >> "$GITHUB_OUTPUT" + - name: Cached Foundry toolchain + uses: actions/cache/save@v3 + with: + path: ${{ steps.find-path.outputs.installation-dir }} + key: ${{ runner.os }}-foundry-${{ inputs.foundry-version }} + - name: Set cache key + id: set-cache-key + run: | + echo "cache-key=${{ runner.os }}-foundry-${{ inputs.foundry-version }}" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index e85fdb1d..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: test - -on: - pull_request: - push: - branches: - - main - - release/** - tags: - - "*" - -env: - FOUNDRY_PROFILE: ci - -jobs: - check: - strategy: - fail-fast: true - - name: Foundry project - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - submodules: recursive - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - # replace nightly because latest nightly release has some breaking changes that result in test failures - # this is a previous recent nightly release that should work - version: nightly-f625d0fa7c51e65b4bf1e8f7931cd1c6e2e285e9 - - - name: Run Forge build - run: | - forge --version - forge build --sizes - id: build - - - name: Run Forge tests - run: | - forge test -vvv - id: test - - - name: Add comment on failure - if: failure() - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: 'The GitHub Actions workflow has failed. Please check the logs for more details.' - }) diff --git a/.gitignore b/.gitignore index f886c552..22bebee6 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ node_modules **/cache_hardhat .idea + +.gas-snapshot diff --git a/foundry.toml b/foundry.toml index 12014e1e..c23f0961 100644 --- a/foundry.toml +++ b/foundry.toml @@ -10,5 +10,13 @@ evm_version = "paris" [rpc_endpoints] ethereum_local_rpc = "${ETHEREUM_LOCAL_RPC}" exocore_local_rpc = "${EXOCORE_LOCAL_RPC}" -# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options +[fmt] +ignore = ["src/libraries/Endian.sol"] +# TODO: enable these after linter is merged +# number_underscore = "thousands" +# sort_imports = true +# wrap_comments = true +# single_line_statement_blocks = "multi" +# contract_new_lines = true +# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options diff --git a/script/10_DeployExocoreGatewayOnly.s.sol b/script/10_DeployExocoreGatewayOnly.s.sol index f976f126..1df50927 100644 --- a/script/10_DeployExocoreGatewayOnly.s.sol +++ b/script/10_DeployExocoreGatewayOnly.s.sol @@ -3,14 +3,14 @@ pragma solidity ^0.8.19; import {ILayerZeroEndpointV2} from "@layerzero-v2/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol"; import {ProxyAdmin} from "@openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol"; -import {TransparentUpgradeableProxy} from "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {TransparentUpgradeableProxy} from + "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {ExocoreGateway} from "../src/core/ExocoreGateway.sol"; import "forge-std/Script.sol"; import {BaseScript} from "./BaseScript.sol"; contract DeployExocoreGatewayOnly is BaseScript { - function setUp() public virtual override { // load keys super.setUp(); @@ -35,8 +35,7 @@ contract DeployExocoreGatewayOnly is BaseScript { address(exocoreGatewayLogic), address(exocoreProxyAdmin), abi.encodeWithSelector( - exocoreGatewayLogic.initialize.selector, - payable(exocoreValidatorSet.addr) + exocoreGatewayLogic.initialize.selector, payable(exocoreValidatorSet.addr) ) ) ) @@ -52,10 +51,8 @@ contract DeployExocoreGatewayOnly is BaseScript { vm.serializeAddress(exocoreContracts, "exocoreGateway", address(exocoreGateway)); string memory deployedContracts = "deployedContracts"; - string memory finalJson = - vm.serializeString(deployedContracts, "exocore", exocoreContractsOutput); + string memory finalJson = vm.serializeString(deployedContracts, "exocore", exocoreContractsOutput); vm.writeJson(finalJson, "script/deployedExocoreGatewayOnly.json"); - } -} \ No newline at end of file +} diff --git a/script/11_SetPeers.s.sol b/script/11_SetPeers.s.sol index c8dac6e5..41e914cf 100644 --- a/script/11_SetPeers.s.sol +++ b/script/11_SetPeers.s.sol @@ -50,8 +50,7 @@ contract SetPeersAndUpgrade is BaseScript { uint256 i = 0; uint256 tries = 5; bool success; - while(i < tries) { - + while (i < tries) { vm.selectFork(exocore); success = gateway.peers(clientChainId) == bootstrapAddr.toBytes32(); @@ -90,8 +89,8 @@ contract SetPeersAndUpgrade is BaseScript { console.log( "source .env && cast send --rpc-url $EXOCORE_TESETNET_RPC", exocoreGatewayAddr, - "\"markBootstrapOnAllChains()\"", + '"markBootstrapOnAllChains()"', "--private-key $TEST_ACCOUNT_THREE_PRIVATE_KEY" ); } -} \ No newline at end of file +} diff --git a/script/12_RedeployClientChainGateway.s.sol b/script/12_RedeployClientChainGateway.s.sol index fa04e4ec..821ad27e 100644 --- a/script/12_RedeployClientChainGateway.s.sol +++ b/script/12_RedeployClientChainGateway.s.sol @@ -1,6 +1,7 @@ pragma solidity ^0.8.19; -import {TransparentUpgradeableProxy} from "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {TransparentUpgradeableProxy} from + "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {UpgradeableBeacon} from "@openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol"; import {Bootstrap} from "../src/core/Bootstrap.sol"; @@ -24,29 +25,19 @@ contract RedeployClientChainGateway is BaseScript { super.setUp(); // load contracts string memory prerequisiteContracts = vm.readFile("script/deployedBootstrapOnly.json"); - clientChainLzEndpoint = ILayerZeroEndpointV2( - stdJson.readAddress(prerequisiteContracts, ".clientChain.lzEndpoint") - ); + clientChainLzEndpoint = + ILayerZeroEndpointV2(stdJson.readAddress(prerequisiteContracts, ".clientChain.lzEndpoint")); require(address(clientChainLzEndpoint) != address(0), "client chain l0 endpoint should not be empty"); - beaconOracle = EigenLayerBeaconOracle( - stdJson.readAddress(prerequisiteContracts, ".clientChain.beaconOracle") - ); + beaconOracle = EigenLayerBeaconOracle(stdJson.readAddress(prerequisiteContracts, ".clientChain.beaconOracle")); require(address(beaconOracle) != address(0), "beacon oracle should not be empty"); - vaultBeacon = UpgradeableBeacon( - stdJson.readAddress(prerequisiteContracts, ".clientChain.vaultBeacon") - ); + vaultBeacon = UpgradeableBeacon(stdJson.readAddress(prerequisiteContracts, ".clientChain.vaultBeacon")); require(address(vaultBeacon) != address(0), "vault beacon should not be empty"); - capsuleBeacon = UpgradeableBeacon( - stdJson.readAddress(prerequisiteContracts, ".clientChain.capsuleBeacon") - ); + capsuleBeacon = UpgradeableBeacon(stdJson.readAddress(prerequisiteContracts, ".clientChain.capsuleBeacon")); require(address(capsuleBeacon) != address(0), "capsule beacon should not be empty"); - beaconProxyBytecode = BeaconProxyBytecode( - stdJson.readAddress(prerequisiteContracts, ".clientChain.beaconProxyBytecode") - ); + beaconProxyBytecode = + BeaconProxyBytecode(stdJson.readAddress(prerequisiteContracts, ".clientChain.beaconProxyBytecode")); require(address(beaconProxyBytecode) != address(0), "beacon proxy bytecode should not be empty"); - bootstrap = Bootstrap( - stdJson.readAddress(prerequisiteContracts, ".clientChain.bootstrap") - ); + bootstrap = Bootstrap(stdJson.readAddress(prerequisiteContracts, ".clientChain.bootstrap")); require(address(bootstrap) != address(0), "bootstrap should not be empty"); clientChain = vm.createSelectFork(clientChainRPCURL); } @@ -64,15 +55,9 @@ contract RedeployClientChainGateway is BaseScript { ); // then the client chain initialization address[] memory emptyList; - bytes memory initialization = abi.encodeWithSelector( - clientGatewayLogic.initialize.selector, - exocoreValidatorSet.addr, - emptyList - ); - bootstrap.setClientChainGatewayLogic( - address(clientGatewayLogic), - initialization - ); + bytes memory initialization = + abi.encodeWithSelector(clientGatewayLogic.initialize.selector, exocoreValidatorSet.addr, emptyList); + bootstrap.setClientChainGatewayLogic(address(clientGatewayLogic), initialization); vm.stopBroadcast(); string memory clientChainContracts = "clientChainContracts"; @@ -80,9 +65,8 @@ contract RedeployClientChainGateway is BaseScript { vm.serializeAddress(clientChainContracts, "clientGatewayLogic", address(clientGatewayLogic)); string memory deployedContracts = "deployedContracts"; - string memory finalJson = - vm.serializeString(deployedContracts, "clientChain", clientChainContractsOutput); + string memory finalJson = vm.serializeString(deployedContracts, "clientChain", clientChainContractsOutput); vm.writeJson(finalJson, "script/redeployClientChainGateway.json"); } -} \ No newline at end of file +} diff --git a/script/2_DeployBoth.s.sol b/script/2_DeployBoth.s.sol index 8f7ff6de..9a7d29a4 100644 --- a/script/2_DeployBoth.s.sol +++ b/script/2_DeployBoth.s.sol @@ -58,7 +58,7 @@ contract DeployScript is BaseScript { // deploy beacon chain oracle beaconOracle = _deployBeaconOracle(); - + /// deploy vault implementation contract and capsule implementation contract /// that has logics called by proxy vaultImplementation = new Vault(); @@ -90,9 +90,7 @@ contract DeployScript is BaseScript { address(clientGatewayLogic), address(clientChainProxyAdmin), abi.encodeWithSelector( - clientGatewayLogic.initialize.selector, - payable(exocoreValidatorSet.addr), - whitelistTokens + clientGatewayLogic.initialize.selector, payable(exocoreValidatorSet.addr), whitelistTokens ) ) ) diff --git a/script/7_DeployBootstrap.s.sol b/script/7_DeployBootstrap.s.sol index 018c6701..a9af511c 100644 --- a/script/7_DeployBootstrap.s.sol +++ b/script/7_DeployBootstrap.s.sol @@ -1,6 +1,7 @@ pragma solidity ^0.8.19; -import {TransparentUpgradeableProxy} from "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {TransparentUpgradeableProxy} from + "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {UpgradeableBeacon} from "@openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol"; import {Bootstrap} from "../src/core/Bootstrap.sol"; @@ -23,37 +24,19 @@ contract DeployBootstrapOnly is BaseScript { super.setUp(); // load contracts string memory prerequisiteContracts = vm.readFile("script/prerequisiteContracts.json"); - clientChainLzEndpoint = ILayerZeroEndpointV2( - stdJson.readAddress(prerequisiteContracts, ".clientChain.lzEndpoint") - ); - require( - address(clientChainLzEndpoint) != address(0), - "Client chain endpoint not found" - ); - restakeToken = ERC20PresetFixedSupply( - stdJson.readAddress(prerequisiteContracts, ".clientChain.erc20Token") - ); - require( - address(restakeToken) != address(0), - "Restake token not found" - ); + clientChainLzEndpoint = + ILayerZeroEndpointV2(stdJson.readAddress(prerequisiteContracts, ".clientChain.lzEndpoint")); + require(address(clientChainLzEndpoint) != address(0), "Client chain endpoint not found"); + restakeToken = ERC20PresetFixedSupply(stdJson.readAddress(prerequisiteContracts, ".clientChain.erc20Token")); + require(address(restakeToken) != address(0), "Restake token not found"); clientChain = vm.createSelectFork(clientChainRPCURL); // we should use the pre-requisite to save gas instead of deploying our own - beaconOracle = EigenLayerBeaconOracle( - stdJson.readAddress(prerequisiteContracts, ".clientChain.beaconOracle") - ); - require( - address(beaconOracle) != address(0), - "Beacon oracle not found" - ); + beaconOracle = EigenLayerBeaconOracle(stdJson.readAddress(prerequisiteContracts, ".clientChain.beaconOracle")); + require(address(beaconOracle) != address(0), "Beacon oracle not found"); // same for BeaconProxyBytecode - beaconProxyBytecode = BeaconProxyBytecode( - stdJson.readAddress(prerequisiteContracts, ".clientChain.beaconProxyBytecode") - ); - require( - address(beaconProxyBytecode) != address(0), - "Beacon proxy bytecode not found" - ); + beaconProxyBytecode = + BeaconProxyBytecode(stdJson.readAddress(prerequisiteContracts, ".clientChain.beaconProxyBytecode")); + require(address(beaconProxyBytecode) != address(0), "Beacon proxy bytecode not found"); } function run() public { @@ -68,27 +51,28 @@ contract DeployBootstrapOnly is BaseScript { vaultBeacon = new UpgradeableBeacon(address(vaultImplementation)); // bootstrap logic Bootstrap bootstrapLogic = new Bootstrap( - address(clientChainLzEndpoint), - exocoreChainId, - address(vaultBeacon), - address(beaconProxyBytecode) + address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode) ); // bootstrap implementation Bootstrap bootstrap = Bootstrap( - payable(address( - new TransparentUpgradeableProxy( - address(bootstrapLogic), address(proxyAdmin), - abi.encodeCall(Bootstrap.initialize, - ( - exocoreValidatorSet.addr, - block.timestamp + 365 days + 24 hours, - 24 hours, - payable(exocoreValidatorSet.addr), - whitelistTokens, // vault is auto deployed - address(proxyAdmin) + payable( + address( + new TransparentUpgradeableProxy( + address(bootstrapLogic), + address(proxyAdmin), + abi.encodeCall( + Bootstrap.initialize, + ( + exocoreValidatorSet.addr, + block.timestamp + 365 days + 24 hours, + 24 hours, + payable(exocoreValidatorSet.addr), + whitelistTokens, // vault is auto deployed + address(proxyAdmin) + ) ) ) - )) + ) ) ); @@ -108,15 +92,9 @@ contract DeployBootstrapOnly is BaseScript { ); // then the client chain initialization address[] memory emptyList; - bytes memory initialization = abi.encodeWithSelector( - clientGatewayLogic.initialize.selector, - exocoreValidatorSet.addr, - emptyList - ); - bootstrap.setClientChainGatewayLogic( - address(clientGatewayLogic), - initialization - ); + bytes memory initialization = + abi.encodeWithSelector(clientGatewayLogic.initialize.selector, exocoreValidatorSet.addr, emptyList); + bootstrap.setClientChainGatewayLogic(address(clientGatewayLogic), initialization); vm.stopBroadcast(); @@ -136,9 +114,8 @@ contract DeployBootstrapOnly is BaseScript { vm.serializeAddress(clientChainContracts, "clientGatewayLogic", address(clientGatewayLogic)); string memory deployedContracts = "deployedContracts"; - string memory finalJson = - vm.serializeString(deployedContracts, "clientChain", clientChainContractsOutput); + string memory finalJson = vm.serializeString(deployedContracts, "clientChain", clientChainContractsOutput); vm.writeJson(finalJson, "script/deployedBootstrapOnly.json"); } -} \ No newline at end of file +} diff --git a/script/8_DepositValidator.s.sol b/script/8_DepositValidator.s.sol index 9901ca9f..cf110fa4 100644 --- a/script/8_DepositValidator.s.sol +++ b/script/8_DepositValidator.s.sol @@ -63,14 +63,14 @@ contract DepositScript is BaseScript { function run() public { bytes memory root = abi.encodePacked(hex"c0fa1dc87438211f4f73fab438558794947572b771f68c905eee959dba104877"); vm.mockCall( - address(beaconOracle), - abi.encodeWithSelector(beaconOracle.timestampToBlockRoot.selector), - abi.encode(root) + address(beaconOracle), abi.encodeWithSelector(beaconOracle.timestampToBlockRoot.selector), abi.encode(root) ); vm.selectFork(clientChain); vm.startBroadcast(depositor.privateKey); - (bool success,) = address(beaconOracle).call(abi.encodeWithSelector(beaconOracle.addTimestamp.selector, validatorProof.beaconBlockTimestamp)); + (bool success,) = address(beaconOracle).call( + abi.encodeWithSelector(beaconOracle.addTimestamp.selector, validatorProof.beaconBlockTimestamp) + ); vm.stopBroadcast(); vm.startBroadcast(depositor.privateKey); @@ -104,9 +104,11 @@ contract DepositScript is BaseScript { validatorProof.stateRoot = stdJson.readBytes32(validatorInfo, ".beaconStateRoot"); require(validatorProof.stateRoot != bytes32(0), "state root should not be empty"); - validatorProof.stateRootProof = stdJson.readBytes32Array(validatorInfo, ".StateRootAgainstLatestBlockHeaderProof"); + validatorProof.stateRootProof = + stdJson.readBytes32Array(validatorInfo, ".StateRootAgainstLatestBlockHeaderProof"); require(validatorProof.stateRootProof.length == 3, "state root proof should have 3 nodes"); - validatorProof.validatorContainerRootProof = stdJson.readBytes32Array(validatorInfo, ".WithdrawalCredentialProof"); + validatorProof.validatorContainerRootProof = + stdJson.readBytes32Array(validatorInfo, ".WithdrawalCredentialProof"); require(validatorProof.validatorContainerRootProof.length == 46, "validator root proof should have 46 nodes"); validatorProof.validatorIndex = stdJson.readUint(validatorInfo, ".validatorIndex"); require(validatorProof.validatorIndex != 0, "validator root index should not be 0"); diff --git a/script/8_RegisterOperatorsAndDelegate.s.sol b/script/8_RegisterOperatorsAndDelegate.s.sol index a20d313c..3eb60af5 100644 --- a/script/8_RegisterOperatorsAndDelegate.s.sol +++ b/script/8_RegisterOperatorsAndDelegate.s.sol @@ -25,12 +25,12 @@ contract RegisterOperatorsAndDelegate is Script { address tokenAddr; // each subarray sums to deposits, and each item is the delegation amount uint256[4][4] amounts = [ - [ 1500 * 1e18, 250 * 1e18, 250 * 1e18, 0 * 1e18 ], - [ 300 * 1e18, 1500 * 1e18, 0 * 1e18, 200 * 1e18 ], - [ 0 * 1e18, 0 * 1e18, 2500 * 1e18, 500 * 1e18 ], - [ 1000 * 1e18, 0 * 1e18, 0 * 1e18, 2000 * 1e18 ] + [1500 * 1e18, 250 * 1e18, 250 * 1e18, 0 * 1e18], + [300 * 1e18, 1500 * 1e18, 0 * 1e18, 200 * 1e18], + [0 * 1e18, 0 * 1e18, 2500 * 1e18, 500 * 1e18], + [1000 * 1e18, 0 * 1e18, 0 * 1e18, 2000 * 1e18] ]; - + function setUp() public { primaryKey = vm.envUint("TEST_ACCOUNT_THREE_PRIVATE_KEY"); operatorKeys = vm.envUint("OPERATOR_KEYS", ","); @@ -42,9 +42,8 @@ contract RegisterOperatorsAndDelegate is Script { clientChain = vm.createSelectFork(clientChainRPCURL); require( - operatorKeys.length == exoAddresses.length && - operatorKeys.length == names.length && - operatorKeys.length == consKeys.length, + operatorKeys.length == exoAddresses.length && operatorKeys.length == names.length + && operatorKeys.length == consKeys.length, "Operator registration data length mismatch" ); @@ -57,13 +56,11 @@ contract RegisterOperatorsAndDelegate is Script { function run() public { vm.selectFork(clientChain); - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e18, 1e18); Bootstrap bootstrap = Bootstrap(bootstrapAddr); ERC20PresetFixedSupply token = ERC20PresetFixedSupply(tokenAddr); address vaultAddr = address(bootstrap.tokenToVault(tokenAddr)); - for(uint256 i = 0; i < operatorKeys.length; i++) { + for (uint256 i = 0; i < operatorKeys.length; i++) { uint256 pk = operatorKeys[i]; address addr = vm.addr(pk); console.log(i, addr); @@ -72,14 +69,12 @@ contract RegisterOperatorsAndDelegate is Script { bytes32 consKey = consKeys[i]; vm.startBroadcast(pk); // register operator - bootstrap.registerOperator( - exoAddr, name, commission, consKey - ); + bootstrap.registerOperator(exoAddr, name, commission, consKey); vm.stopBroadcast(); // give them the balance vm.startBroadcast(primaryKey); uint256 depositAmount = 0; - for(uint256 j = 0; j < amounts[i].length; j++) { + for (uint256 j = 0; j < amounts[i].length; j++) { depositAmount += amounts[i][j]; } if (token.balanceOf(addr) < depositAmount) { @@ -93,10 +88,10 @@ contract RegisterOperatorsAndDelegate is Script { bootstrap.deposit(tokenAddr, depositAmount); vm.stopBroadcast(); } - for(uint256 i = 0; i < operatorKeys.length; i++) { + for (uint256 i = 0; i < operatorKeys.length; i++) { uint256 pk = operatorKeys[i]; vm.startBroadcast(pk); - for(uint256 j = 0; j < operatorKeys.length; j++) { + for (uint256 j = 0; j < operatorKeys.length; j++) { uint256 amount = amounts[i][j]; if (amount == 0) { continue; @@ -108,4 +103,4 @@ contract RegisterOperatorsAndDelegate is Script { vm.stopBroadcast(); } } -} \ No newline at end of file +} diff --git a/script/9_ExtendBootstrapTime.s.sol b/script/9_ExtendBootstrapTime.s.sol index 70b73827..b1a30b02 100644 --- a/script/9_ExtendBootstrapTime.s.sol +++ b/script/9_ExtendBootstrapTime.s.sol @@ -27,4 +27,4 @@ contract SetBootstrapTime is BaseScript { vm.stopBroadcast(); } -} \ No newline at end of file +} diff --git a/script/BaseScript.sol b/script/BaseScript.sol index 29c1c6fa..2b650e1a 100644 --- a/script/BaseScript.sol +++ b/script/BaseScript.sol @@ -10,7 +10,10 @@ import "../src/interfaces/precompiles/IDeposit.sol"; import "../src/interfaces/precompiles/IWithdrawPrinciple.sol"; import "../src/interfaces/precompiles/IClaimReward.sol"; -import {IERC20, ERC20PresetFixedSupply} from "@openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; +import { + IERC20, + ERC20PresetFixedSupply +} from "@openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import "@layerzero-v2/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol"; import "@beacon-oracle/contracts/src/EigenLayerBeaconOracle.sol"; import {IBeacon} from "@openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol"; @@ -127,10 +130,16 @@ contract BaseScript is Script { vm.etch(CLAIM_REWARD_PRECOMPILE_ADDRESS, WithdrawRewardMockCode); } - function _topUpPlayer(uint256 chain, address token, Player memory provider, address recipient, uint256 targetBalance) internal { + function _topUpPlayer( + uint256 chain, + address token, + Player memory provider, + address recipient, + uint256 targetBalance + ) internal { vm.selectFork(chain); vm.startBroadcast(provider.privateKey); - + if (token == address(0)) { if (recipient.balance < targetBalance) { (bool sent,) = recipient.call{value: targetBalance - recipient.balance}(""); diff --git a/script/TestPrecompileErrorFixed_Deploy.s.sol b/script/TestPrecompileErrorFixed_Deploy.s.sol index 5663a4d1..437dc1e8 100644 --- a/script/TestPrecompileErrorFixed_Deploy.s.sol +++ b/script/TestPrecompileErrorFixed_Deploy.s.sol @@ -77,8 +77,8 @@ contract DepositScript is BaseScript { vm.startBroadcast(exocoreValidatorSet.privateKey); exocoreGateway.setPeer(clientChainId, address(clientGateway).toBytes32()); NonShortCircuitEndpointV2Mock(address(exocoreLzEndpoint)).setDestLzEndpoint( - address(clientGateway), address(clientChainLzEndpoint) - ); + address(clientGateway), address(clientChainLzEndpoint) + ); vm.stopBroadcast(); } } diff --git a/script/deployBeaconOracle.s.sol b/script/deployBeaconOracle.s.sol index dbf99850..fcebd696 100644 --- a/script/deployBeaconOracle.s.sol +++ b/script/deployBeaconOracle.s.sol @@ -20,7 +20,8 @@ contract PrerequisitiesScript is BaseScript { vm.startBroadcast(deployer.privateKey); beaconOracle = EigenLayerBeaconOracle(0xd3D285cd1516038dAED61B8BF7Ae2daD63662492); - (bool success,) = address(beaconOracle).call(abi.encodeWithSelector(beaconOracle.addTimestamp.selector, 1715918948)); + (bool success,) = + address(beaconOracle).call(abi.encodeWithSelector(beaconOracle.addTimestamp.selector, 1715918948)); vm.stopPrank(); } } diff --git a/script/integration/1_DeployBootstrap.s.sol b/script/integration/1_DeployBootstrap.s.sol index d7725086..3b1fdee4 100644 --- a/script/integration/1_DeployBootstrap.s.sol +++ b/script/integration/1_DeployBootstrap.s.sol @@ -83,21 +83,17 @@ contract DeployContracts is Script { function deployTokens() private { string[2] memory names = ["MyToken1", "MyToken2"]; string[2] memory symbols = ["MT1", "MT2"]; - uint256[2] memory initialBalances = [ - 2000 * 10 ** decimals[0], 5000 * 10 ** decimals[1] - ]; + uint256[2] memory initialBalances = [2000 * 10 ** decimals[0], 5000 * 10 ** decimals[1]]; address[] memory initialAddresses = new address[](operators.length + stakers.length); - for(uint256 i = 0; i < operators.length; i++) { + for (uint256 i = 0; i < operators.length; i++) { initialAddresses[i] = vm.addr(operators[i]); } - for(uint256 i = 0; i < stakers.length; i++) { + for (uint256 i = 0; i < stakers.length; i++) { initialAddresses[operators.length + i] = vm.addr(stakers[i]); } - for(uint256 i = 0; i < tokenDeployers.length; i++) { + for (uint256 i = 0; i < tokenDeployers.length; i++) { vm.startBroadcast(tokenDeployers[i]); - MyToken myToken = new MyToken( - names[i], symbols[i], decimals[i], initialAddresses, initialBalances[i] - ); + MyToken myToken = new MyToken(names[i], symbols[i], decimals[i], initialAddresses, initialBalances[i]); whitelistTokens.push(address(myToken)); vm.stopBroadcast(); } @@ -118,26 +114,27 @@ contract DeployContracts is Script { proxyAdmin = new CustomProxyAdmin(); EndpointV2Mock clientChainLzEndpoint = new EndpointV2Mock(clientChainId); Bootstrap bootstrapLogic = new Bootstrap( - address(clientChainLzEndpoint), - exocoreChainId, - address(vaultBeacon), - address(beaconProxyBytecode) + address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode) ); bootstrap = Bootstrap( - payable(address( - new TransparentUpgradeableProxy( - address(bootstrapLogic), address(proxyAdmin), - abi.encodeCall(bootstrap.initialize, - ( - vm.addr(contractDeployer), - block.timestamp + 3 minutes, - 1 seconds, - payable(exocoreValidatorSet), - whitelistTokens, - address(proxyAdmin) + payable( + address( + new TransparentUpgradeableProxy( + address(bootstrapLogic), + address(proxyAdmin), + abi.encodeCall( + bootstrap.initialize, + ( + vm.addr(contractDeployer), + block.timestamp + 3 minutes, + 1 seconds, + payable(exocoreValidatorSet), + whitelistTokens, + address(proxyAdmin) + ) ) ) - )) + ) ) ); vm.stopBroadcast(); @@ -146,23 +143,19 @@ contract DeployContracts is Script { function approveAndDeposit() private { // amounts deposited by each operator, for the tokens 1 and 2. - uint256[2] memory operatorAmounts = [ - 1500 * 10 ** decimals[0], 2000 * 10 ** decimals[1] - ]; + uint256[2] memory operatorAmounts = [1500 * 10 ** decimals[0], 2000 * 10 ** decimals[1]]; // stakerAmounts - keep divisible by 3 for delegate - uint256[2] memory stakerAmounts = [ - 300 * 10 ** decimals[0], 600 * 10 ** decimals[1] - ]; - for(uint256 i = 0; i < whitelistTokens.length; i++) { - for(uint256 j = 0; j < operators.length; j++) { + uint256[2] memory stakerAmounts = [300 * 10 ** decimals[0], 600 * 10 ** decimals[1]]; + for (uint256 i = 0; i < whitelistTokens.length; i++) { + for (uint256 j = 0; j < operators.length; j++) { vm.startBroadcast(operators[j]); MyToken(whitelistTokens[i]).approve(address(vaults[i]), type(uint256).max); bootstrap.deposit(whitelistTokens[i], operatorAmounts[i]); vm.stopBroadcast(); } } - for(uint256 i = 0; i < whitelistTokens.length; i++) { - for(uint256 j = 0; j < stakers.length; j++) { + for (uint256 i = 0; i < whitelistTokens.length; i++) { + for (uint256 j = 0; j < stakers.length; j++) { vm.startBroadcast(stakers[j]); MyToken(whitelistTokens[i]).approve(address(vaults[i]), type(uint256).max); bootstrap.deposit(whitelistTokens[i], stakerAmounts[i]); @@ -195,14 +188,10 @@ contract DeployContracts is Script { // wise sister language work muscle parade dad angry across emerge trade bytes32(0x4C9DE94E1F3225906602AE812E30F1BE56427126D60F2F6CB661B7F4FDA638DC) ]; - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e18, 1e18); for (uint256 i = 0; i < operators.length; i++) { vm.startBroadcast(operators[i]); - bootstrap.registerOperator( - exos[i], names[i], commission, pubKeys[i] - ); + bootstrap.registerOperator(exos[i], names[i], commission, pubKeys[i]); vm.stopBroadcast(); } } @@ -233,9 +222,7 @@ contract DeployContracts is Script { string memory operatorExo = bootstrap.ethToExocoreAddress(operator); vm.startBroadcast(delegator); if (amount != 0) { - bootstrap.delegateTo( - operatorExo, whitelistTokens[i], amount - ); + bootstrap.delegateTo(operatorExo, whitelistTokens[i], amount); } vm.stopBroadcast(); } @@ -250,10 +237,8 @@ contract DeployContracts is Script { for (uint256 j = 0; j < stakers.length; j++) { uint256 delegator = stakers[j]; address delegatorAddress = vm.addr(delegator); - uint256 deposit = bootstrap.totalDepositAmounts( - delegatorAddress, whitelistTokens[i] - ); - uint256 stakerDelegationToDo = deposit * (i+1) / 3; + uint256 deposit = bootstrap.totalDepositAmounts(delegatorAddress, whitelistTokens[i]); + uint256 stakerDelegationToDo = (deposit * (i + 1)) / 3; for (uint256 k = 0; k < operators.length; k++) { uint256 amount; if (k == operators.length - 1) { @@ -264,9 +249,7 @@ contract DeployContracts is Script { address operator = vm.addr(operators[k]); string memory exo = bootstrap.ethToExocoreAddress(operator); vm.startBroadcast(delegator); - bootstrap.delegateTo( - exo, whitelistTokens[i], amount - ); + bootstrap.delegateTo(exo, whitelistTokens[i], amount); stakerDelegationToDo -= amount; vm.stopBroadcast(); } @@ -289,7 +272,7 @@ contract DeployContracts is Script { delegate(); console.log("[Delegated]; done!"); - for(uint256 i = 0; i < whitelistTokens.length; i++) { + for (uint256 i = 0; i < whitelistTokens.length; i++) { console.log("Token ", i, " address: ", whitelistTokens[i]); } } @@ -297,7 +280,6 @@ contract DeployContracts is Script { // Helper function to generate a random number within a range function random(uint256 _range) internal view returns (uint256) { // Basic random number generation; consider a more robust approach for production - return uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao))) % (_range - 1) + 1; + return (uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao))) % (_range - 1)) + 1; } - -} \ No newline at end of file +} diff --git a/src/core/BaseRestakingController.sol b/src/core/BaseRestakingController.sol index 96b144f8..99c978e1 100644 --- a/src/core/BaseRestakingController.sol +++ b/src/core/BaseRestakingController.sol @@ -9,7 +9,6 @@ import {IBaseRestakingController} from "../interfaces/IBaseRestakingController.s import {PausableUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/PausableUpgradeable.sol"; import {OptionsBuilder} from "@layerzero-v2/oapp/contracts/oapp/libs/OptionsBuilder.sol"; - abstract contract BaseRestakingController is PausableUpgradeable, OAppSenderUpgradeable, @@ -21,10 +20,11 @@ abstract contract BaseRestakingController is receive() external payable {} function claim(address token, uint256 amount, address recipient) - external - isTokenWhitelisted(token) - isValidAmount(amount) - whenNotPaused { + external + isTokenWhitelisted(token) + isValidAmount(amount) + whenNotPaused + { if (token == VIRTUAL_STAKED_ETH_ADDRESS) { IExoCapsule capsule = _getCapsule(msg.sender); capsule.withdraw(amount, recipient); @@ -39,20 +39,24 @@ abstract contract BaseRestakingController is } function delegateTo(string calldata operator, address token, uint256 amount) - external payable - isTokenWhitelisted(token) - isValidAmount(amount) - isValidBech32Address(operator) - whenNotPaused { + external + payable + isTokenWhitelisted(token) + isValidAmount(amount) + isValidBech32Address(operator) + whenNotPaused + { _processRequest(token, msg.sender, amount, Action.REQUEST_DELEGATE_TO, operator); } function undelegateFrom(string calldata operator, address token, uint256 amount) - external payable - isTokenWhitelisted(token) - isValidAmount(amount) - isValidBech32Address(operator) - whenNotPaused { + external + payable + isTokenWhitelisted(token) + isValidAmount(amount) + isValidBech32Address(operator) + whenNotPaused + { _processRequest(token, msg.sender, amount, Action.REQUEST_UNDELEGATE_FROM, operator); } @@ -73,9 +77,8 @@ abstract contract BaseRestakingController is bool hasOperator = bytes(operator).length > 0; // Use a single abi.encode call via ternary operators to handle both cases. - _registeredRequests[outboundNonce] = hasOperator - ? abi.encode(token, operator, sender, amount) - : abi.encode(token, sender, amount); + _registeredRequests[outboundNonce] = + hasOperator ? abi.encode(token, operator, sender, amount) : abi.encode(token, sender, amount); _registeredRequestActions[outboundNonce] = action; @@ -86,12 +89,16 @@ abstract contract BaseRestakingController is _sendMsgToExocore(action, actionArgs); } + function _sendMsgToExocore(Action action, bytes memory actionArgs) internal { bytes memory payload = abi.encodePacked(action, actionArgs); - bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(DESTINATION_GAS_LIMIT, DESTINATION_MSG_VALUE).addExecutorOrderedExecutionOption(); + bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption( + DESTINATION_GAS_LIMIT, DESTINATION_MSG_VALUE + ).addExecutorOrderedExecutionOption(); MessagingFee memory fee = _quote(exocoreChainId, payload, options, false); - MessagingReceipt memory receipt = _lzSend(exocoreChainId, payload, options, MessagingFee(fee.nativeFee, 0), exocoreValidatorSetAddress, false); + MessagingReceipt memory receipt = + _lzSend(exocoreChainId, payload, options, MessagingFee(fee.nativeFee, 0), exocoreValidatorSetAddress, false); emit MessageSent(action, receipt.guid, receipt.nonce, receipt.fee.nativeFee); } } diff --git a/src/core/Bootstrap.sol b/src/core/Bootstrap.sol index 814708f9..284c6d19 100644 --- a/src/core/Bootstrap.sol +++ b/src/core/Bootstrap.sol @@ -5,14 +5,14 @@ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {Initializable} from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol"; import {OwnableUpgradeable} from "@openzeppelin-upgradeable/contracts/access/OwnableUpgradeable.sol"; import {PausableUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/PausableUpgradeable.sol"; -import {ITransparentUpgradeableProxy} from "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ITransparentUpgradeableProxy} from + "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {OAppCoreUpgradeable} from "../lzApp/OAppCoreUpgradeable.sol"; import {ILSTRestakingController} from "../interfaces/ILSTRestakingController.sol"; import {ICustomProxyAdmin} from "../interfaces/ICustomProxyAdmin.sol"; import {IOperatorRegistry} from "../interfaces/IOperatorRegistry.sol"; -import {ITokenWhitelister} from "../interfaces/ITokenWhitelister.sol"; import {IVault} from "../interfaces/IVault.sol"; import {BootstrapLzReceiver} from "./BootstrapLzReceiver.sol"; @@ -29,17 +29,14 @@ contract Bootstrap is Initializable, PausableUpgradeable, OwnableUpgradeable, - ITokenWhitelister, ILSTRestakingController, IOperatorRegistry, BootstrapLzReceiver { - constructor( - address endpoint_, - uint32 exocoreChainId_, - address vaultBeacon_, - address beaconProxyBytecode_ - ) OAppCoreUpgradeable(endpoint_) BootstrapStorage(exocoreChainId_, vaultBeacon_, beaconProxyBytecode_) { + constructor(address endpoint_, uint32 exocoreChainId_, address vaultBeacon_, address beaconProxyBytecode_) + OAppCoreUpgradeable(endpoint_) + BootstrapStorage(exocoreChainId_, vaultBeacon_, beaconProxyBytecode_) + { _disableInitializers(); } @@ -54,19 +51,13 @@ contract Bootstrap is require(owner != address(0), "Bootstrap: owner should not be empty"); require(spawnTime_ > block.timestamp, "Bootstrap: spawn time should be in the future"); require(offsetDuration_ > 0, "Bootstrap: offset duration should be greater than 0"); - require( - spawnTime_ > offsetDuration_, - "Bootstrap: spawn time should be greater than offset duration" - ); + require(spawnTime_ > offsetDuration_, "Bootstrap: spawn time should be greater than offset duration"); uint256 lockTime = spawnTime_ - offsetDuration_; + require(lockTime > block.timestamp, "Bootstrap: lock time should be in the future"); require( - lockTime > block.timestamp, - "Bootstrap: lock time should be in the future" + exocoreValidatorSetAddress_ != address(0), "Bootstrap: exocore validator set address should not be empty" ); - require(exocoreValidatorSetAddress_ != address(0), - "Bootstrap: exocore validator set address should not be empty"); - require(customProxyAdmin_ != address(0), - "Bootstrap: custom proxy admin should not be empty"); + require(customProxyAdmin_ != address(0), "Bootstrap: custom proxy admin should not be empty"); exocoreSpawnTime = spawnTime_; offsetDuration = offsetDuration_; @@ -81,8 +72,7 @@ contract Bootstrap is _deployVault(underlyingToken); } - _whiteListFunctionSelectors[Action.MARK_BOOTSTRAP] = - this.markBootstrapped.selector; + _whiteListFunctionSelectors[Action.MARK_BOOTSTRAP] = this.markBootstrapped.selector; customProxyAdmin = customProxyAdmin_; bootstrapped = false; @@ -117,21 +107,18 @@ contract Bootstrap is * to perform these operations during the lock period will result in a transaction * revert with an informative error message. */ - modifier beforeLocked { - require( - !isLocked(), - "Bootstrap: operation not allowed after lock time" - ); + modifier beforeLocked() { + require(!isLocked(), "Bootstrap: operation not allowed after lock time"); _; } // pausing and unpausing can happen at all times, including after locked time. - function pause() onlyOwner external { + function pause() external onlyOwner { _pause(); } // pausing and unpausing can happen at all times, including after locked time. - function unpause() onlyOwner external { + function unpause() external onlyOwner { _unpause(); } @@ -143,19 +130,10 @@ contract Bootstrap is * @param _spawnTime The new spawn time in seconds. */ function setSpawnTime(uint256 _spawnTime) external onlyOwner beforeLocked { - require( - _spawnTime > block.timestamp, - "Bootstrap: spawn time should be in the future" - ); - require( - _spawnTime > offsetDuration, - "Bootstrap: spawn time should be greater than offset duration" - ); + require(_spawnTime > block.timestamp, "Bootstrap: spawn time should be in the future"); + require(_spawnTime > offsetDuration, "Bootstrap: spawn time should be greater than offset duration"); uint256 lockTime = _spawnTime - offsetDuration; - require( - lockTime > block.timestamp, - "Bootstrap: lock time should be in the future" - ); + require(lockTime > block.timestamp, "Bootstrap: lock time should be in the future"); // technically the spawn time can be moved backwards in time as well. exocoreSpawnTime = _spawnTime; emit SpawnTimeUpdated(_spawnTime); @@ -170,63 +148,28 @@ contract Bootstrap is * @param _offsetDuration The new offset duration in seconds. */ function setOffsetDuration(uint256 _offsetDuration) external onlyOwner beforeLocked { - require( - exocoreSpawnTime > _offsetDuration, - "Bootstrap: spawn time should be greater than offset duration" - ); + require(exocoreSpawnTime > _offsetDuration, "Bootstrap: spawn time should be greater than offset duration"); uint256 lockTime = exocoreSpawnTime - _offsetDuration; - require( - lockTime > block.timestamp, - "Bootstrap: lock time should be in the future" - ); + require(lockTime > block.timestamp, "Bootstrap: lock time should be in the future"); offsetDuration = _offsetDuration; emit OffsetDurationUpdated(_offsetDuration); } // implementation of ITokenWhitelister - function addWhitelistToken( - address _token - ) external beforeLocked onlyOwner whenNotPaused { - // modifiers: onlyOwner and whenNotPaused copied from client chain gateway. - // i added beforeLocked to ensure that new tokens may not be added after - // the offset duration before the spawn time begins. - // anyway it would be pointless to add such tokens since other operations - // cannot be performed. - require( - !isWhitelistedToken[_token], - "Bootstrap: token should be not whitelisted before" - ); - whitelistTokens.push(_token); - isWhitelistedToken[_token] = true; - - // deploy the corresponding vault if not deployed before - if (address(tokenToVault[_token]) == address(0)) { - _deployVault(_token); - } - - emit WhitelistTokenAdded(_token); + function addWhitelistToken(address _token) public override beforeLocked onlyOwner whenNotPaused { + super.addWhitelistToken(_token); } // implementation of ITokenWhitelister - function removeWhitelistToken( - address _token - ) external beforeLocked onlyOwner whenNotPaused { - require( - isWhitelistedToken[_token], - "Bootstrap: token should be already whitelisted" - ); - isWhitelistedToken[_token] = false; - // the implicit assumption here is that the _token must be included in whitelistTokens - // if isWhitelistedToken[_token] is true - for(uint i = 0; i < whitelistTokens.length; i++) { - if (whitelistTokens[i] == _token) { - whitelistTokens[i] = whitelistTokens[whitelistTokens.length - 1]; - whitelistTokens.pop(); - break; - } - } - - emit WhitelistTokenRemoved(_token); + function removeWhitelistToken(address _token) + public + override + beforeLocked + onlyOwner + whenNotPaused + isTokenWhitelisted(_token) + { + super.removeWhitelistToken(_token); } // implementation of IOperatorRegistry @@ -237,49 +180,25 @@ contract Bootstrap is bytes32 consensusPublicKey ) external beforeLocked whenNotPaused { // ensure the address format is valid. - require( - isValidExocoreAddress(operatorExocoreAddress), - "Bootstrap: invalid bech32 address" - ); + require(isValidExocoreAddress(operatorExocoreAddress), "Bootstrap: invalid bech32 address"); // ensure that there is only one operator per ethereum address - require( - bytes(ethToExocoreAddress[msg.sender]).length == 0, - "Ethereum address already linked to an operator" - ); + require(bytes(ethToExocoreAddress[msg.sender]).length == 0, "Ethereum address already linked to an operator"); // check if operator with the same exocore address already exists require( bytes(operators[operatorExocoreAddress].name).length == 0, "Operator with this Exocore address is already registered" ); // check that the consensus key is unique. - require( - !consensusPublicKeyInUse(consensusPublicKey), - "Consensus public key already in use" - ); + require(!consensusPublicKeyInUse(consensusPublicKey), "Consensus public key already in use"); // and that the name (meta info) is unique. - require( - !nameInUse(name), - "Name already in use" - ); + require(!nameInUse(name), "Name already in use"); // check that the commission is valid. - require( - isCommissionValid(commission), - "invalid commission" - ); + require(isCommissionValid(commission), "invalid commission"); ethToExocoreAddress[msg.sender] = operatorExocoreAddress; - operators[operatorExocoreAddress] = IOperatorRegistry.Operator({ - name: name, - commission: commission, - consensusPublicKey: consensusPublicKey - }); + operators[operatorExocoreAddress] = + IOperatorRegistry.Operator({name: name, commission: commission, consensusPublicKey: consensusPublicKey}); registeredOperators.push(msg.sender); - emit OperatorRegistered( - msg.sender, - operatorExocoreAddress, - name, - commission, - consensusPublicKey - ); + emit OperatorRegistered(msg.sender, operatorExocoreAddress, name, commission, consensusPublicKey); } /** @@ -299,7 +218,7 @@ contract Bootstrap is * existing operator, indicating that the key is not unique. Returns `false` if the * public key is not found among the registered operators, indicating that the key * is unique and can be safely used for a new or updating operator. - */ + */ function consensusPublicKeyInUse(bytes32 newKey) public view returns (bool) { require(newKey != bytes32(0), "Consensus public key cannot be zero"); for (uint256 i = 0; i < registeredOperators.length; i++) { @@ -323,12 +242,8 @@ contract Bootstrap is * `false` otherwise. */ function isCommissionValid(Commission memory commission) public pure returns (bool) { - return - commission.rate <= 1e18 && - commission.maxRate <= 1e18 && - commission.maxChangeRate <= 1e18 && - commission.rate <= commission.maxRate && - commission.maxChangeRate <= commission.maxRate; + return commission.rate <= 1e18 && commission.maxRate <= 1e18 && commission.maxChangeRate <= 1e18 + && commission.rate <= commission.maxRate && commission.maxChangeRate <= commission.maxRate; } /** @@ -346,13 +261,12 @@ contract Bootstrap is * indicating that the name is not unique. Returns `false` if the name is not found * among the registered operators, indicating that the name is unique and can be * safely used for a new operator. - */ + */ function nameInUse(string memory newName) public view returns (bool) { for (uint256 i = 0; i < registeredOperators.length; i++) { address ethAddress = registeredOperators[i]; string memory exoAddress = ethToExocoreAddress[ethAddress]; - if (keccak256(abi.encodePacked(operators[exoAddress].name)) == - keccak256(abi.encodePacked(newName))) { + if (keccak256(abi.encodePacked(operators[exoAddress].name)) == keccak256(abi.encodePacked(newName))) { return true; } } @@ -360,30 +274,17 @@ contract Bootstrap is } // implementation of IOperatorRegistry - function replaceKey( - bytes32 newKey - ) external beforeLocked whenNotPaused { - require( - bytes(ethToExocoreAddress[msg.sender]).length != 0, - "no such operator exists" - ); - require( - !consensusPublicKeyInUse(newKey), - "Consensus public key already in use" - ); + function replaceKey(bytes32 newKey) external beforeLocked whenNotPaused { + require(bytes(ethToExocoreAddress[msg.sender]).length != 0, "no such operator exists"); + require(!consensusPublicKeyInUse(newKey), "Consensus public key already in use"); operators[ethToExocoreAddress[msg.sender]].consensusPublicKey = newKey; emit OperatorKeyReplaced(ethToExocoreAddress[msg.sender], newKey); } // implementation of IOperatorRegistry - function updateRate( - uint256 newRate - ) external beforeLocked whenNotPaused { + function updateRate(uint256 newRate) external beforeLocked whenNotPaused { string memory operatorAddress = ethToExocoreAddress[msg.sender]; - require( - bytes(operatorAddress).length != 0, - "no such operator exists" - ); + require(bytes(operatorAddress).length != 0, "no such operator exists"); // across the lifetime of this contract before network bootstrap, // allow the editing of commission only once. require(!commissionEdited[operatorAddress], "Commission already edited once"); @@ -396,36 +297,23 @@ contract Bootstrap is // to prevent operators from blindsiding users by first registering at low rate and // subsequently increasing it, we should also check that the change is within the // allowed rate change. - require( - newRate <= rate + maxChangeRate, - "Rate change exceeds max change rate" - ); + require(newRate <= rate + maxChangeRate, "Rate change exceeds max change rate"); operators[operatorAddress].commission.rate = newRate; commissionEdited[operatorAddress] = true; emit OperatorCommissionUpdated(newRate); } - /** - * @notice Validates the inputs and returns the vault for the given token. - * @param token The adddress of the token. - * @param amount The amount of the token. - * @dev This function checks if the token is whitelisted, the amount is greater than zero - * and that a vault for the token exists. - */ - function _validateAndGetVault( - address token, uint256 amount - ) view internal returns (IVault) { - require(isWhitelistedToken[token], "Bootstrap: token is not whitelisted"); - require(amount > 0, "Bootstrap: amount should be greater than zero"); - - return _getVault(token); - } - // implementation of IController - function deposit( - address token, uint256 amount - ) override external payable beforeLocked whenNotPaused { - IVault vault = _validateAndGetVault(token, amount); + function deposit(address token, uint256 amount) + external + payable + override + beforeLocked + whenNotPaused + isTokenWhitelisted(token) + isValidAmount(amount) + { + IVault vault = _getVault(token); vault.deposit(msg.sender, amount); if (!isDepositor[msg.sender]) { @@ -448,21 +336,21 @@ contract Bootstrap is // implementation of IController // This will allow release of undelegated (free) funds to the user for claiming separately. - function withdrawPrincipleFromExocore( - address token, uint256 amount - ) override external payable beforeLocked whenNotPaused { - IVault vault = _validateAndGetVault(token, amount); + function withdrawPrincipleFromExocore(address token, uint256 amount) + external + payable + override + beforeLocked + whenNotPaused + isTokenWhitelisted(token) + isValidAmount(amount) + { + IVault vault = _getVault(token); uint256 deposited = totalDepositAmounts[msg.sender][token]; - require( - deposited >= amount, - "Bootstrap: insufficient deposited balance" - ); + require(deposited >= amount, "Bootstrap: insufficient deposited balance"); uint256 withdrawable = withdrawableAmounts[msg.sender][token]; - require( - withdrawable >= amount, - "Bootstrap: insufficient withdrawable balance" - ); + require(withdrawable >= amount, "Bootstrap: insufficient withdrawable balance"); // when the withdraw precompile is called, it does these things. totalDepositAmounts[msg.sender][token] -= amount; @@ -478,38 +366,41 @@ contract Bootstrap is // implementation of IController // there are no rewards before the network bootstrap, so this function is not supported. - function withdrawRewardFromExocore( - address, uint256 - ) override external payable beforeLocked whenNotPaused { + function withdrawRewardFromExocore(address, uint256) external payable override beforeLocked whenNotPaused { revert NotYetSupported(); } // implementation of IController - function claim( - address token, uint256 amount, address recipient - ) override external beforeLocked whenNotPaused { - IVault vault = _validateAndGetVault(token, amount); + function claim(address token, uint256 amount, address recipient) + external + override + beforeLocked + whenNotPaused + isTokenWhitelisted(token) + isValidAmount(amount) + { + IVault vault = _getVault(token); vault.withdraw(msg.sender, recipient, amount); } // implementation of IController - function delegateTo( - string calldata operator, address token, uint256 amount - ) override external payable beforeLocked whenNotPaused { - _validateAndGetVault(token, amount); + function delegateTo(string calldata operator, address token, uint256 amount) + external + payable + override + beforeLocked + whenNotPaused + isTokenWhitelisted(token) + isValidAmount(amount) + isValidBech32Address(operator) + { // check that operator is registered - require( - bytes(operators[operator].name).length != 0, - "Operator does not exist" - ); + require(bytes(operators[operator].name).length != 0, "Operator does not exist"); // operator can't be frozen and amount can't be negative // asset validity has been checked. // now check amounts. uint256 withdrawable = withdrawableAmounts[msg.sender][token]; - require( - withdrawable >= amount, - "Bootstrap: insufficient withdrawable balance" - ); + require(withdrawable >= amount, "Bootstrap: insufficient withdrawable balance"); delegations[msg.sender][operator][token] += amount; delegationsByOperator[operator][token] += amount; withdrawableAmounts[msg.sender][token] -= amount; @@ -518,23 +409,23 @@ contract Bootstrap is } // implementation of IController - function undelegateFrom( - string calldata operator, address token, uint256 amount - ) override external payable beforeLocked whenNotPaused { - _validateAndGetVault(token, amount); + function undelegateFrom(string calldata operator, address token, uint256 amount) + external + payable + override + beforeLocked + whenNotPaused + isTokenWhitelisted(token) + isValidAmount(amount) + isValidBech32Address(operator) + { // check that operator is registered - require( - bytes(operators[operator].name).length != 0, - "Operator does not exist" - ); + require(bytes(operators[operator].name).length != 0, "Operator does not exist"); // operator can't be frozen and amount can't be negative // asset validity has been checked. // now check amounts. uint256 delegated = delegations[msg.sender][operator][token]; - require( - delegated >= amount, - "Bootstrap: insufficient delegated balance" - ); + require(delegated >= amount, "Bootstrap: insufficient delegated balance"); // the undelegation is released immediately since it is not at stake yet. delegations[msg.sender][operator][token] -= amount; delegationsByOperator[operator][token] -= amount; @@ -563,22 +454,14 @@ contract Bootstrap is // nonce match, which requires that inbound nonce is uint64(1). // TSS checks are not super clear since they can be set by anyone // but at this point that does not matter since it is not fully implemented anyway. - require( - block.timestamp >= exocoreSpawnTime, - "Bootstrap: not yet in the bootstrap time" - ); - require( - !bootstrapped, - "Bootstrap: already bootstrapped" - ); - require( - clientChainGatewayLogic != address(0), - "Bootstrap: client chain gateway logic not set" - ); + require(block.timestamp >= exocoreSpawnTime, "Bootstrap: not yet in the bootstrap time"); + require(!bootstrapped, "Bootstrap: already bootstrapped"); + require(clientChainGatewayLogic != address(0), "Bootstrap: client chain gateway logic not set"); ICustomProxyAdmin(customProxyAdmin).changeImplementation( // address(this) is storage address and not logic address. so it is a proxy. ITransparentUpgradeableProxy(address(this)), - clientChainGatewayLogic, clientChainInitializationData + clientChainGatewayLogic, + clientChainInitializationData ); emit Bootstrapped(); } @@ -593,16 +476,15 @@ contract Bootstrap is * @param _clientChainInitializationData The initialization data to be used when setting up * the new logic contract. */ - function setClientChainGatewayLogic( - address _clientChainGatewayLogic, - bytes calldata _clientChainInitializationData - ) public onlyOwner { + function setClientChainGatewayLogic(address _clientChainGatewayLogic, bytes calldata _clientChainInitializationData) + public + onlyOwner + { + require(_clientChainGatewayLogic != address(0), "Bootstrap: client chain gateway logic address cannot be empty"); + require(_clientChainInitializationData.length >= 4, "Bootstrap: client chain initialization data is malformed"); clientChainGatewayLogic = _clientChainGatewayLogic; clientChainInitializationData = _clientChainInitializationData; - emit ClientChainGatewayLogicUpdated( - _clientChainGatewayLogic, - _clientChainInitializationData - ); + emit ClientChainGatewayLogicUpdated(_clientChainGatewayLogic, _clientChainInitializationData); } /** @@ -610,8 +492,7 @@ contract Bootstrap is * @return The number of registered operators. * @notice This function returns the total number of registered operators in the contract. */ - function getOperatorsCount( - ) external view returns (uint256) { + function getOperatorsCount() external view returns (uint256) { return registeredOperators.length; } @@ -620,8 +501,7 @@ contract Bootstrap is * @return The number of depositors. * @notice This function returns the total number of depositors in the contract. */ - function getDepositorsCount( - ) external view returns (uint256) { + function getDepositorsCount() external view returns (uint256) { return depositors.length; } @@ -630,8 +510,7 @@ contract Bootstrap is * @return The number of whitelisted tokens. * @notice This function returns the total number of whitelisted tokens in the contract. */ - function getWhitelistedTokensCount( - ) external view returns (uint256) { + function getWhitelistedTokensCount() external view returns (uint256) { return whitelistTokens.length; } @@ -654,4 +533,4 @@ contract Bootstrap is depositAmount: depositsByToken[tokenAddress] }); } -} \ No newline at end of file +} diff --git a/src/core/BootstrapLzReceiver.sol b/src/core/BootstrapLzReceiver.sol index ce6e1fbc..f2d068c8 100644 --- a/src/core/BootstrapLzReceiver.sol +++ b/src/core/BootstrapLzReceiver.sol @@ -6,11 +6,7 @@ import {OwnableUpgradeable} from "@openzeppelin-upgradeable/contracts/access/Own import {OAppReceiverUpgradeable, Origin} from "../lzApp/OAppReceiverUpgradeable.sol"; import {PausableUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/PausableUpgradeable.sol"; -abstract contract BootstrapLzReceiver is - PausableUpgradeable, - OAppReceiverUpgradeable, - BootstrapStorage -{ +abstract contract BootstrapLzReceiver is PausableUpgradeable, OAppReceiverUpgradeable, BootstrapStorage { modifier onlyCalledFromThis() { require( msg.sender == address(this), @@ -19,9 +15,7 @@ abstract contract BootstrapLzReceiver is _; } - function _lzReceive( - Origin calldata _origin, bytes calldata payload - ) internal virtual override { + function _lzReceive(Origin calldata _origin, bytes calldata payload) internal virtual override { if (_origin.srcEid != exocoreChainId) { revert UnexpectedSourceChain(_origin.srcEid); } @@ -32,8 +26,7 @@ abstract contract BootstrapLzReceiver is if (selector_ == bytes4(0)) { revert UnsupportedRequest(act); } - (bool success, bytes memory reason) = - address(this).call(abi.encodePacked(selector_, abi.encode(payload[1:]))); + (bool success, bytes memory reason) = address(this).call(abi.encodePacked(selector_, abi.encode(payload[1:]))); if (!success) { revert RequestOrResponseExecuteFailed(act, _origin.nonce, reason); } diff --git a/src/core/ClientChainGateway.sol b/src/core/ClientChainGateway.sol index 1630d04d..45a60b5d 100644 --- a/src/core/ClientChainGateway.sol +++ b/src/core/ClientChainGateway.sol @@ -46,20 +46,29 @@ contract ClientChainGateway is address beaconProxyBytecode_ ) OAppCoreUpgradeable(endpoint_) - ClientChainGatewayStorage(exocoreChainId_, beaconOracleAddress_, vaultBeacon_, exoCapsuleBeacon_, beaconProxyBytecode_) + ClientChainGatewayStorage( + exocoreChainId_, + beaconOracleAddress_, + vaultBeacon_, + exoCapsuleBeacon_, + beaconProxyBytecode_ + ) { _disableInitializers(); } // initialization happens from another contract so it must be external. // reinitializer(2) is used so that the ownable and oappcore functions can be called again. - function initialize( - address payable exocoreValidatorSetAddress_, - address[] calldata appendedWhitelistTokens_ - ) external reinitializer(2) { + function initialize(address payable exocoreValidatorSetAddress_, address[] calldata appendedWhitelistTokens_) + external + reinitializer(2) + { _clearBootstrapData(); - require(exocoreValidatorSetAddress_ != address(0), "ClientChainGateway: exocore validator set address should not be empty"); + require( + exocoreValidatorSetAddress_ != address(0), + "ClientChainGateway: exocore validator set address should not be empty" + ); exocoreValidatorSetAddress = exocoreValidatorSetAddress_; @@ -103,82 +112,33 @@ contract ClientChainGateway is // no risk keeping these but they are cheap to clear. delete exocoreSpawnTime; delete offsetDuration; - // // TODO: are these loops even worth it? the maximum refund is 50% of the gas cost. - // // if not, we can remove them. - // // the lines above this set of comments are at least cheaper to clear, - // // and have no utility after initialization. - // for(uint i = 0; i < depositors.length; i++) { - // address depositor = depositors[i]; - // for(uint j = 0; j < whitelistTokens.length; j++) { - // address token = whitelistTokens[j]; - // delete totalDepositAmounts[depositor][token]; - // delete withdrawableAmounts[depositor][token]; - // for(uint k = 0; k < registeredOperators.length; k++) { - // address eth = registeredOperators[k]; - // string memory exo = ethToExocoreAddress[eth]; - // delete delegations[depositor][exo][token]; - // } - // } - // delete isDepositor[depositor]; - // } - // for(uint k = 0; k < registeredOperators.length; k++) { - // address eth = registeredOperators[k]; - // string memory exo = ethToExocoreAddress[eth]; - // delete operators[exo]; - // delete commissionEdited[exo]; - // delete ethToExocoreAddress[eth]; - // for(uint j = 0; j < whitelistTokens.length; j++) { - // address token = whitelistTokens[j]; - // delete delegationsByOperator[exo][token]; - // } - // } - // for(uint j = 0; j < whitelistTokens.length; j++) { - // address token = whitelistTokens[j]; - // delete depositsByToken[token]; - // } - // these should also be cleared - even if the loops are not used - // cheap to clear and potentially large in size. + // previously, we tried clearing the loops but it is too expensive. delete depositors; delete registeredOperators; } function pause() external { require( - msg.sender == exocoreValidatorSetAddress, "ClientChainGateway: caller is not Exocore validator set aggregated address" + msg.sender == exocoreValidatorSetAddress, + "ClientChainGateway: caller is not Exocore validator set aggregated address" ); _pause(); } function unpause() external { require( - msg.sender == exocoreValidatorSetAddress, "ClientChainGateway: caller is not Exocore validator set aggregated address" + msg.sender == exocoreValidatorSetAddress, + "ClientChainGateway: caller is not Exocore validator set aggregated address" ); _unpause(); } - function addWhitelistToken(address _token) public onlyOwner whenNotPaused { - require(!isWhitelistedToken[_token], "ClientChainGateway: token should not be whitelisted before"); - whitelistTokens.push(_token); - isWhitelistedToken[_token] = true; - emit WhitelistTokenAdded(_token); - - // deploy the corresponding vault if not deployed before - if (address(tokenToVault[_token]) == address(0)) { - _deployVault(_token); - } + function addWhitelistToken(address _token) public override onlyOwner whenNotPaused { + super.addWhitelistToken(_token); } - function removeWhitelistToken(address _token) external isTokenWhitelisted(_token) onlyOwner whenNotPaused { - isWhitelistedToken[_token] = false; - for(uint i = 0; i < whitelistTokens.length; i++) { - if (whitelistTokens[i] == _token) { - whitelistTokens[i] = whitelistTokens[whitelistTokens.length - 1]; - whitelistTokens.pop(); - break; - } - } - - emit WhitelistTokenRemoved(_token); + function removeWhitelistToken(address _token) public override isTokenWhitelisted(_token) onlyOwner whenNotPaused { + super.removeWhitelistToken(_token); } function quote(bytes memory _message) public view returns (uint256 nativeFee) { diff --git a/src/core/ClientGatewayLzReceiver.sol b/src/core/ClientGatewayLzReceiver.sol index f25c4343..76f022fc 100644 --- a/src/core/ClientGatewayLzReceiver.sol +++ b/src/core/ClientGatewayLzReceiver.sol @@ -13,7 +13,10 @@ abstract contract ClientGatewayLzReceiver is PausableUpgradeable, OAppReceiverUp error DepositShouldNotFailOnExocore(address token, address depositor); modifier onlyCalledFromThis() { - require(msg.sender == address(this), "ClientChainLzReceiver: could only be called from this contract itself with low level call"); + require( + msg.sender == address(this), + "ClientChainLzReceiver: could only be called from this contract itself with low level call" + ); _; } diff --git a/src/core/CustomProxyAdmin.sol b/src/core/CustomProxyAdmin.sol index 74b5f2ea..4052026f 100644 --- a/src/core/CustomProxyAdmin.sol +++ b/src/core/CustomProxyAdmin.sol @@ -1,7 +1,8 @@ pragma solidity ^0.8.19; import {Initializable} from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol"; -import {ITransparentUpgradeableProxy} from "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ITransparentUpgradeableProxy} from + "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import "@openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol"; // This contract is not upgradeable intentionally, since doing so would produce a lot of risk. @@ -16,19 +17,10 @@ contract CustomProxyAdmin is Initializable, ProxyAdmin { bootstrapper = newBootstrapper; } - function changeImplementation( - address proxy, - address implementation, - bytes memory data - ) public virtual { - require( - msg.sender == bootstrapper, "CustomProxyAdmin: sender must be bootstrapper" - ); - require( - msg.sender == proxy, - "CustomProxyAdmin: sender must be the proxy itself" - ); + function changeImplementation(address proxy, address implementation, bytes memory data) public virtual { + require(msg.sender == bootstrapper, "CustomProxyAdmin: sender must be bootstrapper"); + require(msg.sender == proxy, "CustomProxyAdmin: sender must be the proxy itself"); ITransparentUpgradeableProxy(proxy).upgradeToAndCall(implementation, data); bootstrapper = address(0); } -} \ No newline at end of file +} diff --git a/src/core/ExoCapsule.sol b/src/core/ExoCapsule.sol index 8c749a00..6691cdc4 100644 --- a/src/core/ExoCapsule.sol +++ b/src/core/ExoCapsule.sol @@ -11,11 +11,7 @@ import {WithdrawalContainer} from "../libraries/WithdrawalContainer.sol"; import {IBeaconChainOracle} from "@beacon-oracle/contracts/src/IBeaconChainOracle.sol"; import {Initializable} from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol"; -contract ExoCapsule is - Initializable, - ExoCapsuleStorage, - IExoCapsule -{ +contract ExoCapsule is Initializable, ExoCapsuleStorage, IExoCapsule { using BeaconChainProofs for bytes32; using ValidatorContainer for bytes32[]; using WithdrawalContainer for bytes32[]; @@ -60,10 +56,10 @@ contract ExoCapsule is capsuleOwner = capsuleOwner_; } - function verifyDepositProof( - bytes32[] calldata validatorContainer, - ValidatorContainerProof calldata proof - ) external onlyGateway { + function verifyDepositProof(bytes32[] calldata validatorContainer, ValidatorContainerProof calldata proof) + external + onlyGateway + { bytes32 validatorPubkey = validatorContainer.getPubkey(); bytes32 withdrawalCredentials = validatorContainer.getWithdrawalCredentials(); Validator storage validator = _capsuleValidators[validatorPubkey]; @@ -140,7 +136,7 @@ contract ExoCapsule is if (!validatorContainer.verifyValidatorContainerBasic()) { revert InvalidValidatorContainer(validatorPubkey); } - + if (!fullyWithdrawal) { revert NotPartialWithdrawal(validatorPubkey); } @@ -157,12 +153,11 @@ contract ExoCapsule is function withdraw(uint256 amount, address recipient) external onlyGateway { require( - amount <= withdrawableBalance, - "ExoCapsule: withdrawal amount is larger than staker's withdrawable balance" + amount <= withdrawableBalance, "ExoCapsule: withdrawal amount is larger than staker's withdrawable balance" ); withdrawableBalance -= amount; - (bool sent, ) = recipient.call{value: amount}(""); + (bool sent,) = recipient.call{value: amount}(""); if (!sent) { revert WithdrawalFailure(capsuleOwner, recipient, amount); } @@ -201,7 +196,7 @@ contract ExoCapsule is return root; } - function getRegisteredValidatorByPubkey(bytes32 pubkey) public view returns(Validator memory) { + function getRegisteredValidatorByPubkey(bytes32 pubkey) public view returns (Validator memory) { Validator memory validator = _capsuleValidators[pubkey]; if (validator.status == VALIDATOR_STATUS.UNREGISTERED) { revert UnregisteredValidator(pubkey); @@ -210,7 +205,7 @@ contract ExoCapsule is return validator; } - function getRegisteredValidatorByIndex(uint256 index) public view returns(Validator memory) { + function getRegisteredValidatorByIndex(uint256 index) public view returns (Validator memory) { Validator memory validator = _capsuleValidators[_capsuleValidatorsByIndex[index]]; if (validator.status == VALIDATOR_STATUS.UNREGISTERED) { revert UnregisteredValidator(_capsuleValidatorsByIndex[index]); @@ -219,7 +214,10 @@ contract ExoCapsule is return validator; } - function _verifyValidatorContainer(bytes32[] calldata validatorContainer, ValidatorContainerProof calldata proof) internal view { + function _verifyValidatorContainer(bytes32[] calldata validatorContainer, ValidatorContainerProof calldata proof) + internal + view + { bytes32 beaconBlockRoot = getBeaconBlockRoot(proof.beaconBlockTimestamp); bytes32 validatorContainerRoot = validatorContainer.merklelizeValidatorContainer(); bool valid = validatorContainerRoot.isValidValidatorContainerRoot( @@ -234,7 +232,10 @@ contract ExoCapsule is } } - function _verifyWithdrawalContainer(bytes32[] calldata withdrawalContainer, WithdrawalContainerProof calldata proof) internal view { + function _verifyWithdrawalContainer(bytes32[] calldata withdrawalContainer, WithdrawalContainerProof calldata proof) + internal + view + { bytes32 beaconBlockRoot = getBeaconBlockRoot(proof.beaconBlockTimestamp); bytes32 withdrawalContainerRoot = withdrawalContainer.merklelizeWithdrawalContainer(); bool valid = withdrawalContainerRoot.isValidWithdrawalContainerRoot( @@ -249,7 +250,11 @@ contract ExoCapsule is } } - function _isActivatedAtEpoch(bytes32[] calldata validatorContainer, uint256 atTimestamp) internal pure returns (bool) { + function _isActivatedAtEpoch(bytes32[] calldata validatorContainer, uint256 atTimestamp) + internal + pure + returns (bool) + { uint64 atEpoch = _timestampToEpoch(atTimestamp); uint64 activationEpoch = validatorContainer.getActivationEpoch(); uint64 exitEpoch = validatorContainer.getExitEpoch(); @@ -258,11 +263,13 @@ contract ExoCapsule is } function _isStaleProof(Validator storage validator, uint256 proofTimestamp) internal view returns (bool) { - return proofTimestamp + VERIFY_BALANCE_UPDATE_WINDOW_SECONDS < block.timestamp || proofTimestamp <= validator.mostRecentBalanceUpdateTimestamp; + return proofTimestamp + VERIFY_BALANCE_UPDATE_WINDOW_SECONDS < block.timestamp + || proofTimestamp <= validator.mostRecentBalanceUpdateTimestamp; } function _hasFullyWithdrawn(bytes32[] calldata validatorContainer) internal view returns (bool) { - return validatorContainer.getWithdrawableEpoch() <= _timestampToEpoch(block.timestamp) && validatorContainer.getEffectiveBalance() == 0; + return validatorContainer.getWithdrawableEpoch() <= _timestampToEpoch(block.timestamp) + && validatorContainer.getEffectiveBalance() == 0; } /** @@ -271,7 +278,9 @@ contract ExoCapsule is * reference: https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md */ function _timestampToEpoch(uint256 timestamp) internal pure returns (uint64) { - require(timestamp >= BEACON_CHAIN_GENESIS_TIME, "timestamp should be greater than beacon chain genesis timestamp"); + require( + timestamp >= BEACON_CHAIN_GENESIS_TIME, "timestamp should be greater than beacon chain genesis timestamp" + ); return uint64((timestamp - BEACON_CHAIN_GENESIS_TIME) / BeaconChainProofs.SECONDS_PER_EPOCH); } } diff --git a/src/core/ExocoreGateway.sol b/src/core/ExocoreGateway.sol index 40e45094..8f4d7217 100644 --- a/src/core/ExocoreGateway.sol +++ b/src/core/ExocoreGateway.sol @@ -33,7 +33,10 @@ contract ExocoreGateway is using OptionsBuilder for bytes; modifier onlyCalledFromThis() { - require(msg.sender == address(this), "ExocoreGateway: can only be called from this contract itself with low level call"); + require( + msg.sender == address(this), + "ExocoreGateway: can only be called from this contract itself with low level call" + ); _; } @@ -58,7 +61,8 @@ contract ExocoreGateway is _whiteListFunctionSelectors[Action.REQUEST_DEPOSIT] = this.requestDeposit.selector; _whiteListFunctionSelectors[Action.REQUEST_DELEGATE_TO] = this.requestDelegateTo.selector; _whiteListFunctionSelectors[Action.REQUEST_UNDELEGATE_FROM] = this.requestUndelegateFrom.selector; - _whiteListFunctionSelectors[Action.REQUEST_WITHDRAW_PRINCIPLE_FROM_EXOCORE] = this.requestWithdrawPrinciple.selector; + _whiteListFunctionSelectors[Action.REQUEST_WITHDRAW_PRINCIPLE_FROM_EXOCORE] = + this.requestWithdrawPrinciple.selector; _whiteListFunctionSelectors[Action.REQUEST_WITHDRAW_REWARD_FROM_EXOCORE] = this.requestWithdrawReward.selector; } @@ -67,8 +71,8 @@ contract ExocoreGateway is // For manual calls, this function should be called immediately after deployment and // then never needs to be called again. function markBootstrapOnAllChains() public { - (bool success, bytes memory result) = CLIENT_CHAINS_PRECOMPILE_ADDRESS. - staticcall(abi.encodeWithSelector(IClientChains.getClientChains.selector)); + (bool success, bytes memory result) = + CLIENT_CHAINS_PRECOMPILE_ADDRESS.staticcall(abi.encodeWithSelector(IClientChains.getClientChains.selector)); require(success, "ExocoreGateway: failed to get client chain ids"); // TODO: change to uint32[] when the precompile is upgraded (bool ok, uint16[] memory clientChainIds) = abi.decode(result, (bool, uint16[])); @@ -85,14 +89,16 @@ contract ExocoreGateway is function pause() external { require( - msg.sender == exocoreValidatorSetAddress, "ExocoreGateway: caller is not Exocore validator set aggregated address" + msg.sender == exocoreValidatorSetAddress, + "ExocoreGateway: caller is not Exocore validator set aggregated address" ); _pause(); } function unpause() external { require( - msg.sender == exocoreValidatorSetAddress, "ExocoreGateway: caller is not Exocore validator set aggregated address" + msg.sender == exocoreValidatorSetAddress, + "ExocoreGateway: caller is not Exocore validator set aggregated address" ); _unpause(); } @@ -132,22 +138,22 @@ contract ExocoreGateway is public onlyCalledFromThis { - _validatePayloadLength(payload, WITHDRAW_PRINCIPLE_REQUEST_LENGTH, Action.REQUEST_WITHDRAW_PRINCIPLE_FROM_EXOCORE); + _validatePayloadLength( + payload, WITHDRAW_PRINCIPLE_REQUEST_LENGTH, Action.REQUEST_WITHDRAW_PRINCIPLE_FROM_EXOCORE + ); bytes calldata token = payload[:32]; bytes calldata withdrawer = payload[32:64]; uint256 amount = uint256(bytes32(payload[64:96])); - try WITHDRAW_CONTRACT.withdrawPrinciple(srcChainId, token, withdrawer, amount) returns (bool success, uint256 updatedBalance) { - _sendInterchainMsg( - srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, success, updatedBalance) - ); + try WITHDRAW_CONTRACT.withdrawPrinciple(srcChainId, token, withdrawer, amount) returns ( + bool success, uint256 updatedBalance + ) { + _sendInterchainMsg(srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, success, updatedBalance)); } catch { emit ExocorePrecompileError(WITHDRAW_PRECOMPILE_ADDRESS, lzNonce); - _sendInterchainMsg( - srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, false, uint256(0)) - ); + _sendInterchainMsg(srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, false, uint256(0))); } } @@ -161,16 +167,14 @@ contract ExocoreGateway is bytes calldata withdrawer = payload[32:64]; uint256 amount = uint256(bytes32(payload[64:96])); - try CLAIM_REWARD_CONTRACT.claimReward(srcChainId, token, withdrawer, amount) returns (bool success, uint256 updatedBalance) { - _sendInterchainMsg( - srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, success, updatedBalance) - ); + try CLAIM_REWARD_CONTRACT.claimReward(srcChainId, token, withdrawer, amount) returns ( + bool success, uint256 updatedBalance + ) { + _sendInterchainMsg(srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, success, updatedBalance)); } catch { emit ExocorePrecompileError(CLAIM_REWARD_PRECOMPILE_ADDRESS, lzNonce); - _sendInterchainMsg( - srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, false, uint256(0)) - ); + _sendInterchainMsg(srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, false, uint256(0))); } } @@ -182,16 +186,13 @@ contract ExocoreGateway is bytes calldata operator = payload[64:106]; uint256 amount = uint256(bytes32(payload[106:138])); - try DELEGATION_CONTRACT.delegateToThroughClientChain(srcChainId, lzNonce, token, delegator, operator, amount) returns (bool success) { - _sendInterchainMsg( - srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, success) - ); + try DELEGATION_CONTRACT.delegateToThroughClientChain(srcChainId, lzNonce, token, delegator, operator, amount) + returns (bool success) { + _sendInterchainMsg(srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, success)); } catch { emit ExocorePrecompileError(DELEGATION_PRECOMPILE_ADDRESS, lzNonce); - _sendInterchainMsg( - srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, false) - ); + _sendInterchainMsg(srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, false)); } } @@ -206,16 +207,14 @@ contract ExocoreGateway is bytes memory operator = payload[64:106]; uint256 amount = uint256(bytes32(payload[106:138])); - try DELEGATION_CONTRACT.undelegateFromThroughClientChain(srcChainId, lzNonce, token, delegator, operator, amount) returns (bool success) { - _sendInterchainMsg( - srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, success) - ); + try DELEGATION_CONTRACT.undelegateFromThroughClientChain( + srcChainId, lzNonce, token, delegator, operator, amount + ) returns (bool success) { + _sendInterchainMsg(srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, success)); } catch { emit ExocorePrecompileError(DELEGATION_PRECOMPILE_ADDRESS, lzNonce); - _sendInterchainMsg( - srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, false) - ); + _sendInterchainMsg(srcChainId, Action.RESPOND, abi.encodePacked(lzNonce, false)); } } @@ -261,4 +260,4 @@ contract ExocoreGateway is revert UnexpectedInboundNonce(inboundNonce[srcEid][sender], nonce); } } -} \ No newline at end of file +} diff --git a/src/core/LSTRestakingController.sol b/src/core/LSTRestakingController.sol index 3d5f39ed..3e63b5ee 100644 --- a/src/core/LSTRestakingController.sol +++ b/src/core/LSTRestakingController.sol @@ -7,20 +7,34 @@ import {BaseRestakingController} from "./BaseRestakingController.sol"; import {PausableUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/PausableUpgradeable.sol"; -abstract contract LSTRestakingController is - PausableUpgradeable, - ILSTRestakingController, - BaseRestakingController -{ - function deposit(address token, uint256 amount) external payable isTokenWhitelisted(token) isValidAmount(amount) whenNotPaused { - _processRequest(token, msg.sender, amount, Action.REQUEST_DEPOSIT,""); +abstract contract LSTRestakingController is PausableUpgradeable, ILSTRestakingController, BaseRestakingController { + function deposit(address token, uint256 amount) + external + payable + isTokenWhitelisted(token) + isValidAmount(amount) + whenNotPaused + { + _processRequest(token, msg.sender, amount, Action.REQUEST_DEPOSIT, ""); } - function withdrawPrincipleFromExocore(address token, uint256 principleAmount) external payable isTokenWhitelisted(token) isValidAmount(principleAmount) whenNotPaused { - _processRequest(token, msg.sender, principleAmount, Action.REQUEST_WITHDRAW_PRINCIPLE_FROM_EXOCORE,""); + function withdrawPrincipleFromExocore(address token, uint256 principleAmount) + external + payable + isTokenWhitelisted(token) + isValidAmount(principleAmount) + whenNotPaused + { + _processRequest(token, msg.sender, principleAmount, Action.REQUEST_WITHDRAW_PRINCIPLE_FROM_EXOCORE, ""); } - function withdrawRewardFromExocore(address token, uint256 rewardAmount) external payable isTokenWhitelisted(token) isValidAmount(rewardAmount) whenNotPaused { - _processRequest(token, msg.sender, rewardAmount, Action.REQUEST_WITHDRAW_REWARD_FROM_EXOCORE,""); + function withdrawRewardFromExocore(address token, uint256 rewardAmount) + external + payable + isTokenWhitelisted(token) + isValidAmount(rewardAmount) + whenNotPaused + { + _processRequest(token, msg.sender, rewardAmount, Action.REQUEST_WITHDRAW_REWARD_FROM_EXOCORE, ""); } } diff --git a/src/core/NativeRestakingController.sol b/src/core/NativeRestakingController.sol index 245d709d..11090188 100644 --- a/src/core/NativeRestakingController.sol +++ b/src/core/NativeRestakingController.sol @@ -16,7 +16,11 @@ abstract contract NativeRestakingController is { using ValidatorContainer for bytes32[]; - function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable whenNotPaused { + function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) + external + payable + whenNotPaused + { require(msg.value == 32 ether, "NativeRestakingController: stake value must be exactly 32 ether"); IExoCapsule capsule = ownerToCapsule[msg.sender]; @@ -29,7 +33,10 @@ abstract contract NativeRestakingController is } function createExoCapsule() public whenNotPaused returns (address) { - require(address(ownerToCapsule[msg.sender]) == address(0), "NativeRestakingController: message sender has already created the capsule"); + require( + address(ownerToCapsule[msg.sender]) == address(0), + "NativeRestakingController: message sender has already created the capsule" + ); ExoCapsule capsule = ExoCapsule( Create2.deploy( 0, @@ -55,8 +62,6 @@ abstract contract NativeRestakingController is uint256 depositValue = uint256(validatorContainer.getEffectiveBalance()) * GWEI_TO_WEI; _processRequest(VIRTUAL_STAKED_ETH_ADDRESS, msg.sender, depositValue, Action.REQUEST_DEPOSIT, ""); - - } function processBeaconChainPartialWithdrawal( @@ -64,16 +69,12 @@ abstract contract NativeRestakingController is IExoCapsule.ValidatorContainerProof calldata validatorProof, bytes32[] calldata withdrawalContainer, IExoCapsule.WithdrawalContainerProof calldata withdrawalProof - ) external payable whenNotPaused { - - } + ) external payable whenNotPaused {} function processBeaconChainFullWithdrawal( bytes32[] calldata validatorContainer, IExoCapsule.ValidatorContainerProof calldata validatorProof, bytes32[] calldata withdrawalContainer, IExoCapsule.WithdrawalContainerProof calldata withdrawalProof - ) external payable whenNotPaused { - - } + ) external payable whenNotPaused {} } diff --git a/src/core/Vault.sol b/src/core/Vault.sol index 067ede9f..9bdf3e1d 100644 --- a/src/core/Vault.sol +++ b/src/core/Vault.sol @@ -22,7 +22,7 @@ contract Vault is Initializable, VaultStorage, IVault { function initialize(address underlyingToken_, address gateway_) external initializer { require(underlyingToken_ != address(0), "Vault: underlying token can not be empty"); - require(gateway_!= address(0), "VaultStorage: the gateway address should not be empty"); + require(gateway_ != address(0), "VaultStorage: the gateway address should not be empty"); underlyingToken = IERC20(underlyingToken_); gateway = ILSTRestakingController(gateway_); diff --git a/src/interfaces/IClientChainGateway.sol b/src/interfaces/IClientChainGateway.sol index 65af359f..d8eae341 100644 --- a/src/interfaces/IClientChainGateway.sol +++ b/src/interfaces/IClientChainGateway.sol @@ -4,8 +4,7 @@ import {IOAppReceiver} from "@layerzero-v2/oapp/contracts/oapp/interfaces/IOAppR import {IOAppCore} from "@layerzero-v2/oapp/contracts/oapp/interfaces/IOAppCore.sol"; import {ILSTRestakingController} from "./ILSTRestakingController.sol"; import {INativeRestakingController} from "../interfaces/INativeRestakingController.sol"; -import {ITokenWhitelister} from "../interfaces/ITokenWhitelister.sol"; -interface IClientChainGateway is ITokenWhitelister, IOAppReceiver, IOAppCore, ILSTRestakingController, INativeRestakingController { +interface IClientChainGateway is IOAppReceiver, IOAppCore, ILSTRestakingController, INativeRestakingController { function quote(bytes memory _message) external view returns (uint256 nativeFee); } diff --git a/src/interfaces/ICustomProxyAdmin.sol b/src/interfaces/ICustomProxyAdmin.sol index b8b1109d..f1e45c90 100644 --- a/src/interfaces/ICustomProxyAdmin.sol +++ b/src/interfaces/ICustomProxyAdmin.sol @@ -1,11 +1,10 @@ pragma solidity ^0.8.19; -import {ITransparentUpgradeableProxy} from "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ITransparentUpgradeableProxy} from + "@openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; interface ICustomProxyAdmin { - function changeImplementation( - ITransparentUpgradeableProxy proxy, - address implementation, - bytes memory data - ) external payable; -} \ No newline at end of file + function changeImplementation(ITransparentUpgradeableProxy proxy, address implementation, bytes memory data) + external + payable; +} diff --git a/src/interfaces/IExoCapsule.sol b/src/interfaces/IExoCapsule.sol index 608b08b1..80fd18a8 100644 --- a/src/interfaces/IExoCapsule.sol +++ b/src/interfaces/IExoCapsule.sol @@ -18,10 +18,8 @@ interface IExoCapsule { uint256 withdrawalIndex; } - function verifyDepositProof( - bytes32[] calldata validatorContainer, - ValidatorContainerProof calldata proof - ) external; + function verifyDepositProof(bytes32[] calldata validatorContainer, ValidatorContainerProof calldata proof) + external; function verifyPartialWithdrawalProof( bytes32[] calldata validatorContainer, @@ -44,4 +42,4 @@ interface IExoCapsule { function updateWithdrawableBalance(uint256 unlockPrincipleAmount) external; function capsuleWithdrawalCredentials() external view returns (bytes memory); -} \ No newline at end of file +} diff --git a/src/interfaces/INativeRestakingController.sol b/src/interfaces/INativeRestakingController.sol index 709d585a..6197061d 100644 --- a/src/interfaces/INativeRestakingController.sol +++ b/src/interfaces/INativeRestakingController.sol @@ -7,11 +7,11 @@ interface INativeRestakingController is IBaseRestakingController { /// *** function signatures for staker operations *** /** - * @notice Stakers call this function to deposit to beacon chain validator, and point withdrawal_credentials of + * @notice Stakers call this function to deposit to beacon chain validator, and point withdrawal_credentials of * beacon chain validator to staker's ExoCapsule contract address. An ExoCapsule contract owned by staker would * be created if it does not exist. * @param pubkey the BLS pubkey of beacon chain validator - * @param signature the BLS signature + * @param signature the BLS signature * @param depositDataRoot The SHA-256 hash of the SSZ-encoded DepositData object. * Used as a protection against malformed input. */ @@ -26,13 +26,16 @@ interface INativeRestakingController is IBaseRestakingController { * @notice This is called to deposit ETH that is staked on Ethereum beacon chain to Exocore network to be restaked in future * @dev Before deposit, staker should have created the ExoCapsule that it owns and point the validator's withdrawal crendentials * to the ExoCapsule owned by staker. The effective balance of `validatorContainer` would be credited as deposited value by Exocore network. - * @ param + * @ param */ - function depositBeaconChainValidator(bytes32[] calldata validatorContainer, IExoCapsule.ValidatorContainerProof calldata proof) payable external; + function depositBeaconChainValidator( + bytes32[] calldata validatorContainer, + IExoCapsule.ValidatorContainerProof calldata proof + ) external payable; /** - * @notice When a beacon chain partial withdrawal to an ExoCapsule contract happens(the withdrawal time is less than validator's withdrawable_epoch), - * this function could be called with `validatorContainer`, `withdrawalContainer` and corresponding proofs to prove this partial withdrawal + * @notice When a beacon chain partial withdrawal to an ExoCapsule contract happens(the withdrawal time is less than validator's withdrawable_epoch), + * this function could be called with `validatorContainer`, `withdrawalContainer` and corresponding proofs to prove this partial withdrawal * from beacon chain is done and unlock withdrawn ETH to be claimable for ExoCapsule owner. * @param validatorContainer is the data structure included in `BeaconState` of `BeaconBlock` that contains beacon chain validator information, * refer to: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator @@ -47,11 +50,11 @@ interface INativeRestakingController is IBaseRestakingController { IExoCapsule.ValidatorContainerProof calldata validatorProof, bytes32[] calldata withdrawalContainer, IExoCapsule.WithdrawalContainerProof calldata withdrawalProof - ) payable external; + ) external payable; /** - * @notice When a beacon chain full withdrawal to this capsule contract happens(the withdrawal time is euqal to or greater than - * validator's withdrawable_epoch), this function could be called with `validatorContainer`, `withdrawalContainer` and corresponding + * @notice When a beacon chain full withdrawal to this capsule contract happens(the withdrawal time is euqal to or greater than + * validator's withdrawable_epoch), this function could be called with `validatorContainer`, `withdrawalContainer` and corresponding * proofs to prove this full withdrawal from beacon chain is done, send withdrawal request to Exocore network to be processed. * After Exocore network finishs dealing with withdrawal request and sending back the response, ExoCapsule would unlock corresponding ETH * in response to be cliamable for ExoCapsule owner. @@ -68,5 +71,5 @@ interface INativeRestakingController is IBaseRestakingController { IExoCapsule.ValidatorContainerProof calldata validatorProof, bytes32[] calldata withdrawalContainer, IExoCapsule.WithdrawalContainerProof calldata withdrawalProof - ) payable external; + ) external payable; } diff --git a/src/interfaces/IOperatorRegistry.sol b/src/interfaces/IOperatorRegistry.sol index a241ddf2..8ea76301 100644 --- a/src/interfaces/IOperatorRegistry.sol +++ b/src/interfaces/IOperatorRegistry.sol @@ -9,7 +9,7 @@ interface IOperatorRegistry { * All rates must be less than or equal to 1e18. * For example, a 10% commission rate would be represented as 1e17. * rate must not exceed maxRate, and maxChangeRate must not exceed maxRate. - */ + */ struct Commission { uint256 rate; uint256 maxRate; @@ -50,9 +50,7 @@ interface IOperatorRegistry { * @dev Updates the consensus public key for the operator corresponding to `msg.sender`. * @param newKey The new public key to use for consensus operations. */ - function replaceKey( - bytes32 newKey - ) external; + function replaceKey(bytes32 newKey) external; /** * @notice Updates the commission rate for the calling operator. @@ -62,9 +60,7 @@ interface IOperatorRegistry { * @param newRate The new commission rate to be set for the calling operator. * Must not exceed the operator's maximum rate. */ - function updateRate( - uint256 newRate - ) external; + function updateRate(uint256 newRate) external; /** * @dev Emitted when a new operator is registered in the contract. @@ -87,14 +83,11 @@ interface IOperatorRegistry { * @param operatorExocoreAddress The Exocore address of the operator. * @param newConsensusPublicKey The new consensus key for the operator. */ - event OperatorKeyReplaced( - string operatorExocoreAddress, - bytes32 newConsensusPublicKey - ); + event OperatorKeyReplaced(string operatorExocoreAddress, bytes32 newConsensusPublicKey); /** * @dev Emitted when an operator's commission rate is updated. * @param newRate The new commission rate for the operator. */ event OperatorCommissionUpdated(uint256 newRate); -} \ No newline at end of file +} diff --git a/src/interfaces/ITokenWhitelister.sol b/src/interfaces/ITokenWhitelister.sol index 576faa4d..fa3c2880 100644 --- a/src/interfaces/ITokenWhitelister.sol +++ b/src/interfaces/ITokenWhitelister.sol @@ -20,4 +20,4 @@ interface ITokenWhitelister { * @dev Indicates an operation was attempted with a token that is not authorized. */ error UnauthorizedToken(); -} \ No newline at end of file +} diff --git a/src/interfaces/precompiles/IClientChains.sol b/src/interfaces/precompiles/IClientChains.sol index e687ff06..03ff0da1 100644 --- a/src/interfaces/precompiles/IClientChains.sol +++ b/src/interfaces/precompiles/IClientChains.sol @@ -4,9 +4,7 @@ pragma solidity >=0.8.17; address constant CLIENT_CHAINS_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000801; /// @dev The CLIENT_CHAINS contract's instance. -IClientChains constant CLIENT_CHAINS_CONTRACT = IClientChains( - CLIENT_CHAINS_PRECOMPILE_ADDRESS -); +IClientChains constant CLIENT_CHAINS_CONTRACT = IClientChains(CLIENT_CHAINS_PRECOMPILE_ADDRESS); /// @author Exocore Team /// @title Client Chains Precompile Contract @@ -16,4 +14,3 @@ interface IClientChains { /// @dev Returns the chain indices of the client chains. function getClientChains() external view returns (bool, uint16[] memory); } - diff --git a/src/libraries/BeaconChainProofs.sol b/src/libraries/BeaconChainProofs.sol index 8f570165..e5ae6e51 100644 --- a/src/libraries/BeaconChainProofs.sol +++ b/src/libraries/BeaconChainProofs.sol @@ -103,7 +103,7 @@ library BeaconChainProofs { /// @notice The number of seconds in a slot in the beacon chain uint64 internal constant SECONDS_PER_SLOT = 12; - /// @notice Number of seconds per epoch: 384 == 32 slots/epoch * 12 seconds/slot + /// @notice Number of seconds per epoch: 384 == 32 slots/epoch * 12 seconds/slot uint64 internal constant SECONDS_PER_EPOCH = SLOTS_PER_EPOCH * SECONDS_PER_SLOT; bytes8 internal constant UINT64_MASK = 0xffffffffffffffff; @@ -139,21 +139,20 @@ library BeaconChainProofs { bytes32[] calldata stateRootProof ) internal view returns (bool valid) { bool validStateRoot = isValidStateRoot(stateRoot, beaconBlockRoot, stateRootProof); - bool validVCRootAgainstStateRoot = isValidVCRootAgainstStateRoot(validatorContainerRoot, stateRoot, validatorContainerRootProof, validatorIndex); + bool validVCRootAgainstStateRoot = isValidVCRootAgainstStateRoot( + validatorContainerRoot, stateRoot, validatorContainerRootProof, validatorIndex + ); if (validStateRoot && validVCRootAgainstStateRoot) { valid = true; } } - function isValidStateRoot( - bytes32 stateRoot, - bytes32 beaconBlockRoot, - bytes32[] calldata stateRootProof - ) internal view returns (bool) { - require( - stateRootProof.length == BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT, - "state root proof should have 3 nodes" - ); + function isValidStateRoot(bytes32 stateRoot, bytes32 beaconBlockRoot, bytes32[] calldata stateRootProof) + internal + view + returns (bool) + { + require(stateRootProof.length == BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT, "state root proof should have 3 nodes"); return Merkle.verifyInclusionSha256({ proof: stateRootProof, @@ -192,12 +191,10 @@ library BeaconChainProofs { bytes32 executionPayloadRoot, bytes32[] calldata executionPayloadRootProof ) internal view returns (bool valid) { - bool validExecutionPayloadRoot = isValidExecutionPayloadRoot(executionPayloadRoot, beaconBlockRoot, executionPayloadRootProof); + bool validExecutionPayloadRoot = + isValidExecutionPayloadRoot(executionPayloadRoot, beaconBlockRoot, executionPayloadRootProof); bool validWCRootAgainstExecutionPayloadRoot = isValidWCRootAgainstExecutionPayloadRoot( - withdrawalContainerRoot, - executionPayloadRoot, - withdrawalContainerRootProof, - withdrawalIndex + withdrawalContainerRoot, executionPayloadRoot, withdrawalContainerRootProof, withdrawalIndex ); if (validExecutionPayloadRoot && validWCRootAgainstExecutionPayloadRoot) { valid = true; @@ -210,12 +207,12 @@ library BeaconChainProofs { bytes32[] calldata executionPayloadRootProof ) internal view returns (bool) { require( - executionPayloadRootProof.length == BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT + BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT, + executionPayloadRootProof.length + == BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT + BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT, "state root proof should have 3 nodes" ); - uint256 leafIndex = (BODY_ROOT_INDEX << (BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT)) | - EXECUTION_PAYLOAD_INDEX; + uint256 leafIndex = (BODY_ROOT_INDEX << (BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT)) | EXECUTION_PAYLOAD_INDEX; return Merkle.verifyInclusionSha256({ proof: executionPayloadRootProof, @@ -236,8 +233,7 @@ library BeaconChainProofs { "validator container root proof should have 46 nodes" ); - uint256 leafIndex = (WITHDRAWALS_INDEX << (WITHDRAWALS_TREE_HEIGHT + 1)) | - uint256(withdrawalIndex); + uint256 leafIndex = (WITHDRAWALS_INDEX << (WITHDRAWALS_TREE_HEIGHT + 1)) | uint256(withdrawalIndex); return Merkle.verifyInclusionSha256({ proof: withdrawalContainerRootProof, diff --git a/src/libraries/Merkle.sol b/src/libraries/Merkle.sol index 11046729..9218cb7b 100644 --- a/src/libraries/Merkle.sol +++ b/src/libraries/Merkle.sol @@ -24,12 +24,11 @@ library Merkle { * * Note this is for a Merkle tree using the sha256 hash function */ - function verifyInclusionSha256( - bytes32[] memory proof, - bytes32 root, - bytes32 leaf, - uint256 index - ) internal view returns (bool) { + function verifyInclusionSha256(bytes32[] memory proof, bytes32 root, bytes32 leaf, uint256 index) + internal + view + returns (bool) + { return processInclusionProofSha256(proof, leaf, index) == root; } @@ -43,14 +42,13 @@ library Merkle { * * Note this is for a Merkle tree using the sha256 hash function */ - function processInclusionProofSha256( - bytes32[] memory proof, - bytes32 leaf, - uint256 index - ) internal view returns (bytes32) { + function processInclusionProofSha256(bytes32[] memory proof, bytes32 leaf, uint256 index) + internal + view + returns (bytes32) + { require( - proof.length != 0, - "Merkle.processInclusionProofSha256: proof length should be a non-zero multiple of 32" + proof.length != 0, "Merkle.processInclusionProofSha256: proof length should be a non-zero multiple of 32" ); bytes32[1] memory computedHash = [leaf]; for (uint256 i = 0; i < proof.length; i++) { @@ -60,9 +58,7 @@ library Merkle { assembly { mstore(0x00, mload(computedHash)) mstore(0x20, mload(node)) - if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) { - revert(0, 0) - } + if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) { revert(0, 0) } index := div(index, 2) } } else { @@ -70,9 +66,7 @@ library Merkle { assembly { mstore(0x00, mload(node)) mstore(0x20, mload(computedHash)) - if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) { - revert(0, 0) - } + if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) { revert(0, 0) } index := div(index, 2) } } @@ -81,10 +75,10 @@ library Merkle { } /** - @notice this function returns the merkle root of a tree created from a set of leaves using sha256 as its hash function - @param leaves the leaves of the merkle tree - @return The computed Merkle root of the tree. - @dev A pre-condition to this function is that leaves.length is a power of two. If not, the function will merkleize the inputs incorrectly. + * @notice this function returns the merkle root of a tree created from a set of leaves using sha256 as its hash function + * @param leaves the leaves of the merkle tree + * @return The computed Merkle root of the tree. + * @dev A pre-condition to this function is that leaves.length is a power of two. If not, the function will merkleize the inputs incorrectly. */ function merkleizeSha256(bytes32[] memory leaves) internal pure returns (bytes32) { //there are half as many nodes in the layer above the leaves diff --git a/src/libraries/ValidatorContainer.sol b/src/libraries/ValidatorContainer.sol index 7cf0750d..fa7f2d4c 100644 --- a/src/libraries/ValidatorContainer.sol +++ b/src/libraries/ValidatorContainer.sol @@ -4,22 +4,22 @@ import "../libraries/Endian.sol"; /** * class Validator(Container): - pubkey: BLSPubkey - withdrawal_credentials: Bytes32 # Commitment to pubkey for withdrawals - effective_balance: Gwei # Balance at stake - slashed: boolean - # Status epochs - activation_eligibility_epoch: Epoch # When criteria for activation were met - activation_epoch: Epoch - exit_epoch: Epoch - withdrawable_epoch: Epoch # When validator can withdraw funds + * pubkey: BLSPubkey + * withdrawal_credentials: Bytes32 # Commitment to pubkey for withdrawals + * effective_balance: Gwei # Balance at stake + * slashed: boolean + * # Status epochs + * activation_eligibility_epoch: Epoch # When criteria for activation were met + * activation_epoch: Epoch + * exit_epoch: Epoch + * withdrawable_epoch: Epoch # When validator can withdraw funds */ library ValidatorContainer { using Endian for bytes32; uint256 internal constant VALID_LENGTH = 8; uint256 internal constant MERKLE_TREE_HEIGHT = 3; - + function verifyValidatorContainerBasic(bytes32[] calldata validatorContainer) internal pure returns (bool) { return validatorContainer.length == VALID_LENGTH; } @@ -54,9 +54,9 @@ library ValidatorContainer { function merklelizeValidatorContainer(bytes32[] calldata validatorContainer) internal pure returns (bytes32) { bytes32[] memory leaves = validatorContainer; - for (uint i; i < MERKLE_TREE_HEIGHT; i++) { + for (uint256 i; i < MERKLE_TREE_HEIGHT; i++) { bytes32[] memory roots = new bytes32[](leaves.length / 2); - for (uint j; j < leaves.length / 2; j++) { + for (uint256 j; j < leaves.length / 2; j++) { roots[j] = sha256(abi.encodePacked(leaves[2 * j], leaves[2 * j + 1])); } leaves = roots; @@ -64,4 +64,4 @@ library ValidatorContainer { return leaves[0]; } -} \ No newline at end of file +} diff --git a/src/libraries/WithdrawalContainer.sol b/src/libraries/WithdrawalContainer.sol index a5254671..79a76454 100644 --- a/src/libraries/WithdrawalContainer.sol +++ b/src/libraries/WithdrawalContainer.sol @@ -4,17 +4,17 @@ import "../libraries/Endian.sol"; /** * class Withdrawal(Container): - index: WithdrawalIndex - validator_index: ValidatorIndex - address: ExecutionAddress - amount: Gwei + * index: WithdrawalIndex + * validator_index: ValidatorIndex + * address: ExecutionAddress + * amount: Gwei */ library WithdrawalContainer { using Endian for bytes32; uint256 internal constant VALID_LENGTH = 4; uint256 internal constant MERKLE_TREE_HEIGHT = 2; - + function verifyWithdrawalContainerBasic(bytes32[] calldata withdrawalContainer) internal pure returns (bool) { return withdrawalContainer.length == VALID_LENGTH; } @@ -37,9 +37,9 @@ library WithdrawalContainer { function merklelizeWithdrawalContainer(bytes32[] calldata withdrawalContainer) internal pure returns (bytes32) { bytes32[] memory leaves = withdrawalContainer; - for (uint i; i < MERKLE_TREE_HEIGHT; i++) { + for (uint256 i; i < MERKLE_TREE_HEIGHT; i++) { bytes32[] memory roots = new bytes32[](leaves.length / 2); - for (uint j; j < leaves.length / 2; j++) { + for (uint256 j; j < leaves.length / 2; j++) { roots[j] = sha256(abi.encodePacked(leaves[2 * j], leaves[2 * j + 1])); } leaves = roots; @@ -47,4 +47,4 @@ library WithdrawalContainer { return leaves[0]; } -} \ No newline at end of file +} diff --git a/src/lzApp/OAppSenderUpgradeable.sol b/src/lzApp/OAppSenderUpgradeable.sol index 54b9f12e..916edd65 100644 --- a/src/lzApp/OAppSenderUpgradeable.sol +++ b/src/lzApp/OAppSenderUpgradeable.sol @@ -87,10 +87,10 @@ abstract contract OAppSenderUpgradeable is OAppCoreUpgradeable { uint256 messageValue = _payNative(_fee.nativeFee, byApp); if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee); - return endpoint + return endpoint.send{value: messageValue}( // solhint-disable-next-line check-send-result - .send{value: messageValue}( - MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0), _refundAddress + MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0), + _refundAddress ); } diff --git a/src/storage/BootstrapStorage.sol b/src/storage/BootstrapStorage.sol index fb1328f4..8789b874 100644 --- a/src/storage/BootstrapStorage.sol +++ b/src/storage/BootstrapStorage.sol @@ -7,12 +7,13 @@ import {IBeacon} from "@openzeppelin-contracts/contracts/proxy/beacon/IBeacon.so import {BeaconProxyBytecode} from "../core/BeaconProxyBytecode.sol"; import {Vault} from "../core/Vault.sol"; import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; +import {ITokenWhitelister} from "../interfaces/ITokenWhitelister.sol"; // BootstrapStorage should inherit from GatewayStorage since it exists // prior to ClientChainGateway. ClientChainStorage should inherit from // BootstrapStorage to ensure overlap of positioning between the // members of each contract. -contract BootstrapStorage is GatewayStorage { +contract BootstrapStorage is GatewayStorage, ITokenWhitelister { /* -------------------------------------------------------------------------- */ /* state variables exclusively owned by Bootstrap */ /* -------------------------------------------------------------------------- */ @@ -58,7 +59,7 @@ contract BootstrapStorage is GatewayStorage { * The system used is a delegated POS system, where the vote power of each operator * is determined by the total amount of tokens delegated to them across all supported * tokens. - */ + */ address[] public registeredOperators; /** @@ -70,7 +71,7 @@ contract BootstrapStorage is GatewayStorage { mapping(address ethAddress => string exoAddress) public ethToExocoreAddress; /** - * @dev Maps Exocore addresses to their corresponding operator details stored in an + * @dev Maps Exocore addresses to their corresponding operator details stored in an * Operator` struct. * @notice Use this mapping to access or modify operator details associated with a specific * Exocore address. @@ -95,8 +96,7 @@ contract BootstrapStorage is GatewayStorage { */ // delegationsByOperator means it is indexed by operator address and not that is is // a delegation made by the operator. - mapping(string exoAddress => mapping(address tokenAddress => uint256 amount)) public - delegationsByOperator; + mapping(string exoAddress => mapping(address tokenAddress => uint256 amount)) public delegationsByOperator; // depositor and delegation information /** @@ -119,8 +119,7 @@ contract BootstrapStorage is GatewayStorage { * @notice This mapping is used to keep track of the total deposits made by each account * for each token. */ - mapping(address depositor => mapping(address tokenAddress => uint256 amount)) public - totalDepositAmounts; + mapping(address depositor => mapping(address tokenAddress => uint256 amount)) public totalDepositAmounts; /** * @dev Maps depositor addresses to another mapping, where the key is an token address and @@ -129,8 +128,7 @@ contract BootstrapStorage is GatewayStorage { * token. The amount available for withdrawal is the total deposited amount minus the * amount already delegated. */ - mapping(address depositor => mapping(address tokenAddress => uint256 amount)) public - withdrawableAmounts; + mapping(address depositor => mapping(address tokenAddress => uint256 amount)) public withdrawableAmounts; /** * @dev Maps a delegator address to a nested mapping, where the first key the operator @@ -139,13 +137,8 @@ contract BootstrapStorage is GatewayStorage { * @notice This allows tracking of how much each delegator has delegated to each operator * for all of the whitelisted tokens. */ - mapping( - address delegator => mapping( - string exoAddress => mapping( - address tokenAddress => uint256 - ) - ) - ) public delegations; + mapping(address delegator => mapping(string exoAddress => mapping(address tokenAddress => uint256))) public + delegations; // bootstrapping information - including status, address of proxy, implementation, and // initialization @@ -230,7 +223,7 @@ contract BootstrapStorage is GatewayStorage { // the beacon that stores the Vault implementation contract address for proxy /** - * @notice this stores the Vault implementation contract address for proxy, and it is + * @notice this stores the Vault implementation contract address for proxy, and it is * shsared among all beacon proxies as an immutable. */ IBeacon public immutable vaultBeacon; @@ -282,9 +275,7 @@ contract BootstrapStorage is GatewayStorage { * @param depositor The address of the depositor, on this chain. * @param amount The amount of the token accepted as deposit. */ - event DepositResult( - bool indexed success, address indexed token, address indexed depositor, uint256 amount - ); + event DepositResult(bool indexed success, address indexed token, address indexed depositor, uint256 amount); /** * @notice Emitted when a withdrawal is made from the contract. @@ -308,8 +299,7 @@ contract BootstrapStorage is GatewayStorage { * @param amount The amount of the token delegated. */ event DelegateResult( - bool indexed success, address indexed delegator, string indexed delegatee, - address token, uint256 amount + bool indexed success, address indexed delegator, string indexed delegatee, address token, uint256 amount ); /** @@ -322,8 +312,7 @@ contract BootstrapStorage is GatewayStorage { * @param amount The amount of the token undelegated. */ event UndelegateResult( - bool indexed success, address indexed undelegator, string indexed undelegatee, - address token, uint256 amount + bool indexed success, address indexed undelegator, string indexed undelegatee, address token, uint256 amount ); /** @@ -399,14 +388,34 @@ contract BootstrapStorage is GatewayStorage { uint256[40] private __gap; - constructor( - uint32 exocoreChainId_, - address vaultBeacon_, - address beaconProxyBytecode_ - ) { + modifier isTokenWhitelisted(address token) { + require(isWhitelistedToken[token], "BootstrapStorage: token is not whitelisted"); + _; + } + + modifier isValidAmount(uint256 amount) { + require(amount > 0, "BootstrapStorage: amount should be greater than zero"); + _; + } + + modifier vaultExists(address token) { + require(address(tokenToVault[token]) != address(0), "BootstrapStorage: no vault added for this token"); + _; + } + + modifier isValidBech32Address(string calldata exocoreAddress) { + require(isValidExocoreAddress(exocoreAddress), "BootstrapStorage: invalid bech32 encoded Exocore address"); + _; + } + + constructor(uint32 exocoreChainId_, address vaultBeacon_, address beaconProxyBytecode_) { require(exocoreChainId_ != 0, "BootstrapStorage: exocore chain id should not be empty"); - require(vaultBeacon_ != address(0), "BootstrapStorage: the vaultBeacon address for beacon proxy should not be empty"); - require(beaconProxyBytecode_ != address(0), "BootstrapStorage: the beaconProxyBytecode address should not be empty"); + require( + vaultBeacon_ != address(0), "BootstrapStorage: the vaultBeacon address for beacon proxy should not be empty" + ); + require( + beaconProxyBytecode_ != address(0), "BootstrapStorage: the beaconProxyBytecode address should not be empty" + ); exocoreChainId = exocoreChainId_; vaultBeacon = IBeacon(vaultBeacon_); @@ -421,14 +430,12 @@ contract BootstrapStorage is GatewayStorage { return vault; } - function isValidExocoreAddress( - string calldata operatorExocoreAddress - ) public pure returns (bool) { + function isValidExocoreAddress(string calldata operatorExocoreAddress) public pure returns (bool) { bytes memory stringBytes = bytes(operatorExocoreAddress); if (stringBytes.length != 42) { return false; } - for (uint i = 0; i < EXO_ADDRESS_PREFIX.length; i++) { + for (uint256 i = 0; i < EXO_ADDRESS_PREFIX.length; i++) { if (stringBytes[i] != EXO_ADDRESS_PREFIX[i]) { return false; } @@ -452,4 +459,34 @@ contract BootstrapStorage is GatewayStorage { tokenToVault[underlyingToken] = vault; return vault; } -} \ No newline at end of file + + // implementation of ITokenWhitelister + function addWhitelistToken(address _token) public virtual override { + require(!isWhitelistedToken[_token], "BootstrapStorage: token should be not whitelisted before"); + whitelistTokens.push(_token); + isWhitelistedToken[_token] = true; + + // deploy the corresponding vault if not deployed before + if (address(tokenToVault[_token]) == address(0)) { + _deployVault(_token); + } + + emit WhitelistTokenAdded(_token); + } + + // implementation of ITokenWhitelister + function removeWhitelistToken(address _token) public virtual override { + isWhitelistedToken[_token] = false; + // the implicit assumption here is that the _token must be included in whitelistTokens + // if isWhitelistedToken[_token] is true + for (uint256 i = 0; i < whitelistTokens.length; i++) { + if (whitelistTokens[i] == _token) { + whitelistTokens[i] = whitelistTokens[whitelistTokens.length - 1]; + whitelistTokens.pop(); + break; + } + } + + emit WhitelistTokenRemoved(_token); + } +} diff --git a/src/storage/ClientChainGatewayStorage.sol b/src/storage/ClientChainGatewayStorage.sol index 5c945c3b..f91cef7b 100644 --- a/src/storage/ClientChainGatewayStorage.sol +++ b/src/storage/ClientChainGatewayStorage.sol @@ -50,35 +50,21 @@ contract ClientChainGatewayStorage is BootstrapStorage { error CapsuleNotExist(); - modifier isTokenWhitelisted(address token) { - require(isWhitelistedToken[token], "BaseRestakingController: token is not whitelisted"); - _; - } - - modifier isValidAmount(uint256 amount) { - require(amount > 0, "BaseRestakingController: amount should be greater than zero"); - _; - } - - modifier vaultExists(address token) { - require(address(tokenToVault[token]) != address(0), "BaseRestakingController: no vault added for this token"); - _; - } - - modifier isValidBech32Address(string calldata exocoreAddress) { - require(isValidExocoreAddress(exocoreAddress), "BaseRestakingController: invalid bech32 encoded Exocore address"); - _; - } - constructor( - uint32 exocoreChainId_, - address beaconOracleAddress_, + uint32 exocoreChainId_, + address beaconOracleAddress_, address vaultBeacon_, address exoCapsuleBeacon_, address beaconProxyBytecode_ ) BootstrapStorage(exocoreChainId_, vaultBeacon_, beaconProxyBytecode_) { - require(beaconOracleAddress_ != address(0), "ClientChainGatewayStorage: beacon chain oracle address should not be empty"); - require(exoCapsuleBeacon_ != address(0), "ClientChainGatewayStorage: the exoCapsuleBeacon address for beacon proxy should not be empty"); + require( + beaconOracleAddress_ != address(0), + "ClientChainGatewayStorage: beacon chain oracle address should not be empty" + ); + require( + exoCapsuleBeacon_ != address(0), + "ClientChainGatewayStorage: the exoCapsuleBeacon address for beacon proxy should not be empty" + ); beaconOracleAddress = beaconOracleAddress_; exoCapsuleBeacon = IBeacon(exoCapsuleBeacon_); diff --git a/src/storage/ExoCapsuleStorage.sol b/src/storage/ExoCapsuleStorage.sol index 1dc7a243..80290980 100644 --- a/src/storage/ExoCapsuleStorage.sol +++ b/src/storage/ExoCapsuleStorage.sol @@ -10,6 +10,7 @@ contract ExoCapsuleStorage { UNREGISTERED, // the validator has not been registered in this ExoCapsule REGISTERED, // staked on ethpos and withdrawal credentials are pointed to the ExoCapsule WITHDRAWN // withdrawn from the Beacon Chain + } struct Validator { @@ -38,4 +39,4 @@ contract ExoCapsuleStorage { mapping(uint256 index => bytes32 pubkey) _capsuleValidatorsByIndex; uint256[40] private __gap; -} \ No newline at end of file +} diff --git a/test/foundry/Bootstrap.t.sol b/test/foundry/Bootstrap.t.sol index 347d7571..2ae90698 100644 --- a/test/foundry/Bootstrap.t.sol +++ b/test/foundry/Bootstrap.t.sol @@ -30,12 +30,12 @@ contract BootstrapTest is Test { Bootstrap bootstrap; address[] addrs = new address[](6); uint256[] amounts = [ - 35 * 10 ** 18, // self - 25 * 10 ** 18, // self - 10 * 10 ** 18, // self - 17 * 10 ** 18, // 8 + 9 + 0 - 15 * 10 ** 18, // 0 + 7 + 8 - 8 * 10 ** 18 // 2 + 0 + 6 + 35 * 10 ** 18, // self + 25 * 10 ** 18, // self + 10 * 10 ** 18, // self + 17 * 10 ** 18, // 8 + 9 + 0 + 15 * 10 ** 18, // 0 + 7 + 8 + 8 * 10 ** 18 // 2 + 0 + 6 ]; address deployer = address(0xdeadbeef); uint256 spawnTime; @@ -73,10 +73,10 @@ contract BootstrapTest is Test { appendedToken = new MyToken("MyToken2", "MYT2", 18, addrs, 1000 * 10 ** 18); appendedWhitelistTokensForUpgrade.push(address(appendedToken)); - /// deploy vault implementationcontract that has logics called by proxy + // deploy vault implementationcontract that has logics called by proxy vaultImplementation = new Vault(); - /// deploy the vault beacon that store the implementation contract address + // deploy the vault beacon that store the implementation contract address vaultBeacon = new UpgradeableBeacon(address(vaultImplementation)); // deploy BeaconProxyBytecode to store BeaconProxyBytecode @@ -85,29 +85,33 @@ contract BootstrapTest is Test { // then the ProxyAdmin proxyAdmin = new CustomProxyAdmin(); // then the logic - clientChainLzEndpoint = new NonShortCircuitEndpointV2Mock( - clientChainId, exocoreValidatorSet - ); + clientChainLzEndpoint = new NonShortCircuitEndpointV2Mock(clientChainId, exocoreValidatorSet); Bootstrap bootstrapLogic = new Bootstrap( - address(clientChainLzEndpoint), - exocoreChainId, - address(vaultBeacon), - address(beaconProxyBytecode) + address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode) ); // then the params + proxy spawnTime = block.timestamp + 1 hours; offsetDuration = 30 minutes; bootstrap = Bootstrap( - payable(address( - new TransparentUpgradeableProxy( - address(bootstrapLogic), address(proxyAdmin), - abi.encodeCall(bootstrap.initialize, - (deployer, spawnTime, offsetDuration, - payable(exocoreValidatorSet), whitelistTokens, - address(proxyAdmin)) + payable( + address( + new TransparentUpgradeableProxy( + address(bootstrapLogic), + address(proxyAdmin), + abi.encodeCall( + bootstrap.initialize, + ( + deployer, + spawnTime, + offsetDuration, + payable(exocoreValidatorSet), + whitelistTokens, + address(proxyAdmin) + ) + ) ) ) - )) + ) ); // validate the initialization assertTrue(bootstrap.isWhitelistedToken(address(myToken))); @@ -123,9 +127,7 @@ contract BootstrapTest is Test { ); assertTrue(address(bootstrap.tokenToVault(address(myToken))) == expectedVaultAddress); // now set the gateway address for Exocore. - clientChainLzEndpoint.setDestLzEndpoint( - undeployedExocoreGateway, undeployedExocoreLzEndpoint - ); + clientChainLzEndpoint.setDestLzEndpoint(undeployedExocoreGateway, undeployedExocoreLzEndpoint); bootstrap.setPeer(exocoreChainId, bytes32(bytes20(undeployedExocoreGateway))); // lastly set up the upgrade params @@ -143,25 +145,11 @@ contract BootstrapTest is Test { address(capsuleBeacon), address(beaconProxyBytecode) ); - // uint256 tokenCount = bootstrap.getWhitelistedTokensCount(); - // address[] memory tokensForCall = new address[](tokenCount); - // for (uint256 i = 0; i < tokenCount; i++) { - // tokensForCall[i] = bootstrap.whitelistTokens(i); - // } + // we could also use encodeWithSelector and supply .initialize.selector instead. bytes memory initialization = abi.encodeCall( - clientGatewayLogic.initialize, - ( - // bootstrap.exocoreChainId(), - // bootstrap.exocoreValidatorSetAddress(), - // tokensForCall - payable(exocoreValidatorSet), - appendedWhitelistTokensForUpgrade - ) - ); - bootstrap.setClientChainGatewayLogic( - address(clientGatewayLogic), - initialization + clientGatewayLogic.initialize, (payable(exocoreValidatorSet), appendedWhitelistTokensForUpgrade) ); + bootstrap.setClientChainGatewayLogic(address(clientGatewayLogic), initialization); vm.stopPrank(); } @@ -177,7 +165,7 @@ contract BootstrapTest is Test { function test01_AddWhitelistToken_AlreadyExists() public { vm.startPrank(deployer); - vm.expectRevert("Bootstrap: token should be not whitelisted before"); + vm.expectRevert("BootstrapStorage: token should be not whitelisted before"); bootstrap.addWhitelistToken(address(myToken)); vm.stopPrank(); } @@ -194,34 +182,51 @@ contract BootstrapTest is Test { } vm.stopPrank(); + // get the vault to play with + Vault vault = Vault(address(bootstrap.tokenToVault(address(myToken)))); + // Make deposits and check values for (uint256 i = 0; i < 6; i++) { vm.startPrank(addrs[i]); - Vault vault = Vault(address(bootstrap.tokenToVault(address(myToken)))); + // first approve the vault myToken.approve(address(vault), amounts[i]); + + // store the current state of depositors count and if we are already one uint256 prevDepositorsCount = bootstrap.getDepositorsCount(); bool prevIsDepositor = bootstrap.isDepositor(addrs[i]); + // ...and current balance uint256 prevBalance = myToken.balanceOf(addrs[i]); + // ...and current deposit by us uint256 prevDeposit = bootstrap.totalDepositAmounts(addrs[i], address(myToken)); - uint256 prevWithdrawable = bootstrap.withdrawableAmounts( - addrs[i], address(myToken) - ); + // ...and current withdrawable + uint256 prevWithdrawable = bootstrap.withdrawableAmounts(addrs[i], address(myToken)); + // ...and current total token deposit uint256 prevTokenDeposit = bootstrap.depositsByToken(address(myToken)); + + // finally execute the deposit bootstrap.deposit(address(myToken), amounts[i]); + + // check the balance and if it has decreased by the respective amount uint256 newBalance = myToken.balanceOf(addrs[i]); assertTrue(newBalance == prevBalance - amounts[i]); + + // check the deposit and withdrawable amounts uint256 newDeposit = bootstrap.totalDepositAmounts(addrs[i], address(myToken)); assertTrue(newDeposit == prevDeposit + amounts[i]); uint256 newWithdrawable = bootstrap.withdrawableAmounts(addrs[i], address(myToken)); assertTrue(newWithdrawable == prevWithdrawable + amounts[i]); + + // if previously not a depositor, count will increase if (!prevIsDepositor) { assertTrue(bootstrap.isDepositor(addrs[i])); assertTrue(bootstrap.getDepositorsCount() == prevDepositorsCount + 1); } else { assertTrue(bootstrap.getDepositorsCount() == prevDepositorsCount); } - assertTrue(bootstrap.depositsByToken(address(myToken)) == - prevTokenDeposit + amounts[i]); + + // total deposit amount should increase + assertTrue(bootstrap.depositsByToken(address(myToken)) == prevTokenDeposit + amounts[i]); + vm.stopPrank(); } } @@ -266,7 +271,7 @@ contract BootstrapTest is Test { // now try to deposit myToken.approve(address(bootstrap), amounts[0]); - vm.expectRevert("Bootstrap: token is not whitelisted"); + vm.expectRevert("BootstrapStorage: token is not whitelisted"); bootstrap.deposit(cloneAddress, amounts[0]); vm.stopPrank(); } @@ -311,31 +316,18 @@ contract BootstrapTest is Test { bytes32(0xe2f00b6510e16fd8cc5802a4011d6f093acbbbca7c284cad6aa2c2e474bb50f9), bytes32(0xa29429a3ca352334fbe75df9485544bd517e3718df73725f33c6d06f3c1caade) ]; - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e18, 1e18); for (uint256 i = 0; i < 3; i++) { vm.startPrank(addrs[i]); - bootstrap.registerOperator( - operators[i], names[i], commission, pubKeys[i] - ); + bootstrap.registerOperator(operators[i], names[i], commission, pubKeys[i]); // check count assertTrue(bootstrap.getOperatorsCount() == i + 1); // check ethToExocoreAddress mapping string memory exoAddress = bootstrap.ethToExocoreAddress(addrs[i]); - assertTrue( - keccak256(abi.encodePacked(exoAddress)) == - keccak256(abi.encodePacked(operators[i])) - ); - ( - string memory name, - IOperatorRegistry.Commission memory thisCommision, - bytes32 key - ) = bootstrap.operators(exoAddress); - assertTrue( - keccak256(abi.encodePacked(name)) == - keccak256(abi.encodePacked(names[i])) - ); + assertTrue(keccak256(abi.encodePacked(exoAddress)) == keccak256(abi.encodePacked(operators[i]))); + (string memory name, IOperatorRegistry.Commission memory thisCommision, bytes32 key) = + bootstrap.operators(exoAddress); + assertTrue(keccak256(abi.encodePacked(name)) == keccak256(abi.encodePacked(names[i]))); assertTrue(key == pubKeys[i]); assertTrue(thisCommision.rate == commission.rate); vm.stopPrank(); @@ -343,69 +335,48 @@ contract BootstrapTest is Test { } function test03_RegisterOperator_EthAlreadyRegistered() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e18, 1e18); // Register operator string memory exo = "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac"; string memory name = "operator1"; - bytes32 pubKey = - bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); + bytes32 pubKey = bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); vm.startPrank(addrs[0]); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); // change all identifying params except eth address of operator exo = "exo1wnw7zcl9fy04ax69uffumwkdxftfqsjyj37wt2"; name = "operator1_re"; - pubKey = - bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540783); + pubKey = bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540783); vm.expectRevert("Ethereum address already linked to an operator"); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); vm.stopPrank(); } function test03_RegisterOperator_ExoAlreadyRegistered() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e18, 1e18); // Register operator string memory exo = "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac"; string memory name = "operator1"; - bytes32 pubKey = - bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); + bytes32 pubKey = bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); vm.startPrank(addrs[0]); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); // change all identifying params except exo address of operator vm.stopPrank(); vm.startPrank(addrs[1]); name = "operator1_re"; - pubKey = - bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540783); + pubKey = bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540783); vm.expectRevert("Operator with this Exocore address is already registered"); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); vm.stopPrank(); } function test03_RegisterOperator_ConsensusKeyInUse() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e18, 1e18); // Register operator string memory exo = "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac"; string memory name = "operator1"; - bytes32 pubKey = - bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); + bytes32 pubKey = bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); vm.startPrank(addrs[0]); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); // change all identifying params except consensus key of operator vm.stopPrank(); @@ -413,60 +384,44 @@ contract BootstrapTest is Test { exo = "exo1wnw7zcl9fy04ax69uffumwkdxftfqsjyj37wt2"; name = "operator1_re"; vm.expectRevert("Consensus public key already in use"); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); vm.stopPrank(); } function test03_RegisterOperator_NameInUse() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e18, 1e18); // Register operator string memory exo = "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac"; string memory name = "operator1"; - bytes32 pubKey = - bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); + bytes32 pubKey = bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); vm.startPrank(addrs[0]); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); // change all identifying params except name of operator vm.stopPrank(); vm.startPrank(addrs[1]); exo = "exo1wnw7zcl9fy04ax69uffumwkdxftfqsjyj37wt2"; - pubKey = - bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540783); + pubKey = bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540783); vm.expectRevert("Name already in use"); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); vm.stopPrank(); } function test05_ReplaceKey() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e18, 1e18); // Register operator string memory exo = "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac"; string memory name = "operator1"; - bytes32 pubKey = - bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); + bytes32 pubKey = bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); vm.startPrank(addrs[0]); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); assertTrue(bootstrap.getOperatorsCount() == 1); - (, , bytes32 consensusPublicKey ) = bootstrap.operators(exo); + (,, bytes32 consensusPublicKey) = bootstrap.operators(exo); assertTrue(consensusPublicKey == pubKey); // Then change the key - bytes32 newKey = - bytes32(0xd995b7f4b2178b0466cfa512955ce2299a4487ebcd86f817d686880dd2b7c4b0); + bytes32 newKey = bytes32(0xd995b7f4b2178b0466cfa512955ce2299a4487ebcd86f817d686880dd2b7c4b0); bootstrap.replaceKey(newKey); - (, , consensusPublicKey ) = bootstrap.operators(exo); + (,, consensusPublicKey) = bootstrap.operators(exo); assertTrue(consensusPublicKey == newKey); vm.stopPrank(); } @@ -475,8 +430,7 @@ contract BootstrapTest is Test { test03_RegisterOperator(); // Then change the key vm.startPrank(addrs[0]); - bytes32 newKey = - bytes32(0xe2f00b6510e16fd8cc5802a4011d6f093acbbbca7c284cad6aa2c2e474bb50f9); + bytes32 newKey = bytes32(0xe2f00b6510e16fd8cc5802a4011d6f093acbbbca7c284cad6aa2c2e474bb50f9); vm.expectRevert("Consensus public key already in use"); bootstrap.replaceKey(newKey); vm.stopPrank(); @@ -486,8 +440,7 @@ contract BootstrapTest is Test { test03_RegisterOperator(); // Then change the key for the same address vm.startPrank(addrs[1]); - bytes32 newKey = - bytes32(0xe2f00b6510e16fd8cc5802a4011d6f093acbbbca7c284cad6aa2c2e474bb50f9); + bytes32 newKey = bytes32(0xe2f00b6510e16fd8cc5802a4011d6f093acbbbca7c284cad6aa2c2e474bb50f9); vm.expectRevert("Consensus public key already in use"); bootstrap.replaceKey(newKey); vm.stopPrank(); @@ -495,47 +448,36 @@ contract BootstrapTest is Test { function test05_ReplaceKey_Unregistered() public { vm.startPrank(addrs[1]); - bytes32 newKey = - bytes32(0xe2f00b6510e16fd8cc5802a4011d6f093acbbbca7c284cad6aa2c2e474bb50f9); + bytes32 newKey = bytes32(0xe2f00b6510e16fd8cc5802a4011d6f093acbbbca7c284cad6aa2c2e474bb50f9); vm.expectRevert("no such operator exists"); bootstrap.replaceKey(newKey); vm.stopPrank(); } function test06_UpdateRate() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e18, 1e18); // Register one operator string memory exo = "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac"; string memory name = "operator1"; - bytes32 pubKey = - bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); + bytes32 pubKey = bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); vm.startPrank(addrs[0]); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); bootstrap.updateRate(1e17); - (, IOperatorRegistry.Commission memory newCommission, ) = bootstrap.operators(exo); + (, IOperatorRegistry.Commission memory newCommission,) = bootstrap.operators(exo); assertTrue(newCommission.rate == 1e17); vm.stopPrank(); } function test06_UpdateRate_Twice() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e18, 1e18); // Register one operator string memory exo = "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac"; string memory name = "operator1"; - bytes32 pubKey = - bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); + bytes32 pubKey = bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); vm.startPrank(addrs[0]); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); bootstrap.updateRate(1e17); - (, IOperatorRegistry.Commission memory newCommission, ) = bootstrap.operators(exo); + (, IOperatorRegistry.Commission memory newCommission,) = bootstrap.operators(exo); assertTrue(newCommission.rate == 1e17); vm.expectRevert("Commission already edited once"); bootstrap.updateRate(1e17); @@ -543,18 +485,13 @@ contract BootstrapTest is Test { } function test06_UpdateRate_MoreThanMaxRate() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e17, 1e17 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e17, 1e17); // Register one operator string memory exo = "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac"; string memory name = "operator1"; - bytes32 pubKey = - bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); + bytes32 pubKey = bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); vm.startPrank(addrs[0]); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); vm.expectRevert("Rate exceeds max rate"); bootstrap.updateRate(2e17); vm.stopPrank(); @@ -562,18 +499,13 @@ contract BootstrapTest is Test { function test06_UpdateRate_MoreThanMaxChangeRate() public { // 0, 0.1, 0.01 - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e17, 1e16 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e17, 1e16); // Register one operator string memory exo = "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac"; string memory name = "operator1"; - bytes32 pubKey = - bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); + bytes32 pubKey = bytes32(0x27165ec2f29a4815b7c29e47d8700845b5ae267f2d61ad29fb3939aec5540782); vm.startPrank(addrs[0]); - bootstrap.registerOperator( - exo, name, commission, pubKey - ); + bootstrap.registerOperator(exo, name, commission, pubKey); vm.expectRevert("Rate change exceeds max change rate"); bootstrap.updateRate(2e16); vm.stopPrank(); @@ -605,33 +537,21 @@ contract BootstrapTest is Test { function test07_AddWhitelistedToken_AlreadyWhitelisted() public { vm.startPrank(deployer); - vm.expectRevert("Bootstrap: token should be not whitelisted before"); + vm.expectRevert("BootstrapStorage: token should be not whitelisted before"); bootstrap.addWhitelistToken(address(myToken)); vm.stopPrank(); } function test08_ExocoreAddressIsValid() public { - assertTrue( - bootstrap.isValidExocoreAddress( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac" - ) - ); + assertTrue(bootstrap.isValidExocoreAddress("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac")); } function test08_ExocoreAddressIsValid_Length() public { - assertFalse( - bootstrap.isValidExocoreAddress( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7acaa" - ) - ); + assertFalse(bootstrap.isValidExocoreAddress("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7acaa")); } function test08_ExocoreAddressIsValid_Prefix() public { - assertFalse( - bootstrap.isValidExocoreAddress( - "asd" - ) - ); + assertFalse(bootstrap.isValidExocoreAddress("asd")); } function test09_DelegateTo() public { @@ -643,70 +563,36 @@ contract BootstrapTest is Test { for (uint256 i = 0; i < 3; i++) { vm.startPrank(addrs[i]); string memory exo = bootstrap.ethToExocoreAddress(addrs[i]); - uint256 prevDelegation = bootstrap.delegations( - addrs[i], exo, address(myToken) - ); - uint256 prevDelegationByOperator = bootstrap.delegationsByOperator( - exo, address(myToken) - ); - uint256 prevWithdrawableAmount = bootstrap.withdrawableAmounts( - addrs[i], address(myToken) - ); - bootstrap.delegateTo( - exo, address(myToken), amounts[i] - ); - uint256 postDelegation = bootstrap.delegations( - addrs[i], exo, address(myToken) - ); - uint256 postDelegationByOperator = bootstrap.delegationsByOperator( - exo, address(myToken) - ); - uint256 postWithdrawableAmount = bootstrap.withdrawableAmounts( - addrs[i], address(myToken) - ); + uint256 prevDelegation = bootstrap.delegations(addrs[i], exo, address(myToken)); + uint256 prevDelegationByOperator = bootstrap.delegationsByOperator(exo, address(myToken)); + uint256 prevWithdrawableAmount = bootstrap.withdrawableAmounts(addrs[i], address(myToken)); + bootstrap.delegateTo(exo, address(myToken), amounts[i]); + uint256 postDelegation = bootstrap.delegations(addrs[i], exo, address(myToken)); + uint256 postDelegationByOperator = bootstrap.delegationsByOperator(exo, address(myToken)); + uint256 postWithdrawableAmount = bootstrap.withdrawableAmounts(addrs[i], address(myToken)); assertTrue(postDelegation == prevDelegation + amounts[i]); assertTrue(postDelegationByOperator == prevDelegationByOperator + amounts[i]); assertTrue(postWithdrawableAmount == prevWithdrawableAmount - amounts[i]); vm.stopPrank(); } // finally, delegate from stakers to the operators - uint8[3][3] memory delegations = [ - [8, 9, 0], - [0, 7, 8], - [2, 0, 6] - ]; + uint8[3][3] memory delegations = [[8, 9, 0], [0, 7, 8], [2, 0, 6]]; for (uint256 i = 0; i < 3; i++) { address delegator = addrs[i + 3]; vm.startPrank(delegator); - for(uint256 j = 0; j < 3; j++) { + for (uint256 j = 0; j < 3; j++) { uint256 amount = delegations[i][j] * 10 ** 18; if (amount != 0) { string memory exo = bootstrap.ethToExocoreAddress(addrs[j]); - uint256 prevDelegation = bootstrap.delegations( - delegator, exo, address(myToken) - ); - uint256 prevDelegationByOperator = bootstrap.delegationsByOperator( - exo, address(myToken) - ); - uint256 prevWithdrawableAmount = bootstrap.withdrawableAmounts( - delegator, address(myToken) - ); - bootstrap.delegateTo( - exo, address(myToken), uint256(amount) - ); - uint256 postDelegation = bootstrap.delegations( - delegator, exo, address(myToken) - ); - uint256 postDelegationByOperator = bootstrap.delegationsByOperator( - exo, address(myToken) - ); - uint256 postWithdrawableAmount = bootstrap.withdrawableAmounts( - delegator, address(myToken) - ); + uint256 prevDelegation = bootstrap.delegations(delegator, exo, address(myToken)); + uint256 prevDelegationByOperator = bootstrap.delegationsByOperator(exo, address(myToken)); + uint256 prevWithdrawableAmount = bootstrap.withdrawableAmounts(delegator, address(myToken)); + bootstrap.delegateTo(exo, address(myToken), uint256(amount)); + uint256 postDelegation = bootstrap.delegations(delegator, exo, address(myToken)); + uint256 postDelegationByOperator = bootstrap.delegationsByOperator(exo, address(myToken)); + uint256 postWithdrawableAmount = bootstrap.withdrawableAmounts(delegator, address(myToken)); assertTrue(postDelegation == prevDelegation + amount); - assertTrue( - postDelegationByOperator == prevDelegationByOperator + amount - ); + assertTrue(postDelegationByOperator == prevDelegationByOperator + amount); assertTrue(postWithdrawableAmount == prevWithdrawableAmount - amount); } } @@ -718,19 +604,15 @@ contract BootstrapTest is Test { test02_Deposit(); vm.startPrank(addrs[0]); vm.expectRevert("Operator does not exist"); - bootstrap.delegateTo( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), amounts[0] - ); + bootstrap.delegateTo("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), amounts[0]); } function test09_DelegateTo_TokenNotWhitelisted() public { test03_RegisterOperator(); test02_Deposit(); vm.startPrank(addrs[0]); - vm.expectRevert("Bootstrap: token is not whitelisted"); - bootstrap.delegateTo( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(0xa), amounts[0] - ); + vm.expectRevert("BootstrapStorage: token is not whitelisted"); + bootstrap.delegateTo("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(0xa), amounts[0]); } function test09_DelegateTo_NotEnoughBlance() public { @@ -740,28 +622,22 @@ contract BootstrapTest is Test { vm.stopPrank(); vm.startPrank(addrs[0]); vm.expectRevert(bytes("Bootstrap: insufficient withdrawable balance")); - bootstrap.delegateTo( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(0xa), amounts[0] - ); + bootstrap.delegateTo("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(0xa), amounts[0]); } function test09_DelegateTo_ZeroAmount() public { test03_RegisterOperator(); test02_Deposit(); vm.startPrank(addrs[0]); - vm.expectRevert("Bootstrap: amount should be greater than zero"); - bootstrap.delegateTo( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), 0 - ); + vm.expectRevert("BootstrapStorage: amount should be greater than zero"); + bootstrap.delegateTo("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), 0); } function test09_DelegateTo_NoDeposits() public { test03_RegisterOperator(); vm.startPrank(addrs[0]); vm.expectRevert("Bootstrap: insufficient withdrawable balance"); - bootstrap.delegateTo( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), amounts[0] - ); + bootstrap.delegateTo("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), amounts[0]); } function test09_DelegateTo_Excess() public { @@ -769,9 +645,7 @@ contract BootstrapTest is Test { test02_Deposit(); vm.startPrank(addrs[0]); vm.expectRevert("Bootstrap: insufficient withdrawable balance"); - bootstrap.delegateTo( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), amounts[0] + 1 - ); + bootstrap.delegateTo("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), amounts[0] + 1); } function test10_UndelegateFrom() public { @@ -780,70 +654,36 @@ contract BootstrapTest is Test { for (uint256 i = 0; i < 3; i++) { vm.startPrank(addrs[i]); string memory exo = bootstrap.ethToExocoreAddress(addrs[i]); - uint256 prevDelegation = bootstrap.delegations( - addrs[i], exo, address(myToken) - ); - uint256 prevDelegationByOperator = bootstrap.delegationsByOperator( - exo, address(myToken) - ); - uint256 prevWithdrawableAmount = bootstrap.withdrawableAmounts( - addrs[i], address(myToken) - ); - bootstrap.undelegateFrom( - exo, address(myToken), amounts[i] - ); - uint256 postDelegation = bootstrap.delegations( - addrs[i], exo, address(myToken) - ); - uint256 postDelegationByOperator = bootstrap.delegationsByOperator( - exo, address(myToken) - ); - uint256 postWithdrawableAmount = bootstrap.withdrawableAmounts( - addrs[i], address(myToken) - ); + uint256 prevDelegation = bootstrap.delegations(addrs[i], exo, address(myToken)); + uint256 prevDelegationByOperator = bootstrap.delegationsByOperator(exo, address(myToken)); + uint256 prevWithdrawableAmount = bootstrap.withdrawableAmounts(addrs[i], address(myToken)); + bootstrap.undelegateFrom(exo, address(myToken), amounts[i]); + uint256 postDelegation = bootstrap.delegations(addrs[i], exo, address(myToken)); + uint256 postDelegationByOperator = bootstrap.delegationsByOperator(exo, address(myToken)); + uint256 postWithdrawableAmount = bootstrap.withdrawableAmounts(addrs[i], address(myToken)); assertTrue(postDelegation == prevDelegation - amounts[i]); assertTrue(postDelegationByOperator == prevDelegationByOperator - amounts[i]); assertTrue(postWithdrawableAmount == prevWithdrawableAmount + amounts[i]); vm.stopPrank(); } // finally, undelegate from stakers to the operators - uint8[3][3] memory delegations = [ - [8, 9, 0], - [0, 7, 8], - [2, 0, 6] - ]; + uint8[3][3] memory delegations = [[8, 9, 0], [0, 7, 8], [2, 0, 6]]; for (uint256 i = 0; i < 3; i++) { address delegator = addrs[i + 3]; vm.startPrank(delegator); - for(uint256 j = 0; j < 3; j++) { + for (uint256 j = 0; j < 3; j++) { uint256 amount = delegations[i][j] * 10 ** 18; if (amount != 0) { string memory exo = bootstrap.ethToExocoreAddress(addrs[j]); - uint256 prevDelegation = bootstrap.delegations( - delegator, exo, address(myToken) - ); - uint256 prevDelegationByOperator = bootstrap.delegationsByOperator( - exo, address(myToken) - ); - uint256 prevWithdrawableAmount = bootstrap.withdrawableAmounts( - delegator, address(myToken) - ); - bootstrap.undelegateFrom( - exo, address(myToken), uint256(amount) - ); - uint256 postDelegation = bootstrap.delegations( - delegator, exo, address(myToken) - ); - uint256 postDelegationByOperator = bootstrap.delegationsByOperator( - exo, address(myToken) - ); - uint256 postWithdrawableAmount = bootstrap.withdrawableAmounts( - delegator, address(myToken) - ); + uint256 prevDelegation = bootstrap.delegations(delegator, exo, address(myToken)); + uint256 prevDelegationByOperator = bootstrap.delegationsByOperator(exo, address(myToken)); + uint256 prevWithdrawableAmount = bootstrap.withdrawableAmounts(delegator, address(myToken)); + bootstrap.undelegateFrom(exo, address(myToken), uint256(amount)); + uint256 postDelegation = bootstrap.delegations(delegator, exo, address(myToken)); + uint256 postDelegationByOperator = bootstrap.delegationsByOperator(exo, address(myToken)); + uint256 postWithdrawableAmount = bootstrap.withdrawableAmounts(delegator, address(myToken)); assertTrue(postDelegation == prevDelegation - amount); - assertTrue( - postDelegationByOperator == prevDelegationByOperator - amount - ); + assertTrue(postDelegationByOperator == prevDelegationByOperator - amount); assertTrue(postWithdrawableAmount == prevWithdrawableAmount + amount); } } @@ -855,18 +695,14 @@ contract BootstrapTest is Test { test09_DelegateTo(); vm.startPrank(addrs[0]); vm.expectRevert("Operator does not exist"); - bootstrap.undelegateFrom( - "exo1awm72f4sc5yhedurdunx9afcshfq6ymqva8an4", address(myToken), amounts[0] - ); + bootstrap.undelegateFrom("exo1awm72f4sc5yhedurdunx9afcshfq6ymqva8an4", address(myToken), amounts[0]); } function test10_UndelegateFrom_TokenNotWhitelisted() public { test03_RegisterOperator(); vm.startPrank(addrs[0]); - vm.expectRevert("Bootstrap: token is not whitelisted"); - bootstrap.undelegateFrom( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(0xa), amounts[0] - ); + vm.expectRevert("BootstrapStorage: token is not whitelisted"); + bootstrap.undelegateFrom("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(0xa), amounts[0]); } function test10_UndelegateFrom_NotEnoughBalance() public { @@ -876,37 +712,29 @@ contract BootstrapTest is Test { vm.stopPrank(); vm.startPrank(addrs[0]); vm.expectRevert(bytes("Bootstrap: insufficient delegated balance")); - bootstrap.undelegateFrom( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(0xa), amounts[0] - ); + bootstrap.undelegateFrom("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(0xa), amounts[0]); } function test10_UndelegateFrom_ZeroAmount() public { test03_RegisterOperator(); test02_Deposit(); vm.startPrank(addrs[0]); - vm.expectRevert("Bootstrap: amount should be greater than zero"); - bootstrap.undelegateFrom( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), 0 - ); + vm.expectRevert("BootstrapStorage: amount should be greater than zero"); + bootstrap.undelegateFrom("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), 0); } function test10_UndelegateFromOperator_Excess() public { test09_DelegateTo(); vm.startPrank(addrs[0]); vm.expectRevert("Bootstrap: insufficient delegated balance"); - bootstrap.undelegateFrom( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), amounts[0] + 1 - ); + bootstrap.undelegateFrom("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), amounts[0] + 1); } function test10_UndelegateFrom_NoDelegation() public { test03_RegisterOperator(); vm.startPrank(addrs[0]); vm.expectRevert("Bootstrap: insufficient delegated balance"); - bootstrap.undelegateFrom( - "exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), amounts[0] - ); + bootstrap.undelegateFrom("exo13hasr43vvq8v44xpzh0l6yuym4kca98f87j7ac", address(myToken), amounts[0]); } function test11_WithdrawPrincipleFromExocore() public { @@ -916,22 +744,16 @@ contract BootstrapTest is Test { for (uint256 i = 0; i < 6; i++) { vm.startPrank(addrs[i]); uint256 prevDeposit = bootstrap.totalDepositAmounts(addrs[i], address(myToken)); - uint256 prevWithdrawable = bootstrap.withdrawableAmounts( - addrs[i], address(myToken) - ); + uint256 prevWithdrawable = bootstrap.withdrawableAmounts(addrs[i], address(myToken)); uint256 prevTokenDeposit = bootstrap.depositsByToken(address(myToken)); - uint256 prevVaultWithdrawable = Vault( - address(bootstrap.tokenToVault(address(myToken))) - ).withdrawableBalances(addrs[i]); + uint256 prevVaultWithdrawable = + Vault(address(bootstrap.tokenToVault(address(myToken)))).withdrawableBalances(addrs[i]); bootstrap.withdrawPrincipleFromExocore(address(myToken), amounts[i]); uint256 postDeposit = bootstrap.totalDepositAmounts(addrs[i], address(myToken)); - uint256 postWithdrawable = bootstrap.withdrawableAmounts( - addrs[i], address(myToken) - ); + uint256 postWithdrawable = bootstrap.withdrawableAmounts(addrs[i], address(myToken)); uint256 postTokenDeposit = bootstrap.depositsByToken(address(myToken)); - uint256 postVaultWithdrawable = Vault( - address(bootstrap.tokenToVault(address(myToken))) - ).withdrawableBalances(addrs[i]); + uint256 postVaultWithdrawable = + Vault(address(bootstrap.tokenToVault(address(myToken)))).withdrawableBalances(addrs[i]); assertTrue(postDeposit == prevDeposit - amounts[i]); assertTrue(postWithdrawable == prevWithdrawable - amounts[i]); assertTrue(postTokenDeposit == prevTokenDeposit - amounts[i]); @@ -943,14 +765,14 @@ contract BootstrapTest is Test { function test11_WithdrawPrincipleFromExocore_TokenNotWhitelisted() public { vm.startPrank(addrs[0]); - vm.expectRevert("Bootstrap: token is not whitelisted"); + vm.expectRevert("BootstrapStorage: token is not whitelisted"); bootstrap.withdrawPrincipleFromExocore(address(0xa), amounts[0]); vm.stopPrank(); } function test11_WithdrawPrincipleFromExocore_ZeroAmount() public { vm.startPrank(addrs[0]); - vm.expectRevert("Bootstrap: amount should be greater than zero"); + vm.expectRevert("BootstrapStorage: amount should be greater than zero"); bootstrap.withdrawPrincipleFromExocore(address(myToken), 0); vm.stopPrank(); } @@ -1014,7 +836,9 @@ contract BootstrapTest is Test { function test12_MarkBootstrapped_AlreadyBootstrapped() public { test12_MarkBootstrapped(); vm.startPrank(address(clientChainLzEndpoint)); - vm.expectRevert(abi.encodeWithSelector(GatewayStorage.UnsupportedRequest.selector, GatewayStorage.Action.MARK_BOOTSTRAP)); + vm.expectRevert( + abi.encodeWithSelector(GatewayStorage.UnsupportedRequest.selector, GatewayStorage.Action.MARK_BOOTSTRAP) + ); bootstrap.lzReceive( Origin(exocoreChainId, bytes32(bytes20(undeployedExocoreGateway)), uint64(2)), generateUID(1), @@ -1028,9 +852,7 @@ contract BootstrapTest is Test { function test12_MarkBootstrapped_DirectCall() public { vm.startPrank(address(0x20)); vm.warp(spawnTime + 2); - vm.expectRevert( - "BootstrapLzReceiver: could only be called from this contract itself with low level call" - ); + vm.expectRevert("BootstrapLzReceiver: could only be called from this contract itself with low level call"); bootstrap.markBootstrapped(); vm.stopPrank(); } @@ -1044,218 +866,227 @@ contract BootstrapTest is Test { } function test14_IsCommissionValid() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e18, 1e18); assertTrue(bootstrap.isCommissionValid(commission)); } function test14_IsCommissionValidRateLarge() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 1.1e18, 1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(1.1e18, 1e18, 1e18); assertFalse(bootstrap.isCommissionValid(commission)); } function test14_IsCommissionValidMaxRateLarge() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1.1e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1.1e18, 1e18); assertFalse(bootstrap.isCommissionValid(commission)); } function test14_IsCommissionValidMaxChangeRateLarge() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0, 1e18, 1.1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0, 1e18, 1.1e18); assertFalse(bootstrap.isCommissionValid(commission)); } function test14_IsCommissionValidRateExceedsMaxRate() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0.5e18, 0.2e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0.5e18, 0.2e18, 1e18); assertFalse(bootstrap.isCommissionValid(commission)); } function test14_IsCommissionValidMaxChangeRateExceedsMaxRate() public { - IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission( - 0.1e18, 0.2e18, 1e18 - ); + IOperatorRegistry.Commission memory commission = IOperatorRegistry.Commission(0.1e18, 0.2e18, 1e18); assertFalse(bootstrap.isCommissionValid(commission)); } - function generateUID( - uint64 nonce - ) internal view returns (bytes32 uid) { + function generateUID(uint64 nonce) internal view returns (bytes32 uid) { uid = GUID.generate( - nonce, exocoreChainId, + nonce, + exocoreChainId, address(undeployedExocoreGateway), - clientChainId, bytes32(bytes20(address(bootstrap))) + clientChainId, + bytes32(bytes20(address(bootstrap))) ); } function test15_Initialize_OwnerZero() public { vm.startPrank(deployer); Bootstrap bootstrapLogic = new Bootstrap( - address(clientChainLzEndpoint), - exocoreChainId, - address(vaultBeacon), - address(beaconProxyBytecode) + address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode) ); vm.expectRevert("Bootstrap: owner should not be empty"); Bootstrap( - payable(address( - new TransparentUpgradeableProxy( - address(bootstrapLogic), address(proxyAdmin), - abi.encodeCall(bootstrap.initialize, - (address(0x0), spawnTime, offsetDuration, - payable(exocoreValidatorSet), whitelistTokens, - address(proxyAdmin)) + payable( + address( + new TransparentUpgradeableProxy( + address(bootstrapLogic), + address(proxyAdmin), + abi.encodeCall( + bootstrap.initialize, + ( + address(0x0), + spawnTime, + offsetDuration, + payable(exocoreValidatorSet), + whitelistTokens, + address(proxyAdmin) + ) + ) ) ) - )) + ) ); } function test15_Initialize_SpawnTimeNotFuture() public { vm.startPrank(deployer); Bootstrap bootstrapLogic = new Bootstrap( - address(clientChainLzEndpoint), - exocoreChainId, - address(vaultBeacon), - address(beaconProxyBytecode) + address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode) ); vm.warp(20); vm.expectRevert("Bootstrap: spawn time should be in the future"); Bootstrap( - payable(address( - new TransparentUpgradeableProxy( - address(bootstrapLogic), address(proxyAdmin), - abi.encodeCall(bootstrap.initialize, - (deployer, block.timestamp - 10, offsetDuration, - payable(exocoreValidatorSet), whitelistTokens, - address(proxyAdmin)) + payable( + address( + new TransparentUpgradeableProxy( + address(bootstrapLogic), + address(proxyAdmin), + abi.encodeCall( + bootstrap.initialize, + ( + deployer, + block.timestamp - 10, + offsetDuration, + payable(exocoreValidatorSet), + whitelistTokens, + address(proxyAdmin) + ) + ) ) ) - )) + ) ); } function test15_Initialize_OffsetDurationZero() public { vm.startPrank(deployer); Bootstrap bootstrapLogic = new Bootstrap( - address(clientChainLzEndpoint), - exocoreChainId, - address(vaultBeacon), - address(beaconProxyBytecode) + address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode) ); vm.expectRevert("Bootstrap: offset duration should be greater than 0"); Bootstrap( - payable(address( - new TransparentUpgradeableProxy( - address(bootstrapLogic), address(proxyAdmin), - abi.encodeCall(bootstrap.initialize, - (deployer, spawnTime, 0, - payable(exocoreValidatorSet), whitelistTokens, - address(proxyAdmin)) + payable( + address( + new TransparentUpgradeableProxy( + address(bootstrapLogic), + address(proxyAdmin), + abi.encodeCall( + bootstrap.initialize, + (deployer, spawnTime, 0, payable(exocoreValidatorSet), whitelistTokens, address(proxyAdmin)) + ) ) ) - )) + ) ); } function test15_Initialize_SpawnTimeLTOffsetDuration() public { vm.startPrank(deployer); Bootstrap bootstrapLogic = new Bootstrap( - address(clientChainLzEndpoint), - exocoreChainId, - address(vaultBeacon), - address(beaconProxyBytecode) + address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode) ); vm.expectRevert("Bootstrap: spawn time should be greater than offset duration"); vm.warp(20); Bootstrap( - payable(address( - new TransparentUpgradeableProxy( - address(bootstrapLogic), address(proxyAdmin), - abi.encodeCall(bootstrap.initialize, - (deployer, 21, 22, - payable(exocoreValidatorSet), whitelistTokens, - address(proxyAdmin)) + payable( + address( + new TransparentUpgradeableProxy( + address(bootstrapLogic), + address(proxyAdmin), + abi.encodeCall( + bootstrap.initialize, + (deployer, 21, 22, payable(exocoreValidatorSet), whitelistTokens, address(proxyAdmin)) + ) ) ) - )) + ) ); } function test15_Initialize_LockTimeNotFuture() public { vm.startPrank(deployer); Bootstrap bootstrapLogic = new Bootstrap( - address(clientChainLzEndpoint), - exocoreChainId, - address(vaultBeacon), - address(beaconProxyBytecode) + address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode) ); vm.expectRevert("Bootstrap: lock time should be in the future"); vm.warp(20); Bootstrap( - payable(address( - new TransparentUpgradeableProxy( - address(bootstrapLogic), address(proxyAdmin), - abi.encodeCall(bootstrap.initialize, - (deployer, 21, 9, - payable(exocoreValidatorSet), whitelistTokens, - address(proxyAdmin)) + payable( + address( + new TransparentUpgradeableProxy( + address(bootstrapLogic), + address(proxyAdmin), + abi.encodeCall( + bootstrap.initialize, + (deployer, 21, 9, payable(exocoreValidatorSet), whitelistTokens, address(proxyAdmin)) + ) ) ) - )) + ) ); } function test15_Initialize_ExocoreValSetZero() public { vm.startPrank(deployer); Bootstrap bootstrapLogic = new Bootstrap( - address(clientChainLzEndpoint), - exocoreChainId, - address(vaultBeacon), - address(beaconProxyBytecode) + address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode) ); vm.expectRevert("Bootstrap: exocore validator set address should not be empty"); Bootstrap( - payable(address( - new TransparentUpgradeableProxy( - address(bootstrapLogic), address(proxyAdmin), - abi.encodeCall(bootstrap.initialize, - (deployer, spawnTime, offsetDuration, - payable(address(0)), whitelistTokens, - address(proxyAdmin)) + payable( + address( + new TransparentUpgradeableProxy( + address(bootstrapLogic), + address(proxyAdmin), + abi.encodeCall( + bootstrap.initialize, + ( + deployer, + spawnTime, + offsetDuration, + payable(address(0)), + whitelistTokens, + address(proxyAdmin) + ) + ) ) ) - )) + ) ); } function test15_Initialize_CustomProxyAdminZero() public { vm.startPrank(deployer); Bootstrap bootstrapLogic = new Bootstrap( - address(clientChainLzEndpoint), - exocoreChainId, - address(vaultBeacon), - address(beaconProxyBytecode) + address(clientChainLzEndpoint), exocoreChainId, address(vaultBeacon), address(beaconProxyBytecode) ); vm.expectRevert("Bootstrap: custom proxy admin should not be empty"); Bootstrap( - payable(address( - new TransparentUpgradeableProxy( - address(bootstrapLogic), address(proxyAdmin), - abi.encodeCall(bootstrap.initialize, - (deployer, spawnTime, offsetDuration, - payable(exocoreValidatorSet), whitelistTokens, - address(0x0)) + payable( + address( + new TransparentUpgradeableProxy( + address(bootstrapLogic), + address(proxyAdmin), + abi.encodeCall( + bootstrap.initialize, + ( + deployer, + spawnTime, + offsetDuration, + payable(exocoreValidatorSet), + whitelistTokens, + address(0x0) + ) + ) ) ) - )) + ) ); } @@ -1317,7 +1148,7 @@ contract BootstrapTest is Test { function test18_RemoveWhitelistToken_DoesNotExist() public { address fakeToken = address(0xa); vm.startPrank(deployer); - vm.expectRevert("Bootstrap: token should be already whitelisted"); + vm.expectRevert("BootstrapStorage: token is not whitelisted"); bootstrap.removeWhitelistToken(fakeToken); } @@ -1328,7 +1159,7 @@ contract BootstrapTest is Test { function test22_Claim() public { test11_WithdrawPrincipleFromExocore(); - for(uint256 i = 0; i < 6; i++) { + for (uint256 i = 0; i < 6; i++) { vm.startPrank(addrs[i]); uint256 prevBalance = myToken.balanceOf(addrs[i]); bootstrap.claim(address(myToken), amounts[i], addrs[i]); @@ -1340,22 +1171,20 @@ contract BootstrapTest is Test { function test22_Claim_TokenNotWhitelisted() public { vm.startPrank(addrs[0]); - vm.expectRevert("Bootstrap: token is not whitelisted"); + vm.expectRevert("BootstrapStorage: token is not whitelisted"); bootstrap.claim(address(0xa), amounts[0], addrs[0]); } function test22_Claim_ZeroAmount() public { vm.startPrank(addrs[0]); - vm.expectRevert("Bootstrap: amount should be greater than zero"); + vm.expectRevert("BootstrapStorage: amount should be greater than zero"); bootstrap.claim(address(myToken), 0, addrs[0]); } function test22_Claim_Excess() public { test11_WithdrawPrincipleFromExocore(); vm.startPrank(addrs[0]); - vm.expectRevert( - "Vault: withdrawal amount is larger than depositor's withdrawable balance" - ); + vm.expectRevert("Vault: withdrawal amount is larger than depositor's withdrawable balance"); bootstrap.claim(address(myToken), amounts[0] + 5, addrs[0]); } } diff --git a/test/foundry/ClientChainGateway.t.sol b/test/foundry/ClientChainGateway.t.sol index 713fd4e1..0456cf12 100644 --- a/test/foundry/ClientChainGateway.t.sol +++ b/test/foundry/ClientChainGateway.t.sol @@ -77,9 +77,8 @@ contract SetUp is Test { vaultBeacon = new UpgradeableBeacon(address(vaultImplementation)); capsuleBeacon = new UpgradeableBeacon(address(capsuleImplementation)); - // deploy BeaconProxyBytecode to store BeaconProxyBytecode beaconProxyBytecode = new BeaconProxyBytecode(); - + restakeToken = new ERC20PresetFixedSupply("rest", "rest", 1e16, exocoreValidatorSet.addr); whitelistTokens.push(address(restakeToken)); @@ -97,10 +96,7 @@ contract SetUp is Test { payable(address(new TransparentUpgradeableProxy(address(clientGatewayLogic), address(proxyAdmin), ""))) ); - clientGateway.initialize( - payable(exocoreValidatorSet.addr), - whitelistTokens - ); + clientGateway.initialize(payable(exocoreValidatorSet.addr), whitelistTokens); vm.stopPrank(); } @@ -111,13 +107,13 @@ contract SetUp is Test { // mainnet if (block.chainid == 1) { GENESIS_BLOCK_TIMESTAMP = 1606824023; - // goerli + // goerli } else if (block.chainid == 5) { GENESIS_BLOCK_TIMESTAMP = 1616508000; - // sepolia + // sepolia } else if (block.chainid == 11155111) { GENESIS_BLOCK_TIMESTAMP = 1655733600; - // holesky + // holesky } else if (block.chainid == 17000) { GENESIS_BLOCK_TIMESTAMP = 1695902400; } else { diff --git a/test/foundry/CustomProxyAdmin.t.sol b/test/foundry/CustomProxyAdmin.t.sol index 6053b470..55c41af5 100644 --- a/test/foundry/CustomProxyAdmin.t.sol +++ b/test/foundry/CustomProxyAdmin.t.sol @@ -27,15 +27,11 @@ contract ImplementationChanger is Initializable, StorageOld { implementationChanged = false; } - function changeImplementation( - address customProxyAdmin, - address newImplementation - ) public { + function changeImplementation(address customProxyAdmin, address newImplementation) public { ICustomProxyAdmin(customProxyAdmin).changeImplementation( ITransparentUpgradeableProxy(address(this)), - newImplementation, abi.encodeCall( - NewImplementation.initialize, () - ) + newImplementation, + abi.encodeCall(NewImplementation.initialize, ()) ); } } @@ -81,17 +77,12 @@ contract CustomProxyAdminTest is Test { // validate that the implementation has not changed already assertFalse(implementationChanger.implementationChanged()); // check that it does not have a `hi` function in there. - NewImplementation newImplementation = NewImplementation( - address(implementationChanger) - ); - vm.expectRevert(); // EVM error + NewImplementation newImplementation = NewImplementation(address(implementationChanger)); + vm.expectRevert(); // EVM error assertFalse(newImplementation.hi()); // now change the implementation proxyAdmin.initialize(address(implementationChanger)); - implementationChanger.changeImplementation( - address(proxyAdmin), - address(new NewImplementation()) - ); + implementationChanger.changeImplementation(address(proxyAdmin), address(new NewImplementation())); // validate that it has changed assertTrue(implementationChanger.implementationChanged()); assertTrue(newImplementation.hi()); @@ -114,10 +105,7 @@ contract CustomProxyAdminTest is Test { // for some reason, i could not get `vm.expectRevert` to work here. // if i had that line, it would not revert. // if i didn't have that line, it would not revert. - try implementationChanger.changeImplementation( - address(proxyAdmin), - address(new NewImplementation()) - ) { + try implementationChanger.changeImplementation(address(proxyAdmin), address(new NewImplementation())) { // should never happen assertTrue(false); } catch {} @@ -153,4 +141,4 @@ contract CustomProxyAdminTest is Test { } catch {} assertFalse(implementationChanger.implementationChanged()); } -} \ No newline at end of file +} diff --git a/test/foundry/Delegation.t.sol b/test/foundry/Delegation.t.sol index 4537615f..c91510f8 100644 --- a/test/foundry/Delegation.t.sol +++ b/test/foundry/Delegation.t.sol @@ -22,7 +22,7 @@ contract DelegateTest is ExocoreDeployer { event DelegateResult( bool indexed success, address indexed delegator, string indexed delegatee, address token, uint256 amount ); - event UndelegateResult( + event UndelegateResult( bool indexed success, address indexed undelegator, string indexed undelegatee, address token, uint256 amount ); event DelegateRequestProcessed( @@ -68,7 +68,9 @@ contract DelegateTest is ExocoreDeployer { _testUndelegate(delegator.addr, relayer.addr, operatorAddress, undelegateAmount); } - function _testDelegate(address delegator, address relayer, string memory operator, uint256 delegateAmount) internal { + function _testDelegate(address delegator, address relayer, string memory operator, uint256 delegateAmount) + internal + { /* ------------------------- delegate workflow test ------------------------- */ // 1. first user call client chain gateway to delegate @@ -146,7 +148,9 @@ contract DelegateTest is ExocoreDeployer { vm.stopPrank(); /// assert that DelegationMock contract should have recorded the delegate - uint256 actualDelegateAmount = DelegationMock(DELEGATION_PRECOMPILE_ADDRESS).getDelegateAmount(delegator, operator, clientChainId, address(restakeToken)); + uint256 actualDelegateAmount = DelegationMock(DELEGATION_PRECOMPILE_ADDRESS).getDelegateAmount( + delegator, operator, clientChainId, address(restakeToken) + ); assertEq(actualDelegateAmount, delegateAmount); // 3. third layerzero relayers should watch the response message packet and relay the message to source chain endpoint @@ -167,9 +171,13 @@ contract DelegateTest is ExocoreDeployer { vm.stopPrank(); } - function _testUndelegate(address delegator, address relayer, string memory operator, uint256 undelegateAmount) internal { + function _testUndelegate(address delegator, address relayer, string memory operator, uint256 undelegateAmount) + internal + { /* ------------------------- undelegate workflow test ------------------------- */ - uint256 totalDelegate = DelegationMock(DELEGATION_PRECOMPILE_ADDRESS).getDelegateAmount(delegator, operator, clientChainId, address(restakeToken)); + uint256 totalDelegate = DelegationMock(DELEGATION_PRECOMPILE_ADDRESS).getDelegateAmount( + delegator, operator, clientChainId, address(restakeToken) + ); require(undelegateAmount <= totalDelegate, "undelegate amount overflow"); // 1. first user call client chain gateway to undelegate @@ -247,7 +255,9 @@ contract DelegateTest is ExocoreDeployer { vm.stopPrank(); /// assert that DelegationMock contract should have recorded the undelegation - uint256 actualDelegateAmount = DelegationMock(DELEGATION_PRECOMPILE_ADDRESS).getDelegateAmount(delegator, operator, clientChainId, address(restakeToken)); + uint256 actualDelegateAmount = DelegationMock(DELEGATION_PRECOMPILE_ADDRESS).getDelegateAmount( + delegator, operator, clientChainId, address(restakeToken) + ); assertEq(actualDelegateAmount, totalDelegate - undelegateAmount); // 3. third layerzero relayers should watch the response message packet and relay the message to source chain endpoint diff --git a/test/foundry/DepositWithdrawPrinciple.t.sol b/test/foundry/DepositWithdrawPrinciple.t.sol index 9088deef..c582167e 100644 --- a/test/foundry/DepositWithdrawPrinciple.t.sol +++ b/test/foundry/DepositWithdrawPrinciple.t.sol @@ -207,7 +207,8 @@ contract DepositWithdrawPrincipleTest is ExocoreDeployer { // before native stake and deposit, we simulate proper block environment states to make proof valid /// we set the timestamp of proof to be exactly the timestamp that the validator container get activated on beacon chain - uint256 activationTimestamp = BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; + uint256 activationTimestamp = + BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; mockProofTimestamp = activationTimestamp; validatorProof.beaconBlockTimestamp = mockProofTimestamp; @@ -223,11 +224,13 @@ contract DepositWithdrawPrincipleTest is ExocoreDeployer { ); // 1. firstly depositor should stake to beacon chain by depositing 32 ETH to ETHPOS contract - ExoCapsule expectedCapsule = ExoCapsule(Create2.computeAddress( - bytes32(uint256(uint160(depositor.addr))), - keccak256(abi.encodePacked(BEACON_PROXY_BYTECODE, abi.encode(address(capsuleBeacon), ""))), - address(clientGateway) - )); + ExoCapsule expectedCapsule = ExoCapsule( + Create2.computeAddress( + bytes32(uint256(uint160(depositor.addr))), + keccak256(abi.encodePacked(BEACON_PROXY_BYTECODE, abi.encode(address(capsuleBeacon), ""))), + address(clientGateway) + ) + ); vm.expectEmit(true, true, true, true, address(clientGateway)); emit CapsuleCreated(depositor.addr, address(expectedCapsule)); emit StakedWithCapsule(depositor.addr, address(expectedCapsule)); @@ -246,11 +249,7 @@ contract DepositWithdrawPrincipleTest is ExocoreDeployer { /// replace expectedCapsule with capsule bytes32 capsuleSlotInGateway = bytes32( - stdstore - .target(address(clientGatewayLogic)) - .sig("ownerToCapsule(address)") - .with_key(depositor.addr) - .find() + stdstore.target(address(clientGatewayLogic)).sig("ownerToCapsule(address)").with_key(depositor.addr).find() ); vm.store(address(clientGateway), capsuleSlotInGateway, bytes32(uint256(uint160(address(capsule))))); assertEq(address(clientGateway.ownerToCapsule(depositor.addr)), address(capsule)); diff --git a/test/foundry/ExoCapsule.t.sol b/test/foundry/ExoCapsule.t.sol index 58484e61..8cf32b61 100644 --- a/test/foundry/ExoCapsule.t.sol +++ b/test/foundry/ExoCapsule.t.sol @@ -19,14 +19,14 @@ contract SetUp is Test { bytes32[] validatorContainer; /** - struct ValidatorContainerProof { - uint256 beaconBlockTimestamp; - bytes32 stateRoot; - bytes32[] stateRootProof; - bytes32[] validatorContainerRootProof; - uint256 validatorContainerRootIndex; - } - */ + * struct ValidatorContainerProof { + * uint256 beaconBlockTimestamp; + * bytes32 stateRoot; + * bytes32[] stateRootProof; + * bytes32[] validatorContainerRootProof; + * uint256 validatorContainerRootIndex; + * } + */ IExoCapsule.ValidatorContainerProof validatorProof; bytes32 beaconBlockRoot; @@ -39,7 +39,7 @@ contract SetUp is Test { uint64 internal constant SLOTS_PER_EPOCH = 32; /// @notice The number of seconds in a slot in the beacon chain uint64 internal constant SECONDS_PER_SLOT = 12; - /// @notice Number of seconds per epoch: 384 == 32 slots/epoch * 12 seconds/slot + /// @notice Number of seconds per epoch: 384 == 32 slots/epoch * 12 seconds/slot uint64 internal constant SECONDS_PER_EPOCH = SLOTS_PER_EPOCH * SECONDS_PER_SLOT; uint256 internal constant VERIFY_BALANCE_UPDATE_WINDOW_SECONDS = 4.5 hours; @@ -54,9 +54,11 @@ contract SetUp is Test { validatorProof.stateRoot = stdJson.readBytes32(validatorInfo, ".beaconStateRoot"); require(validatorProof.stateRoot != bytes32(0), "state root should not be empty"); - validatorProof.stateRootProof = stdJson.readBytes32Array(validatorInfo, ".StateRootAgainstLatestBlockHeaderProof"); + validatorProof.stateRootProof = + stdJson.readBytes32Array(validatorInfo, ".StateRootAgainstLatestBlockHeaderProof"); require(validatorProof.stateRootProof.length == 3, "state root proof should have 3 nodes"); - validatorProof.validatorContainerRootProof = stdJson.readBytes32Array(validatorInfo, ".WithdrawalCredentialProof"); + validatorProof.validatorContainerRootProof = + stdJson.readBytes32Array(validatorInfo, ".WithdrawalCredentialProof"); require(validatorProof.validatorContainerRootProof.length == 46, "validator root proof should have 46 nodes"); validatorProof.validatorIndex = stdJson.readUint(validatorInfo, ".validatorIndex"); require(validatorProof.validatorIndex != 0, "validator root index should not be 0"); @@ -80,7 +82,9 @@ contract SetUp is Test { stdstore.target(capsuleAddress).sig("capsuleOwner()").checked_write(bytes32(uint256(uint160(capsuleOwner)))); - stdstore.target(capsuleAddress).sig("beaconOracle()").checked_write(bytes32(uint256(uint160(address(beaconOracle))))); + stdstore.target(capsuleAddress).sig("beaconOracle()").checked_write( + bytes32(uint256(uint160(address(beaconOracle)))) + ); } function _getCapsuleFromWithdrawalCredentials(bytes32 withdrawalCredentials) internal pure returns (address) { @@ -113,7 +117,8 @@ contract VerifyDepositProof is SetUp { using stdStorage for StdStorage; function test_verifyDepositProof_success() public { - uint256 activationTimestamp = BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; + uint256 activationTimestamp = + BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; mockProofTimestamp = activationTimestamp; mockCurrentBlockTimestamp = mockProofTimestamp + SECONDS_PER_SLOT; vm.warp(mockCurrentBlockTimestamp); @@ -127,7 +132,8 @@ contract VerifyDepositProof is SetUp { capsule.verifyDepositProof(validatorContainer, validatorProof); - ExoCapsuleStorage.Validator memory validator = capsule.getRegisteredValidatorByPubkey(_getPubkey(validatorContainer)); + ExoCapsuleStorage.Validator memory validator = + capsule.getRegisteredValidatorByPubkey(_getPubkey(validatorContainer)); assertEq(uint8(validator.status), uint8(ExoCapsuleStorage.VALIDATOR_STATUS.REGISTERED)); assertEq(validator.validatorIndex, validatorProof.validatorIndex); assertEq(validator.mostRecentBalanceUpdateTimestamp, validatorProof.beaconBlockTimestamp); @@ -135,7 +141,8 @@ contract VerifyDepositProof is SetUp { } function test_verifyDepositProof_revert_validatorAlreadyDeposited() public { - uint256 activationTimestamp = BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; + uint256 activationTimestamp = + BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; mockProofTimestamp = activationTimestamp; mockCurrentBlockTimestamp = mockProofTimestamp + SECONDS_PER_SLOT; vm.warp(mockCurrentBlockTimestamp); @@ -150,12 +157,15 @@ contract VerifyDepositProof is SetUp { capsule.verifyDepositProof(validatorContainer, validatorProof); // deposit again should revert - vm.expectRevert(abi.encodeWithSelector(ExoCapsule.DoubleDepositedValidator.selector, _getPubkey(validatorContainer))); + vm.expectRevert( + abi.encodeWithSelector(ExoCapsule.DoubleDepositedValidator.selector, _getPubkey(validatorContainer)) + ); capsule.verifyDepositProof(validatorContainer, validatorProof); } function test_verifyDepositProof_revert_staleProof() public { - uint256 activationTimestamp = BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; + uint256 activationTimestamp = + BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; mockProofTimestamp = activationTimestamp + 1 hours; mockCurrentBlockTimestamp = mockProofTimestamp + VERIFY_BALANCE_UPDATE_WINDOW_SECONDS + 1 seconds; vm.warp(mockCurrentBlockTimestamp); @@ -168,12 +178,17 @@ contract VerifyDepositProof is SetUp { ); // deposit should revert because of proof is stale - vm.expectRevert(abi.encodeWithSelector(ExoCapsule.StaleValidatorContainer.selector, _getPubkey(validatorContainer), mockProofTimestamp)); + vm.expectRevert( + abi.encodeWithSelector( + ExoCapsule.StaleValidatorContainer.selector, _getPubkey(validatorContainer), mockProofTimestamp + ) + ); capsule.verifyDepositProof(validatorContainer, validatorProof); } function test_verifyDepositProof_revert_malformedValidatorContainer() public { - uint256 activationTimestamp = BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; + uint256 activationTimestamp = + BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; mockProofTimestamp = activationTimestamp; mockCurrentBlockTimestamp = mockProofTimestamp + SECONDS_PER_SLOT; vm.warp(mockCurrentBlockTimestamp); @@ -189,18 +204,23 @@ contract VerifyDepositProof is SetUp { // construct malformed validator container that has extra fields validatorContainer.push(bytes32(uint256(123))); - vm.expectRevert(abi.encodeWithSelector(ExoCapsule.InvalidValidatorContainer.selector, _getPubkey(validatorContainer))); + vm.expectRevert( + abi.encodeWithSelector(ExoCapsule.InvalidValidatorContainer.selector, _getPubkey(validatorContainer)) + ); capsule.verifyDepositProof(validatorContainer, validatorProof); vm.revertTo(snapshot); // construct malformed validator container that misses fields validatorContainer.pop(); - vm.expectRevert(abi.encodeWithSelector(ExoCapsule.InvalidValidatorContainer.selector, _getPubkey(validatorContainer))); + vm.expectRevert( + abi.encodeWithSelector(ExoCapsule.InvalidValidatorContainer.selector, _getPubkey(validatorContainer)) + ); capsule.verifyDepositProof(validatorContainer, validatorProof); } function test_verifyDepositProof_revert_inactiveValidatorContainer() public { - uint256 activationTimestamp = BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; + uint256 activationTimestamp = + BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; vm.mockCall( address(beaconOracle), @@ -213,12 +233,15 @@ contract VerifyDepositProof is SetUp { mockCurrentBlockTimestamp = mockProofTimestamp + SECONDS_PER_SLOT; vm.warp(mockCurrentBlockTimestamp); validatorProof.beaconBlockTimestamp = mockProofTimestamp; - vm.expectRevert(abi.encodeWithSelector(ExoCapsule.InactiveValidatorContainer.selector, _getPubkey(validatorContainer))); + vm.expectRevert( + abi.encodeWithSelector(ExoCapsule.InactiveValidatorContainer.selector, _getPubkey(validatorContainer)) + ); capsule.verifyDepositProof(validatorContainer, validatorProof); } function test_verifyDepositProof_revert_mismatchWithdrawalCredentials() public { - uint256 activationTimestamp = BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; + uint256 activationTimestamp = + BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; mockProofTimestamp = activationTimestamp; mockCurrentBlockTimestamp = mockProofTimestamp + SECONDS_PER_SLOT; vm.warp(mockCurrentBlockTimestamp); @@ -247,7 +270,8 @@ contract VerifyDepositProof is SetUp { } function test_verifyDepositProof_revert_proofNotMatchWithBeaconRoot() public { - uint256 activationTimestamp = BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; + uint256 activationTimestamp = + BEACON_CHAIN_GENESIS_TIME + _getActivationEpoch(validatorContainer) * SECONDS_PER_EPOCH; mockProofTimestamp = activationTimestamp; mockCurrentBlockTimestamp = mockProofTimestamp + SECONDS_PER_SLOT; vm.warp(mockCurrentBlockTimestamp); @@ -261,7 +285,9 @@ contract VerifyDepositProof is SetUp { ); // verify proof against mismatch beacon block root - vm.expectRevert(abi.encodeWithSelector(ExoCapsule.InvalidValidatorContainer.selector, _getPubkey(validatorContainer))); + vm.expectRevert( + abi.encodeWithSelector(ExoCapsule.InvalidValidatorContainer.selector, _getPubkey(validatorContainer)) + ); capsule.verifyDepositProof(validatorContainer, validatorProof); } -} \ No newline at end of file +} diff --git a/test/foundry/ExocoreDeployer.t.sol b/test/foundry/ExocoreDeployer.t.sol index a922ecb0..05c7c0c4 100644 --- a/test/foundry/ExocoreDeployer.t.sol +++ b/test/foundry/ExocoreDeployer.t.sol @@ -56,7 +56,7 @@ contract ExocoreDeployer is Test { uint64 internal constant SLOTS_PER_EPOCH = 32; /// @notice The number of seconds in a slot in the beacon chain uint64 internal constant SECONDS_PER_SLOT = 12; - /// @notice Number of seconds per epoch: 384 == 32 slots/epoch * 12 seconds/slot + /// @notice Number of seconds per epoch: 384 == 32 slots/epoch * 12 seconds/slot uint64 internal constant SECONDS_PER_EPOCH = SLOTS_PER_EPOCH * SECONDS_PER_SLOT; uint256 internal constant VERIFY_BALANCE_UPDATE_WINDOW_SECONDS = 4.5 hours; uint256 constant GWEI_TO_WEI = 1e9; @@ -106,9 +106,11 @@ contract ExocoreDeployer is Test { validatorProof.stateRoot = stdJson.readBytes32(validatorInfo, ".beaconStateRoot"); require(validatorProof.stateRoot != bytes32(0), "state root should not be empty"); - validatorProof.stateRootProof = stdJson.readBytes32Array(validatorInfo, ".StateRootAgainstLatestBlockHeaderProof"); + validatorProof.stateRootProof = + stdJson.readBytes32Array(validatorInfo, ".StateRootAgainstLatestBlockHeaderProof"); require(validatorProof.stateRootProof.length == 3, "state root proof should have 3 nodes"); - validatorProof.validatorContainerRootProof = stdJson.readBytes32Array(validatorInfo, ".WithdrawalCredentialProof"); + validatorProof.validatorContainerRootProof = + stdJson.readBytes32Array(validatorInfo, ".WithdrawalCredentialProof"); require(validatorProof.validatorContainerRootProof.length == 46, "validator root proof should have 46 nodes"); validatorProof.validatorIndex = stdJson.readUint(validatorInfo, ".validatorIndex"); require(validatorProof.validatorIndex != 0, "validator root index should not be 0"); @@ -146,7 +148,7 @@ contract ExocoreDeployer is Test { // deploy and initialize client chain contracts whitelistTokens.push(address(restakeToken)); - + ProxyAdmin proxyAdmin = new ProxyAdmin(); clientGatewayLogic = new ClientChainGateway( address(clientChainLzEndpoint), @@ -163,9 +165,7 @@ contract ExocoreDeployer is Test { address(clientGatewayLogic), address(proxyAdmin), abi.encodeWithSelector( - clientGatewayLogic.initialize.selector, - payable(exocoreValidatorSet.addr), - whitelistTokens + clientGatewayLogic.initialize.selector, payable(exocoreValidatorSet.addr), whitelistTokens ) ) ) @@ -227,13 +227,13 @@ contract ExocoreDeployer is Test { // mainnet if (block.chainid == 1) { GENESIS_BLOCK_TIMESTAMP = 1606824023; - // goerli + // goerli } else if (block.chainid == 5) { GENESIS_BLOCK_TIMESTAMP = 1616508000; - // sepolia + // sepolia } else if (block.chainid == 11155111) { GENESIS_BLOCK_TIMESTAMP = 1655733600; - // holesky + // holesky } else if (block.chainid == 17000) { GENESIS_BLOCK_TIMESTAMP = 1695902400; } else { diff --git a/test/foundry/ExocoreGateway.t.sol b/test/foundry/ExocoreGateway.t.sol index 942ea33b..d01a55df 100644 --- a/test/foundry/ExocoreGateway.t.sol +++ b/test/foundry/ExocoreGateway.t.sol @@ -79,9 +79,7 @@ contract SetUp is Test { vm.prank(exocoreValidatorSet.addr); exocoreGateway.setPeer(clientChainId, address(clientGateway).toBytes32()); - exocoreLzEndpoint.setDestLzEndpoint( - address(clientGateway), address(clientLzEndpoint) - ); + exocoreLzEndpoint.setDestLzEndpoint(address(clientGateway), address(clientLzEndpoint)); // transfer some gas fee to exocore gateway as it has to pay for the relay fee to layerzero endpoint when sending back response deal(address(exocoreGateway), 1e22); @@ -103,7 +101,7 @@ contract SetUp is Test { contract Pausable is SetUp { using AddressCast for address; - + function test_PauseExocoreGateway() public { vm.expectEmit(true, true, true, true, address(exocoreGateway)); emit Paused(exocoreValidatorSet.addr); @@ -150,6 +148,7 @@ contract Pausable is SetUp { contract LzReceive is SetUp { using AddressCast for address; + uint256 constant WITHDRAWAL_AMOUNT = 123; function test_NotRevert_WithdrawalAmountOverflow() public { @@ -158,16 +157,10 @@ contract LzReceive is SetUp { abi.encodePacked(bytes32(bytes20(withdrawer.addr))), uint256(WITHDRAWAL_AMOUNT) ); - bytes memory msg_ = abi.encodePacked( - GatewayStorage.Action.REQUEST_WITHDRAW_PRINCIPLE_FROM_EXOCORE, - payload - ); + bytes memory msg_ = abi.encodePacked(GatewayStorage.Action.REQUEST_WITHDRAW_PRINCIPLE_FROM_EXOCORE, payload); vm.expectEmit(true, true, true, true, address(exocoreGateway)); - emit ExocorePrecompileError( - WITHDRAW_PRECOMPILE_ADDRESS, - uint64(1) - ); + emit ExocorePrecompileError(WITHDRAW_PRECOMPILE_ADDRESS, uint64(1)); vm.prank(address(exocoreLzEndpoint)); exocoreGateway.lzReceive( @@ -178,4 +171,4 @@ contract LzReceive is SetUp { bytes("") ); } -} \ No newline at end of file +} diff --git a/test/foundry/MyToken.sol b/test/foundry/MyToken.sol index 19adad31..e3092656 100644 --- a/test/foundry/MyToken.sol +++ b/test/foundry/MyToken.sol @@ -7,11 +7,14 @@ contract MyToken is ERC20Burnable { uint8 private _decimals; constructor( - string memory name, string memory symbol, uint8 customDecimals, - address[] memory initialAddresses, uint256 initialBalance + string memory name, + string memory symbol, + uint8 customDecimals, + address[] memory initialAddresses, + uint256 initialBalance ) ERC20(name, symbol) { _mint(msg.sender, initialBalance * 100); - for(uint256 i = 0; i < initialAddresses.length; i++) { + for (uint256 i = 0; i < initialAddresses.length; i++) { _mint(initialAddresses[i], initialBalance); } _decimals = customDecimals; diff --git a/test/mocks/DelegationMock.sol b/test/mocks/DelegationMock.sol index 473ded91..1f086021 100644 --- a/test/mocks/DelegationMock.sol +++ b/test/mocks/DelegationMock.sol @@ -61,7 +61,11 @@ contract DelegationMock is IDelegation { return true; } - function getDelegateAmount(address delegator, string memory operator, uint32 clientChainLzId, address token) public view returns (uint256) { + function getDelegateAmount(address delegator, string memory operator, uint32 clientChainLzId, address token) + public + view + returns (uint256) + { return delegateTo[_addressToBytes(delegator)][bytes(operator)][clientChainLzId][_addressToBytes(token)]; } diff --git a/test/mocks/DepositMock.sol b/test/mocks/DepositMock.sol index a21ecb4d..ada91b99 100644 --- a/test/mocks/DepositMock.sol +++ b/test/mocks/DepositMock.sol @@ -6,19 +6,17 @@ import "./WithdrawPrincipleMock.sol"; contract DepositMock is IDeposit { mapping(uint32 => mapping(bytes => mapping(bytes => uint256))) principleBalances; - function depositTo( - uint32 clientChainLzId, - bytes memory assetsAddress, - bytes memory stakerAddress, - uint256 opAmount - ) - external - returns (bool success,uint256 latestAssetState) - { + + function depositTo(uint32 clientChainLzId, bytes memory assetsAddress, bytes memory stakerAddress, uint256 opAmount) + external + returns (bool success, uint256 latestAssetState) + { require(assetsAddress.length == 32, "invalid asset address"); require(stakerAddress.length == 32, "invalid staker address"); principleBalances[clientChainLzId][assetsAddress][stakerAddress] += opAmount; - WithdrawPrincipleMock(WITHDRAW_PRECOMPILE_ADDRESS).depositTo(clientChainLzId, assetsAddress, stakerAddress, opAmount); + WithdrawPrincipleMock(WITHDRAW_PRECOMPILE_ADDRESS).depositTo( + clientChainLzId, assetsAddress, stakerAddress, opAmount + ); return (true, principleBalances[clientChainLzId][assetsAddress][stakerAddress]); } @@ -27,11 +25,8 @@ contract DepositMock is IDeposit { bytes memory assetsAddress, bytes memory withdrawer, uint256 opAmount - ) - external - returns (bool success,uint256 latestAssetState) - { + ) external returns (bool success, uint256 latestAssetState) { require(opAmount <= principleBalances[clientChainLzId][assetsAddress][withdrawer], "withdraw amount overflow"); principleBalances[clientChainLzId][assetsAddress][withdrawer] -= opAmount; } -} \ No newline at end of file +} diff --git a/test/mocks/ETHPOSDepositMock.sol b/test/mocks/ETHPOSDepositMock.sol index 8dee88c1..4250b848 100644 --- a/test/mocks/ETHPOSDepositMock.sol +++ b/test/mocks/ETHPOSDepositMock.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.19; import "src/interfaces/IETHPOSDeposit.sol"; contract ETHPOSDepositMock is IETHPOSDeposit { - function deposit( bytes calldata pubkey, bytes calldata withdrawal_credentials, @@ -11,7 +10,6 @@ contract ETHPOSDepositMock is IETHPOSDeposit { bytes32 deposit_data_root ) external payable {} - function get_deposit_root() external pure returns (bytes32) { bytes32 root; return root; @@ -24,4 +22,3 @@ contract ETHPOSDepositMock is IETHPOSDeposit { return root; } } - diff --git a/test/mocks/EndpointV2Mock.sol b/test/mocks/EndpointV2Mock.sol index a230117a..45c5430b 100644 --- a/test/mocks/EndpointV2Mock.sol +++ b/test/mocks/EndpointV2Mock.sol @@ -433,19 +433,23 @@ contract EndpointV2Mock is ILayerZeroEndpointV2, MessagingContext { return ExecutionState.NotExecutable; } - function getConfig(address, /*_oapp*/ address, /*_lib*/ uint32, /*_eid*/ uint32 /*_configType*/ ) - external - pure - returns (bytes memory config) - { + function getConfig( + address, + /*_oapp*/ + address, + /*_lib*/ + uint32, + /*_eid*/ + uint32 /*_configType*/ + ) external pure returns (bytes memory config) { return bytes("0x"); } - function getReceiveLibrary(address, /*receiver*/ uint32 /*_eid*/ ) - external - pure - returns (address lib, bool isDefault) - { + function getReceiveLibrary( + address, + /*receiver*/ + uint32 /*_eid*/ + ) external pure returns (address lib, bool isDefault) { return (address(0), false); } @@ -500,11 +504,13 @@ contract EndpointV2Mock is ILayerZeroEndpointV2, MessagingContext { return address(0); } - function nextGuid(address, /*_sender,*/ uint32, /*_dstEid,*/ bytes32 /*_receiver*/ ) - external - pure - returns (bytes32) - { + function nextGuid( + address, + /*_sender,*/ + uint32, + /*_dstEid,*/ + bytes32 /*_receiver*/ + ) external pure returns (bytes32) { return 0; } @@ -648,11 +654,13 @@ contract EndpointV2Mock is ILayerZeroEndpointV2, MessagingContext { /// @dev called when the endpoint checks if the msgLib attempting to verify the msg is the configured msgLib of the Oapp /// @dev this check provides the ability for Oapp to lock in a trusted msgLib /// @dev it will fist check if the msgLib is the currently configured one. then check if the msgLib is the one in grace period of msgLib versioning upgrade - function isValidReceiveLibrary(address, /*_receiver*/ uint32, /*_srcEid*/ address /*_actualReceiveLib*/ ) - public - pure - returns (bool) - { + function isValidReceiveLibrary( + address, + /*_receiver*/ + uint32, + /*_srcEid*/ + address /*_actualReceiveLib*/ + ) public pure returns (bool) { return true; } } diff --git a/test/mocks/ExocoreGatewayMock.sol b/test/mocks/ExocoreGatewayMock.sol index 974c807f..d16b225b 100644 --- a/test/mocks/ExocoreGatewayMock.sol +++ b/test/mocks/ExocoreGatewayMock.sol @@ -2,7 +2,13 @@ pragma solidity ^0.8.19; import {ECDSA} from "@openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol"; import {Initializable} from "@openzeppelin-upgradeable/contracts/proxy/utils/Initializable.sol"; -import {OAppUpgradeable, Origin, MessagingFee, MessagingReceipt, OAppReceiverUpgradeable} from "src/lzApp/OAppUpgradeable.sol"; +import { + OAppUpgradeable, + Origin, + MessagingFee, + MessagingReceipt, + OAppReceiverUpgradeable +} from "src/lzApp/OAppUpgradeable.sol"; import {BytesLib} from "@layerzero-contracts/util/BytesLib.sol"; import {PausableUpgradeable} from "@openzeppelin-upgradeable/contracts/utils/PausableUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin-upgradeable/contracts/access/OwnableUpgradeable.sol"; @@ -133,14 +139,16 @@ contract ExocoreGatewayMock is function pause() external { require( - msg.sender == exocoreValidatorSetAddress, "ExocoreGateway: caller is not Exocore validator set aggregated address" + msg.sender == exocoreValidatorSetAddress, + "ExocoreGateway: caller is not Exocore validator set aggregated address" ); _pause(); } function unpause() external { require( - msg.sender == exocoreValidatorSetAddress, "ExocoreGateway: caller is not Exocore validator set aggregated address" + msg.sender == exocoreValidatorSetAddress, + "ExocoreGateway: caller is not Exocore validator set aggregated address" ); _unpause(); } @@ -171,13 +179,7 @@ contract ExocoreGatewayMock is uint256 amount = uint256(bytes32(payload[64:96])); (bool success, bytes memory responseOrReason) = DEPOSIT_PRECOMPILE_MOCK_ADDRESS.call( - abi.encodeWithSelector( - DEPOSIT_FUNCTION_SELECTOR, - srcChainId, - token, - depositor, - amount - ) + abi.encodeWithSelector(DEPOSIT_FUNCTION_SELECTOR, srcChainId, token, depositor, amount) ); uint256 lastlyUpdatedPrincipleBalance; @@ -194,7 +196,9 @@ contract ExocoreGatewayMock is onlyCalledFromThis { if (payload.length != WITHDRAW_PRINCIPLE_REQUEST_LENGTH) { - revert InvalidRequestLength(Action.REQUEST_WITHDRAW_PRINCIPLE_FROM_EXOCORE, WITHDRAW_PRINCIPLE_REQUEST_LENGTH, payload.length); + revert InvalidRequestLength( + Action.REQUEST_WITHDRAW_PRINCIPLE_FROM_EXOCORE, WITHDRAW_PRINCIPLE_REQUEST_LENGTH, payload.length + ); } bytes calldata token = payload[:32]; @@ -202,13 +206,7 @@ contract ExocoreGatewayMock is uint256 amount = uint256(bytes32(payload[64:96])); (bool success, bytes memory responseOrReason) = WITHDRAW_PRINCIPLE_PRECOMPILE_MOCK_ADDRESS.call( - abi.encodeWithSelector( - WITHDRAW_PRINCIPLE_FUNCTION_SELECTOR, - srcChainId, - token, - withdrawer, - amount - ) + abi.encodeWithSelector(WITHDRAW_PRINCIPLE_FUNCTION_SELECTOR, srcChainId, token, withdrawer, amount) ); uint256 lastlyUpdatedPrincipleBalance; @@ -225,7 +223,9 @@ contract ExocoreGatewayMock is onlyCalledFromThis { if (payload.length != CLAIM_REWARD_REQUEST_LENGTH) { - revert InvalidRequestLength(Action.REQUEST_WITHDRAW_REWARD_FROM_EXOCORE, CLAIM_REWARD_REQUEST_LENGTH, payload.length); + revert InvalidRequestLength( + Action.REQUEST_WITHDRAW_REWARD_FROM_EXOCORE, CLAIM_REWARD_REQUEST_LENGTH, payload.length + ); } bytes calldata token = payload[:32]; @@ -233,13 +233,7 @@ contract ExocoreGatewayMock is uint256 amount = uint256(bytes32(payload[64:96])); (bool success, bytes memory responseOrReason) = CLAIM_REWARD_PRECOMPILE_MOCK_ADDRESS.call( - abi.encodeWithSelector( - CLAIM_REWARD_FUNCTION_SELECTOR, - srcChainId, - token, - withdrawer, - amount - ) + abi.encodeWithSelector(CLAIM_REWARD_FUNCTION_SELECTOR, srcChainId, token, withdrawer, amount) ); uint256 lastlyUpdatedRewardBalance; diff --git a/test/mocks/NonShortCircuitEndpointV2Mock.sol b/test/mocks/NonShortCircuitEndpointV2Mock.sol index ea39122a..62c47ca6 100644 --- a/test/mocks/NonShortCircuitEndpointV2Mock.sol +++ b/test/mocks/NonShortCircuitEndpointV2Mock.sol @@ -509,19 +509,23 @@ contract NonShortCircuitEndpointV2Mock is ILayerZeroEndpointV2, MessagingContext return ExecutionState.NotExecutable; } - function getConfig(address, /*_oapp*/ address, /*_lib*/ uint32, /*_eid*/ uint32 /*_configType*/ ) - external - pure - returns (bytes memory config) - { + function getConfig( + address, + /*_oapp*/ + address, + /*_lib*/ + uint32, + /*_eid*/ + uint32 /*_configType*/ + ) external pure returns (bytes memory config) { return bytes("0x"); } - function getReceiveLibrary(address, /*receiver*/ uint32 /*_eid*/ ) - external - pure - returns (address lib, bool isDefault) - { + function getReceiveLibrary( + address, + /*receiver*/ + uint32 /*_eid*/ + ) external pure returns (address lib, bool isDefault) { return (address(0), false); } @@ -576,11 +580,13 @@ contract NonShortCircuitEndpointV2Mock is ILayerZeroEndpointV2, MessagingContext return address(0); } - function nextGuid(address, /*_sender,*/ uint32, /*_dstEid,*/ bytes32 /*_receiver*/ ) - external - pure - returns (bytes32) - { + function nextGuid( + address, + /*_sender,*/ + uint32, + /*_dstEid,*/ + bytes32 /*_receiver*/ + ) external pure returns (bytes32) { return 0; } @@ -726,11 +732,13 @@ contract NonShortCircuitEndpointV2Mock is ILayerZeroEndpointV2, MessagingContext /// @dev called when the endpoint checks if the msgLib attempting to verify the msg is the configured msgLib of the Oapp /// @dev this check provides the ability for Oapp to lock in a trusted msgLib /// @dev it will fist check if the msgLib is the currently configured one. then check if the msgLib is the one in grace period of msgLib versioning upgrade - function isValidReceiveLibrary(address, /*_receiver*/ uint32, /*_srcEid*/ address /*_actualReceiveLib*/ ) - public - pure - returns (bool) - { + function isValidReceiveLibrary( + address, + /*_receiver*/ + uint32, + /*_srcEid*/ + address /*_actualReceiveLib*/ + ) public pure returns (bool) { return true; } } diff --git a/test/mocks/NonShortCircuitLzEndpointMock.sol b/test/mocks/NonShortCircuitLzEndpointMock.sol index 9ea1bc23..4813a7b0 100644 --- a/test/mocks/NonShortCircuitLzEndpointMock.sol +++ b/test/mocks/NonShortCircuitLzEndpointMock.sol @@ -319,12 +319,15 @@ contract NonShortCircuitLzEndpointMock is ILayerZeroEndpoint { return _receive_entered_state == _ENTERED; } - function getConfig(uint16, /*_version*/ uint16, /*_chainId*/ address, /*_ua*/ uint256 /*_configType*/ ) - external - pure - override - returns (bytes memory) - { + function getConfig( + uint16, + /*_version*/ + uint16, + /*_chainId*/ + address, + /*_ua*/ + uint256 /*_configType*/ + ) external pure override returns (bytes memory) { return ""; } @@ -336,10 +339,15 @@ contract NonShortCircuitLzEndpointMock is ILayerZeroEndpoint { return 1; } - function setConfig(uint16, /*_version*/ uint16, /*_chainId*/ uint256, /*_configType*/ bytes memory /*_config*/ ) - external - override - {} + function setConfig( + uint16, + /*_version*/ + uint16, + /*_chainId*/ + uint256, + /*_configType*/ + bytes memory /*_config*/ + ) external override {} function setSendVersion(uint16 /*version*/ ) external override {} diff --git a/test/mocks/WithdrawPrincipleMock.sol b/test/mocks/WithdrawPrincipleMock.sol index 364ab911..da96a264 100644 --- a/test/mocks/WithdrawPrincipleMock.sol +++ b/test/mocks/WithdrawPrincipleMock.sol @@ -6,16 +6,13 @@ import "./DepositMock.sol"; contract WithdrawPrincipleMock is IWithdraw { mapping(uint32 => mapping(bytes => mapping(bytes => uint256))) principleBalances; - function depositTo( - uint32 clientChainLzId, - bytes memory assetsAddress, - bytes memory stakerAddress, - uint256 opAmount - ) - external - returns (bool success,uint256 latestAssetState) + + function depositTo(uint32 clientChainLzId, bytes memory assetsAddress, bytes memory stakerAddress, uint256 opAmount) + external + returns (bool, uint256) { principleBalances[clientChainLzId][assetsAddress][stakerAddress] += opAmount; + return (true, principleBalances[clientChainLzId][assetsAddress][stakerAddress]); } function withdrawPrinciple( @@ -23,10 +20,7 @@ contract WithdrawPrincipleMock is IWithdraw { bytes memory assetsAddress, bytes memory withdrawer, uint256 opAmount - ) - external - returns (bool success,uint256 latestAssetState) - { + ) external returns (bool success, uint256 latestAssetState) { require(assetsAddress.length == 32, "invalid asset address"); require(withdrawer.length == 32, "invalid staker address"); require(opAmount <= principleBalances[clientChainLzId][assetsAddress][withdrawer], "withdraw amount overflow"); @@ -34,4 +28,4 @@ contract WithdrawPrincipleMock is IWithdraw { DepositMock(DEPOSIT_PRECOMPILE_ADDRESS).withdrawPrinciple(clientChainLzId, assetsAddress, withdrawer, opAmount); return (true, principleBalances[clientChainLzId][assetsAddress][withdrawer]); } -} \ No newline at end of file +}