diff --git a/.env.example b/.env.example index bc16bbe..4314cea 100644 --- a/.env.example +++ b/.env.example @@ -9,8 +9,12 @@ PRIVATE_KEY_CALIBNET= PRIVATE_KEY_MAINNET= FILECOIN_PAY= -ALLOCATOR= SP_REGISTRY= TERMINATION_ORACLE= ORACLE= -META_ALLOCATOR= \ No newline at end of file +META_ALLOCATOR= + +# Upgradeable contract envs +UPGRADE_CONTRACT_NAME=Client +UPGRADE_CALLDATA=0x + diff --git a/deployments/devnet/3476134.json b/deployments/devnet/3476134.json new file mode 100644 index 0000000..77aa5dd --- /dev/null +++ b/deployments/devnet/3476134.json @@ -0,0 +1,48 @@ +{ + "Allocator": "0x2E6A0C4F8D1B3e7a9c5f2d4B6a8e0C1f3D5B7A90", + "Client": { + "codeHash": "0xe0ae09ae80420c88ee45f280a19e656898a8c20660452d30ff8a9ba16e549f43", + "deployedCodeHash": "0x25327e766b559d88ebd826b565abd3ebba15a665274dbe7dd9676437091bcb24", + "impl": "0x03655d36fEF529E29Cf60a26F50db5782F47B624", + "proxy": "0xcb863DF4C3BbAC402dCE5dFab2BB67241602c7a1" + }, + "FilecoinPay": "0x4A8F3C2e1D9B7f6A0E5c8b3D2a1F9e7C4B6d8a2E", + "PoRepMarket": { + "codeHash": "0xf47f6d1abf76ba7754f42341f35431e05b7fabf765b9f47f53642e9fa9165d8f", + "deployedCodeHash": "0x1ddc2e2e17549589fc87faee0a66110b7f054d561fc8029fb9ca5b67db65f196", + "impl": "0xc1694a7a3d4FC77f4340755B93Ff2c1d80afF7c4", + "proxy": "0x4f6109Ebf278f6932B562C2D117c36a7800cAE1D" + }, + "PoRepService": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", + "SLIOracle": { + "codeHash": "0x6f437785368109b7d03ea34b13ec0ec9ad2792d664453f56c4a17d3aa8ae2b60", + "deployedCodeHash": "0xb2cf4f478ff232504963e838fb3110330b5241417adaa2d6ccd5ede0269a1de9", + "impl": "0x2076731193e63152d9A54C0637dEBB3b2fbF9C1D", + "proxy": "0x37Ddf4D9a9636aB12797967356aD727899d9aa15" + }, + "SLIScorer": { + "codeHash": "0xbadcd86fdee7e08b50b157ad3d6992e19ddc06111443d546912b8ae4eac14758", + "deployedCodeHash": "0xd2688d4ad5ed90b831c776f4fd081f79660dbdcb90e09397b642b2bf939eb33b", + "impl": "0x3a04e095eff0aeCea4C29dBf8AC61aed32120C0B", + "proxy": "0xc22aBcE7feCfF60f25e62482aFB3A6013FF92FeD" + }, + "SPRegistry": { + "codeHash": "0xf897e7f9d2dd5ada7d5534db82d86ec45a98941aac1d0939d597602e39c1ad9b", + "deployedCodeHash": "0x841ec3c8e2087c2690cb4195ab420d76660e4164c8bde081bfc9c632719951d4", + "impl": "0x6d52a6318e67Ee6fFde7f8Eb63800d25bc47f50d", + "proxy": "0xeD2322C4003fdB0D3532E79858A52A761F4F7304" + }, + "TerminationOracle": "0xe4Cd56f91Bc79cC610AEfB1bE92b07BB5b6F2e30", + "ValidatorBeacon": "0x66423783463AAcE944eBE562f9813D7fDF1fB625", + "ValidatorFactory": { + "codeHash": "0xd7c5a2c10bcf42de0c5986c906a8b61a54a0320137e70f64b12151dc6052119f", + "deployedCodeHash": "0x7137a3a01a3cb4e34e66441270fc99681c6640dac5bff2454605b6368c91e3e3", + "impl": "0x8F8543B857a30Cd0F4F9F158bf9B80EE62f2c3F3", + "proxy": "0x77E1C92c38bD2e4Aa78Ee71B0d063e686171B34F" + }, + "ValidatorImpl": "0x2d1Cd62D37F12f29e8130e41Bd8dBF8f6e2BE34C", + "block": 3476134, + "chainId": 31415926, + "deployer": "0x149661aB3B2d343114e4F518fF3cC3b47266d8C4", + "timestamp": 1773998289 +} \ No newline at end of file diff --git a/deployments/devnet/latest.json b/deployments/devnet/latest.json index cdca9ee..96016db 100644 --- a/deployments/devnet/latest.json +++ b/deployments/devnet/latest.json @@ -1,48 +1,48 @@ { "Allocator": "0x2E6A0C4F8D1B3e7a9c5f2d4B6a8e0C1f3D5B7A90", "Client": { - "codeHash": "0xa252a99ff38a463e73c73299a53b2002404fa49c2b4de33d86ba2315d2ce7ab9", - "deployedCodeHash": "0x11475ad5bb7cb44a3140c08d808466f94273230cdc8044af58f5498f5e91298d", - "impl": "0xbB455D4fc035cDe378C68D7DFDF51A29e3616a11", - "proxy": "0x691551C4ae2f693Ac84577fa35326746EF649eD9" + "codeHash": "0x1322b987c6e2fc8d60302b7a46d3d0fe0e530aa1b0bb9262a807cd2368e015e9", + "deployedCodeHash": "0x16b6a8ddaa80b097e7c2f7e229b2ee1698a42406e620c875b70f702dc98e237f", + "impl": "0xb519DFe9C3F5744DF7364B65938624435f21242b", + "proxy": "0xcb863DF4C3BbAC402dCE5dFab2BB67241602c7a1" }, "FilecoinPay": "0x4A8F3C2e1D9B7f6A0E5c8b3D2a1F9e7C4B6d8a2E", "PoRepMarket": { - "codeHash": "0x326171121bb051a255b22a5f9adf9eeaea77d62e8b9cd6d30fdeffa551122359", - "deployedCodeHash": "0x5ab3ca5ed1436801a7dfce3358a6f2e0a465e2e3a8dfd392fe14f8229e6143aa", - "impl": "0x84e07eb1855B177f2512228a48f3E887a9E8EAEE", - "proxy": "0x9CcaB4b6a09AbcCa34a723ceb8AC21791818D6C3" + "codeHash": "0xf47f6d1abf76ba7754f42341f35431e05b7fabf765b9f47f53642e9fa9165d8f", + "deployedCodeHash": "0x1ddc2e2e17549589fc87faee0a66110b7f054d561fc8029fb9ca5b67db65f196", + "impl": "0xc1694a7a3d4FC77f4340755B93Ff2c1d80afF7c4", + "proxy": "0x4f6109Ebf278f6932B562C2D117c36a7800cAE1D" }, "PoRepService": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F", "SLIOracle": { - "codeHash": "0xb8bb7516363fda691713fd7d440a6b09d2c19a6e8978ac93a1a51cd47426cdfd", - "deployedCodeHash": "0x84c90af6d48f5b7c953e9867829dbf0272b2a5312886dc8a572e6e4b0ce27df1", - "impl": "0x3BB762A405D9561112fc96cF23B3d3418Dd757e1", - "proxy": "0xE0728674c584928656457b50f16f5606b0D39D67" + "codeHash": "0x6f437785368109b7d03ea34b13ec0ec9ad2792d664453f56c4a17d3aa8ae2b60", + "deployedCodeHash": "0xb2cf4f478ff232504963e838fb3110330b5241417adaa2d6ccd5ede0269a1de9", + "impl": "0x2076731193e63152d9A54C0637dEBB3b2fbF9C1D", + "proxy": "0x37Ddf4D9a9636aB12797967356aD727899d9aa15" }, "SLIScorer": { - "codeHash": "0x0a46f9f465431e644c2b6d93cd497f49fd5c25b2f08000a5a542ad42c0dc8cee", - "deployedCodeHash": "0x60e6845fddd07ad022ba2b208194ce68cc92851a4ccbd428fd3ced081582d003", - "impl": "0xF0Bd955e9bCE3bd6729264F93D7DD15FB9224d30", - "proxy": "0x59482b61Ca25cDb3073d9Ebaa5F4025670DE0610" + "codeHash": "0xbadcd86fdee7e08b50b157ad3d6992e19ddc06111443d546912b8ae4eac14758", + "deployedCodeHash": "0xd2688d4ad5ed90b831c776f4fd081f79660dbdcb90e09397b642b2bf939eb33b", + "impl": "0x3a04e095eff0aeCea4C29dBf8AC61aed32120C0B", + "proxy": "0xc22aBcE7feCfF60f25e62482aFB3A6013FF92FeD" }, "SPRegistry": { - "codeHash": "0xd58505cd8ee976c9cb314682fb45150e17257ac891db1f651399ff5d38f71afa", - "deployedCodeHash": "0xd070d695c53beeae44a3df17a38bc39556740bcbbd9bc1e1f5d27ebd5088be36", - "impl": "0x1e69B532a6e11b8964523353F6E94a3C34a7d9cf", - "proxy": "0xF8f395a1c84b1F77aA9F704607afc0BD1D90c724" + "codeHash": "0xf897e7f9d2dd5ada7d5534db82d86ec45a98941aac1d0939d597602e39c1ad9b", + "deployedCodeHash": "0x841ec3c8e2087c2690cb4195ab420d76660e4164c8bde081bfc9c632719951d4", + "impl": "0x6d52a6318e67Ee6fFde7f8Eb63800d25bc47f50d", + "proxy": "0xeD2322C4003fdB0D3532E79858A52A761F4F7304" }, - "TerminationOracle": "0x9F1c5A3e7B2d4f6C8a0e3B1D5c7A9f2e4B6D8C00", - "ValidatorBeacon": "0x6a998bF68578cD33092C0aF9e91eF91C68729D2a", + "TerminationOracle": "0xe4Cd56f91Bc79cC610AEfB1bE92b07BB5b6F2e30", + "ValidatorBeacon": "0x66423783463AAcE944eBE562f9813D7fDF1fB625", "ValidatorFactory": { - "codeHash": "0xc2192b248c7f0bc3780c9681a056da041fc1b5653542b082214956dcf5516e58", - "deployedCodeHash": "0xea8dbaf35a14828a7317a10d2b16ff4bd993924ece23b4e7dba23cbd6c829e33", - "impl": "0x393cA3B9003d6C360371CF5Fa9C423C34e3F1aB8", - "proxy": "0xE531100D4c3dAC1977932a0454d6eB974707eBC5" + "codeHash": "0xd7c5a2c10bcf42de0c5986c906a8b61a54a0320137e70f64b12151dc6052119f", + "deployedCodeHash": "0x7137a3a01a3cb4e34e66441270fc99681c6640dac5bff2454605b6368c91e3e3", + "impl": "0x8F8543B857a30Cd0F4F9F158bf9B80EE62f2c3F3", + "proxy": "0x77E1C92c38bD2e4Aa78Ee71B0d063e686171B34F" }, - "ValidatorImpl": "0xAeda26aBf2Ce4B59b36e5527a9Fe5BCff87CBadb", - "block": 2779998, + "ValidatorImpl": "0x2d1Cd62D37F12f29e8130e41Bd8dBF8f6e2BE34C", + "block": 3476134, "chainId": 31415926, "deployer": "0x149661aB3B2d343114e4F518fF3cC3b47266d8C4", - "timestamp": 1771213745 + "timestamp": 1773998289 } \ No newline at end of file diff --git a/deployments/devnet/upgrades/3476201_Client.json b/deployments/devnet/upgrades/3476201_Client.json new file mode 100644 index 0000000..4efbfd7 --- /dev/null +++ b/deployments/devnet/upgrades/3476201_Client.json @@ -0,0 +1,11 @@ +{ + "chainId": 31415926, + "deployedCodeHash": "0x16b6a8ddaa80b097e7c2f7e229b2ee1698a42406e620c875b70f702dc98e237f", + "deployer": "0x149661aB3B2d343114e4F518fF3cC3b47266d8C4", + "newCodeHash": "0x1322b987c6e2fc8d60302b7a46d3d0fe0e530aa1b0bb9262a807cd2368e015e9", + "newImpl": "0xb519DFe9C3F5744DF7364B65938624435f21242b", + "prevCodeHash": "0xe0ae09ae80420c88ee45f280a19e656898a8c20660452d30ff8a9ba16e549f43", + "prevImpl": "0x03655d36fEF529E29Cf60a26F50db5782F47B624", + "proxy": "0xcb863DF4C3BbAC402dCE5dFab2BB67241602c7a1", + "upgradedAt": 1773998557 +} \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index b4be143..f646854 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,5 +1,5 @@ [profile.default] -src = "src" +src = "src" out = "out" libs = ["lib"] via_ir = true diff --git a/justfile b/justfile index 6a55fba..555ee92 100644 --- a/justfile +++ b/justfile @@ -17,6 +17,9 @@ test: build: forge build --build-info --sizes +clean: + forge clean + gen-abis: forge build for f in $(find src -name '*.sol' ! -path "*/interfaces/*" ! -path "*/types/*" ! -path "*/libs/*"); do \ @@ -33,10 +36,24 @@ coverage: check-coverage: ./ci/check-full-coverage.sh -devnet_deploy: - forge clean && forge build - forge script script/Deploy.s.sol --gas-estimate-multiplier 100000 --disable-block-gas-limit -vvvv --broadcast --rpc-url $RPC_TEST --private-key $PRIVATE_KEY_TEST +deploy flags='': + forge script script/Deploy.s.sol:Deploy --gas-estimate-multiplier 100000 --disable-block-gas-limit -vvvv --broadcast --rpc-url $RPC_URL --private-key $PRIVATE_KEY {{flags}} + +upgrade flags='': + forge script script/Upgrade.s.sol:Upgrade --gas-estimate-multiplier 100000 --disable-block-gas-limit -vvvv --broadcast --rpc-url $RPC_URL --private-key $PRIVATE_KEY {{flags}} + +devnet_deploy: clean build + RPC_URL=$RPC_TEST PRIVATE_KEY=$PRIVATE_KEY_TEST just deploy + +calibnet_deploy: clean build + RPC_URL=$RPC_CALIBNET PRIVATE_KEY=$PRIVATE_KEY_CALIBNET just deploy --slow + +devnet_upgrade: clean build + RPC_URL=$RPC_TEST PRIVATE_KEY=$PRIVATE_KEY_TEST just upgrade +calibnet_upgrade: clean build + RPC_URL=$RPC_CALIBNET PRIVATE_KEY=$PRIVATE_KEY_CALIBNET just upgrade --slow + # CI equivalent check check: fmt-check lint test check-coverage build check-abis @echo "All checks passed." diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index f269d92..5a8cdcf 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -42,10 +42,8 @@ contract Deploy is Script, DeployUtils { address internal operatorAddress; address internal metaAllocator; - error InvalidEnv(); - function run() external { - admin = vm.addr(vm.envUint("PRIVATE_KEY_TEST")); + admin = vm.addr(vm.envUint("PRIVATE_KEY")); terminationOracle = vm.envAddress("TERMINATION_ORACLE"); filecoinPay = vm.envAddress("FILECOIN_PAY"); oracleAddress = vm.envAddress("ORACLE"); @@ -53,15 +51,15 @@ contract Deploy is Script, DeployUtils { operatorAddress = vm.envOr("OPERATOR_ADDR", address(0)); metaAllocator = vm.envAddress("META_ALLOCATOR"); - vm.startBroadcast(vm.envUint("PRIVATE_KEY_TEST")); + vm.startBroadcast(admin); (validatorFactory, validatorFactoryImpl, validatorImpl) = _deployValidatorFactory(admin); + (spRegistry, spRegistryImpl) = _deploySPRegistry(admin); (poRepMarket, poRepMarketImpl) = _deployPoRepMarket(admin, validatorFactory, spRegistry); (clientSmartContract, clientSmartContractImpl) = _deployClientSmartContract(admin, terminationOracle, poRepMarket, metaAllocator); (sliOracle, sliOracleImpl) = _deploySLIOracle(admin, oracleAddress); (sliScorer, sliScorerImpl) = _deploySliScorer(admin, sliOracle); - (spRegistry, spRegistryImpl) = _deploySPRegistry(admin); validatorBeacon = ValidatorFactory(validatorFactory).getBeacon(); diff --git a/script/Upgrade.s.sol b/script/Upgrade.s.sol new file mode 100644 index 0000000..845be1d --- /dev/null +++ b/script/Upgrade.s.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: MIT +// solhint-disable use-natspec +pragma solidity =0.8.30; + +import {Script} from "forge-std/Script.sol"; +import {DeployUtils} from "./utils/DeployUtils.sol"; +import {stdJson} from "forge-std/StdJson.sol"; + +interface IUpgradeable { + function upgradeToAndCall(address newImpl, bytes calldata data) external; +} + +contract Upgrade is Script, DeployUtils { + using stdJson for string; + + address internal admin; + address internal proxy; + address internal prevImpl; + address internal impl; + string internal name; + bytes32 internal deployedCodeHash; + bytes internal cd; + + error ContractAlreadyDeployed(); + + function run() external { + admin = vm.addr(vm.envUint("PRIVATE_KEY")); + name = vm.envString("UPGRADE_CONTRACT_NAME"); + cd = vm.envOr("UPGRADE_CALLDATA", bytes("")); + + bytes32 hash = generateContractHash(name); + string memory json = readLatestDeploymentArtifact(); + (proxy, prevImpl,, deployedCodeHash) = deserializeContract(json, name); + + if (hash == deployedCodeHash) { + revert ContractAlreadyDeployed(); + } + + vm.startBroadcast(admin); + + impl = vm.deployCode(string.concat(name, ".sol:", name)); + IUpgradeable(proxy).upgradeToAndCall(impl, cd); + + vm.stopBroadcast(); + serializeAndSaveArtifact(); + } + + function serializeAndSaveArtifact() internal { + string memory json = name; + + json.serialize("proxy", proxy); + json.serialize("prevImpl", prevImpl); + json.serialize("newImpl", impl); + json.serialize("prevCodeHash", vm.toString(prevImpl.codehash)); + json.serialize("newCodeHash", vm.toString(impl.codehash)); + json.serialize("upgradedAt", block.timestamp); + json.serialize("chainId", block.chainid); + json.serialize("deployer", admin); + + string memory output = + json.serialize("deployedCodeHash", keccak256(vm.getDeployedCode(string.concat(name, ".sol:", name)))); + + saveUpgrade(output, name); + updateLatestImpl(name, impl); + } +} diff --git a/script/utils/DeployUtils.sol b/script/utils/DeployUtils.sol index 3d12a4e..270a486 100644 --- a/script/utils/DeployUtils.sol +++ b/script/utils/DeployUtils.sol @@ -17,6 +17,23 @@ contract DeployUtils is Script { vm.writeJson(json, string.concat(base, "/", vm.toString(block.number), ".json")); } + function saveUpgrade(string memory json, string memory contractName) internal { + string memory base = string.concat("./deployments/", network(), "/upgrades"); + vm.createDir(base, true); + vm.writeJson(json, string.concat(base, "/", vm.toString(block.number), "_", contractName, ".json")); + } + + function updateLatestImpl(string memory contractName, address newImpl) internal { + string memory path = string.concat("./deployments/", network(), "/latest.json"); + vm.writeJson(vm.toString(newImpl), path, string.concat(".", contractName, ".impl")); + vm.writeJson(vm.toString(newImpl.codehash), path, string.concat(".", contractName, ".codeHash")); + vm.writeJson( + vm.toString(keccak256(vm.getDeployedCode(string.concat(contractName, ".sol:", contractName)))), + path, + string.concat(".", contractName, ".deployedCodeHash") + ); + } + function createProxy(bytes memory init, address impl) internal returns (address proxy) { proxy = address(new ERC1967Proxy(address(impl), init)); } @@ -26,10 +43,32 @@ contract DeployUtils is Script { obj.serialize("proxy", proxy); obj.serialize("impl", impl); obj.serialize("codeHash", vm.toString(impl.codehash)); - string memory serialized = obj.serialize("deployedCodeHash", keccak256(vm.getDeployedCode(contractName))); + string memory serialized = obj.serialize( + "deployedCodeHash", + keccak256(vm.getDeployedCode(string.concat(contractName, ".sol:", contractName))) // <-- fix + ); json.serialize(contractName, serialized); } + function readLatestDeploymentArtifact() internal view returns (string memory json) { + json = vm.readFile(string.concat("./deployments/", network(), "/latest.json")); + } + + function deserializeContract(string memory json, string memory contractName) + internal + pure + returns (address proxy, address impl, bytes32 codeHash, bytes32 deployedCodeHash) + { + proxy = abi.decode(json.parseRaw(string.concat(".", contractName, ".proxy")), (address)); + impl = abi.decode(json.parseRaw(string.concat(".", contractName, ".impl")), (address)); + codeHash = abi.decode(json.parseRaw(string.concat(".", contractName, ".codeHash")), (bytes32)); + deployedCodeHash = abi.decode(json.parseRaw(string.concat(".", contractName, ".deployedCodeHash")), (bytes32)); + } + + function generateContractHash(string memory contractName) internal view returns (bytes32 hash) { + hash = keccak256(vm.getDeployedCode(string.concat(contractName, ".sol:", contractName))); + } + function network() internal view returns (string memory) { if (block.chainid == 31415926) return "devnet"; else if (block.chainid == 314159) return "calibnet";