From a16bd0fd7e3a9a4e59d5a573b40d2230de3641e7 Mon Sep 17 00:00:00 2001 From: excaliborr Date: Fri, 24 Nov 2023 15:35:38 -0500 Subject: [PATCH] chore: refactor and fixing bugs --- package.json | 10 +- proofs/proof.json | 8 +- proofs/proof_utils.py | 2 +- solidity/contracts/VerifierModule.sol | 6 +- solidity/scripts/DeployE2E.s.sol | 91 +++++-- solidity/scripts/DeployHomeChain.s.sol | 2 +- solidity/scripts/DeployNonHomeChain.s.sol | 2 +- solidity/scripts/Deployments.json | 5 - solidity/scripts/HomeChainDeployments.json | 5 - solidity/scripts/NonHomeChainDeployments.json | 9 - solidity/scripts/SafeDeployments.json | 10 - .../deployments/E2ESafeDeployments.json | 10 + .../deployments/HomeChainDeployments.json | 5 + .../deployments/NonHomeChainDeployments.json | 9 + solidity/test/e2e/Common.sol | 247 ++++-------------- solidity/test/e2e/VerifierModule.t.sol | 45 +++- 16 files changed, 200 insertions(+), 266 deletions(-) delete mode 100644 solidity/scripts/Deployments.json delete mode 100644 solidity/scripts/HomeChainDeployments.json delete mode 100644 solidity/scripts/NonHomeChainDeployments.json delete mode 100644 solidity/scripts/SafeDeployments.json create mode 100644 solidity/scripts/deployments/E2ESafeDeployments.json create mode 100644 solidity/scripts/deployments/HomeChainDeployments.json create mode 100644 solidity/scripts/deployments/NonHomeChainDeployments.json diff --git a/package.json b/package.json index 6577237..1f6baa9 100644 --- a/package.json +++ b/package.json @@ -10,23 +10,23 @@ }, "author": "Wonderland", "scripts": { - "anvil:mainnet": "anvil --port 8545 -f $MAINNET_RPC --fork-block-number 18621047 --chain-id 1", - "anvil:optimism": "anvil --port 9545 -f $OPTIMISM_RPC --fork-block-number 112491451 --chain-id 10", - "build": "forge build --via-ir", + "build": "forge build", "build:optimized": "FOUNDRY_PROFILE=optimized forge build", "coverage": "forge coverage --match-contract Unit", "deploy:goerli": "bash -c 'source .env && forge script -vv --rpc-url $GOERLI_RPC --slow --broadcast --private-key $DEPLOYER_GOERLI_PRIVATE_KEY solidity/scripts/DeployGoerli.s.sol:DeployGoerli'", "deploy:mainnet": "bash -c 'source .env && forge script -vv --rpc-url $MAINNET_E2E_RPC --slow --broadcast --private-key $DEPLOYER_MAINNNET_PRIVATE_KEY solidity/scripts/DeployMainnet.s.sol:DeployMainnet'", "deploy:optimism": "bash -c 'source .env && forge script -vv --rpc-url $OPTIMISM_E2E_RPC --slow --broadcast --private-key $DEPLOYER_OPTIMISM_PRIVATE_KEY solidity/scripts/DeployOptimism.s.sol:DeployOptimism'", "deploy:optimismGoerli": "bash -c 'source .env && forge script -vv --rpc-url $OPTIMISM_GOERLI_RPC --slow --broadcast --private-key $DEPLOYER_OPTIMISM_GOERLI_PRIVATE_KEY solidity/scripts/DeployOptimismGoerli.s.sol:DeployOptimismGoerli'", + "ganache:mainnet": "ganache --port 8545 --mnemonic 'chapter polar wool ethics pudding undo slide social second put segment chair'", + "ganache:optimism": "ganache --port 9545 --mnemonic 'chapter polar wool ethics pudding undo slide social second put segment chair'", "lint:check": "yarn lint:sol-tests && yarn lint:sol-logic && forge fmt check", "lint:fix": "sort-package-json && forge fmt && yarn lint:sol-tests --fix && yarn lint:sol-logic --fix", "lint:sol-logic": "solhint -c .solhint.json 'solidity/contracts/**/*.sol' 'solidity/interfaces/**/*.sol'", "lint:sol-tests": "solhint 'solidity/test/**/*.sol'", "prepare": "husky install", "proof": "python3 proofs/generate_proof.py", - "test": "forge test -vvv", - "test:e2e": "forge test --match-contract E2E -vvv", + "test": "forge test --ffi -vvv", + "test:e2e": "forge test --ffi --match-contract E2E -vvv", "test:unit": "forge test --match-contract Unit -vvv", "test:unit:deep": "FOUNDRY_FUZZ_RUNS=5000 yarn test:unit" }, diff --git a/proofs/proof.json b/proofs/proof.json index 94369e5..4fb644f 100644 --- a/proofs/proof.json +++ b/proofs/proof.json @@ -1,6 +1,6 @@ { - "blockNumber": 23, - "blockHeader": "f901f5a098025019b679c7d07a94be981c4d89dfd7e181ab0a6bf552ebbbd8b79c0d5e43a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0fa44db5328a4efcd29a62fc7256bd65991b619bf92a388bdd98a0671a4d92757a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000178401c9c38000846560aaa180a0b6f10f40b56cdd7e601090ad40d430220882d56a6b4833d4c821f6faca31d7b4880000000000000000", - "accountProof": "f9025ff901f1a08612f63b7f9a11408e2f23f321e5136d332dd57790ed36735777b23957310993a016ef7dfdd5a2499becbb81956a38788bfc057f9d52dd5c576ebcb85de995040ea030235cd697b3c3a0f85fa35fad88d3fc176fa60cd74b1d3cd7add06250b40305a0153a661f74405ad9d8f5d1df1138e82bfef064d71da5eec6df62aedf25868aeba0de26cb1b4fd99c4d3ed75d4a67931e3c252605c7d68e0148d5327f341bfd5283a0409e3997e67d3963cccc4b306dbf32d9b4790db921fe414a1be1030c5327e27ca0865d7ca964ec30d14b72f9744bad3e9f4cd12f3ee0eabfa5b7bf4e3a13c0753e80a0ea85562bb917489f2aa6151418d9c34428721c7d8e3ebd8fb07404a1ef5217fba0650baffbb20b2e9ff377c5518cf910c01caeeb7bc32907c60cda835edb70dff1a07ea03eb36e3087a210f9e1fb8e56dc0ccb528b59e1637443139e5a18312c238da0b584f3ace57d374da950843baaf0c847348d627c4cd625dd66e5dcc41fffffdaa0b6e213ee6b464afba5190eef562a503a089087df5bf722f694bfcc0709413968a0a5ac64bb99d260ef6b13a4f2040ed48a4936664ec13d400238b5004841a4d888a02cced9104a6e072cfcff4bc51d16ad481678fc128ebea28446a982234c65227ba0efc69d2819d03c1d5c708bf8f59905a501ed8d23ef08fb1270cfb345221f28da80f869a034b14a79c7136d5a01f70ed75f70e07b9dbd7d85dc331e9404805af6671a9d96b846f8440180a076f4ebdb9e788380676986fe28d3997be29c3492d9f3f666c9ed91891306beb0a0fd79d9f0b0ab6ee2f4166bb9632d934d81e28cd5fdb396e3f3e06ef9580cfd32", - "storageProof": "f846f844a120de506b3ca792e2f384432fef433a68be75fe11a8028a454651f138569ff3d1e0a1a0a362927a7b493db164d1728c370827794def1c9f44b655434ab20f05d39e7478" + "blockNumber": 36, + "blockHeader": "f901f5a0f39983753ddfc18c23a4b39f747294f130da825e5dffb40a3b5f60035a4ec57ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0bb207649ed9410038954b38b4255b74cafc1f42d3009c140b65559da5fbe4d27a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000248401c9c3800084656108ab80a087319fde05bca7b338486f083acd366a7a0b5d611e30824a130dd3265599b348880000000000000000", + "accountProof": "f90344f90211a08612f63b7f9a11408e2f23f321e5136d332dd57790ed36735777b23957310993a016ef7dfdd5a2499becbb81956a38788bfc057f9d52dd5c576ebcb85de995040ea0fe6b255e122c54ba054bccdaf3852e3ec34465f640e4b73aa726874bd5469f96a02c97aa6929b910f31d98eb3d0f476cb6fe1ec36a5928fe6229e720d31e996317a0de26cb1b4fd99c4d3ed75d4a67931e3c252605c7d68e0148d5327f341bfd5283a05be23df6da58dc30280666f326ffe2195cb7dfa9ce4a84ba717037122fae8038a0f06b89db96623466bc5ea383fb27224ef44444881917a22bc0f1c62ab2eae315a0138ee0184f6efe0e45598b6464db22cb9223675716aceb3c140c1851c6ca410ca0ea85562bb917489f2aa6151418d9c34428721c7d8e3ebd8fb07404a1ef5217fba0650baffbb20b2e9ff377c5518cf910c01caeeb7bc32907c60cda835edb70dff1a07ea03eb36e3087a210f9e1fb8e56dc0ccb528b59e1637443139e5a18312c238da06edfd510f74c19fcd730f511b0299da90d8bc6728c6881b8fb85377201965d5fa0838811f973bc4b33943c91dcf89cbe3a880bc8b54546341fb5f1fa718771c27ea092ce65498a7c2b08b130753f4473761c6d90ef094119a66cc482b622f4116bb0a093b6bc9719692906bfc192f9e4b738a809a0c3ef0daabe08b4ad055c66130bfba0efc69d2819d03c1d5c708bf8f59905a501ed8d23ef08fb1270cfb345221f28da80f871808080808080a02bac582e860fd49c3f34de2a6f9fa706ea1ad70f4193a1a9823addd0d92b065b8080a0d81b357ccc2c72f765a68c399c9b05a8583067fd455a628068ed0f8b58306dfa80a08a0d76872abbc84b8b8ebad07baec7e6d30439fc2f62882638966a0f2b7307e28080808080f8518080808080808080808080a05115ad990b35e082788c4c3623594518d365075459aa656a4cc82db67d243c8da02ff07d5c68978593cd1e03533f1a14fda2e6828680ee2241e7616cec87f4f83580808080f8689f3fca9caaefa3f5b6ed8c22b6c44aa2bada0e861d7ab419ae9a05e03df85357b846f8440180a0110b0f4e2d6d23319a04333093205f8d1159ecd7a04317afcd47b41024d1ab8da0fd79d9f0b0ab6ee2f4166bb9632d934d81e28cd5fdb396e3f3e06ef9580cfd32", + "storageProof": "f846f844a120ccf9afdf934e310256e17a4e9d00f805abdf656335d78ac9a72ed7beac729e12a1a0a362927a7b493db164d1728c370827794def1c9f44b655434ab20f05d39e7478" } \ No newline at end of file diff --git a/proofs/proof_utils.py b/proofs/proof_utils.py index 165cdcc..7ec509f 100644 --- a/proofs/proof_utils.py +++ b/proofs/proof_utils.py @@ -53,7 +53,7 @@ def request_account_proof(rpc_endpoint, block_number, address, slots): storage_proofs = [ decode_rpc_proof(slot_data["proof"]) for slot_data in result["storageProof"] ] - + return (account_proof, storage_proofs) diff --git a/solidity/contracts/VerifierModule.sol b/solidity/contracts/VerifierModule.sol index b871dec..d39caaf 100644 --- a/solidity/contracts/VerifierModule.sol +++ b/solidity/contracts/VerifierModule.sol @@ -112,7 +112,7 @@ contract VerifierModule is IVerifierModule { // Verify the account proof against the state root bytes memory _rlpAccount = MerklePatriciaProofVerifier.extractProofValue( _parsedBlockHeader.stateRootHash, - abi.encodePacked(keccak256(abi.encode(STORAGE_MIRROR))), + abi.encodePacked(keccak256(abi.encodePacked(STORAGE_MIRROR))), _storageMirrorAccountProof.toRlpItem().toList() ); @@ -309,11 +309,11 @@ contract VerifierModule is IVerifierModule { // Ensure the source data is 32 bytes or less // Sanity check the keccak256() of the security settings should always fit in 32 bytes - if (_source.length > 32) revert VerifierModule_BytesToBytes32Failed(); + if (_source.length > 33) revert VerifierModule_BytesToBytes32Failed(); // Copy the data into the bytes32 variable assembly { - _result := mload(add(_source, 32)) + _result := mload(add(add(_source, 2), 32)) } } } diff --git a/solidity/scripts/DeployE2E.s.sol b/solidity/scripts/DeployE2E.s.sol index c1acedd..68b0882 100644 --- a/solidity/scripts/DeployE2E.s.sol +++ b/solidity/scripts/DeployE2E.s.sol @@ -30,6 +30,7 @@ contract DeployE2E is Script, DeployHomeChain, DeployNonHomeChain { uint256 internal _pk = vm.envUint('MAINNET_DEPLOYER_PK'); address[] internal _owners = [_deployer]; Safe internal _singletonSafe; + Safe internal _singletonSafeOp; IVerifierModule.SafeTxnParams internal _vars; function run() external { @@ -42,7 +43,7 @@ contract DeployE2E is Script, DeployHomeChain, DeployNonHomeChain { _deployHomeChain(_deployVarsHomeChain); ISafe _safe = ISafe(address(new SafeProxy(address(_singletonSafe)))); address _storageMirrorAddr = - vm.parseJsonAddress(vm.readFile('./solidity/scripts/HomeChainDeployments.json'), '$.StorageMirror'); + vm.parseJsonAddress(vm.readFile('./solidity/scripts/deployments/HomeChainDeployments.json'), '$.StorageMirror'); _setupHomeChain(_safe, _storageMirrorAddr); @@ -52,19 +53,25 @@ contract DeployE2E is Script, DeployHomeChain, DeployNonHomeChain { vm.createSelectFork(vm.rpcUrl('optimism_e2e')); vm.startBroadcast(_deployer); + _singletonSafeOp = new Safe(); + ISafe _nonHomeChainSafe = ISafe(address(new SafeProxy(address(_singletonSafeOp)))); // Deploy protocol _deployNonHomeChain(_deployVarsNonHomeChain); + address _verifierModule = vm.parseJsonAddress( + vm.readFile('./solidity/scripts/deployments/NonHomeChainDeployments.json'), '$.VerifierModule' + ); + + _setupNonHomeChain(_nonHomeChainSafe, _verifierModule); + vm.stopBroadcast(); string memory _objectKey = 'deployments'; string memory _output = vm.serializeAddress(_objectKey, 'Safe', address(_safe)); - vm.writeJson(_output, './solidity/scripts/SafeDeployments.json'); - - // saveProof(vm.rpcUrl('mainnet_e2e'), vm.toString(_storageMirrorAddr), vm.toString((keccak256(abi.encode(address(_safe), 0))))); + vm.writeJson(_output, './solidity/scripts/deployments/E2ESafeDeployments.json'); } /** @@ -94,8 +101,9 @@ contract DeployE2E is Script, DeployHomeChain, DeployNonHomeChain { function _setupHomeChain(ISafe _safe, address _storageMirrorAddr) internal { _safe.setup(_owners, 1, address(_safe), bytes(''), address(0), address(0), 0, payable(address(0))); - address _guardCallbackModule = - vm.parseJsonAddress(vm.readFile('./solidity/scripts/HomeChainDeployments.json'), '$.GuardCallbackModule'); + address _guardCallbackModule = vm.parseJsonAddress( + vm.readFile('./solidity/scripts/deployments/HomeChainDeployments.json'), '$.GuardCallbackModule' + ); enableModule(_safe, _pk, _guardCallbackModule); @@ -179,22 +187,57 @@ contract DeployE2E is Script, DeployHomeChain, DeployNonHomeChain { ); } - // function saveProof( - // string memory _rpc, - // string memory _contractAddress, - // string memory _storageSlot - // ) public { - // string[] memory _commands = new string[](8); - // _commands[0] = 'yarn'; - // _commands[1] = 'proof'; - // _commands[2] = '--rpc'; - // _commands[3] = _rpc; - // _commands[4] = '--contract'; - // _commands[5] = _contractAddress; - // _commands[6] = '--slot'; - // _commands[7] = _storageSlot; - - // bytes memory _res = vm.ffi(_commands); - // string memory _output = string(_res); - // } + function _setupNonHomeChain(ISafe _safe, address _verifierModule) internal { + _safe.setup(_owners, 1, address(_safe), bytes(''), address(0), address(0), 0, payable(address(0))); + enableModule(_safe, _pk, _verifierModule); + + address _needsUpdateGuard = vm.parseJsonAddress( + vm.readFile('./solidity/scripts/deployments/NonHomeChainDeployments.json'), '$.NeedsUpdateGuard' + ); + + // data to sign and send to set the guard + bytes memory _txData = _safe.encodeTransactionData( + address(_safe), + 0, + abi.encodeWithSelector(ISafe.setGuard.selector, _needsUpdateGuard), + Enum.Operation.Call, + 0, + 0, + 0, + address(0), + payable(0), + _safe.nonce() + ); + + Signature memory _signature; + + // signature + (_signature.v, _signature.r, _signature.s) = vm.sign(_pk, keccak256(_txData)); + + _vars = IVerifierModule.SafeTxnParams({ + to: address(_safe), + value: 0, + data: abi.encodeWithSelector(ISafe.setGuard.selector, _needsUpdateGuard), + operation: Enum.Operation.Call, + safeTxGas: 0, + baseGas: 0, + gasPrice: 0, + gasToken: address(0), + refundReceiver: payable(address(0)), + signatures: abi.encodePacked(_signature.r, _signature.s, _signature.v) + }); + + _safe.execTransaction( + _vars.to, + _vars.value, + _vars.data, + _vars.operation, + _vars.safeTxGas, + _vars.baseGas, + _vars.gasPrice, + _vars.gasToken, + _vars.refundReceiver, + _vars.signatures + ); + } } diff --git a/solidity/scripts/DeployHomeChain.s.sol b/solidity/scripts/DeployHomeChain.s.sol index 80e1e2e..e81f974 100644 --- a/solidity/scripts/DeployHomeChain.s.sol +++ b/solidity/scripts/DeployHomeChain.s.sol @@ -49,6 +49,6 @@ abstract contract DeployHomeChain is Script, TestConstants { vm.serializeAddress(_objectKey, 'UpdateStorageMirrorGuard', address(_updateStorageMirrorGuard)); string memory _output = vm.serializeAddress(_objectKey, 'GuardCallbackModule', address(_guardCallbackModule)); - vm.writeJson(_output, './solidity/scripts/HomeChainDeployments.json'); + vm.writeJson(_output, './solidity/scripts/deployments/HomeChainDeployments.json'); } } diff --git a/solidity/scripts/DeployNonHomeChain.s.sol b/solidity/scripts/DeployNonHomeChain.s.sol index 2ed6bb6..9cedede 100644 --- a/solidity/scripts/DeployNonHomeChain.s.sol +++ b/solidity/scripts/DeployNonHomeChain.s.sol @@ -56,6 +56,6 @@ abstract contract DeployNonHomeChain is Script, TestConstants { vm.serializeAddress(_objectKey, 'StorageMirrorRootRegistry', address(_storageMirrorRootRegistry)); string memory _output = vm.serializeAddress(_objectKey, 'VerifierModule', address(_verifierModule)); - vm.writeJson(_output, './solidity/scripts/NonHomeChainDeployments.json'); + vm.writeJson(_output, './solidity/scripts/deployments/NonHomeChainDeployments.json'); } } diff --git a/solidity/scripts/Deployments.json b/solidity/scripts/Deployments.json deleted file mode 100644 index 17e46dd..0000000 --- a/solidity/scripts/Deployments.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "GuardCallbackModule": "0x8d375dE3D5DDde8d8caAaD6a4c31bD291756180b", - "StorageMirror": "0x4458AcB1185aD869F982D51b5b0b87e23767A3A9", - "UpdateStorageMirrorGuard": "0x721a1ecB9105f2335a8EA7505D343a5a09803A06" -} \ No newline at end of file diff --git a/solidity/scripts/HomeChainDeployments.json b/solidity/scripts/HomeChainDeployments.json deleted file mode 100644 index 9af81ff..0000000 --- a/solidity/scripts/HomeChainDeployments.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "GuardCallbackModule": "0x15C31F52d65867015E99690Ee17438C5c5C187A6", - "StorageMirror": "0xd1132644779978752075ec0d8E3A4B206bd80420", - "UpdateStorageMirrorGuard": "0x4974711198287D8058dc4a866E5F5f13B5fB11fF" -} \ No newline at end of file diff --git a/solidity/scripts/NonHomeChainDeployments.json b/solidity/scripts/NonHomeChainDeployments.json deleted file mode 100644 index d9291de..0000000 --- a/solidity/scripts/NonHomeChainDeployments.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "BlockHeaderOracle": "0x35405D4CED44D7370f4a868165612D020eDa57Ad", - "GuardCallbackModule": "0x15C31F52d65867015E99690Ee17438C5c5C187A6", - "NeedsUpdateGuard": "0x9f24e39DAa3F15D2A261d3e8ec84867D93c655Ff", - "StorageMirror": "0xd1132644779978752075ec0d8E3A4B206bd80420", - "StorageMirrorRootRegistry": "0x62eE67efd6780364dD9c9555FD96859327AFE895", - "UpdateStorageMirrorGuard": "0x4974711198287D8058dc4a866E5F5f13B5fB11fF", - "VerifierModule": "0xBE081bf326F43c17d27b8a47bC5F32Aeb8b036B7" -} \ No newline at end of file diff --git a/solidity/scripts/SafeDeployments.json b/solidity/scripts/SafeDeployments.json deleted file mode 100644 index 1fad435..0000000 --- a/solidity/scripts/SafeDeployments.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "BlockHeaderOracle": "0x35405D4CED44D7370f4a868165612D020eDa57Ad", - "GuardCallbackModule": "0x15C31F52d65867015E99690Ee17438C5c5C187A6", - "NeedsUpdateGuard": "0x9f24e39DAa3F15D2A261d3e8ec84867D93c655Ff", - "Safe": "0x1cCc7fae21A35605AA7031AE6FBf2f304B80aC4D", - "StorageMirror": "0xd1132644779978752075ec0d8E3A4B206bd80420", - "StorageMirrorRootRegistry": "0x62eE67efd6780364dD9c9555FD96859327AFE895", - "UpdateStorageMirrorGuard": "0x4974711198287D8058dc4a866E5F5f13B5fB11fF", - "VerifierModule": "0xBE081bf326F43c17d27b8a47bC5F32Aeb8b036B7" -} \ No newline at end of file diff --git a/solidity/scripts/deployments/E2ESafeDeployments.json b/solidity/scripts/deployments/E2ESafeDeployments.json new file mode 100644 index 0000000..90f3bd0 --- /dev/null +++ b/solidity/scripts/deployments/E2ESafeDeployments.json @@ -0,0 +1,10 @@ +{ + "BlockHeaderOracle": "0x818d7aA843fb975fE4cd1024DCc3ad3f0F3F3052", + "GuardCallbackModule": "0xdd272bf1C9bC8ac7E1a2F66608758552924486D5", + "NeedsUpdateGuard": "0x2A636e72883279AD118c9031341Ea8d0ea1C2e69", + "Safe": "0x55289098C49303EF9bC83fC3093B8CcE8be084d2", + "StorageMirror": "0x2A636e72883279AD118c9031341Ea8d0ea1C2e69", + "StorageMirrorRootRegistry": "0x6333aD39eE291441034d278920821092A6E609b3", + "UpdateStorageMirrorGuard": "0xBb5C18Aa963B677B3DCC6e93F63B3AAe7eCb854F", + "VerifierModule": "0x2c1fd361958e736546fE0AF3EC6A27FE1830C644" +} \ No newline at end of file diff --git a/solidity/scripts/deployments/HomeChainDeployments.json b/solidity/scripts/deployments/HomeChainDeployments.json new file mode 100644 index 0000000..4b38597 --- /dev/null +++ b/solidity/scripts/deployments/HomeChainDeployments.json @@ -0,0 +1,5 @@ +{ + "GuardCallbackModule": "0xdd272bf1C9bC8ac7E1a2F66608758552924486D5", + "StorageMirror": "0x2A636e72883279AD118c9031341Ea8d0ea1C2e69", + "UpdateStorageMirrorGuard": "0xBb5C18Aa963B677B3DCC6e93F63B3AAe7eCb854F" +} \ No newline at end of file diff --git a/solidity/scripts/deployments/NonHomeChainDeployments.json b/solidity/scripts/deployments/NonHomeChainDeployments.json new file mode 100644 index 0000000..87e2644 --- /dev/null +++ b/solidity/scripts/deployments/NonHomeChainDeployments.json @@ -0,0 +1,9 @@ +{ + "BlockHeaderOracle": "0x818d7aA843fb975fE4cd1024DCc3ad3f0F3F3052", + "GuardCallbackModule": "0xdd272bf1C9bC8ac7E1a2F66608758552924486D5", + "NeedsUpdateGuard": "0x2A636e72883279AD118c9031341Ea8d0ea1C2e69", + "StorageMirror": "0x2A636e72883279AD118c9031341Ea8d0ea1C2e69", + "StorageMirrorRootRegistry": "0x6333aD39eE291441034d278920821092A6E609b3", + "UpdateStorageMirrorGuard": "0xBb5C18Aa963B677B3DCC6e93F63B3AAe7eCb854F", + "VerifierModule": "0x2c1fd361958e736546fE0AF3EC6A27FE1830C644" +} \ No newline at end of file diff --git a/solidity/test/e2e/Common.sol b/solidity/test/e2e/Common.sol index 1d22a5c..c0fda30 100644 --- a/solidity/test/e2e/Common.sol +++ b/solidity/test/e2e/Common.sol @@ -33,7 +33,7 @@ contract CommonE2EBase is DSTestPlus, TestConstants, Script { uint256 internal _mainnetForkId; uint256 internal _optimismForkId; - address public deployer; + address internal _deployer = vm.rememberKey(vm.envUint('MAINNET_DEPLOYER_PK')); uint256 public deployerKey; address public deployerOptimism = makeAddr('deployerOptimism'); address public proposer = makeAddr('proposer'); @@ -55,12 +55,11 @@ contract CommonE2EBase is DSTestPlus, TestConstants, Script { IGnosisSafeProxyFactory public gnosisSafeProxyFactory = IGnosisSafeProxyFactory(GNOSIS_SAFE_PROXY_FACTORY); function setUp() public virtual { - string[] memory _commands = new string[](5); + string[] memory _commands = new string[](4); _commands[0] = 'forge'; _commands[1] = 'script'; _commands[2] = 'solidity/scripts/DeployE2E.s.sol:DeployE2E'; _commands[3] = '--broadcast'; - _commands[4] = '--ffi'; vm.ffi(_commands); @@ -68,209 +67,50 @@ contract CommonE2EBase is DSTestPlus, TestConstants, Script { _mainnetForkId = vm.createSelectFork(vm.rpcUrl('mainnet_e2e')); _optimismForkId = vm.createSelectFork(vm.rpcUrl('optimism_e2e')); - storageMirror = - StorageMirror(vm.parseJsonAddress(vm.readFile('./solidity/scripts/HomeChainDeployments.json'), '$.StorageMirror')); + storageMirror = StorageMirror( + vm.parseJsonAddress(vm.readFile('./solidity/scripts/deployments/HomeChainDeployments.json'), '$.StorageMirror') + ); updateStorageMirrorGuard = UpdateStorageMirrorGuard( - vm.parseJsonAddress(vm.readFile('./solidity/scripts/HomeChainDeployments.json'), '$.UpdateStorageMirrorGuard') + vm.parseJsonAddress( + vm.readFile('./solidity/scripts/deployments/HomeChainDeployments.json'), '$.UpdateStorageMirrorGuard' + ) ); guardCallbackModule = GuardCallbackModule( - vm.parseJsonAddress(vm.readFile('./solidity/scripts/HomeChainDeployments.json'), '$.GuardCallbackModule') + vm.parseJsonAddress( + vm.readFile('./solidity/scripts/deployments/HomeChainDeployments.json'), '$.GuardCallbackModule' + ) ); oracle = BlockHeaderOracle( - vm.parseJsonAddress(vm.readFile('./solidity/scripts/NonHomeChainDeployments.json'), '$.BlockHeaderOracle') + vm.parseJsonAddress( + vm.readFile('./solidity/scripts/deployments/NonHomeChainDeployments.json'), '$.BlockHeaderOracle' + ) ); needsUpdateGuard = NeedsUpdateGuard( - vm.parseJsonAddress(vm.readFile('./solidity/scripts/NonHomeChainDeployments.json'), '$.NeedsUpdateGuard') + vm.parseJsonAddress( + vm.readFile('./solidity/scripts/deployments/NonHomeChainDeployments.json'), '$.NeedsUpdateGuard' + ) ); verifierModule = VerifierModule( - vm.parseJsonAddress(vm.readFile('./solidity/scripts/NonHomeChainDeployments.json'), '$.VerifierModule') + vm.parseJsonAddress( + vm.readFile('./solidity/scripts/deployments/NonHomeChainDeployments.json'), '$.VerifierModule' + ) ); storageMirrorRootRegistry = StorageMirrorRootRegistry( - vm.parseJsonAddress(vm.readFile('./solidity/scripts/NonHomeChainDeployments.json'), '$.StorageMirrorRootRegistry') + vm.parseJsonAddress( + vm.readFile('./solidity/scripts/deployments/NonHomeChainDeployments.json'), '$.StorageMirrorRootRegistry' + ) ); - safe = ISafe(vm.parseJsonAddress(vm.readFile('./solidity/scripts/SafeDeployments.json'), '$.Safe')); - - // NOTE: BELOW IS UNNECCESARY LOGIC I JUST HAVENT REMOVED IT YET - - // Set up both forks - // _mainnetForkId = vm.createSelectFork(vm.rpcUrl('mainnet_e2e')); - // _optimismForkId = vm.createSelectFork(vm.rpcUrl('optimism_e2e')); - // // Select mainnet fork - // vm.selectFork(_mainnetForkId); - - // // Make address and key of safe owner - // safeOwner = vm.envAddress('MAINNET_SAFE_OWNER_ADDR'); - // safeOwnerKey = vm.envUint('MAINNET_SAFE_OWNER_PK'); - - // // Make address and key of deployer - // deployer = vm.envAddress('MAINNET_DEPlOYER_ADDR'); - // deployerKey = vm.envUint('MAINNET_DEPLOYER_PK'); - - // /// =============== HOME CHAIN =============== - // vm.broadcast(safeOwnerKey); - // safe = ISafe(address(gnosisSafeProxyFactory.createProxy(GNOSIS_SAFE_SINGLETON, ''))); // safeOwner nonce 0 - // label(address(safe), 'SafeProxy'); - - // uint256 _nonce = vm.getNonce(deployer); - - // address _updateStorageMirrorGuardTheoriticalAddress = ContractDeploymentAddress.addressFrom(deployer, _nonce + 2); - - // vm.broadcast(deployer); - // storageMirror = new StorageMirror(); // deployer nonce 0 - // label(address(storageMirror), 'StorageMirror'); - - // vm.broadcast(deployer); - // guardCallbackModule = new GuardCallbackModule(address(storageMirror), _updateStorageMirrorGuardTheoriticalAddress); // deployer nonce 1 - // label(address(guardCallbackModule), 'GuardCallbackModule'); - - // vm.broadcast(deployer); - // updateStorageMirrorGuard = new UpdateStorageMirrorGuard(guardCallbackModule); // deployer nonce 2 - // label(address(updateStorageMirrorGuard), 'UpdateStorageMirrorGuard'); - - // // Make sure the theoritical address was calculated correctly - // assert(address(updateStorageMirrorGuard) == _updateStorageMirrorGuardTheoriticalAddress); - - // // Set up owner home chain safe - // address[] memory _owners = new address[](1); - // _owners[0] = safeOwner; - // vm.broadcast(safeOwnerKey); // safeOwner nonce 1 - // safe.setup(_owners, 1, address(safe), bytes(''), address(0), address(0), 0, payable(0)); - - // // Enable guard callback module - // enableModule(safe, safeOwnerKey, address(guardCallbackModule)); - - // // data to sign and send to set the guard - // bytes memory _setGuardData = abi.encodeWithSelector(IGuardCallbackModule.setGuard.selector); - // bytes memory _setGuardEncodedTxData = safe.encodeTransactionData( - // address(guardCallbackModule), 0, _setGuardData, Enum.Operation.Call, 0, 0, 0, address(0), payable(0), safe.nonce() - // ); - - // // signature - // (uint8 _v, bytes32 _r, bytes32 _s) = vm.sign(safeOwnerKey, keccak256(_setGuardEncodedTxData)); - // bytes memory _setGuardSignature = abi.encodePacked(_r, _s, _v); - - // // execute setup of guard - // vm.broadcast(safeOwnerKey); - // safe.execTransaction( - // address(guardCallbackModule), - // 0, - // _setGuardData, - // Enum.Operation.Call, - // 0, - // 0, - // 0, - // address(0), - // payable(0), - // _setGuardSignature - // ); - - // /// =============== NON HOME CHAIN =============== - // vm.selectFork(_optimismForkId); - // // Make address and key of non home chain safe owner - // (nonHomeChainSafeOwner, nonHomeChainSafeOwnerKey) = makeAddrAndKey('nonHomeChainSafeOwner'); - - // address _storageMirrorRootRegistryTheoriticalAddress = ContractDeploymentAddress.addressFrom(deployerOptimism, 2); - - // // Set up non home chain safe - // vm.broadcast(nonHomeChainSafeOwnerKey); - // nonHomeChainSafe = ISafe(address(gnosisSafeProxyFactory.createProxy(GNOSIS_SAFE_SINGLETON_L2, ''))); // nonHomeChainSafeOwner nonce 0 - // label(address(nonHomeChainSafe), 'NonHomeChainSafeProxy'); - - // // Deploy non home chain contracts - // oracle = new BlockHeaderOracle(); // deployerOptimism nonce 0 - // label(address(oracle), 'BlockHeaderOracle'); - - // vm.broadcast(deployerOptimism); - // verifierModule = - // new VerifierModule(IStorageMirrorRootRegistry(_storageMirrorRootRegistryTheoriticalAddress), address(storageMirror)); // deployerOptimism nonce 1 - // label(address(verifierModule), 'VerifierModule'); + safe = ISafe(vm.parseJsonAddress(vm.readFile('./solidity/scripts/deployments/E2ESafeDeployments.json'), '$.Safe')); - // vm.broadcast(deployerOptimism); - // storageMirrorRootRegistry = - // new StorageMirrorRootRegistry(address(storageMirror), IVerifierModule(verifierModule), IBlockHeaderOracle(oracle)); // deployerOptimism nonce 2 - // label(address(storageMirrorRootRegistry), 'StorageMirrorRootRegistry'); - - // vm.broadcast(deployerOptimism); - // needsUpdateGuard = new NeedsUpdateGuard(verifierModule); // deployer nonce 3 - // label(address(needsUpdateGuard), 'NeedsUpdateGuard'); - - // // set up non home chain safe - // address[] memory _nonHomeChainSafeOwners = new address[](1); - // _nonHomeChainSafeOwners[0] = nonHomeChainSafeOwner; - - // vm.broadcast(nonHomeChainSafeOwnerKey); // nonHomeChainSafeOwner nonce 1 - // nonHomeChainSafe.setup( - // _nonHomeChainSafeOwners, 1, address(nonHomeChainSafe), bytes(''), address(0), address(0), 0, payable(0) - // ); - - // // enable verifier module - // enableModule(nonHomeChainSafe, nonHomeChainSafeOwnerKey, address(verifierModule)); - - // // data to sign and send to set the guard - // _setGuardData = abi.encodeWithSelector(ISafe.setGuard.selector, address(needsUpdateGuard)); - // _setGuardEncodedTxData = nonHomeChainSafe.encodeTransactionData( - // address(nonHomeChainSafe), - // 0, - // _setGuardData, - // Enum.Operation.Call, - // 0, - // 0, - // 0, - // address(0), - // payable(0), - // nonHomeChainSafe.nonce() - // ); - - // // signature - // (_v, _r, _s) = vm.sign(nonHomeChainSafeOwnerKey, keccak256(_setGuardEncodedTxData)); - // _setGuardSignature = abi.encodePacked(_r, _s, _v); - - // // set needs update guard - // vm.broadcast(nonHomeChainSafeOwnerKey); - // nonHomeChainSafe.execTransaction( - // address(nonHomeChainSafe), - // 0, - // _setGuardData, - // Enum.Operation.Call, - // 0, - // 0, - // 0, - // address(0), - // payable(0), - // _setGuardSignature - // ); - } - - /** - * @notice Enables a module for the given safe - * @param _safe The safe that will enable the module - * @param _safeOwnerKey The private key to sign the tx - * @param _module The module address to enable - */ - function enableModule(ISafe _safe, uint256 _safeOwnerKey, address _module) public { - uint256 _safeNonce = _safe.nonce(); - // data to sign to enable module - bytes memory _enableModuleData = abi.encodeWithSelector(ISafe.enableModule.selector, address(_module)); - bytes memory _enableModuleEncodedTxData = _safe.encodeTransactionData( - address(_safe), 0, _enableModuleData, Enum.Operation.Call, 0, 0, 0, address(0), payable(0), _safeNonce - ); - - // signature - (uint8 _v, bytes32 _r, bytes32 _s) = vm.sign(_safeOwnerKey, keccak256(_enableModuleEncodedTxData)); - bytes memory _enableModuleSignature = abi.encodePacked(_r, _s, _v); - - // execute enable module - vm.broadcast(safeOwnerKey); - _safe.execTransaction( - address(_safe), 0, _enableModuleData, Enum.Operation.Call, 0, 0, 0, address(0), payable(0), _enableModuleSignature + // Save the storage mirror proofs + saveProof( + vm.rpcUrl('mainnet_e2e'), + vm.toString(address(storageMirror)), + vm.toString((keccak256(abi.encode(address(safe), 0)))) ); } - function getProof( - string memory _rpc, - string memory _contractAddress, - string memory _storageSlot - ) public returns (bytes memory _storageProof, bytes memory _accountProof, bytes memory _blockHeader) { + function saveProof(string memory _rpc, string memory _contractAddress, string memory _storageSlot) public { string[] memory _commands = new string[](8); _commands[0] = 'yarn'; _commands[1] = 'proof'; @@ -281,12 +121,33 @@ contract CommonE2EBase is DSTestPlus, TestConstants, Script { _commands[6] = '--slot'; _commands[7] = _storageSlot; - bytes memory _res = vm.ffi(_commands); - string memory _output = string(_res); - emit log_string(_output); + vm.ffi(_commands); + } + function getProof() + public + returns (bytes memory _storageProof, bytes memory _accountProof, bytes memory _blockHeader) + { _storageProof = vm.parseJsonBytes(vm.readFile('./proofs/proof.json'), '$.storageProof'); _blockHeader = vm.parseJsonBytes(vm.readFile('./proofs/proof.json'), '$.blockHeader'); _accountProof = vm.parseJsonBytes(vm.readFile('./proofs/proof.json'), '$.accountProof'); } + + /** + * @notice Helpers function to convert bytes to bytes32 + * + * @param _source The bytes to convert + * @return _result The bytes32 variable + */ + function _bytesToBytes32(bytes memory _source) internal pure returns (bytes32 _result) { + // Ensure the source data is 32 bytes or less + + // Sanity check the keccak256() of the security settings should always fit in 32 bytes + if (_source.length > 33) revert('cant fit'); + + // Copy the data into the bytes32 variable + assembly { + _result := mload(add(add(_source, 1), 32)) + } + } } diff --git a/solidity/test/e2e/VerifierModule.t.sol b/solidity/test/e2e/VerifierModule.t.sol index 101bd05..8d23cb7 100644 --- a/solidity/test/e2e/VerifierModule.t.sol +++ b/solidity/test/e2e/VerifierModule.t.sol @@ -3,20 +3,55 @@ pragma solidity >=0.8.4 <0.9.0; import {CommonE2EBase} from 'test/e2e/Common.sol'; import {StateVerifier} from 'libraries/StateVerifier.sol'; +import {MerklePatriciaProofVerifier} from 'libraries/MerklePatriciaProofVerifier.sol'; +import {RLPReader} from 'solidity-rlp/contracts/RLPReader.sol'; +import {IStorageMirror} from 'interfaces/IStorageMirror.sol'; contract VerifierModuleE2E is CommonE2EBase { + using RLPReader for RLPReader.RLPItem; + using RLPReader for bytes; + + function setUp() public override { + super.setUp(); + + vm.selectFork(_optimismForkId); + } + function testExtractStateRoot() public { - (, bytes memory _accountProof, bytes memory _blockHeader) = getProof( - vm.rpcUrl('mainnet_e2e'), - vm.toString(address(storageMirror)), - vm.toString((keccak256(abi.encode(address(safe), 0)))) - ); + (, bytes memory _accountProof, bytes memory _blockHeader) = getProof(); + (bytes32 _stateRoot, uint256 _blockNumber) = verifierModule.extractStorageMirrorStorageRoot(_accountProof, _blockHeader); uint256 _expectedBlockNumber = vm.parseJsonUint(vm.readFile('./proofs/proof.json'), '$.blockNumber'); + assertEq(address(storageMirror), verifierModule.STORAGE_MIRROR()); assertTrue(_stateRoot != bytes32(0)); assertEq(_blockNumber, _expectedBlockNumber); } + + function testStorageProofIsValid() public { + (bytes memory _storageProof, bytes memory _accountProof, bytes memory _blockHeader) = getProof(); + + (bytes32 _stateRoot,) = verifierModule.extractStorageMirrorStorageRoot(_accountProof, _blockHeader); + + bytes32 _slot = keccak256(abi.encode(address(safe), 0)); + bytes32 _slotHash = keccak256(abi.encodePacked(_slot)); + + address[] memory _owners = new address[](1); + _owners[0] = _deployer; + + uint256 _threshold = 1; + + bytes32 _expectedSettingsHash = + keccak256(abi.encode(IStorageMirror.SafeSettings({owners: _owners, threshold: _threshold}))); + + bytes memory _calculatedSettingsHash = MerklePatriciaProofVerifier.extractProofValue( + _stateRoot, abi.encodePacked(_slotHash), _storageProof.toRlpItem().toList() + ); + + bytes32 _calculatedSettingsHashBytes32 = _bytesToBytes32(_calculatedSettingsHash); + + assertEq(_calculatedSettingsHashBytes32, _expectedSettingsHash); + } }