From 838bf2ddd0d437eafc108057ef71ac725ad8a53c Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Fri, 20 Sep 2024 13:21:53 -0600 Subject: [PATCH 1/5] build: init gov --- src/utils/InitGov.sol | 76 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/utils/InitGov.sol diff --git a/src/utils/InitGov.sol b/src/utils/InitGov.sol new file mode 100644 index 0000000..8015eb8 --- /dev/null +++ b/src/utils/InitGov.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity ^0.8.18; + +import {Governance} from "./Governance.sol"; + +/// @notice Multi chain contract to be the initial governance for contracts on deployment. +contract InitGov { + address public constant SAFE = 0x33333333D5eFb92f19a5F94a43456b3cec2797AE; + + address public constant SIGNER_ONE = + 0xD7392bcc3D3611adF1793fDdaAAB4770772AC35A; + address public constant SIGNER_TWO = + 0xa05c4256ff0dd38697e63D48dF146e6e2FE7fe4A; + address public constant SIGNER_THREE = + 0x305af52AC31d3F9Daa1EC6231bA7b36Bb40f42f4; + address public constant SIGNER_FOUR = + 0x80f751EdcB3012d5AF5530AFE97d5dC6EE176Bc0; + address public constant SIGNER_FIVE = + 0x6d2b80BA79871281Be7F70b079996a052B8D62F4; + address public constant SIGNER_SIX = + 0x623d4A04e19328244924D1dee48252987C02fC0a; + + uint256 public constant THRESHOLD = 3; + + mapping(address => bool) public isSigner; + + mapping(bytes32 => uint256) public numberSigned; + + mapping(address => mapping(bytes32 => bool)) public signed; + + constructor() { + isSigner[SIGNER_ONE] = true; + isSigner[SIGNER_TWO] = true; + isSigner[SIGNER_THREE] = true; + isSigner[SIGNER_FOUR] = true; + isSigner[SIGNER_FIVE] = true; + isSigner[SIGNER_SIX] = true; + } + + /// @notice To sign a txn from an eoa. + function signTxn(address _contract, address _newGovernance) external { + require(isSigner[msg.sender], "!signer"); + bytes32 id = getTxnId(_contract, _newGovernance); + require(!signed[msg.sender][id], "already signer"); + + signed[msg.sender][id] = true; + numberSigned[id] += 1; + + // Execute if we have reached the threshold. + if (numberSigned[id] == THRESHOLD) + _transferGovernance(_contract, _newGovernance); + } + + /// @notice Can only be called by safe + function transferGovernance( + address _contract, + address _newGovernance + ) external { + require(msg.sender == SAFE, "!safe"); + _transferGovernance(_contract, _newGovernance); + } + + function _transferGovernance( + address _contract, + address _newGovernance + ) internal { + Governance(_contract).transferGovernance(_newGovernance); + } + + function getTxnId( + address _contract, + address _newGovernance + ) public pure returns (bytes32) { + return keccak256(abi.encodePacked(_contract, _newGovernance)); + } +} From 10728064750fc4acbb591b52da6a48c2f715fcd0 Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Fri, 20 Sep 2024 14:41:12 -0600 Subject: [PATCH 2/5] test: init gov --- src/test/InitGov.t.sol | 130 +++++++++++++++++++++++++++++++++++++++++ src/utils/InitGov.sol | 2 +- 2 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/test/InitGov.t.sol diff --git a/src/test/InitGov.t.sol b/src/test/InitGov.t.sol new file mode 100644 index 0000000..7b68675 --- /dev/null +++ b/src/test/InitGov.t.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.18; + +import "forge-std/console.sol"; +import {Setup, IStrategy, SafeERC20, ERC20} from "./utils/Setup.sol"; + +import {AprOracle} from "../AprOracle/AprOracle.sol"; +import {InitGov} from "../utils/InitGov.sol"; + +contract InitGovTest is Setup { + address safe = 0x33333333D5eFb92f19a5F94a43456b3cec2797AE; + + address public constant SIGNER_ONE = + 0xD7392bcc3D3611adF1793fDdaAAB4770772AC35A; + address public constant SIGNER_TWO = + 0xa05c4256ff0dd38697e63D48dF146e6e2FE7fe4A; + address public constant SIGNER_THREE = + 0x305af52AC31d3F9Daa1EC6231bA7b36Bb40f42f4; + address public constant SIGNER_FOUR = + 0x80f751EdcB3012d5AF5530AFE97d5dC6EE176Bc0; + address public constant SIGNER_FIVE = + 0x6d2b80BA79871281Be7F70b079996a052B8D62F4; + address public constant SIGNER_SIX = + 0x623d4A04e19328244924D1dee48252987C02fC0a; + + InitGov public initGov; + + function setUp() public override { + super.setUp(); + + initGov = new InitGov(); + + assertTrue(initGov.isSigner(SIGNER_ONE)); + assertTrue(initGov.isSigner(SIGNER_TWO)); + assertTrue(initGov.isSigner(SIGNER_THREE)); + assertTrue(initGov.isSigner(SIGNER_FOUR)); + assertTrue(initGov.isSigner(SIGNER_FIVE)); + assertTrue(initGov.isSigner(SIGNER_SIX)); + } + + function test_transferGov_withSafe() public { + AprOracle oracle = new AprOracle(address(initGov)); + + assertEq(oracle.governance(), address(initGov)); + + vm.expectRevert("!safe"); + initGov.transferGovernance(address(oracle), user); + + assertEq(oracle.governance(), address(initGov)); + + vm.expectRevert("!safe"); + vm.prank(SIGNER_ONE); + initGov.transferGovernance(address(oracle), user); + + assertEq(oracle.governance(), address(initGov)); + + vm.prank(safe); + initGov.transferGovernance(address(oracle), user); + + assertEq(oracle.governance(), user); + } + + function test_transferGov_signers() public { + AprOracle oracle = new AprOracle(address(initGov)); + + assertEq(oracle.governance(), address(initGov)); + + bytes32 id = initGov.getTxnId(address(oracle), user); + + assertEq(initGov.numberSigned(id), 0); + assertFalse(initGov.signed(SIGNER_ONE, id)); + assertFalse(initGov.signed(SIGNER_TWO, id)); + assertFalse(initGov.signed(SIGNER_THREE, id)); + assertFalse(initGov.signed(SIGNER_FOUR, id)); + assertFalse(initGov.signed(SIGNER_FIVE, id)); + assertFalse(initGov.signed(SIGNER_SIX, id)); + + vm.expectRevert("!signer"); + initGov.signTxn(address(oracle), user); + + vm.prank(SIGNER_ONE); + initGov.signTxn(address(oracle), user); + + assertEq(oracle.governance(), address(initGov)); + assertEq(initGov.numberSigned(id), 1); + assertTrue(initGov.signed(SIGNER_ONE, id)); + assertFalse(initGov.signed(SIGNER_TWO, id)); + assertFalse(initGov.signed(SIGNER_THREE, id)); + assertFalse(initGov.signed(SIGNER_FOUR, id)); + assertFalse(initGov.signed(SIGNER_FIVE, id)); + assertFalse(initGov.signed(SIGNER_SIX, id)); + + vm.expectRevert("already signed"); + vm.prank(SIGNER_ONE); + initGov.signTxn(address(oracle), user); + + assertEq(oracle.governance(), address(initGov)); + assertEq(initGov.numberSigned(id), 1); + assertTrue(initGov.signed(SIGNER_ONE, id)); + assertFalse(initGov.signed(SIGNER_TWO, id)); + assertFalse(initGov.signed(SIGNER_THREE, id)); + assertFalse(initGov.signed(SIGNER_FOUR, id)); + assertFalse(initGov.signed(SIGNER_FIVE, id)); + assertFalse(initGov.signed(SIGNER_SIX, id)); + + vm.prank(SIGNER_FOUR); + initGov.signTxn(address(oracle), user); + + assertEq(oracle.governance(), address(initGov)); + assertEq(initGov.numberSigned(id), 2); + assertTrue(initGov.signed(SIGNER_ONE, id)); + assertFalse(initGov.signed(SIGNER_TWO, id)); + assertFalse(initGov.signed(SIGNER_THREE, id)); + assertTrue(initGov.signed(SIGNER_FOUR, id)); + assertFalse(initGov.signed(SIGNER_FIVE, id)); + assertFalse(initGov.signed(SIGNER_SIX, id)); + + vm.prank(SIGNER_TWO); + initGov.signTxn(address(oracle), user); + + assertEq(oracle.governance(), user); + assertEq(initGov.numberSigned(id), 3); + assertTrue(initGov.signed(SIGNER_ONE, id)); + assertTrue(initGov.signed(SIGNER_TWO, id)); + assertFalse(initGov.signed(SIGNER_THREE, id)); + assertTrue(initGov.signed(SIGNER_FOUR, id)); + assertFalse(initGov.signed(SIGNER_FIVE, id)); + assertFalse(initGov.signed(SIGNER_SIX, id)); + } +} diff --git a/src/utils/InitGov.sol b/src/utils/InitGov.sol index 8015eb8..c100d67 100644 --- a/src/utils/InitGov.sol +++ b/src/utils/InitGov.sol @@ -41,7 +41,7 @@ contract InitGov { function signTxn(address _contract, address _newGovernance) external { require(isSigner[msg.sender], "!signer"); bytes32 id = getTxnId(_contract, _newGovernance); - require(!signed[msg.sender][id], "already signer"); + require(!signed[msg.sender][id], "already signed"); signed[msg.sender][id] = true; numberSigned[id] += 1; From ac517506c9fbed27fe2ba27c4f86d21504e188ec Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Mon, 23 Sep 2024 12:51:15 -0600 Subject: [PATCH 3/5] chore: addy --- src/test/InitGov.t.sol | 12 ++++++------ src/utils/InitGov.sol | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/test/InitGov.t.sol b/src/test/InitGov.t.sol index 7b68675..fc95cbc 100644 --- a/src/test/InitGov.t.sol +++ b/src/test/InitGov.t.sol @@ -11,17 +11,17 @@ contract InitGovTest is Setup { address safe = 0x33333333D5eFb92f19a5F94a43456b3cec2797AE; address public constant SIGNER_ONE = - 0xD7392bcc3D3611adF1793fDdaAAB4770772AC35A; + 0x6d2b80BA79871281Be7F70b079996a052B8D62F4; address public constant SIGNER_TWO = - 0xa05c4256ff0dd38697e63D48dF146e6e2FE7fe4A; - address public constant SIGNER_THREE = 0x305af52AC31d3F9Daa1EC6231bA7b36Bb40f42f4; + address public constant SIGNER_THREE = + 0xa05c4256ff0dd38697e63D48dF146e6e2FE7fe4A; address public constant SIGNER_FOUR = - 0x80f751EdcB3012d5AF5530AFE97d5dC6EE176Bc0; + 0x623d4A04e19328244924D1dee48252987C02fC0a; address public constant SIGNER_FIVE = - 0x6d2b80BA79871281Be7F70b079996a052B8D62F4; + 0x5C166A5919cC07d785837d8Cc1261c67229d271D; address public constant SIGNER_SIX = - 0x623d4A04e19328244924D1dee48252987C02fC0a; + 0x80f751EdcB3012d5AF5530AFE97d5dC6EE176Bc0; InitGov public initGov; diff --git a/src/utils/InitGov.sol b/src/utils/InitGov.sol index c100d67..7883edc 100644 --- a/src/utils/InitGov.sol +++ b/src/utils/InitGov.sol @@ -8,17 +8,17 @@ contract InitGov { address public constant SAFE = 0x33333333D5eFb92f19a5F94a43456b3cec2797AE; address public constant SIGNER_ONE = - 0xD7392bcc3D3611adF1793fDdaAAB4770772AC35A; + 0x6d2b80BA79871281Be7F70b079996a052B8D62F4; address public constant SIGNER_TWO = - 0xa05c4256ff0dd38697e63D48dF146e6e2FE7fe4A; - address public constant SIGNER_THREE = 0x305af52AC31d3F9Daa1EC6231bA7b36Bb40f42f4; + address public constant SIGNER_THREE = + 0xa05c4256ff0dd38697e63D48dF146e6e2FE7fe4A; address public constant SIGNER_FOUR = - 0x80f751EdcB3012d5AF5530AFE97d5dC6EE176Bc0; + 0x623d4A04e19328244924D1dee48252987C02fC0a; address public constant SIGNER_FIVE = - 0x6d2b80BA79871281Be7F70b079996a052B8D62F4; + 0x5C166A5919cC07d785837d8Cc1261c67229d271D; address public constant SIGNER_SIX = - 0x623d4A04e19328244924D1dee48252987C02fC0a; + 0x80f751EdcB3012d5AF5530AFE97d5dC6EE176Bc0; uint256 public constant THRESHOLD = 3; From 3f93cec0162711b15d784817e657199eba61850c Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Mon, 23 Sep 2024 13:24:21 -0600 Subject: [PATCH 4/5] fix: scripts --- README.md | 10 +++++++--- script/BaseScript.sol | 28 ++++++++++++++++++++++++++++ script/DeployAprOracle.s.sol | 20 ++++---------------- script/DeployAuctionFactory.sol | 18 +++--------------- script/DeployCommonTrigger.s.sol | 3 +-- script/DeployInitGov.sol | 24 ++++++++++++++++++++++++ 6 files changed, 67 insertions(+), 36 deletions(-) create mode 100644 script/BaseScript.sol create mode 100644 script/DeployInitGov.sol diff --git a/README.md b/README.md index 019985c..2756ca0 100644 --- a/README.md +++ b/README.md @@ -45,11 +45,15 @@ Deployment of periphery contracts such as the [Apr Oracle](https://github.com/ye This can be done permissionlessly if the most recent contract has not yet been deployed on a chain you would like to use it on. -1. Add your deployers Private key under PRIVATE_KEY in your .env file. - - NOTE: make sure to add `0x` to the beginning of the key. +1. If you have not added a keystore private key to foundry before add your address to use + +```shell +$ cast wallet import --interactive +``` + 2. Run the deployment script for the contract you want to deploy. ```sh - forge script script/DeployContractName.s.sol:DeployContractName --broadcast --rpc-url YOUR_RPC_URL + forge script script/DeployContractName.s.sol:DeployContractName --broadcast --rpc-url YOUR_RPC_URL --account ACCOUNT_NAME ``` - You can do a dry run before officially deploying by removing the `--broadcast` flag. - For chains that don't support 1559 tx's you may need to add a `--legacy` flag. diff --git a/script/BaseScript.sol b/script/BaseScript.sol new file mode 100644 index 0000000..1b68ff2 --- /dev/null +++ b/script/BaseScript.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.18; + +import "forge-std/Script.sol"; + +interface Deployer { + event ContractCreation(address indexed newContract, bytes32 indexed salt); + + function deployCreate3( + bytes32 salt, + bytes memory initCode + ) external payable returns (address newContract); + + function deployCreate2( + bytes32 salt, + bytes memory initCode + ) external payable returns (address newContract); +} + +// Deploy a contract to a deterministic address with create2 +contract BaseScript is Script { + + Deployer public deployer = Deployer(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed); + + address public v3Safe = 0x33333333D5eFb92f19a5F94a43456b3cec2797AE; + + address public initGov; +} diff --git a/script/DeployAprOracle.s.sol b/script/DeployAprOracle.s.sol index de44198..6376570 100644 --- a/script/DeployAprOracle.s.sol +++ b/script/DeployAprOracle.s.sol @@ -1,19 +1,16 @@ // SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; -import "forge-std/Script.sol"; +import "./BaseScript.sol"; // Deploy a contract to a deterministic address with create2 -contract DeployAprOracle is Script { - - Deployer public deployer = Deployer(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed); +contract DeployAprOracle is BaseScript { function run() external { - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - vm.startBroadcast(deployerPrivateKey); + vm.startBroadcast(); // Encode constructor arguments - bytes memory construct = abi.encode(0x33333333D5eFb92f19a5F94a43456b3cec2797AE); + bytes memory construct = abi.encode(v3Safe); // Get the bytecode bytes memory bytecode = abi.encodePacked(vm.getCode("AprOracle.sol:AprOracle"), construct); @@ -27,13 +24,4 @@ contract DeployAprOracle is Script { vm.stopBroadcast(); } -} - -contract Deployer { - event ContractCreation(address indexed newContract, bytes32 indexed salt); - - function deployCreate2( - bytes32 salt, - bytes memory initCode - ) public payable returns (address newContract) {} } \ No newline at end of file diff --git a/script/DeployAuctionFactory.sol b/script/DeployAuctionFactory.sol index a2b95b3..cfb2e77 100644 --- a/script/DeployAuctionFactory.sol +++ b/script/DeployAuctionFactory.sol @@ -1,16 +1,13 @@ // SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; -import "forge-std/Script.sol"; +import "./BaseScript.sol"; // Deploy a contract to a deterministic address with create2 -contract DeployAuctionFactory is Script { - - Deployer public deployer = Deployer(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed); +contract DeployAuctionFactory is BaseScript { function run() external { - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - vm.startBroadcast(deployerPrivateKey); + vm.startBroadcast(); // Get the bytecode bytes memory bytecode = abi.encodePacked(vm.getCode("AuctionFactory.sol:AuctionFactory")); @@ -24,13 +21,4 @@ contract DeployAuctionFactory is Script { vm.stopBroadcast(); } -} - -interface Deployer { - event ContractCreation(address indexed newContract, bytes32 indexed salt); - - function deployCreate3( - bytes32 salt, - bytes memory initCode - ) external payable returns (address newContract); } \ No newline at end of file diff --git a/script/DeployCommonTrigger.s.sol b/script/DeployCommonTrigger.s.sol index 6b8281d..3bfcf24 100644 --- a/script/DeployCommonTrigger.s.sol +++ b/script/DeployCommonTrigger.s.sol @@ -9,8 +9,7 @@ contract DeployCommonTrigger is Script { Deployer public deployer = Deployer(0x8D85e7c9A4e369E53Acc8d5426aE1568198b0112); function run() external { - uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); - vm.startBroadcast(deployerPrivateKey); + vm.startBroadcast(); // Encode constructor arguments bytes memory construct = abi.encode(0x33333333D5eFb92f19a5F94a43456b3cec2797AE); diff --git a/script/DeployInitGov.sol b/script/DeployInitGov.sol new file mode 100644 index 0000000..321d228 --- /dev/null +++ b/script/DeployInitGov.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.18; + +import "./BaseScript.sol"; + +// Deploy a contract to a deterministic address with create2 +contract DeployAuctionFactory is BaseScript { + + function run() external { + vm.startBroadcast(); + + // Get the bytecode + bytes memory bytecode = abi.encodePacked(vm.getCode("InitGov.sol:InitGov")); + + // Pick an unique salt + bytes32 salt = keccak256("Init Gov"); + + address contractAddress = deployer.deployCreate2(salt, bytecode); + + console.log("Address is ", contractAddress); + + vm.stopBroadcast(); + } +} From 876859e6496d4dcd11eca5452fb0d8045fa2014a Mon Sep 17 00:00:00 2001 From: Schlagonia Date: Mon, 23 Sep 2024 16:14:28 -0600 Subject: [PATCH 5/5] chore: fix scripts --- script/{BaseScript.sol => BaseScript.s.sol} | 2 +- script/DeployAprOracle.s.sol | 2 +- script/DeployAuctionFactory.sol | 2 +- script/{DeployInitGov.sol => DeployInitGov.s.sol} | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) rename script/{BaseScript.sol => BaseScript.s.sol} (94%) rename script/{DeployInitGov.sol => DeployInitGov.s.sol} (88%) diff --git a/script/BaseScript.sol b/script/BaseScript.s.sol similarity index 94% rename from script/BaseScript.sol rename to script/BaseScript.s.sol index 1b68ff2..045eebd 100644 --- a/script/BaseScript.sol +++ b/script/BaseScript.s.sol @@ -18,7 +18,7 @@ interface Deployer { } // Deploy a contract to a deterministic address with create2 -contract BaseScript is Script { +abstract contract BaseScript is Script { Deployer public deployer = Deployer(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed); diff --git a/script/DeployAprOracle.s.sol b/script/DeployAprOracle.s.sol index 6376570..b6bd530 100644 --- a/script/DeployAprOracle.s.sol +++ b/script/DeployAprOracle.s.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; -import "./BaseScript.sol"; +import "./BaseScript.s.sol"; // Deploy a contract to a deterministic address with create2 contract DeployAprOracle is BaseScript { diff --git a/script/DeployAuctionFactory.sol b/script/DeployAuctionFactory.sol index cfb2e77..2000f91 100644 --- a/script/DeployAuctionFactory.sol +++ b/script/DeployAuctionFactory.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; -import "./BaseScript.sol"; +import "./BaseScript.s.sol"; // Deploy a contract to a deterministic address with create2 contract DeployAuctionFactory is BaseScript { diff --git a/script/DeployInitGov.sol b/script/DeployInitGov.s.sol similarity index 88% rename from script/DeployInitGov.sol rename to script/DeployInitGov.s.sol index 321d228..3300ec5 100644 --- a/script/DeployInitGov.sol +++ b/script/DeployInitGov.s.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.8.18; -import "./BaseScript.sol"; +import "./BaseScript.s.sol"; // Deploy a contract to a deterministic address with create2 -contract DeployAuctionFactory is BaseScript { +contract DeployInitGov is BaseScript { function run() external { vm.startBroadcast();