From 7fbf8f8e20e957e0c79db34db2429923452abd28 Mon Sep 17 00:00:00 2001 From: 0xtekgrinder <0xtekgrinder@protonmail.com> Date: Mon, 8 Jan 2024 10:03:34 -0500 Subject: [PATCH 01/27] feat: add all scripts from multisig to governance --- .gitmodules | 17 +- lib/angle-transmuter | 1 + lib/borrow-contracts | 1 + lib/chainlink | 1 + lib/new-oz | 1 + lib/new-oz-upgradeable | 1 + lib/openzeppelin-contracts | 2 +- lib/openzeppelin-contracts-upgradeable | 2 +- remappings.txt | 13 +- scripts/Constants.s.sol | 22 +- scripts/Interfaces.s.sol | 59 ++++ scripts/Utils.s.sol | 247 ++++++++++++++++- scripts/borrow/PauseVaultManagers.s.sol | 48 ++++ scripts/borrow/SetRateVaultManager.s.sol | 57 ++++ scripts/governance/RevokeMultiSig.s.sol | 254 ++++++++++++++++++ scripts/interaction/CrossChainProposal.s.sol | 5 +- .../interaction/ProposalReceiverConnect.s.sol | 3 +- scripts/interaction/ProposalSenderRetry.s.sol | 1 + scripts/savings/SavingsSetRate.s.sol | 40 +++ scripts/transmuter/InitAndBootstrap.s.sol | 114 ++++++++ scripts/transmuter/TransmuterPause.s.sol | 63 +++++ .../TransmuterSetRedemptionParams.s.sol | 42 +++ test/unit/SimulationSetup.t.sol | 2 + 23 files changed, 975 insertions(+), 21 deletions(-) create mode 160000 lib/angle-transmuter create mode 160000 lib/borrow-contracts create mode 160000 lib/chainlink create mode 160000 lib/new-oz create mode 160000 lib/new-oz-upgradeable create mode 100644 scripts/Interfaces.s.sol create mode 100644 scripts/borrow/PauseVaultManagers.s.sol create mode 100644 scripts/borrow/SetRateVaultManager.s.sol create mode 100644 scripts/governance/RevokeMultiSig.s.sol create mode 100644 scripts/savings/SavingsSetRate.s.sol create mode 100644 scripts/transmuter/InitAndBootstrap.s.sol create mode 100644 scripts/transmuter/TransmuterPause.s.sol create mode 100644 scripts/transmuter/TransmuterSetRedemptionParams.s.sol diff --git a/.gitmodules b/.gitmodules index 32f4fc9..6cc88ab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,4 +16,19 @@ [submodule "lib/solidity-stringutils"] path = lib/solidity-stringutils url = https://github.com/Arachnid/solidity-stringutils - ignore = dirty \ No newline at end of file + ignore = dirty +[submodule "lib/angle-transmuter"] + path = lib/angle-transmuter + url = https://github.com/AngleProtocol/angle-transmuter +[submodule "lib/borrow-contracts"] + path = lib/borrow-contracts + url = https://github.com/AngleProtocol/borrow-contracts +[submodule "lib/new-oz"] + path = lib/new-oz + url = https://github.com/OpenZeppelin/openzeppelin-contracts +[submodule "lib/new-oz-upgradeable"] + path = lib/new-oz-upgradeable + url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable +[submodule "lib/chainlink"] + path = lib/chainlink + url = https://github.com/smartcontractkit/chainlink diff --git a/lib/angle-transmuter b/lib/angle-transmuter new file mode 160000 index 0000000..7fd03d3 --- /dev/null +++ b/lib/angle-transmuter @@ -0,0 +1 @@ +Subproject commit 7fd03d3135c8d2ee8bcfe174b5b80c309823560f diff --git a/lib/borrow-contracts b/lib/borrow-contracts new file mode 160000 index 0000000..407a0e9 --- /dev/null +++ b/lib/borrow-contracts @@ -0,0 +1 @@ +Subproject commit 407a0e92653570e469bf1915ef3046e416e01582 diff --git a/lib/chainlink b/lib/chainlink new file mode 160000 index 0000000..3cf93c9 --- /dev/null +++ b/lib/chainlink @@ -0,0 +1 @@ +Subproject commit 3cf93c9f849be99a451ddd77ac203395760302c2 diff --git a/lib/new-oz b/lib/new-oz new file mode 160000 index 0000000..01ef448 --- /dev/null +++ b/lib/new-oz @@ -0,0 +1 @@ +Subproject commit 01ef448981be9d20ca85f2faf6ebdf591ce409f3 diff --git a/lib/new-oz-upgradeable b/lib/new-oz-upgradeable new file mode 160000 index 0000000..fbdb824 --- /dev/null +++ b/lib/new-oz-upgradeable @@ -0,0 +1 @@ +Subproject commit fbdb824a735891908d5588b28e0da5852d7ed7ba diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts index 0b1b5f8..cffb2f1 160000 --- a/lib/openzeppelin-contracts +++ b/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit 0b1b5f89ef342b73e23e2fb6783d7a377478181f +Subproject commit cffb2f1ddcd87efd68effc92cfd336c5145acabd diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable index e10c70d..ebf264c 160000 --- a/lib/openzeppelin-contracts-upgradeable +++ b/lib/openzeppelin-contracts-upgradeable @@ -1 +1 @@ -Subproject commit e10c70d922c30c3cd09777b868cbd9a892bb57f8 +Subproject commit ebf264cc4b812e6557ed7d539e947211acd5670c diff --git a/remappings.txt b/remappings.txt index 73debcd..aa04ca4 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,6 +1,13 @@ ds-test/=lib/forge-std/lib/ds-test/src/ forge-std/=lib/forge-std/src/ -oz/=lib/openzeppelin-contracts/contracts/ -oz-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/ +oz/=lib/new-oz/contracts/ +oz-upgradeable/=lib/new-oz-upgradeable/contracts/ lz/=lib/solidity-examples/contracts -stringutils/=lib/solidity-stringutils \ No newline at end of file +stringutils/=lib/solidity-stringutils +borrow/=lib/borrow-contracts/contracts +transmuter/=lib/angle-transmuter/contracts +contracts/=contracts +test/=test +@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts +@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts +@chainlink/=lib/chainlink \ No newline at end of file diff --git a/scripts/Constants.s.sol b/scripts/Constants.s.sol index c35e414..645b6aa 100644 --- a/scripts/Constants.s.sol +++ b/scripts/Constants.s.sol @@ -4,6 +4,14 @@ pragma solidity ^0.8.9; import { ILayerZeroEndpoint } from "lz/lzApp/interfaces/ILayerZeroEndpoint.sol"; import { IVotes } from "oz/governance/extensions/GovernorVotes.sol"; +import { ITransmuter } from "transmuter/interfaces/ITransmuter.sol"; +import { IAgToken } from "borrow/interfaces/IAgToken.sol"; +import { ProxyAdmin } from "oz/proxy/transparent/ProxyAdmin.sol"; +import { Ownable } from "oz/access/Ownable.sol"; +import { CoreBorrow } from "borrow/coreBorrow/CoreBorrow.sol"; +import { ITreasury } from "borrow/interfaces/ITreasury.sol"; +import { AngleGovernor } from "contracts/AngleGovernor.sol"; +import "./Interfaces.s.sol"; enum ContractType { Timelock, @@ -15,7 +23,6 @@ enum ContractType { TransmuterAgEUR, CoreBorrow, GovernorMultisig, - GuardianMultisig, ProxyAdmin, Angle, veANGLE, @@ -27,6 +34,13 @@ enum ContractType { FeeDistributor } +struct SubCall { + uint256 chainId; + address target; + uint256 value; + bytes data; +} + uint256 constant timelockDelay = 1 days; uint48 constant initialVotingDelay = 1 days; uint256 constant initialVotingDelayBlocks = 1 days / 12; @@ -52,3 +66,9 @@ uint256 constant CHAIN_BASE = 8453; uint256 constant CHAIN_LINEA = 59144; uint256 constant CHAIN_MANTLE = 5000; uint256 constant CHAIN_AURORA = 1313161554; +uint256 constant BASE_18 = 1e18; +uint256 constant BASE_9 = 1e9; + +uint64 constant twoPoint5Rate = 782997666703977344; +uint64 constant fourRate = 1243680713969297408; +uint64 constant fourPoint3Rate = 1335019428339023872; diff --git a/scripts/Interfaces.s.sol b/scripts/Interfaces.s.sol new file mode 100644 index 0000000..ab800ff --- /dev/null +++ b/scripts/Interfaces.s.sol @@ -0,0 +1,59 @@ +pragma solidity ^0.8.19; + +interface IVaultManagerGovernance { + function setUint64(uint64 param, bytes32 what) external; + + function interestRate() external view returns (uint64); +} + +interface ISavings { + function setRate(uint208 newRate) external; + + function rate() external view returns (uint208); +} + +interface IAngle { + function setMinter(address minter) external; +} + +interface IVeAngle { + function commit_transfer_ownership(address newAdmin) external; + + function apply_transfer_ownership() external; +} + +interface IGaugeController { + function commit_transfer_ownership(address newAdmin) external; + + function apply_transfer_ownership() external; +} + +interface ILiquidityGauge { + function commit_transfer_ownership(address newAdmin) external; + + function apply_transfer_ownership() external; +} + +interface IVeBoost { + function commit_transfer_ownership(address newAdmin) external; + + function apply_transfer_ownership() external; +} + +interface IVeBoostProxy { + function commit_admin(address newAdmin) external; + + function apply_transfer_ownership() external; +} + +interface ISmartWalletWhitelist { + function commitAdmin(address newAdmin) external; + + function applyAdmin() external; +} + +interface IFeeDistributor { + function commit_admin(address newAdmin) external; + + function accept_admin() external; +} diff --git a/scripts/Utils.s.sol b/scripts/Utils.s.sol index 3e0396b..ce4d914 100644 --- a/scripts/Utils.s.sol +++ b/scripts/Utils.s.sol @@ -2,25 +2,17 @@ pragma solidity ^0.8.19; import "forge-std/Script.sol"; -import "oz/proxy/transparent/ProxyAdmin.sol"; -import "oz/proxy/transparent/TransparentUpgradeableProxy.sol"; import { AngleGovernor } from "contracts/AngleGovernor.sol"; import { ProposalReceiver } from "contracts/ProposalReceiver.sol"; import { ProposalSender } from "contracts/ProposalSender.sol"; import { TimelockControllerWithCounter } from "contracts/TimelockControllerWithCounter.sol"; import { ILayerZeroEndpoint } from "lz/lzApp/interfaces/ILayerZeroEndpoint.sol"; +import { ITreasury } from "borrow/interfaces/ITreasury.sol"; import "./Constants.s.sol"; -import { console } from "forge-std/console.sol"; - +/// @title Utils +/// @author Angle Labs, Inc. contract Utils is Script { - //Update this address based on needs - address public constant PROXY_ADMIN = 0x1D941EF0D3Bba4ad67DBfBCeE5262F4CEE53A32b; - - function deployUpgradeable(address implementation, bytes memory data) public returns (address) { - return address(new TransparentUpgradeableProxy(implementation, PROXY_ADMIN, data)); - } - function lzEndPoint(uint256 chainId) public returns (ILayerZeroEndpoint) { // TODO temporary check if LZ updated their sdk if (chainId == CHAIN_GNOSIS) { @@ -100,4 +92,237 @@ contract Utils is Script { if (res.length == 0) revert("Chain not supported"); return uint16(stringToUint(string(res))); } + + enum ContractType { + Timelock, + ProposalSender, + Governor, + ProposalReceiver, + TreasuryAgEUR, + StEUR, + TransmuterAgEUR, + CoreBorrow, + GovernorMultisig, + ProxyAdmin, + Angle, + veANGLE, + SmartWalletWhitelist, + veBoostProxy, + GaugeController, + AngleDistributor, + AngleMiddleman, + FeeDistributor + } + + function _chainToContract(uint256 chainId, ContractType name) internal view returns (address) { + string[] memory cmd = new string[](3); + cmd[0] = "node"; + cmd[1] = "utils/contractAddress.js"; + cmd[2] = vm.toString(chainId); + + if (name == ContractType.Timelock) cmd[3] = "timelock"; + else if (name == ContractType.ProposalReceiver) cmd[3] = "proposalReceiver"; + else if (name == ContractType.ProposalSender) cmd[3] = "proposalSender"; + else if (name == ContractType.Governor) cmd[3] = "governor"; + else if (name == ContractType.TreasuryAgEUR) cmd[3] = "treasury"; + else if (name == ContractType.StEUR) cmd[3] = "stEUR"; + else if (name == ContractType.TransmuterAgEUR) cmd[3] = "transmuterAgEUR"; + else if (name == ContractType.CoreBorrow) cmd[3] = "coreBorrow"; + else if (name == ContractType.GovernorMultisig) cmd[3] = "governorMultisig"; + else if (name == ContractType.ProxyAdmin) cmd[3] = "proxyAdmin"; + else if (name == ContractType.Angle) cmd[3] = "angle"; + else if (name == ContractType.veANGLE) cmd[3] = "veANGLE"; + else if (name == ContractType.SmartWalletWhitelist) cmd[3] = "smartWalletWhitelist"; + else if (name == ContractType.veBoostProxy) cmd[3] = "veBoostProxy"; + else if (name == ContractType.GaugeController) cmd[3] = "gaugeController"; + else if (name == ContractType.AngleDistributor) cmd[3] = "angleDistributor"; + else if (name == ContractType.AngleMiddleman) cmd[3] = "angleMiddleman"; + else if (name == ContractType.FeeDistributor) cmd[3] = "feeDistributor"; + else revert("contract not supported"); + + bytes memory res = vm.ffi(cmd); + // When process exit code is 1, it will return an empty bytes "0x" + if (res.length == 0) revert("Chain not supported"); + console.log(address(bytes20(res))); + return address(bytes20(res)); + } + + function wrapTimelock( + uint256 chainId, + SubCall[] memory p + ) public view returns (address target, uint256 value, bytes memory data) { + TimelockControllerWithCounter timelock = TimelockControllerWithCounter( + payable(_chainToContract(chainId, ContractType.Timelock)) + ); + ( + address[] memory batchTargets, + uint256[] memory batchValues, + bytes[] memory batchCalldatas + ) = filterChainSubCalls(chainId, p); + if (batchTargets.length == 1) { + // In case the operation has already been done add a salt + uint256 salt = computeSalt(chainId, p); + // Simple schedule on timelock + target = address(timelock); + value = 0; + data = abi.encodeWithSelector( + timelock.schedule.selector, + batchTargets[0], + batchValues[0], + batchCalldatas[0], + bytes32(0), + salt, + timelock.getMinDelay() + ); + } else { + // In case the operation has already been done add a salt + uint256 salt = computeSalt(chainId, p); + target = address(timelock); + value = 0; + data = abi.encodeWithSelector( + timelock.scheduleBatch.selector, + batchTargets, + batchValues, + batchCalldatas, + bytes32(0), + salt, + timelock.getMinDelay() + ); + } + } + + function computeSalt(uint256 chainId, SubCall[] memory p) internal view returns (uint256 salt) { + TimelockControllerWithCounter timelock = TimelockControllerWithCounter( + payable(_chainToContract(chainId, ContractType.Timelock)) + ); + ( + address[] memory batchTargets, + uint256[] memory batchValues, + bytes[] memory batchCalldatas + ) = filterChainSubCalls(chainId, p); + if (batchTargets.length == 1) { + salt = 0; + while ( + timelock.isOperation( + timelock.hashOperation( + batchTargets[0], + batchValues[0], + batchCalldatas[0], + bytes32(0), + bytes32(salt) + ) + ) + ) { + salt++; + } + } else { + salt = 0; + while ( + timelock.isOperation( + timelock.hashOperationBatch(batchTargets, batchValues, batchCalldatas, bytes32(0), bytes32(salt)) + ) + ) { + salt++; + } + } + } + + function filterChainSubCalls( + uint256 chainId, + SubCall[] memory prop + ) + internal + pure + returns (address[] memory batchTargets, uint256[] memory batchValues, bytes[] memory batchCalldatas) + { + uint256 count; + batchTargets = new address[](prop.length); + batchValues = new uint256[](prop.length); + batchCalldatas = new bytes[](prop.length); + for (uint256 j; j < prop.length; j++) { + if (prop[j].chainId == chainId) { + batchTargets[count] = prop[j].target; + batchValues[count] = prop[j].value; + batchCalldatas[count] = prop[j].data; + count++; + } + } + + assembly ("memory-safe") { + mstore(batchTargets, count) + mstore(batchValues, count) + mstore(batchCalldatas, count) + } + } + + function _wrap( + SubCall[] memory prop + ) internal returns (address[] memory targets, uint256[] memory values, bytes[] memory calldatas) { + targets = new address[](prop.length); + values = new uint256[](prop.length); + calldatas = new bytes[](prop.length); + uint256 finalPropLength; + uint256 i; + while (i < prop.length) { + uint256 chainId = prop[i].chainId; + // Check the number of same chainId actions + uint256 count = 1; + while (i + count < prop.length && prop[i + count].chainId == chainId) { + count++; + } + + // Check that the chainId are consecutives + for (uint256 j = i + count; j < prop.length; j++) { + if (prop[j].chainId == chainId) { + revert("Invalid proposal, chainId must be gathered"); + } + } + + if (chainId == 1) { + ( + address[] memory batchTargets, + uint256[] memory batchValues, + bytes[] memory batchCalldatas + ) = filterChainSubCalls(chainId, prop); + (targets[finalPropLength], values[finalPropLength], calldatas[finalPropLength]) = wrapTimelock( + chainId, + prop + ); + finalPropLength += 1; + i += count; + } else { + ( + address[] memory batchTargets, + uint256[] memory batchValues, + bytes[] memory batchCalldatas + ) = filterChainSubCalls(chainId, prop); + (address target, uint256 value, bytes memory data) = wrapTimelock(chainId, prop); + + batchTargets = new address[](1); + batchTargets[0] = target; + batchValues = new uint256[](1); + batchValues[0] = value; + batchCalldatas = new bytes[](1); + batchCalldatas[0] = data; + + // Wrap for proposal sender + ProposalSender proposalSender = ProposalSender(_chainToContract(chainId, ContractType.ProposalSender)); + targets[finalPropLength] = address(proposalSender); + values[finalPropLength] = 0.1 ether; + calldatas[finalPropLength] = abi.encodeWithSelector( + proposalSender.execute.selector, + getLZChainId(chainId), + abi.encode(batchTargets, batchValues, new string[](1), batchCalldatas), + abi.encodePacked(uint16(1), uint256(300000)) + ); + finalPropLength += 1; + i += count; + } + } + assembly ("memory-safe") { + mstore(targets, finalPropLength) + mstore(values, finalPropLength) + mstore(calldatas, finalPropLength) + } + } } diff --git a/scripts/borrow/PauseVaultManagers.s.sol b/scripts/borrow/PauseVaultManagers.s.sol new file mode 100644 index 0000000..b851050 --- /dev/null +++ b/scripts/borrow/PauseVaultManagers.s.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.20; + +import { console } from "forge-std/console.sol"; +import { IVaultManagerFunctions } from "borrow/interfaces/IVaultManager.sol"; +import { IERC721Metadata } from "oz/token/ERC721/extensions/IERC721Metadata.sol"; +import { ITreasury, Utils } from "../Utils.s.sol"; +import "../Constants.s.sol"; + +/** This script suppose that the state of all the vaultManager on the chain are identical (all paused or unpause) +/** Otherwise behaviour is chaotic +*/ +contract PauseVaultManagers is Utils { + SubCall[] private subCalls; + + function run() external { + bytes memory transactions; + uint8 isDelegateCall = 0; + uint256 value = 0; + string memory description = "Pause all vault managers"; + + uint256 chainId = vm.envUint("CHAIN_ID"); + + ITreasury treasury = ITreasury(_chainToContract(chainId, ContractType.TreasuryAgEUR)); + uint256 i; + while (true) { + try treasury.vaultManagerList(i) returns (address vault) { + string memory name = IERC721Metadata(vault).name(); + console.log("Pausing %s", name); + { + subCalls.push(SubCall(chainId, vault, 0, abi.encode(IVaultManagerFunctions.togglePause.selector))); + } + i++; + } catch { + break; + } + } + + // TODO find a way to switch to the destination chain + (address[] memory targets, uint256[] memory values, bytes[] memory calldatas) = _wrap(subCalls); + AngleGovernor governor = AngleGovernor(payable(_chainToContract(chainId, ContractType.Governor))); + uint256 proposalId = governor.propose(targets, values, calldatas, description); + + // bytes memory payloadMultiSend = abi.encodeWithSelector(MultiSend.multiSend.selector, transactions); + // address multiSend = address(_chainToMultiSend(chainId)); + // _serializeJson(chainId, multiSend, 0, payloadMultiSend, Enum.Operation.DelegateCall, additionalData); + } +} diff --git a/scripts/borrow/SetRateVaultManager.s.sol b/scripts/borrow/SetRateVaultManager.s.sol new file mode 100644 index 0000000..4631af6 --- /dev/null +++ b/scripts/borrow/SetRateVaultManager.s.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.20; + +import { console } from "forge-std/console.sol"; +import { IERC721Metadata } from "oz/token/ERC721/extensions/IERC721Metadata.sol"; +import { ITreasury, Utils } from "../Utils.s.sol"; +import { IVaultManagerGovernance } from "scripts/Interfaces.s.sol"; +import "../Constants.s.sol"; + +contract SetRateVaultManager is Utils { + function run() external { + uint256 chainId = vm.envUint("CHAIN_ID"); + + ITreasury treasury = ITreasury(_chainToContract(chainId, ContractType.TreasuryAgEUR)); + + bytes memory transactions; + uint8 isDelegateCall = 0; + uint256 value = 0; + + uint256 i; + while (true) { + try treasury.vaultManagerList(i) returns (address vault) { + uint64 rate; + /** TODO complete */ + // Non yield bearing vaults + if (i == 0 || i == 1 || i == 2) rate = twoPoint5Rate; + else rate = fourRate; + /** END complete */ + + string memory name = IERC721Metadata(vault).name(); + console.log("Setting rate %s", name); + { + address to = vault; + bytes32 what = "IR"; + bytes memory data = abi.encodeWithSelector(IVaultManagerGovernance.setUint64.selector, rate, what); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + i++; + } catch { + break; + } + } + + // bytes memory payloadMultiSend = abi.encodeWithSelector(MultiSend.multiSend.selector, transactions); + // + // address multiSend = address(_chainToMultiSend(chainId)); + // address guardian = address(_chainToContract(chainId, ContractType.GuardianMultisig)); + // // Verify that the calls will succeed + // vm.startBroadcast(guardian); + // address(multiSend).delegatecall(payloadMultiSend); + // vm.stopBroadcast(); + + // _serializeJson(chainId, multiSend, 0, payloadMultiSend, Enum.Operation.DelegateCall, hex""); + } +} diff --git a/scripts/governance/RevokeMultiSig.s.sol b/scripts/governance/RevokeMultiSig.s.sol new file mode 100644 index 0000000..bddf061 --- /dev/null +++ b/scripts/governance/RevokeMultiSig.s.sol @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.20; + +import { console } from "forge-std/console.sol"; +import { IVaultManagerFunctions } from "borrow/interfaces/IVaultManager.sol"; +import { IAgToken } from "borrow/interfaces/IAgToken.sol"; +import { IERC721Metadata } from "oz/token/ERC721/extensions/IERC721Metadata.sol"; +import { IAccessControl } from "oz/access/IAccessControl.sol"; + +import { Utils } from "../Utils.s.sol"; +import "../Constants.s.sol"; + +interface ITreasuryWithRole { + function addMinter(address minter) external; + + function removeMinter(address minter) external; +} + +contract RevokeMultiSig is Utils { + address public gaugeSushiAngleAgEUR = 0xBa625B318483516F7483DD2c4706aC92d44dBB2B; + + function run() external { + bytes memory transactions; + uint8 isDelegateCall = 0; + uint256 value = 0; + address to; + /** TODO complete */ + uint256 chainId = CHAIN_ETHEREUM; + /** END complete */ + CoreBorrow core = CoreBorrow(_chainToContract(chainId, ContractType.CoreBorrow)); + bytes32 governorRole = core.GOVERNOR_ROLE(); + bytes32 guardianRole = core.GUARDIAN_ROLE(); + if ( + chainId == CHAIN_ETHEREUM || + chainId == CHAIN_POLYGON || + chainId == CHAIN_ARBITRUM || + chainId == CHAIN_OPTIMISM || + chainId == CHAIN_AVALANCHE || + chainId == CHAIN_BNB + ) { + /** Add minting agEUR privilege to the on chain governance */ + { + to = _chainToContract(chainId, ContractType.TreasuryAgEUR); + bytes memory data = abi.encodeWithSelector( + ITreasuryWithRole.addMinter.selector, + address(_chainToContract(chainId, ContractType.Governor)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + /** Remove minting agEUR privilege from the governance multisig */ + { + to = _chainToContract(chainId, ContractType.TreasuryAgEUR); + bytes memory data = abi.encodeWithSelector( + ITreasuryWithRole.removeMinter.selector, + address(_chainToContract(chainId, ContractType.GovernorMultisig)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + } + /** Add coreBorrow privilege to the on chain governance */ + { + to = _chainToContract(chainId, ContractType.CoreBorrow); + bytes memory data = abi.encodeWithSelector( + CoreBorrow.addGovernor.selector, + address(_chainToContract(chainId, ContractType.Governor)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + // /** Remove coreBorrow privilege from the governor multisig */ + // { + // to = _chainToContract(chainId, ContractType.CoreBorrow); + // bytes memory data = abi.encodeWithSelector( + // CoreBorrow.removeGovernor.selector, + // address(_chainToContract(chainId, ContractType.GovernorMultisig)) + // ); + // uint256 dataLength = data.length; + // bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + // transactions = abi.encodePacked(transactions, internalTx); + // } + // /** Remove proxy admin privilege from the governance multisig */ + // { + // to = _chainToContract(chainId, ContractType.ProxyAdmin); + // bytes memory data = abi.encodeWithSelector( + // Ownable.transferOwnership.selector, + // address(_chainToContract(chainId, ContractType.Governor)) + // ); + // uint256 dataLength = data.length; + // bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + // transactions = abi.encodePacked(transactions, internalTx); + // } + if (chainId == CHAIN_ETHEREUM) { + { + to = _chainToContract(chainId, ContractType.Angle); + bytes memory data = abi.encodeWithSelector( + IAngle.setMinter.selector, + address(_chainToContract(chainId, ContractType.Governor)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + /** Propose a new admin + On chain governance will have to accept it + Better in this way to verify this address is valid and can accept it + */ + { + to = _chainToContract(chainId, ContractType.veANGLE); + bytes memory data = abi.encodeWithSelector( + IVeAngle.commit_transfer_ownership.selector, + address(_chainToContract(chainId, ContractType.Governor)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + /** Change veANGLE smart wallet whitelist admin */ + { + to = _chainToContract(chainId, ContractType.SmartWalletWhitelist); + bytes memory data = abi.encodeWithSelector( + ISmartWalletWhitelist.commitAdmin.selector, + address(_chainToContract(chainId, ContractType.Governor)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + /** Change veBoostProxy admin */ + { + to = _chainToContract(chainId, ContractType.veBoostProxy); + bytes memory data = abi.encodeWithSelector( + IVeBoostProxy.commit_admin.selector, + address(_chainToContract(chainId, ContractType.Governor)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + /** Change Gauge Controller admin */ + { + to = _chainToContract(chainId, ContractType.GaugeController); + bytes memory data = abi.encodeWithSelector( + IGaugeController.commit_transfer_ownership.selector, + address(_chainToContract(chainId, ContractType.Governor)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + /** Change Gauge Sushi ANGLE-agEUR admin */ + { + to = gaugeSushiAngleAgEUR; + bytes memory data = abi.encodeWithSelector( + ILiquidityGauge.commit_transfer_ownership.selector, + address(_chainToContract(chainId, ContractType.Governor)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + /** Add the on chain governor as governor of Angle Distributor */ + { + to = _chainToContract(chainId, ContractType.AngleDistributor); + bytes memory data = abi.encodeWithSelector( + IAccessControl.grantRole.selector, + governorRole, + address(_chainToContract(chainId, ContractType.Governor)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + /** Add the on chain governor as guardian of Angle Distributor */ + { + to = _chainToContract(chainId, ContractType.AngleDistributor); + bytes memory data = abi.encodeWithSelector( + IAccessControl.grantRole.selector, + guardianRole, + address(_chainToContract(chainId, ContractType.Governor)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + /** Remove the multisig as guardian of Angle Distributor */ + { + to = _chainToContract(chainId, ContractType.AngleDistributor); + bytes memory data = abi.encodeWithSelector( + IAccessControl.revokeRole.selector, + guardianRole, + address(_chainToContract(chainId, ContractType.GovernorMultisig)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + /** Remove the multisig as governor of Angle Distributor */ + { + to = _chainToContract(chainId, ContractType.AngleDistributor); + bytes memory data = abi.encodeWithSelector( + IAccessControl.revokeRole.selector, + governorRole, + address(_chainToContract(chainId, ContractType.GovernorMultisig)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + /** Add the on chain governor as governor of Angle Middleman */ + { + to = _chainToContract(chainId, ContractType.AngleMiddleman); + bytes memory data = abi.encodeWithSelector( + IAccessControl.grantRole.selector, + guardianRole, + address(_chainToContract(chainId, ContractType.Governor)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + /** Remove the multisig as guardian of Angle Distributor */ + { + to = _chainToContract(chainId, ContractType.AngleMiddleman); + bytes memory data = abi.encodeWithSelector( + IAccessControl.revokeRole.selector, + guardianRole, + address(_chainToContract(chainId, ContractType.GovernorMultisig)) + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + // /** Change Fee Distributor admin */ + // { + // to = _chainToContract(chainId, ContractType.FeeDistributor); + // bytes memory data = abi.encodeWithSelector( + // IFeeDistributor.commit_admin.selector, + // address(_chainToContract(chainId, ContractType.Governor)) + // ); + // uint256 dataLength = data.length; + // bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + // transactions = abi.encodePacked(transactions, internalTx); + // } + } + // bytes memory payloadMultiSend = abi.encodeWithSelector(MultiSend.multiSend.selector, transactions); + // address multiSend = address(_chainToMultiSend(chainId)); + // _serializeJson(chainId, multiSend, 0, payloadMultiSend, Enum.Operation.DelegateCall, hex""); + } +} diff --git a/scripts/interaction/CrossChainProposal.s.sol b/scripts/interaction/CrossChainProposal.s.sol index fead025..7f0e3a4 100644 --- a/scripts/interaction/CrossChainProposal.s.sol +++ b/scripts/interaction/CrossChainProposal.s.sol @@ -12,6 +12,7 @@ contract CrossChainProposal is Utils { // TODO can be modified to deploy on any chain uint256 srcChainId = CHAIN_ETHEREUM; uint256 destChainId = CHAIN_POLYGON; + uint256 srcChainId = CHAIN_GNOSIS; // END uint256 deployerPrivateKey = vm.deriveKey(vm.envString("MNEMONIC_GNOSIS"), "m/44'/60'/0'/0/", 0); @@ -75,8 +76,8 @@ contract CrossChainProposal is Utils { abi.encodePacked(uint16(1), uint256(300000)) ); - // uint256 proposalId = governor.propose(targets, values, calldatas, description); - uint256 proposalId = 0x7f3a7bfba6ab7cdc0f85cfaa8bc2b03178c4d28dabbf53a1908604d2cb2d6891; + uint256 proposalId = governor.propose(targets, values, calldatas, description); + // uint256 proposalId = 0x7f3a7bfba6ab7cdc0f85cfaa8bc2b03178c4d28dabbf53a1908604d2cb2d6891; governor.castVote(proposalId, 1); governor.execute{ value: feeLZ }(targets, values, calldatas, keccak256(bytes(description))); diff --git a/scripts/interaction/ProposalReceiverConnect.s.sol b/scripts/interaction/ProposalReceiverConnect.s.sol index e8a065a..326a728 100644 --- a/scripts/interaction/ProposalReceiverConnect.s.sol +++ b/scripts/interaction/ProposalReceiverConnect.s.sol @@ -12,6 +12,7 @@ contract ProposalReceiverConnect is Utils { // TODO can be modified to deploy on any chain uint256 srcChainId = CHAIN_ETHEREUM; uint256 destChainId = CHAIN_POLYGON; + uint256 srcChainId = CHAIN_GNOSIS; // END uint256 deployerPrivateKey = vm.deriveKey(vm.envString("MNEMONIC_GNOSIS"), "m/44'/60'/0'/0/", 0); @@ -39,8 +40,8 @@ contract ProposalReceiverConnect is Utils { ); // uint256 proposalId = governor.propose(targets, values, calldatas, description); - uint256 proposalId = 0x5af180d896738e85d65edfa0f75944289b65485e86ee38fd0776e140a89634d4; + governor.castVote(proposalId, 1); governor.execute(targets, values, calldatas, keccak256(bytes(description))); diff --git a/scripts/interaction/ProposalSenderRetry.s.sol b/scripts/interaction/ProposalSenderRetry.s.sol index 013a3ed..b6ffcf6 100644 --- a/scripts/interaction/ProposalSenderRetry.s.sol +++ b/scripts/interaction/ProposalSenderRetry.s.sol @@ -12,6 +12,7 @@ contract ProposalSenderRetry is Utils { // TODO can be modified to deploy on any chain uint256 srcChainId = CHAIN_ETHEREUM; uint256 destChainId = CHAIN_POLYGON; + uint256 srcChainId = CHAIN_GNOSIS; // END uint256 deployerPrivateKey = vm.deriveKey(vm.envString("MNEMONIC_GNOSIS"), "m/44'/60'/0'/0/", 0); diff --git a/scripts/savings/SavingsSetRate.s.sol b/scripts/savings/SavingsSetRate.s.sol new file mode 100644 index 0000000..0915852 --- /dev/null +++ b/scripts/savings/SavingsSetRate.s.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.20; + +import { console } from "forge-std/console.sol"; +import { IVaultManagerFunctions } from "borrow/interfaces/IVaultManager.sol"; +import { IERC721Metadata } from "oz/token/ERC721/extensions/IERC721Metadata.sol"; + +import { Utils } from "../Utils.s.sol"; +import "../Constants.s.sol"; + +contract SavingsSetRate is Utils { + function run() external { + bytes memory transactions; + uint8 isDelegateCall = 0; + uint256 value = 0; + + uint256 chainId = vm.envUint("CHAIN_ID"); + + /** TODO complete */ + uint208 rate = uint208(uint256(fourPoint3Rate)); + /** END complete */ + address stEUR = _chainToContract(chainId, ContractType.StEUR); + + bytes memory data = abi.encodeWithSelector(ISavings.setRate.selector, rate); + uint256 dataLength = data.length; + address to = stEUR; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + + // bytes memory payloadMultiSend = abi.encodeWithSelector(MultiSend.multiSend.selector, transactions); + + // // Verify that the calls will succeed + // address multiSend = address(_chainToMultiSend(chainId)); + // address guardian = address(_chainToContract(chainId, ContractType.GuardianMultisig)); + // vm.startBroadcast(guardian); + // address(multiSend).delegatecall(payloadMultiSend); + // vm.stopBroadcast(); + // _serializeJson(chainId, multiSend, 0, payloadMultiSend, Enum.Operation.DelegateCall, data); + } +} diff --git a/scripts/transmuter/InitAndBootstrap.s.sol b/scripts/transmuter/InitAndBootstrap.s.sol new file mode 100644 index 0000000..e7df7a2 --- /dev/null +++ b/scripts/transmuter/InitAndBootstrap.s.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.20; + +import { console } from "forge-std/console.sol"; +import "transmuter/transmuter/Storage.sol" as Storage; +import { ISettersGuardian } from "transmuter/interfaces/ISetters.sol"; +import { IDiamondCut } from "transmuter/interfaces/IDiamondCut.sol"; + +import { Utils } from "../Utils.s.sol"; +import "../Constants.s.sol"; +import { Treasury } from "borrow/treasury/Treasury.sol"; +import { IERC20 } from "oz/token/ERC20/IERC20.sol"; +import { IERC20Metadata } from "oz/token/ERC20/extensions/IERC20Metadata.sol"; + +contract InitAndBootstrap is Utils { + function run() external { + bytes memory transactions; + uint8 isDelegateCall = 0; + uint256 value = 0; + address to; + + uint256 chainId = vm.envUint("CHAIN_ID"); + + ITransmuter transmuter = ITransmuter(_chainToContract(chainId, ContractType.TransmuterAgEUR)); + // Update Redeemer to non via ir implementation + { + Storage.FacetCut[] memory addCut = new Storage.FacetCut[](1); + Storage.FacetCut[] memory removeCut = new Storage.FacetCut[](1); + // Get Selectors from json + bytes4[] memory selectors = new bytes4[](4); + selectors[0] = hex"d703a0cd"; + selectors[1] = hex"815822c1"; + selectors[2] = hex"2e7639bc"; + selectors[3] = hex"fd7daaf8"; + addCut[0] = Storage.FacetCut({ + // new Redeemer address + facetAddress: 0x1e45b65CdD3712fEf0024d063d6574A609985E59, + action: Storage.FacetCutAction.Add, + functionSelectors: selectors + }); + + removeCut[0] = Storage.FacetCut({ + facetAddress: address(0), + action: Storage.FacetCutAction.Remove, + functionSelectors: selectors + }); + + to = address(transmuter); + bytes memory callData; + { + bytes memory data = abi.encodeWithSelector( + IDiamondCut.diamondCut.selector, + removeCut, + address(0), + callData + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + + { + bytes memory data = abi.encodeWithSelector( + IDiamondCut.diamondCut.selector, + addCut, + address(0), + callData + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + } + + // Transfer funds to make live transmuter + { + to = EUROC; + bytes memory data = abi.encodeWithSelector( + IERC20.transfer.selector, + address(transmuter), + 9_500_000 * 10 ** IERC20Metadata(to).decimals() + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + + { + to = BC3M; + bytes memory data = abi.encodeWithSelector( + IERC20.transfer.selector, + address(transmuter), + 38446 * 10 ** IERC20Metadata(to).decimals() + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + + // add transmuter as `agEUR` minter + { + address treasury = address(_chainToContract(chainId, ContractType.TreasuryAgEUR)); + to = address(treasury); + bytes memory data = abi.encodeWithSelector(Treasury.addMinter.selector, address(transmuter)); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + + // bytes memory payloadMultiSend = abi.encodeWithSelector(MultiSend.multiSend.selector, transactions); + // address multiSend = address(_chainToMultiSend(chainId)); + // _serializeJson(chainId, multiSend, 0, payloadMultiSend, Enum.Operation.DelegateCall, hex""); + } +} diff --git a/scripts/transmuter/TransmuterPause.s.sol b/scripts/transmuter/TransmuterPause.s.sol new file mode 100644 index 0000000..dc01d84 --- /dev/null +++ b/scripts/transmuter/TransmuterPause.s.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.20; + +import { console } from "forge-std/console.sol"; +import "transmuter/transmuter/Storage.sol" as Storage; +import { ISettersGuardian } from "transmuter/interfaces/ISetters.sol"; + +import { Utils } from "../Utils.s.sol"; +import "../Constants.s.sol"; + +contract PauseTransmuter is Utils { + function run() external { + uint256 chainId = vm.envUint("CHAIN_ID"); + + ITransmuter transmuter = ITransmuter(_chainToContract(chainId, ContractType.TransmuterAgEUR)); + + address[] memory collateralList = transmuter.getCollateralList(); + bytes memory transactions; + uint8 isDelegateCall = 0; + address to = address(transmuter); + uint256 value = 0; + + { + bytes memory data = abi.encodeWithSelector( + ISettersGuardian.togglePause.selector, + address(0x0), + Storage.ActionType.Redeem + ); + + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + for (uint256 i = 0; i < collateralList.length; i++) { + address collateral = collateralList[i]; + console.log("Pausing %s", collateral); + { + bytes memory data = abi.encodeWithSelector( + ISettersGuardian.togglePause.selector, + collateral, + Storage.ActionType.Mint + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + { + bytes memory data = abi.encodeWithSelector( + ISettersGuardian.togglePause.selector, + collateral, + Storage.ActionType.Burn + ); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + } + } + + // bytes memory payloadMultiSend = abi.encodeWithSelector(MultiSend.multiSend.selector, transactions); + // address multiSend = address(_chainToMultiSend(chainId)); + // _serializeJson(chainId, multiSend, 0, payloadMultiSend, Enum.Operation.DelegateCall, hex""); + } +} diff --git a/scripts/transmuter/TransmuterSetRedemptionParams.s.sol b/scripts/transmuter/TransmuterSetRedemptionParams.s.sol new file mode 100644 index 0000000..b5e042c --- /dev/null +++ b/scripts/transmuter/TransmuterSetRedemptionParams.s.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.20; + +import { console } from "forge-std/console.sol"; +import "transmuter/transmuter/Storage.sol" as Storage; +import { ISettersGuardian } from "transmuter/interfaces/ISetters.sol"; + +import { Utils } from "../Utils.s.sol"; +import "../Constants.s.sol"; + +contract PauseTransmuter is Utils { + function run() external { + uint256 chainId = vm.envUint("CHAIN_ID"); + + /** TODO complete */ + uint64[] memory xFee = new uint64[](2); + int64[] memory yFee = new int64[](2); + + xFee[0] = 0; + xFee[1] = uint64(BASE_9); + yFee[0] = 0; + yFee[1] = 0; + /** END complete */ + + ITransmuter transmuter = ITransmuter(_chainToContract(chainId, ContractType.TransmuterAgEUR)); + + bytes memory transactions; + uint8 isDelegateCall = 0; + address to = address(transmuter); + uint256 value = 0; + + bytes memory data = abi.encodeWithSelector(ISettersGuardian.setRedemptionCurveParams.selector, xFee, yFee); + uint256 dataLength = data.length; + bytes memory internalTx = abi.encodePacked(isDelegateCall, to, value, dataLength, data); + transactions = abi.encodePacked(transactions, internalTx); + + // bytes memory payloadMultiSend = abi.encodeWithSelector(MultiSend.multiSend.selector, transactions); + // console.logBytes(payloadMultiSend); + // address multiSend = address(_chainToMultiSend(chainId)); + // _serializeJson(chainId, multiSend, 0, payloadMultiSend, Enum.Operation.DelegateCall, hex""); + } +} diff --git a/test/unit/SimulationSetup.t.sol b/test/unit/SimulationSetup.t.sol index 643a073..3e9ac77 100644 --- a/test/unit/SimulationSetup.t.sol +++ b/test/unit/SimulationSetup.t.sol @@ -204,6 +204,7 @@ contract SimulationSetup is Test { HELPERS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/ + // TODO USE IT /// @notice Build the governor proposal based on all the transaction that need to be executed function wrap( SubCall[] memory prop @@ -229,6 +230,7 @@ contract SimulationSetup is Test { } if (chainId == 1) { + // TODO cannot use a select fork vm.selectFork(forkIdentifier[1]); ( From ead5efb7e4a99399f341b78311c5fa076a951c75 Mon Sep 17 00:00:00 2001 From: 0xtekgrinder <0xtekgrinder@protonmail.com> Date: Thu, 11 Jan 2024 08:22:58 -0500 Subject: [PATCH 02/27] feat: add a way to propose transactions and create them beforehand --- foundry.toml | 1 + package.json | 2 +- scripts/Utils.s.sol | 37 ++++++++++++++++++++++--- scripts/borrow/PauseVaultManagers.s.sol | 8 +----- scripts/interaction/Propose.s.sol | 37 +++++++++++++++++++++++++ scripts/proposals.json | 7 +++++ test/unit/SimulationSetup.t.sol | 1 - yarn.lock | 8 +++--- 8 files changed, 84 insertions(+), 17 deletions(-) create mode 100644 scripts/interaction/Propose.s.sol create mode 100644 scripts/proposals.json diff --git a/foundry.toml b/foundry.toml index e3a0c73..1d16e8d 100644 --- a/foundry.toml +++ b/foundry.toml @@ -12,6 +12,7 @@ optimizer = true optimizer_runs = 1000 solc_version = "0.8.23" ffi = true +fs_permissions = [{ access = "read-write", path = "./scripts/proposals.json"}] [fuzz] runs = 10000 diff --git a/package.json b/package.json index 76fc7fd..2915c54 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "url": "https://github.com/AngleProtocol/boilerplate/issues" }, "devDependencies": { - "@angleprotocol/sdk": "0.20.0", + "@angleprotocol/sdk": "^0.23.1", "@layerzerolabs/lz-sdk": "^0.0.30", "prettier": "^2.0.0", "prettier-plugin-solidity": "^1.1.3", diff --git a/scripts/Utils.s.sol b/scripts/Utils.s.sol index ce4d914..483a5bf 100644 --- a/scripts/Utils.s.sol +++ b/scripts/Utils.s.sol @@ -114,8 +114,8 @@ contract Utils is Script { FeeDistributor } - function _chainToContract(uint256 chainId, ContractType name) internal view returns (address) { - string[] memory cmd = new string[](3); + function _chainToContract(uint256 chainId, ContractType name) internal returns (address) { + string[] memory cmd = new string[](4); cmd[0] = "node"; cmd[1] = "utils/contractAddress.js"; cmd[2] = vm.toString(chainId); @@ -150,7 +150,7 @@ contract Utils is Script { function wrapTimelock( uint256 chainId, SubCall[] memory p - ) public view returns (address target, uint256 value, bytes memory data) { + ) public returns (address target, uint256 value, bytes memory data) { TimelockControllerWithCounter timelock = TimelockControllerWithCounter( payable(_chainToContract(chainId, ContractType.Timelock)) ); @@ -191,7 +191,7 @@ contract Utils is Script { } } - function computeSalt(uint256 chainId, SubCall[] memory p) internal view returns (uint256 salt) { + function computeSalt(uint256 chainId, SubCall[] memory p) internal returns (uint256 salt) { TimelockControllerWithCounter timelock = TimelockControllerWithCounter( payable(_chainToContract(chainId, ContractType.Timelock)) ); @@ -279,6 +279,7 @@ contract Utils is Script { } if (chainId == 1) { + vm.selectFork(forkIdentifier[1]); ( address[] memory batchTargets, uint256[] memory batchValues, @@ -291,6 +292,7 @@ contract Utils is Script { finalPropLength += 1; i += count; } else { + vm.selectFork(forkIdentifier[chainId]); ( address[] memory batchTargets, uint256[] memory batchValues, @@ -325,4 +327,31 @@ contract Utils is Script { mstore(calldatas, finalPropLength) } } + + // TODO fix it so we can use array + function _serializeJson( + uint256 chainId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) internal { + string memory json = ""; + vm.serializeString(json, "description", description); + for (uint256 i; i < targets.length; i++) { + vm.serializeAddress(json, string.concat("targets[", vm.toString(i), "]"), targets[i]); + } + for (uint256 i; i < values.length; i++) { + vm.serializeUint(json, string.concat("values[", vm.toString(i), "]"), values[i]); + } + for (uint256 i; i < calldatas.length; i++) { + vm.serializeBytes(json, string.concat("calldatas[", vm.toString(i), "]"), calldatas[i]); + } + string memory obj1 = ""; + string memory finalJson = vm.serializeString(obj1, vm.toString(chainId), json); + + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/scripts/proposals.json"); + vm.writeJson(finalJson, path); + } } diff --git a/scripts/borrow/PauseVaultManagers.s.sol b/scripts/borrow/PauseVaultManagers.s.sol index b851050..c6164cb 100644 --- a/scripts/borrow/PauseVaultManagers.s.sol +++ b/scripts/borrow/PauseVaultManagers.s.sol @@ -36,13 +36,7 @@ contract PauseVaultManagers is Utils { } } - // TODO find a way to switch to the destination chain (address[] memory targets, uint256[] memory values, bytes[] memory calldatas) = _wrap(subCalls); - AngleGovernor governor = AngleGovernor(payable(_chainToContract(chainId, ContractType.Governor))); - uint256 proposalId = governor.propose(targets, values, calldatas, description); - - // bytes memory payloadMultiSend = abi.encodeWithSelector(MultiSend.multiSend.selector, transactions); - // address multiSend = address(_chainToMultiSend(chainId)); - // _serializeJson(chainId, multiSend, 0, payloadMultiSend, Enum.Operation.DelegateCall, additionalData); + _serializeJson(chainId, targets, values, calldatas, description); } } diff --git a/scripts/interaction/Propose.s.sol b/scripts/interaction/Propose.s.sol new file mode 100644 index 0000000..bf9591f --- /dev/null +++ b/scripts/interaction/Propose.s.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import { console } from "forge-std/console.sol"; +import "../Utils.s.sol"; +import { stdJson } from "forge-std/StdJson.sol"; +import { AngleGovernor } from "contracts/AngleGovernor.sol"; + +struct Proposal { + bytes[] calldatas; + string description; + address[] targets; + uint256[] values; +} + +contract Propose is Utils { + using stdJson for string; + + function run() external { + uint256 chainId = vm.envUint("CHAIN_ID"); + + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/scripts/proposals.json"); + string memory json = vm.readFile(path); + bytes memory proposalDetails = json.parseRaw(string.concat(".", vm.toString(chainId))); + Proposal memory rawProposal = abi.decode(proposalDetails, (Proposal)); + + AngleGovernor governor = AngleGovernor(payable(_chainToContract(chainId, ContractType.Governor))); + uint256 proposalId = governor.propose( + rawProposal.targets, + rawProposal.values, + rawProposal.calldatas, + rawProposal.description + ); + console.log("Proposal id: %d", proposalId); + } +} diff --git a/scripts/proposals.json b/scripts/proposals.json new file mode 100644 index 0000000..c94fff8 --- /dev/null +++ b/scripts/proposals.json @@ -0,0 +1,7 @@ +{ + "1": "", + "calldatas[0]": "0x8f2a0bb000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000241d7598bd1eb819c0e9ded456acb24aca6236790000000000000000000000001bece8193f8dc2b170135da9f1fa8b81c7ad18b100000000000000000000000073aaf8694ba137a7537e7ef544fcf5e2475f227b0000000000000000000000008e2277929b2d849c0c344043d9b9507982e6add0000000000000000000000000deee8e8a89338241fe622509414ff535fb02b4790000000000000000000000000652b4b3d205300f9848f0431296d67ca4397f3b000000000000000000000000e1c084e6e2ec9d32ec098e102a73c4c27eb9ee580000000000000000000000000b3af9fb0de42ae70432abc5aaeab8f9774bf87b000000000000000000000000989ed2ddcd4d2dc237ce014432aeb40efe738e3100000000000000000000000029e9d3d8e295e23b1b39dcd3d8d595761e032306000000000000000000000000e0c8b6c4ea301c8a221e8838ca5b80ac76e7a10b000000000000000000000000913e8e1ed659c27613e937a6b6119b91d985094c00000000000000000000000096de5c30f2bf4683c7903f3e921f720602f8868a0000000000000000000000009ffc8a23eafc25635dae822ea9c4ff440226a001000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae316800000000000000000000000000000000000000000000000000000000", + "description": "Pause all vault managers", + "targets[0]": "0x5183f032bf42109cD370B9559FD22207e432301E", + "values[0]": 0 +} \ No newline at end of file diff --git a/test/unit/SimulationSetup.t.sol b/test/unit/SimulationSetup.t.sol index 3e9ac77..331c9ac 100644 --- a/test/unit/SimulationSetup.t.sol +++ b/test/unit/SimulationSetup.t.sol @@ -230,7 +230,6 @@ contract SimulationSetup is Test { } if (chainId == 1) { - // TODO cannot use a select fork vm.selectFork(forkIdentifier[1]); ( diff --git a/yarn.lock b/yarn.lock index 8f90319..a924bec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@angleprotocol/sdk@0.20.0": - version "0.20.0" - resolved "https://npm.pkg.github.com/download/@angleprotocol/sdk/0.20.0/5905906aef82e97cd217b3e63881323f9379b205#5905906aef82e97cd217b3e63881323f9379b205" - integrity sha512-IHGbHsywZn7W42d6pm/btj6a3ZeWyCxZd36Fubl+Fq9EMYqHjc+nfeclmMkHfMQJwihOpbMrCAohy8MfeL5usw== +"@angleprotocol/sdk@^0.23.1": + version "0.23.1" + resolved "https://npm.pkg.github.com/download/@angleprotocol/sdk/0.23.1/99032da90ddedd1f7c2c609cc76c054515e29667#99032da90ddedd1f7c2c609cc76c054515e29667" + integrity sha512-9EJzVSrZkz65/2PVOeGoKWnTMaDojfeZ22MJpIIh96IP2Gj9/wuaz9qqgV6KR1woJak8rmRM/+RVUWzH7oLnbA== dependencies: "@apollo/client" "^3.7.17" "@typechain/ethers-v5" "^10.0.0" From 0d2f221f6de9659c87c867790cc87770dfb9fa88 Mon Sep 17 00:00:00 2001 From: 0xtekgrinder <0xtekgrinder@protonmail.com> Date: Thu, 11 Jan 2024 10:58:58 -0500 Subject: [PATCH 03/27] feat: serialize json array object --- scripts/Utils.s.sol | 86 +++++++++++++++++++++++++----------------- scripts/proposals.json | 17 ++++++--- 2 files changed, 64 insertions(+), 39 deletions(-) diff --git a/scripts/Utils.s.sol b/scripts/Utils.s.sol index 483a5bf..def6f59 100644 --- a/scripts/Utils.s.sol +++ b/scripts/Utils.s.sol @@ -13,6 +13,30 @@ import "./Constants.s.sol"; /// @title Utils /// @author Angle Labs, Inc. contract Utils is Script { + mapping(uint256 => uint256) forkIdentifier; + uint256 public arbitrumFork; + uint256 public avalancheFork; + uint256 public ethereumFork; + uint256 public optimismFork; + uint256 public gnosisFork; + uint256 public polygonFork; + + function setUp() public { + arbitrumFork = vm.createFork(vm.envString("ETH_NODE_URI_ARBITRUM")); + avalancheFork = vm.createFork(vm.envString("ETH_NODE_URI_AVALANCHE")); + ethereumFork = vm.createFork(vm.envString("ETH_NODE_URI_MAINNET")); + optimismFork = vm.createFork(vm.envString("ETH_NODE_URI_OPTIMISM")); + gnosisFork = vm.createFork(vm.envString("ETH_NODE_URI_GNOSIS")); + polygonFork = vm.createFork(vm.envString("ETH_NODE_URI_POLYGON")); + + forkIdentifier[CHAIN_ARBITRUM] = arbitrumFork; + forkIdentifier[CHAIN_AVALANCHE] = avalancheFork; + forkIdentifier[CHAIN_ETHEREUM] = ethereumFork; + forkIdentifier[CHAIN_OPTIMISM] = optimismFork; + forkIdentifier[CHAIN_GNOSIS] = gnosisFork; + forkIdentifier[CHAIN_POLYGON] = polygonFork; + } + function lzEndPoint(uint256 chainId) public returns (ILayerZeroEndpoint) { // TODO temporary check if LZ updated their sdk if (chainId == CHAIN_GNOSIS) { @@ -93,27 +117,6 @@ contract Utils is Script { return uint16(stringToUint(string(res))); } - enum ContractType { - Timelock, - ProposalSender, - Governor, - ProposalReceiver, - TreasuryAgEUR, - StEUR, - TransmuterAgEUR, - CoreBorrow, - GovernorMultisig, - ProxyAdmin, - Angle, - veANGLE, - SmartWalletWhitelist, - veBoostProxy, - GaugeController, - AngleDistributor, - AngleMiddleman, - FeeDistributor - } - function _chainToContract(uint256 chainId, ContractType name) internal returns (address) { string[] memory cmd = new string[](4); cmd[0] = "node"; @@ -143,7 +146,6 @@ contract Utils is Script { bytes memory res = vm.ffi(cmd); // When process exit code is 1, it will return an empty bytes "0x" if (res.length == 0) revert("Chain not supported"); - console.log(address(bytes20(res))); return address(bytes20(res)); } @@ -328,7 +330,7 @@ contract Utils is Script { } } - // TODO fix it so we can use array + // TODO don't overwrite the file each time function _serializeJson( uint256 chainId, address[] memory targets, @@ -336,22 +338,38 @@ contract Utils is Script { bytes[] memory calldatas, string memory description ) internal { - string memory json = ""; - vm.serializeString(json, "description", description); - for (uint256 i; i < targets.length; i++) { - vm.serializeAddress(json, string.concat("targets[", vm.toString(i), "]"), targets[i]); + string memory json = "chain"; + + { + string memory jsonTargets = "targets"; + string memory targetsOutput; + for (uint256 i; i < targets.length; i++) { + targetsOutput = vm.serializeAddress(jsonTargets, vm.toString(i), targets[i]); + } + vm.serializeString(json, "targets", targetsOutput); } - for (uint256 i; i < values.length; i++) { - vm.serializeUint(json, string.concat("values[", vm.toString(i), "]"), values[i]); + { + string memory jsonValues = "values"; + string memory valuesOutput; + for (uint256 i; i < values.length; i++) { + valuesOutput = vm.serializeUint(jsonValues, vm.toString(i), values[i]); + } + vm.serializeString(json, "values", valuesOutput); } - for (uint256 i; i < calldatas.length; i++) { - vm.serializeBytes(json, string.concat("calldatas[", vm.toString(i), "]"), calldatas[i]); + { + string memory jsonCalldatas = "calldatas"; + string memory calldatasOutput; + for (uint256 i; i < calldatas.length; i++) { + calldatasOutput = vm.serializeBytes(jsonCalldatas, vm.toString(i), calldatas[i]); + } + vm.serializeString(json, "calldatas", calldatasOutput); } - string memory obj1 = ""; - string memory finalJson = vm.serializeString(obj1, vm.toString(chainId), json); + string memory chainOutput = vm.serializeString(json, "description", description); + string memory jsonFinal = "final"; + string memory output = vm.serializeString(jsonFinal, vm.toString(chainId), chainOutput); string memory root = vm.projectRoot(); string memory path = string.concat(root, "/scripts/proposals.json"); - vm.writeJson(finalJson, path); + vm.writeJson(output, path); } } diff --git a/scripts/proposals.json b/scripts/proposals.json index c94fff8..a3d2fdc 100644 --- a/scripts/proposals.json +++ b/scripts/proposals.json @@ -1,7 +1,14 @@ { - "1": "", - "calldatas[0]": "0x8f2a0bb000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000241d7598bd1eb819c0e9ded456acb24aca6236790000000000000000000000001bece8193f8dc2b170135da9f1fa8b81c7ad18b100000000000000000000000073aaf8694ba137a7537e7ef544fcf5e2475f227b0000000000000000000000008e2277929b2d849c0c344043d9b9507982e6add0000000000000000000000000deee8e8a89338241fe622509414ff535fb02b4790000000000000000000000000652b4b3d205300f9848f0431296d67ca4397f3b000000000000000000000000e1c084e6e2ec9d32ec098e102a73c4c27eb9ee580000000000000000000000000b3af9fb0de42ae70432abc5aaeab8f9774bf87b000000000000000000000000989ed2ddcd4d2dc237ce014432aeb40efe738e3100000000000000000000000029e9d3d8e295e23b1b39dcd3d8d595761e032306000000000000000000000000e0c8b6c4ea301c8a221e8838ca5b80ac76e7a10b000000000000000000000000913e8e1ed659c27613e937a6b6119b91d985094c00000000000000000000000096de5c30f2bf4683c7903f3e921f720602f8868a0000000000000000000000009ffc8a23eafc25635dae822ea9c4ff440226a001000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae316800000000000000000000000000000000000000000000000000000000", - "description": "Pause all vault managers", - "targets[0]": "0x5183f032bf42109cD370B9559FD22207e432301E", - "values[0]": 0 + "1": { + "calldatas": { + "0": "0x8f2a0bb000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000241d7598bd1eb819c0e9ded456acb24aca6236790000000000000000000000001bece8193f8dc2b170135da9f1fa8b81c7ad18b100000000000000000000000073aaf8694ba137a7537e7ef544fcf5e2475f227b0000000000000000000000008e2277929b2d849c0c344043d9b9507982e6add0000000000000000000000000deee8e8a89338241fe622509414ff535fb02b4790000000000000000000000000652b4b3d205300f9848f0431296d67ca4397f3b000000000000000000000000e1c084e6e2ec9d32ec098e102a73c4c27eb9ee580000000000000000000000000b3af9fb0de42ae70432abc5aaeab8f9774bf87b000000000000000000000000989ed2ddcd4d2dc237ce014432aeb40efe738e3100000000000000000000000029e9d3d8e295e23b1b39dcd3d8d595761e032306000000000000000000000000e0c8b6c4ea301c8a221e8838ca5b80ac76e7a10b000000000000000000000000913e8e1ed659c27613e937a6b6119b91d985094c00000000000000000000000096de5c30f2bf4683c7903f3e921f720602f8868a0000000000000000000000009ffc8a23eafc25635dae822ea9c4ff440226a001000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae3168000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020c4ae316800000000000000000000000000000000000000000000000000000000" + }, + "description": "Pause all vault managers", + "targets": { + "0": "0x5183f032bf42109cD370B9559FD22207e432301E" + }, + "values": { + "0": 0 + } + } } \ No newline at end of file From 32ca79aa4c6616fc1edb74acdf5e4d84775515f6 Mon Sep 17 00:00:00 2001 From: 0xtekgrinder <0xtekgrinder@protonmail.com> Date: Thu, 11 Jan 2024 11:59:46 -0500 Subject: [PATCH 04/27] feat: deserialize proposal to propose script --- scripts/Utils.s.sol | 47 +++++++++++++++++++++++++++++++ scripts/interaction/Propose.s.sol | 18 +++++------- utils/contractAddress.js | 2 +- 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/scripts/Utils.s.sol b/scripts/Utils.s.sol index def6f59..83ca5a4 100644 --- a/scripts/Utils.s.sol +++ b/scripts/Utils.s.sol @@ -21,6 +21,11 @@ contract Utils is Script { uint256 public gnosisFork; uint256 public polygonFork; + bytes[] private calldatas; + string private description; + address[] private targets; + uint256[] private values; + function setUp() public { arbitrumFork = vm.createFork(vm.envString("ETH_NODE_URI_ARBITRUM")); avalancheFork = vm.createFork(vm.envString("ETH_NODE_URI_AVALANCHE")); @@ -330,6 +335,48 @@ contract Utils is Script { } } + function _deserializeJson( + uint256 chainId + ) internal returns (bytes[] memory, string memory, address[] memory, uint256[] memory) { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/scripts/proposals.json"); + string memory json = vm.readFile(path); + + bytes memory encodedStruct = vm.parseJson(json, string.concat(".", vm.toString(chainId), ".description")); + description = abi.decode(encodedStruct, (string)); + { + string memory calldataKey = string.concat(".", vm.toString(chainId), ".calldatas"); + string[] memory keys = vm.parseJsonKeys(json, calldataKey); + // Iterate over the encoded structs + for (uint256 i = 0; i < keys.length; ++i) { + string memory structKey = string.concat(calldataKey, ".", keys[i]); + bytes memory encodedStruct = vm.parseJson(json, structKey); + calldatas.push(abi.decode(encodedStruct, (bytes))); + } + } + { + string memory targetsKey = string.concat(".", vm.toString(chainId), ".targets"); + string[] memory keys = vm.parseJsonKeys(json, targetsKey); + // Iterate over the encoded structs + for (uint256 i = 0; i < keys.length; ++i) { + string memory structKey = string.concat(targetsKey, ".", keys[i]); + bytes memory encodedStruct = vm.parseJson(json, structKey); + targets.push(abi.decode(encodedStruct, (address))); + } + } + { + string memory valuesKey = string.concat(".", vm.toString(chainId), ".values"); + string[] memory keys = vm.parseJsonKeys(json, valuesKey); + // Iterate over the encoded structs + for (uint256 i = 0; i < keys.length; ++i) { + string memory structKey = string.concat(valuesKey, ".", keys[i]); + bytes memory encodedStruct = vm.parseJson(json, structKey); + values.push(abi.decode(encodedStruct, (uint256))); + } + } + return (calldatas, description, targets, values); + } + // TODO don't overwrite the file each time function _serializeJson( uint256 chainId, diff --git a/scripts/interaction/Propose.s.sol b/scripts/interaction/Propose.s.sol index bf9591f..d461dcf 100644 --- a/scripts/interaction/Propose.s.sol +++ b/scripts/interaction/Propose.s.sol @@ -19,19 +19,15 @@ contract Propose is Utils { function run() external { uint256 chainId = vm.envUint("CHAIN_ID"); - string memory root = vm.projectRoot(); - string memory path = string.concat(root, "/scripts/proposals.json"); - string memory json = vm.readFile(path); - bytes memory proposalDetails = json.parseRaw(string.concat(".", vm.toString(chainId))); - Proposal memory rawProposal = abi.decode(proposalDetails, (Proposal)); + ( + bytes[] memory calldatas, + string memory description, + address[] memory targets, + uint256[] memory values + ) = _deserializeJson(chainId); AngleGovernor governor = AngleGovernor(payable(_chainToContract(chainId, ContractType.Governor))); - uint256 proposalId = governor.propose( - rawProposal.targets, - rawProposal.values, - rawProposal.calldatas, - rawProposal.description - ); + uint256 proposalId = governor.propose(targets, values, calldatas, description); console.log("Proposal id: %d", proposalId); } } diff --git a/utils/contractAddress.js b/utils/contractAddress.js index 1ca6422..f2e6283 100644 --- a/utils/contractAddress.js +++ b/utils/contractAddress.js @@ -20,7 +20,7 @@ const parsedInput = Number(chainInput); let contract -if(contracTtype == "governor") contract = registry(parsedInput)?.AngleGovernor; +if(contracTtype == "governor") contract = registry(parsedInput)?.Governor; else if(contracTtype == "proposalReceiver") contract = registry(parsedInput)?.ProposalReceiver; else if(contracTtype == "timelock") contract = registry(parsedInput)?.Timelock; else if(contracTtype == "proposalSender") contract = registry(parsedInput)?.ProposalSender; From cbb168e01ed7927d01ec335ffb1149395a931d0c Mon Sep 17 00:00:00 2001 From: 0xtekgrinder <0xtekgrinder@protonmail.com> Date: Thu, 11 Jan 2024 19:29:57 -0500 Subject: [PATCH 05/27] feat: createProposal script --- helpers/createProposal.sh | 198 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 helpers/createProposal.sh diff --git a/helpers/createProposal.sh b/helpers/createProposal.sh new file mode 100644 index 0000000..2d37ca8 --- /dev/null +++ b/helpers/createProposal.sh @@ -0,0 +1,198 @@ +#! /bin/bash + +function chain_to_uri { + chain=$1 + + case $chain in + "1") + echo $ETH_NODE_URI_MAINNET + ;; + "2") + echo $ETH_NODE_URI_ARBITRUM + ;; + "3") + echo $ETH_NODE_URI_POLYGON + ;; + "4") + echo $ETH_NODE_URI_GNOSIS + ;; + "5") + echo $ETH_NODE_URI_AVALANCHE + ;; + "6") + echo $ETH_NODE_URI_BASE + ;; + "7") + echo $ETH_NODE_URI_BSC + ;; + "8") + echo $ETH_NODE_URI_CELO + ;; + "9") + echo $ETH_NODE_URI_POLYGON_ZKEVM + ;; + "10") + echo $ETH_NODE_URI_OPTIMISM + ;; + "11") + echo $ETH_NODE_URI_LINEA + ;; + *) + ;; + esac +} + +function chain_to_chainId { + chain=$1 + + case $chain in + "1") + echo "1" + ;; + "2") + echo "42161" + ;; + "3") + echo "137" + ;; + "4") + echo "100" + ;; + "5") + echo "43114" + ;; + "6") + echo "8453" + ;; + "7") + echo "56" + ;; + "8") + echo "42220" + ;; + "9") + echo "1101" + ;; + "10") + echo "10" + ;; + "11") + echo "59144" + ;; + *) + ;; + esac +} + +function usage { + echo "bash createTx.sh