mirror of
https://github.com/Instadapp/dsa-governance.git
synced 2024-07-29 22:27:52 +00:00
Merge pull request #5 from Instadapp/timelock-v2
Timelock and Governor contract changes
This commit is contained in:
commit
cb99f3ddb3
|
|
@ -11,7 +11,7 @@ import { SafeMath } from "./SafeMath.sol";
|
|||
|
||||
contract InstaGovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorBravoEvents {
|
||||
/// @notice The name of this contract
|
||||
string public constant name = "DSL Governor Bravo";
|
||||
string public constant name = "INST Governor Bravo";
|
||||
|
||||
/// @notice The minimum setable proposal threshold
|
||||
uint public constant MIN_PROPOSAL_THRESHOLD = 500000e18; // 500,000
|
||||
|
|
@ -20,22 +20,22 @@ contract InstaGovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorB
|
|||
uint public constant MAX_PROPOSAL_THRESHOLD = 50000000e18; // 5,000,000
|
||||
|
||||
/// @notice The minimum setable voting period
|
||||
uint public constant MIN_VOTING_PERIOD = 5760; // About 24 hours
|
||||
uint public constant MIN_VOTING_PERIOD = 7200; // About 24 hours, 12s per block
|
||||
|
||||
/// @notice The max setable voting period
|
||||
uint public constant MAX_VOTING_PERIOD = 80640; // About 2 weeks
|
||||
uint public constant MAX_VOTING_PERIOD = 100800; // About 2 weeks, 12s per block
|
||||
|
||||
/// @notice The min setable voting delay
|
||||
uint public constant MIN_VOTING_DELAY = 1;
|
||||
|
||||
/// @notice The max setable voting delay
|
||||
uint public constant MAX_VOTING_DELAY = 40320; // About 1 week
|
||||
uint public constant MAX_VOTING_DELAY = 50400; // About 1 week, 12s per block
|
||||
|
||||
/// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed
|
||||
uint public constant quorumVotes = 4000000e18; // 4,000,000
|
||||
|
||||
/// @notice The maximum number of actions that can be included in a proposal
|
||||
uint public constant proposalMaxOperations = 10; // 10 actions
|
||||
uint public constant proposalMaxOperations = 30; // 30 actions
|
||||
|
||||
/// @notice The EIP-712 typehash for the contract's domain
|
||||
bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
|
||||
|
|
@ -359,6 +359,9 @@ contract InstaGovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorB
|
|||
|
||||
// Store admin with value pendingAdmin
|
||||
admin = pendingAdmin;
|
||||
// Store timelock with value pendingAdmin
|
||||
emit NewTimelock(address(timelock), pendingAdmin);
|
||||
timelock = TimelockInterface(pendingAdmin);
|
||||
|
||||
// Clear the pending value
|
||||
pendingAdmin = address(0);
|
||||
|
|
@ -367,6 +370,15 @@ contract InstaGovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorB
|
|||
emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Accepts transfer of admin rights on timelock contract. msg.sender must be admin of this contract
|
||||
* @dev Admin function for pending admin to accept role and update admin on timelock contract
|
||||
*/
|
||||
function _acceptAdminOnTimelock() external {
|
||||
require(msg.sender == admin, "GovernorBravo:_acceptAdminOnTimelock: pending admin only");
|
||||
timelock.acceptAdmin();
|
||||
}
|
||||
|
||||
|
||||
function getChainIdInternal() internal pure returns (uint) {
|
||||
uint chainId;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,9 @@ contract GovernorBravoEvents {
|
|||
|
||||
/// @notice Emitted when pendingAdmin is accepted, which means admin is updated
|
||||
event NewAdmin(address oldAdmin, address newAdmin);
|
||||
|
||||
/// @notice Emitted when pendingAdmin is accepted, which means timelock is updated
|
||||
event NewTimelock(address oldTimelock, address newTimelock);
|
||||
}
|
||||
|
||||
contract GovernorBravoDelegatorStorage {
|
||||
|
|
|
|||
|
|
@ -8,27 +8,27 @@ contract InstaTimelock {
|
|||
event NewAdmin(address indexed newAdmin);
|
||||
event NewPendingAdmin(address indexed newPendingAdmin);
|
||||
event NewDelay(uint indexed newDelay);
|
||||
event NewGuardian(address indexed newGuardian);
|
||||
event CancelTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint eta);
|
||||
event ExecuteTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint eta);
|
||||
event QueueTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint eta);
|
||||
|
||||
uint public constant GRACE_PERIOD = 14 days;
|
||||
uint public constant MINIMUM_DELAY = 2 days;
|
||||
uint public constant MINIMUM_DELAY = 1 hours;
|
||||
uint public constant MAXIMUM_DELAY = 30 days;
|
||||
|
||||
address public admin;
|
||||
address public pendingAdmin;
|
||||
address public guardian;
|
||||
uint public delay;
|
||||
|
||||
mapping (bytes32 => bool) public queuedTransactions;
|
||||
|
||||
|
||||
constructor(address admin_, uint delay_) {
|
||||
require(delay_ >= MINIMUM_DELAY, "Timelock::constructor: Delay must exceed minimum delay.");
|
||||
require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay.");
|
||||
|
||||
constructor(address admin_, address guardian_) {
|
||||
admin = admin_;
|
||||
delay = delay_;
|
||||
delay = 0; // delay set to "0"
|
||||
guardian = guardian_;
|
||||
}
|
||||
|
||||
fallback() external payable { }
|
||||
|
|
@ -42,6 +42,13 @@ contract InstaTimelock {
|
|||
emit NewDelay(delay);
|
||||
}
|
||||
|
||||
function setGuardian(address guardian_) public {
|
||||
require(msg.sender == address(this), "Timelock::setGuardian: Call must come from Timelock.");
|
||||
guardian = guardian_;
|
||||
|
||||
emit NewGuardian(guardian_);
|
||||
}
|
||||
|
||||
function acceptAdmin() public {
|
||||
require(msg.sender == pendingAdmin, "Timelock::acceptAdmin: Call must come from pendingAdmin.");
|
||||
admin = msg.sender;
|
||||
|
|
@ -59,7 +66,7 @@ contract InstaTimelock {
|
|||
|
||||
function queueTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public returns (bytes32) {
|
||||
require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin.");
|
||||
require(eta >= getBlockTimestamp().add(delay), "Timelock::queueTransaction: Estimated execution block must satisfy delay.");
|
||||
require(delay == 0 || eta >= getBlockTimestamp().add(delay), "Timelock::queueTransaction: Estimated execution block must satisfy delay.");
|
||||
|
||||
bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
|
||||
queuedTransactions[txHash] = true;
|
||||
|
|
@ -69,7 +76,7 @@ contract InstaTimelock {
|
|||
}
|
||||
|
||||
function cancelTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public {
|
||||
require(msg.sender == admin, "Timelock::cancelTransaction: Call must come from admin.");
|
||||
require(msg.sender == admin || msg.sender == guardian, "Timelock::cancelTransaction: Call must come from admin or guardian.");
|
||||
|
||||
bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
|
||||
queuedTransactions[txHash] = false;
|
||||
|
|
@ -104,6 +111,23 @@ contract InstaTimelock {
|
|||
return returnData;
|
||||
}
|
||||
|
||||
function executePayload(address target, string memory signature, bytes memory data) public returns (bytes memory) {
|
||||
require(msg.sender == address(this), "Timelock::executePayload: Call must come from Timelock.");
|
||||
bytes memory callData;
|
||||
|
||||
if (bytes(signature).length == 0) {
|
||||
callData = data;
|
||||
} else {
|
||||
callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);
|
||||
}
|
||||
|
||||
// solium-disable-next-line security/no-call-value
|
||||
(bool success, bytes memory returnData) = target.delegatecall(callData);
|
||||
require(success, "Timelock::executePayload: Transaction execution reverted.");
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
function getBlockTimestamp() internal view returns (uint) {
|
||||
// solium-disable-next-line security/no-block-members
|
||||
return block.timestamp;
|
||||
|
|
|
|||
337
contracts/payloads/IGP7/PayloadIGP7.sol
Normal file
337
contracts/payloads/IGP7/PayloadIGP7.sol
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface IGovernorBravo {
|
||||
function _acceptAdmin() external;
|
||||
function _setVotingDelay(uint newVotingDelay) external;
|
||||
function _setVotingPeriod(uint newVotingPeriod) external;
|
||||
function _acceptAdminOnTimelock() external;
|
||||
function _setImplementation(address implementation_) external;
|
||||
function propose(address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description) external returns (uint);
|
||||
function admin() external view returns(address);
|
||||
function pendingAdmin() external view returns(address);
|
||||
function timelock() external view returns(address);
|
||||
function votingDelay() external view returns(uint256);
|
||||
function votingPeriod() external view returns(uint256);
|
||||
}
|
||||
|
||||
interface ITimelock {
|
||||
function acceptAdmin() external;
|
||||
function setDelay(uint delay_) external;
|
||||
function setPendingAdmin(address pendingAdmin_) external;
|
||||
function queueTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) external returns (bytes32);
|
||||
function executeTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) external payable returns (bytes memory);
|
||||
function pendingAdmin() external view returns(address);
|
||||
function admin() external view returns(address);
|
||||
function delay() external view returns(uint256);
|
||||
}
|
||||
|
||||
interface IInstaIndex {
|
||||
function changeMaster(address _newMaster) external;
|
||||
function updateMaster() external;
|
||||
function master() external view returns(address);
|
||||
}
|
||||
|
||||
interface ILite {
|
||||
function setAdmin(address newAdmin) external;
|
||||
function getAdmin() external view returns(address);
|
||||
}
|
||||
|
||||
interface IDSAV2 {
|
||||
function cast(
|
||||
string[] memory _targetNames,
|
||||
bytes[] memory _datas,
|
||||
address _origin
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (bytes32);
|
||||
|
||||
function isAuth(address user) external view returns (bool);
|
||||
}
|
||||
|
||||
contract PayloadIGP7 {
|
||||
uint256 public constant PROPOSAL_ID = 7;
|
||||
|
||||
address public constant PROPOSER = 0xA45f7bD6A5Ff45D31aaCE6bCD3d426D9328cea01;
|
||||
|
||||
IGovernorBravo public constant GOVERNOR = IGovernorBravo(0x0204Cd037B2ec03605CFdFe482D8e257C765fA1B);
|
||||
ITimelock public constant OLD_TIMELOCK = ITimelock(0xC7Cb1dE2721BFC0E0DA1b9D526bCdC54eF1C0eFC);
|
||||
ITimelock public immutable TIMELOCK;
|
||||
address public immutable ADDRESS_THIS;
|
||||
|
||||
IInstaIndex public constant INSTAINDEX = IInstaIndex(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723);
|
||||
ILite public constant LITE = ILite(0xA0D3707c569ff8C87FA923d3823eC5D81c98Be78);
|
||||
IDSAV2 public constant TREASURY = IDSAV2(0x28849D2b63fA8D361e5fc15cB8aBB13019884d09);
|
||||
|
||||
uint256 public constant ONE_DAY_TIME_IN_SECONDS = 1 days; // 1 day in seconds. 86400s
|
||||
uint256 public constant ONE_DAY_TIME_IN_BLOCKS = 7_200; // 1 day in blocks. 12s per block
|
||||
uint256 public constant TWO_DAY_TIME_IN_BLOCKS = 14_400; // 2 day in blocks. 12s per block
|
||||
|
||||
address public immutable GOVERNOR_IMPLEMENTATION_ADDRESS;
|
||||
address public constant TEAM_MULTISIG = 0x4F6F977aCDD1177DCD81aB83074855EcB9C2D49e;
|
||||
|
||||
constructor (address governor_, address timelock_) {
|
||||
TIMELOCK = ITimelock(address(timelock_));
|
||||
GOVERNOR_IMPLEMENTATION_ADDRESS = address(governor_);
|
||||
ADDRESS_THIS = address(this);
|
||||
}
|
||||
|
||||
|
||||
function propose(string memory description) external {
|
||||
require(msg.sender == PROPOSER, "msg.sender-not-proposer");
|
||||
|
||||
uint256 totalActions = 8;
|
||||
address[] memory targets = new address[](totalActions);
|
||||
uint256[] memory values = new uint256[](totalActions);
|
||||
string[] memory signatures = new string[](totalActions);
|
||||
bytes[] memory calldatas = new bytes[](totalActions);
|
||||
|
||||
// Action 1: call cast() - transfer rewards to Team Multisig, add new Timelock as auth & remove old Timelock as auth on Treasury
|
||||
(targets[0], values[0], signatures[0], calldatas[0]) = action1();
|
||||
|
||||
// Action 2: call _setImplementation() - upgrade governor contract to new implementation
|
||||
(targets[1], values[1], signatures[1], calldatas[1]) = action2();
|
||||
|
||||
// Action 3: call changeMaster() - change ownership of DSA to new timelock contract
|
||||
(targets[2], values[2], signatures[2], calldatas[2]) = action3();
|
||||
|
||||
// Action 4: call setAdmin() - change ownership of Lite to new timelock contract
|
||||
(targets[3], values[3], signatures[3], calldatas[3]) = action4();
|
||||
|
||||
// Action 5: call _setPendingAdmin() - on governor contract with new timelock address
|
||||
(targets[4], values[4], signatures[4], calldatas[4]) = action5();
|
||||
|
||||
// Action 6: call setPendingAdmin() - on old timelock to change team multisig
|
||||
(targets[5], values[5], signatures[5], calldatas[5]) = action6();
|
||||
|
||||
// Action 7: call queueTransaction - new timelock contract to queue below payload
|
||||
(targets[6], values[6], signatures[6], calldatas[6]) = action7();
|
||||
|
||||
// Action 8: call executeTransaction - new timelock contract to execute below payload
|
||||
(targets[7], values[7], signatures[7], calldatas[7]) = action8();
|
||||
|
||||
uint256 proposedId = GOVERNOR.propose(
|
||||
targets,
|
||||
values,
|
||||
signatures,
|
||||
calldatas,
|
||||
description
|
||||
);
|
||||
|
||||
require(proposedId == PROPOSAL_ID, "PROPOSAL_IS_NOT_SAME");
|
||||
}
|
||||
|
||||
function execute() external {
|
||||
// Action 1: updateMaster() function on DSA instaIndex
|
||||
INSTAINDEX.updateMaster();
|
||||
|
||||
// Action 2: _acceptAdmin() function on governor contract
|
||||
GOVERNOR._acceptAdmin();
|
||||
|
||||
// Action 3: _setVotingDelay() function on governor contract with 1 days
|
||||
GOVERNOR._setVotingDelay(ONE_DAY_TIME_IN_BLOCKS);
|
||||
|
||||
// Action 4: _setVotingPeriod() function on governor contract with 2 days
|
||||
GOVERNOR._setVotingPeriod(TWO_DAY_TIME_IN_BLOCKS);
|
||||
|
||||
// Action 5: setPendingAdmin() on new timelock contract
|
||||
TIMELOCK.setPendingAdmin(address(GOVERNOR));
|
||||
|
||||
// Action 6: _acceptAdminOnTimelock() on governor contract
|
||||
GOVERNOR._acceptAdminOnTimelock();
|
||||
|
||||
// Action 7: setDelay() on new timelock contract with 1 day
|
||||
TIMELOCK.setDelay(ONE_DAY_TIME_IN_SECONDS);
|
||||
|
||||
// Action 8: call verifyProposal() - on this payload contract to verify proposal execution
|
||||
PayloadIGP7(ADDRESS_THIS).verifyProposal();
|
||||
}
|
||||
|
||||
function verifyProposal() external view {
|
||||
// Verify 1 : Verify DSA Master
|
||||
require(INSTAINDEX.master() == address(TIMELOCK), "InstaIndex-wrong-master");
|
||||
|
||||
// Verify 2 : Verify Lite Admin
|
||||
require(LITE.getAdmin() == address(TIMELOCK), "Lite-wrong-admin");
|
||||
|
||||
// Verify 3 : Verify Governor Admin
|
||||
require(GOVERNOR.admin() == address(TIMELOCK), "Governor-wrong-admin");
|
||||
|
||||
// Verify 4 : Verify Governor Timelock
|
||||
require(GOVERNOR.timelock() == address(TIMELOCK), "Governor-wrong-timelock");
|
||||
|
||||
// Verify 5 : Verify Governor Pending Admin
|
||||
require(GOVERNOR.pendingAdmin() == address(0), "Governor-wrong-pending-admin");
|
||||
|
||||
// Verify 6 : Verify Old Timelock Admin
|
||||
require(OLD_TIMELOCK.admin() == address(GOVERNOR), "Old-timelock-wrong-admin");
|
||||
|
||||
// Verify 7 : Verify Old Timelock Pending Admin
|
||||
require(OLD_TIMELOCK.pendingAdmin() == address(TEAM_MULTISIG), "Old-timelock-wrong-pending-admin");
|
||||
|
||||
// Verify 8 : Verify New Timelock Admin
|
||||
require(TIMELOCK.admin() == address(GOVERNOR), "Timelock-wrong-admin");
|
||||
|
||||
// Verify 9 : Verify Timelock Pending Admin
|
||||
require(TIMELOCK.pendingAdmin() == address(0), "Timelock-wrong-pending-admin");
|
||||
|
||||
// Verify 10 : Verify Treasury remove of old timelock
|
||||
require(TREASURY.isAuth(address(OLD_TIMELOCK)) == false, "Treasury-old-timelock-not-removed");
|
||||
|
||||
// Verify 11: Verify Treasury add of new timelock
|
||||
require(TREASURY.isAuth(address(TIMELOCK)) == true, "Treasury-new-timelock-not-added");
|
||||
|
||||
// Verify 12: Verify voting delay
|
||||
require(GOVERNOR.votingDelay() == ONE_DAY_TIME_IN_BLOCKS, "Voting-delay-not-set-to-one-day");
|
||||
|
||||
// Verify 13: Verify voting period
|
||||
require(GOVERNOR.votingPeriod() == TWO_DAY_TIME_IN_BLOCKS, "Voting-period-not-set-to-two-day");
|
||||
|
||||
// Verify 14: Verify queueing period
|
||||
require(TIMELOCK.delay() == ONE_DAY_TIME_IN_SECONDS, "Timelock-delay-not-set-to-one-day");
|
||||
}
|
||||
|
||||
///////// PROPOSAL ACTIONS - 8 Actions ///////
|
||||
|
||||
/// @notice Action 1: call cast() - transfer rewards to Team Multisig, add new Timelock as auth & remove old Timelock as auth on Treasury
|
||||
function action1() public view returns(address target, uint256 value, string memory signature, bytes memory calldatas) {
|
||||
string[] memory targets = new string[](7);
|
||||
bytes[] memory encodedSpells = new bytes[](7);
|
||||
|
||||
string memory withdrawSignature = "withdraw(address,uint256,address,uint256,uint256)";
|
||||
|
||||
// Spell 1: Transfer wETH
|
||||
{
|
||||
address ETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
uint256 ETH_AMOUNT = 230 * 1e18; // 230 ETH
|
||||
targets[0] = "BASIC-A";
|
||||
encodedSpells[0] = abi.encodeWithSignature(withdrawSignature, ETH_ADDRESS, ETH_AMOUNT, TEAM_MULTISIG, 0, 0);
|
||||
}
|
||||
|
||||
// Spell 2: Transfer USDC
|
||||
{
|
||||
address USDC_ADDRESS = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
|
||||
uint256 USDC_AMOUNT = 247_900 * 1e6; // 247.9k USDC
|
||||
targets[1] = "BASIC-A";
|
||||
encodedSpells[1] = abi.encodeWithSignature(withdrawSignature, USDC_ADDRESS, USDC_AMOUNT, TEAM_MULTISIG, 0, 0);
|
||||
}
|
||||
|
||||
// Spell 3: Transfer DAI
|
||||
{
|
||||
address DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
|
||||
uint256 DAI_AMOUNT = 59_000 * 1e18; // 59k DAI
|
||||
targets[2] = "BASIC-A";
|
||||
encodedSpells[2] = abi.encodeWithSignature(withdrawSignature, DAI_ADDRESS, DAI_AMOUNT, TEAM_MULTISIG, 0, 0);
|
||||
}
|
||||
|
||||
// Spell 4: Transfer USDT
|
||||
{
|
||||
address USDT_ADDRESS = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
|
||||
uint256 USDT_AMOUNT = 28_700 * 1e6; // 28.8k USDT
|
||||
targets[3] = "BASIC-A";
|
||||
encodedSpells[3] = abi.encodeWithSignature(withdrawSignature, USDT_ADDRESS, USDT_AMOUNT, TEAM_MULTISIG, 0, 0);
|
||||
}
|
||||
|
||||
// Spell 5: Transfer stETH
|
||||
{
|
||||
address STETH_ADDRESS = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;
|
||||
uint256 STETH_AMOUNT = 320 * 1e18; // 320 stETH
|
||||
targets[4] = "BASIC-A";
|
||||
encodedSpells[4] = abi.encodeWithSignature(withdrawSignature, STETH_ADDRESS, STETH_AMOUNT, TEAM_MULTISIG, 0, 0);
|
||||
}
|
||||
|
||||
// Spell 6: Add new Timelock as auth
|
||||
{
|
||||
targets[5] = "AUTHORITY-A";
|
||||
encodedSpells[5] = abi.encodeWithSignature("add(address)", address(TIMELOCK));
|
||||
}
|
||||
|
||||
// Spell 7: Remove old Timelock as auth
|
||||
{
|
||||
targets[6] = "AUTHORITY-A";
|
||||
encodedSpells[6] = abi.encodeWithSignature("remove(address)", address(OLD_TIMELOCK));
|
||||
}
|
||||
|
||||
target = address(TREASURY);
|
||||
value = 0;
|
||||
signature = "cast(string[],bytes[],address)";
|
||||
calldatas = abi.encode(targets, encodedSpells, address(this));
|
||||
}
|
||||
|
||||
/// @notice Action 2: call _setImplementation() - upgrade governor contract to new implementation
|
||||
function action2() public view returns(address target, uint256 value, string memory signature, bytes memory calldatas) {
|
||||
target = address(GOVERNOR);
|
||||
value = 0;
|
||||
signature = "_setImplementation(address)";
|
||||
calldatas = abi.encode(GOVERNOR_IMPLEMENTATION_ADDRESS);
|
||||
}
|
||||
|
||||
/// @notice Action 3: call changeMaster() - change ownership of DSA to new timelock contract
|
||||
function action3() public view returns(address target, uint256 value, string memory signature, bytes memory calldatas) {
|
||||
target = address(INSTAINDEX);
|
||||
value = 0;
|
||||
signature = "changeMaster(address)";
|
||||
calldatas = abi.encode(TIMELOCK);
|
||||
}
|
||||
|
||||
/// @notice Action 4: call setAdmin() - change ownership of Lite to new timelock contract
|
||||
function action4() public view returns(address target, uint256 value, string memory signature, bytes memory calldatas) {
|
||||
target = address(LITE);
|
||||
value = 0;
|
||||
signature = "setAdmin(address)";
|
||||
calldatas = abi.encode(TIMELOCK);
|
||||
}
|
||||
|
||||
/// @notice Action 5: call _setPendingAdmin() - on governor contract with new timelock address
|
||||
function action5() public view returns(address target, uint256 value, string memory signature, bytes memory calldatas) {
|
||||
target = address(GOVERNOR);
|
||||
value = 0;
|
||||
signature = "_setPendingAdmin(address)";
|
||||
calldatas = abi.encode(TIMELOCK);
|
||||
}
|
||||
|
||||
/// @notice Action 6: call setPendingAdmin() - on old timelock to change team multisig
|
||||
function action6() public pure returns(address target, uint256 value, string memory signature, bytes memory calldatas) {
|
||||
target = address(OLD_TIMELOCK);
|
||||
value = 0;
|
||||
signature = "setPendingAdmin(address)";
|
||||
calldatas = abi.encode(TEAM_MULTISIG);
|
||||
}
|
||||
|
||||
/// @notice Action 7: call queueTransaction - new timelock contract to queue below payload
|
||||
function action7() public view returns(address target, uint256 value, string memory signature, bytes memory calldatas) {
|
||||
target = address(TIMELOCK);
|
||||
value = 0;
|
||||
signature = "queueTransaction(address,uint256,string,bytes,uint256)";
|
||||
calldatas = abi.encode(
|
||||
TIMELOCK,
|
||||
0,
|
||||
"executePayload(address,string,bytes)",
|
||||
abi.encode(
|
||||
address(this),
|
||||
"execute()",
|
||||
abi.encode()
|
||||
),
|
||||
block.timestamp
|
||||
);
|
||||
}
|
||||
|
||||
/// @notice Action 8: call executeTransaction - new timelock contract to execute below payload
|
||||
function action8() public view returns(address target, uint256 value, string memory signature, bytes memory calldatas) {
|
||||
target = address(TIMELOCK);
|
||||
value = 0;
|
||||
signature = "executeTransaction(address,uint256,string,bytes,uint256)";
|
||||
calldatas = abi.encode(
|
||||
TIMELOCK,
|
||||
0,
|
||||
"executePayload(address,string,bytes)",
|
||||
abi.encode(
|
||||
address(this),
|
||||
"execute()",
|
||||
abi.encode()
|
||||
),
|
||||
block.timestamp
|
||||
);
|
||||
}
|
||||
}
|
||||
226
contracts/payloads/IGP7/mocks/PayloadIGP8Mock.sol
Normal file
226
contracts/payloads/IGP7/mocks/PayloadIGP8Mock.sol
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface IGovernorBravo {
|
||||
function _acceptAdmin() external;
|
||||
function _setVotingDelay(uint newVotingDelay) external;
|
||||
function _setVotingPeriod(uint newVotingPeriod) external;
|
||||
function _acceptAdminOnTimelock() external;
|
||||
function _setImplementation(address implementation_) external;
|
||||
function propose(address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description) external returns (uint);
|
||||
function admin() external view returns(address);
|
||||
function pendingAdmin() external view returns(address);
|
||||
function timelock() external view returns(address);
|
||||
function votingDelay() external view returns(uint256);
|
||||
function votingPeriod() external view returns(uint256);
|
||||
}
|
||||
|
||||
interface ITimelock {
|
||||
function acceptAdmin() external;
|
||||
function setDelay(uint delay_) external;
|
||||
function setPendingAdmin(address pendingAdmin_) external;
|
||||
function queueTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) external returns (bytes32);
|
||||
function executeTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) external payable returns (bytes memory);
|
||||
function pendingAdmin() external view returns(address);
|
||||
function admin() external view returns(address);
|
||||
function delay() external view returns(uint256);
|
||||
}
|
||||
|
||||
interface IInstaIndex {
|
||||
function changeMaster(address _newMaster) external;
|
||||
function updateMaster() external;
|
||||
function master() external view returns(address);
|
||||
}
|
||||
|
||||
interface ILite {
|
||||
function setAdmin(address newAdmin) external;
|
||||
function getAdmin() external view returns(address);
|
||||
function updateSecondaryAuth(address secondaryAuth_) external;
|
||||
}
|
||||
|
||||
interface IDSAV2 {
|
||||
function cast(
|
||||
string[] memory _targetNames,
|
||||
bytes[] memory _datas,
|
||||
address _origin
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (bytes32);
|
||||
|
||||
function isAuth(address user) external view returns (bool);
|
||||
}
|
||||
|
||||
contract PayloadIGP8Mock {
|
||||
uint256 public constant PROPOSAL_ID = 8;
|
||||
|
||||
IGovernorBravo public constant GOVERNOR = IGovernorBravo(0x0204Cd037B2ec03605CFdFe482D8e257C765fA1B);
|
||||
IDSAV2 public constant TREASURY = IDSAV2(0x28849D2b63fA8D361e5fc15cB8aBB13019884d09);
|
||||
|
||||
IInstaIndex public constant INSTAINDEX = IInstaIndex(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723);
|
||||
ILite public constant LITE = ILite(0xA0D3707c569ff8C87FA923d3823eC5D81c98Be78);
|
||||
|
||||
ITimelock public constant OLD_TIMELOCK = ITimelock(0xC7Cb1dE2721BFC0E0DA1b9D526bCdC54eF1C0eFC);
|
||||
|
||||
address public immutable ADDRESS_THIS;
|
||||
ITimelock public immutable TIMELOCK;
|
||||
address public immutable GOVERNOR_IMPLEMENTATION_ADDRESS;
|
||||
|
||||
address public constant TEAM_MULTISIG = 0x4F6F977aCDD1177DCD81aB83074855EcB9C2D49e;
|
||||
|
||||
uint256 public constant ONE_DAY_TIME_IN_SECONDS = 1 days; // 1 day in seconds. 86400s
|
||||
uint256 public constant ONE_DAY_TIME_IN_BLOCKS = 7_200; // 1 day in blocks. 12s per block
|
||||
uint256 public constant TWO_DAY_TIME_IN_BLOCKS = 14_400; // 2 day in blocks. 12s per block
|
||||
|
||||
constructor (address governor_, address timelock_) {
|
||||
TIMELOCK = ITimelock(address(timelock_));
|
||||
GOVERNOR_IMPLEMENTATION_ADDRESS = address(governor_);
|
||||
ADDRESS_THIS = address(this);
|
||||
}
|
||||
|
||||
|
||||
function propose(string memory description) external {
|
||||
uint256 totalActions = 3;
|
||||
address[] memory targets = new address[](totalActions);
|
||||
uint256[] memory values = new uint256[](totalActions);
|
||||
string[] memory signatures = new string[](totalActions);
|
||||
bytes[] memory calldatas = new bytes[](totalActions);
|
||||
|
||||
(targets[0], values[0], signatures[0], calldatas[0]) = action1();
|
||||
|
||||
(targets[1], values[1], signatures[1], calldatas[1]) = action2();
|
||||
|
||||
(targets[2], values[2], signatures[2], calldatas[2]) = action3();
|
||||
|
||||
uint256 proposedId = GOVERNOR.propose(
|
||||
targets,
|
||||
values,
|
||||
signatures,
|
||||
calldatas,
|
||||
description
|
||||
);
|
||||
|
||||
require(proposedId == PROPOSAL_ID, "PROPOSAL_IS_NOT_SAME");
|
||||
}
|
||||
|
||||
function execute() external {
|
||||
LITE.updateSecondaryAuth(msg.sender);
|
||||
}
|
||||
|
||||
function verifyProposal() external view {
|
||||
// Verify 1 : Verify DSA Master
|
||||
require(INSTAINDEX.master() == address(TIMELOCK), "InstaIndex-wrong-master");
|
||||
|
||||
// Verify 2 : Verify Lite Admin
|
||||
require(LITE.getAdmin() == address(TIMELOCK), "Lite-wrong-admin");
|
||||
|
||||
// Verify 3 : Verify Governor Admin
|
||||
require(GOVERNOR.admin() == address(TIMELOCK), "Governor-wrong-admin");
|
||||
|
||||
// Verify 4 : Verify Governor Timelock
|
||||
require(GOVERNOR.timelock() == address(TIMELOCK), "Governor-wrong-timelock");
|
||||
|
||||
// Verify 5 : Verify Governor Pending Admin
|
||||
require(GOVERNOR.pendingAdmin() == address(0), "Governor-wrong-timelock");
|
||||
|
||||
// Verify 6 : Verify Old Timelock Admin
|
||||
require(OLD_TIMELOCK.admin() == address(GOVERNOR), "Old-timelock-wrong-admin");
|
||||
|
||||
// Verify 7 : Verify Old Timelock Pending Admin
|
||||
require(OLD_TIMELOCK.pendingAdmin() == address(TEAM_MULTISIG), "Old-timelock-wrong-pending-admin");
|
||||
|
||||
// Verify 8 : Verify New Timelock Admin
|
||||
require(TIMELOCK.admin() == address(GOVERNOR), "Timelock-wrong-admin");
|
||||
|
||||
// Verify 9 : Verify Timelock Pending Admin
|
||||
require(TIMELOCK.pendingAdmin() == address(0), "Old-timelock-wrong-pending-admin");
|
||||
|
||||
// Verify 10 : Verify Treasury remove of old timelock
|
||||
require(TREASURY.isAuth(address(OLD_TIMELOCK)) == false, "Treasury-old-timelock-not-removed");
|
||||
|
||||
// Verify 11: Verify Treasury add of new timelock
|
||||
require(TREASURY.isAuth(address(TIMELOCK)) == true, "Treasury-new-timelock-not-added");
|
||||
|
||||
// Verify 12: Verify voting delay
|
||||
require(GOVERNOR.votingDelay() == ONE_DAY_TIME_IN_BLOCKS, "Voting-delay-not-set-to-one-day");
|
||||
|
||||
// Verify 13: Verify voting period
|
||||
require(GOVERNOR.votingPeriod() == TWO_DAY_TIME_IN_BLOCKS, "Voting-period-not-set-to-two-day");
|
||||
|
||||
// Verify 14: Verify queueing period
|
||||
require(TIMELOCK.delay() == ONE_DAY_TIME_IN_SECONDS, "Timelock-delay-not-set-to-one-day");
|
||||
}
|
||||
|
||||
///////// PROPOSAL ACTIONS - 8 Actions ///////
|
||||
|
||||
/// @notice Action 1: call cast() - transfer rewards to Team Multisig, add new Timelock as auth & remove old Timelock as auth on Treasury
|
||||
function action1() public view returns(address target, uint256 value, string memory signature, bytes memory calldatas) {
|
||||
string[] memory targets = new string[](5);
|
||||
bytes[] memory encodedSpells = new bytes[](5);
|
||||
|
||||
string memory withdrawSignature = "withdraw(address,uint256,address,uint256,uint256)";
|
||||
|
||||
// Spell 1: Transfer wETH
|
||||
{
|
||||
address ETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
|
||||
uint256 ETH_AMOUNT = 1;
|
||||
targets[0] = "BASIC-A";
|
||||
encodedSpells[0] = abi.encodeWithSignature(withdrawSignature, ETH_ADDRESS, ETH_AMOUNT, TEAM_MULTISIG, 0, 0);
|
||||
}
|
||||
|
||||
// Spell 2: Transfer USDC
|
||||
{
|
||||
address USDC_ADDRESS = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
|
||||
uint256 USDC_AMOUNT = 100;
|
||||
targets[1] = "BASIC-A";
|
||||
encodedSpells[1] = abi.encodeWithSignature(withdrawSignature, USDC_ADDRESS, USDC_AMOUNT, TEAM_MULTISIG, 0, 0);
|
||||
}
|
||||
|
||||
// Spell 3: Transfer DAI
|
||||
{
|
||||
address DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
|
||||
uint256 DAI_AMOUNT = 100;
|
||||
targets[2] = "BASIC-A";
|
||||
encodedSpells[2] = abi.encodeWithSignature(withdrawSignature, DAI_ADDRESS, DAI_AMOUNT, TEAM_MULTISIG, 0, 0);
|
||||
}
|
||||
|
||||
// Spell 4: Transfer USDT
|
||||
{
|
||||
address USDT_ADDRESS = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
|
||||
uint256 USDT_AMOUNT = 100;
|
||||
targets[3] = "BASIC-A";
|
||||
encodedSpells[3] = abi.encodeWithSignature(withdrawSignature, USDT_ADDRESS, USDT_AMOUNT, TEAM_MULTISIG, 0, 0);
|
||||
}
|
||||
|
||||
// Spell 5: Transfer stETH
|
||||
{
|
||||
address STETH_ADDRESS = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;
|
||||
uint256 STETH_AMOUNT = 1;
|
||||
targets[4] = "BASIC-A";
|
||||
encodedSpells[4] = abi.encodeWithSignature(withdrawSignature, STETH_ADDRESS, STETH_AMOUNT, TEAM_MULTISIG, 0, 0);
|
||||
}
|
||||
|
||||
target = address(TREASURY);
|
||||
value = 0;
|
||||
signature = "cast(string[],bytes[],address)";
|
||||
calldatas = abi.encode(targets, encodedSpells, address(this));
|
||||
}
|
||||
|
||||
function action2() public view returns(address target, uint256 value, string memory signature, bytes memory calldatas) {
|
||||
target = address(TIMELOCK);
|
||||
value = 0;
|
||||
signature = "executePayload(address,string,bytes)";
|
||||
calldatas = abi.encode(
|
||||
address(this),
|
||||
"execute()",
|
||||
abi.encode()
|
||||
);
|
||||
}
|
||||
|
||||
function action3() public view returns(address target, uint256 value, string memory signature, bytes memory calldatas) {
|
||||
target = address(this);
|
||||
value = 0;
|
||||
signature = "verifyProposal()";
|
||||
calldatas = abi.encode();
|
||||
}
|
||||
}
|
||||
1
deployments/mainnet_1/PayloadIGP7.json
Normal file
1
deployments/mainnet_1/PayloadIGP7.json
Normal file
File diff suppressed because one or more lines are too long
1
deployments/mainnet_1/PayloadIGP8Mock.json
Normal file
1
deployments/mainnet_1/PayloadIGP8Mock.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -26,15 +26,14 @@ module.exports = {
|
|||
networks: {
|
||||
hardhat: {
|
||||
forking: {
|
||||
url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`,
|
||||
url: `https://1rpc.io/eth`,
|
||||
blockNumber: 12308027,
|
||||
},
|
||||
blockGasLimit: 12000000,
|
||||
},
|
||||
kovan: {
|
||||
url: `https://eth-kovan.alchemyapi.io/v2/${ALCHEMY_ID}`,
|
||||
accounts: [`0x${PRIVATE_KEY}`],
|
||||
gas: 12500000,
|
||||
mainnet: {
|
||||
url: `https://1rpc.io/eth`,
|
||||
accounts: !PRIVATE_KEY ? [] : [ `0x${PRIVATE_KEY}`],
|
||||
},
|
||||
},
|
||||
etherscan: {
|
||||
|
|
|
|||
11245
package-lock.json
generated
11245
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "dsl-governance",
|
||||
"name": "inst-governance",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@nomiclabs/hardhat-etherscan": "^2.1.1",
|
||||
"@tenderly/hardhat-tenderly": "^2.2.1",
|
||||
"dotenv": "^8.2.0",
|
||||
"rlp": "^2.2.6"
|
||||
}
|
||||
|
|
|
|||
48
scripts/deployIGP7.js
Normal file
48
scripts/deployIGP7.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
const hre = require("hardhat");
|
||||
const { ethers } = hre;
|
||||
|
||||
async function main() {
|
||||
const oldTimelockAddress = "0xC7Cb1dE2721BFC0E0DA1b9D526bCdC54eF1C0eFC"
|
||||
const guardain = "0x4F6F977aCDD1177DCD81aB83074855EcB9C2D49e"
|
||||
|
||||
// const Timelock = await ethers.getContractFactory("InstaTimelock")
|
||||
const timelock = await ethers.getContractAt("InstaTimelock", "0x2386dc45added673317ef068992f19421b481f4c")
|
||||
// const timelock = await Timelock.deploy(oldTimelockAddress, guardain)
|
||||
// await timelock.deployed()
|
||||
|
||||
// const GovernorDelegate = await ethers.getContractFactory("InstaGovernorBravoDelegate")
|
||||
const governorDelegate = await ethers.getContractAt("InstaGovernorBravoDelegate", "0x00613f7e762124711c7647f9eab5c8a88632ee47")
|
||||
// const governorDelegate = await GovernorDelegate.deploy()
|
||||
// await governorDelegate.deployed()
|
||||
|
||||
const PayloadIGP7 = await ethers.getContractFactory("PayloadIGP7")
|
||||
const payloadIGP7 = await PayloadIGP7.deploy(governorDelegate.address, timelock.address)
|
||||
await payloadIGP7.deployed()
|
||||
|
||||
console.log("PayloadIGP7: ", payloadIGP7.address)
|
||||
console.log("InstaTimelock: ", timelock.address)
|
||||
console.log("InstaGovernorBravoDelegate: ", governorDelegate.address)
|
||||
|
||||
|
||||
await hre.run("verify:verify", {
|
||||
address: timelock.address,
|
||||
constructorArguments: [oldTimelockAddress, guardain]
|
||||
})
|
||||
|
||||
await hre.run("verify:verify", {
|
||||
address: governorDelegate.address,
|
||||
constructorArguments: []
|
||||
})
|
||||
|
||||
await hre.run("verify:verify", {
|
||||
address: payloadIGP7.address,
|
||||
constructorArguments: [governorDelegate.address, timelock.address]
|
||||
})
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
46
scripts/deployIGP7_simulation.js
Normal file
46
scripts/deployIGP7_simulation.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
const hre = require("hardhat");
|
||||
const { ethers } = hre;
|
||||
|
||||
async function main() {
|
||||
const oldTimelockAddress = "0xC7Cb1dE2721BFC0E0DA1b9D526bCdC54eF1C0eFC"
|
||||
const guardain = "0x4F6F977aCDD1177DCD81aB83074855EcB9C2D49e"
|
||||
|
||||
const governorDelegate = await ethers.deployContract("InstaGovernorBravoDelegate")
|
||||
|
||||
await governorDelegate.waitForDeployment()
|
||||
|
||||
console.log(governorDelegate)
|
||||
|
||||
const timelock = await ethers.deployContract("InstaTimelock", [oldTimelockAddress, guardain])
|
||||
|
||||
await timelock.waitForDeployment()
|
||||
|
||||
const payload = await ethers.deployContract("PayloadIGP7", [governorDelegate.target, timelock.target])
|
||||
await payload.waitForDeployment()
|
||||
|
||||
const payload2 = await ethers.deployContract("PayloadIGP8Mock", [governorDelegate.target, timelock.target])
|
||||
await payload2.waitForDeployment()
|
||||
|
||||
console.log("InstaTimelock: ", timelock.target)
|
||||
console.log("InstaGovernorBravoDelegate: ", governorDelegate.target)
|
||||
console.log("PayloadIGP7: ", payload.target)
|
||||
console.log("PayloadIGP8Mock: ", payload2.target)
|
||||
console.log()
|
||||
|
||||
await hre.run("verify:verify", {
|
||||
address: governorDelegate.target,
|
||||
constructorArguments: []
|
||||
})
|
||||
|
||||
await hre.run("verify:verify", {
|
||||
address: timelock.target,
|
||||
constructorArguments: [oldTimelockAddress, guardain]
|
||||
})
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user