Governance integration testing (#683)

* Segregate tests and mocks and wire up integration test base

* Switch to a production version of predicting a deployment address

* Add integration test for exchange governor migration

* Add integration test for treassury migration

* Add integration test for migrating the treasury

* Add governance upgrade action to transfer ZRX tokens to new governor

* Add governance upgrade action to transfer wCELO tokens to new governor

* Add governance upgrade action to transfer WYV tokens to new governor

* Turn on verbose logging
This commit is contained in:
Elena
2023-04-05 09:35:08 +03:00
committed by GitHub
parent cfbb9c6f6c
commit b7bf5b5dfe
19 changed files with 735 additions and 51 deletions

View File

@@ -0,0 +1,246 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2023 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.19;
import "@openzeppelin/token/ERC20/IERC20.sol";
import "../mocks/IZeroExMock.sol";
import "../mocks/IZrxTreasuryMock.sol";
import "../mocks/IStakingMock.sol";
import "../BaseTest.t.sol";
import "../../src/ZRXWrappedToken.sol";
import "../../src/ZeroExVotes.sol";
import "../../src/ZeroExTimelock.sol";
import "../../src/ZeroExProtocolGovernor.sol";
import "../../src/ZeroExTreasuryGovernor.sol";
contract GovernanceE2ETest is BaseTest {
uint256 internal mainnetFork;
string internal MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL");
address internal constant ZRX_TOKEN = 0xE41d2489571d322189246DaFA5ebDe1F4699F498;
address internal constant MATIC_TOKEN = 0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0;
address internal constant WCELO_TOKEN = 0xE452E6Ea2dDeB012e20dB73bf5d3863A3Ac8d77a;
address internal constant WYV_TOKEN = 0x056017c55aE7AE32d12AeF7C679dF83A85ca75Ff;
address internal constant EXCHANGE_PROXY = 0xDef1C0ded9bec7F1a1670819833240f027b25EfF;
address internal constant EXCHANGE_GOVERNOR = 0x618F9C67CE7Bf1a50afa1E7e0238422601b0ff6e;
address internal constant TREASURY = 0x0bB1810061C2f5b2088054eE184E6C79e1591101;
address internal constant STAKING = 0xa26e80e7Dea86279c6d778D702Cc413E6CFfA777;
address internal staker = 0x5265Bde27F57E738bE6c1F6AB3544e82cdc92a8f;
bytes32 internal stakerPool = 0x0000000000000000000000000000000000000000000000000000000000000032;
bytes32[] internal staker_operated_poolIds = [stakerPool];
// voting power 1500000e18
address internal voter1 = 0x292c6DAE7417B3D31d8B6e1d2EeA0258d14C4C4b;
bytes32 internal voter1Pool = 0x0000000000000000000000000000000000000000000000000000000000000030;
bytes32[] internal voter1_operated_poolIds = [voter1Pool];
// voting power 1500000.5e18
address internal voter2 = 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08;
bytes32 internal voter2Pool = 0x0000000000000000000000000000000000000000000000000000000000000031;
bytes32[] internal voter2_operated_poolIds = [voter2Pool];
// voting power 1500000e18
address internal voter3 = 0x5265Bde27F57E738bE6c1F6AB3544e82cdc92a8f;
bytes32 internal voter3Pool = 0x0000000000000000000000000000000000000000000000000000000000000032;
bytes32[] internal voter3_operated_poolIds = [voter3Pool];
// voting power 1500000e18
address internal voter4 = 0xcA9F5049c1Ea8FC78574f94B7Cf5bE5fEE354C31;
bytes32 internal voter4Pool = 0x0000000000000000000000000000000000000000000000000000000000000034;
bytes32[] internal voter4_operated_poolIds = [voter4Pool];
// voting power 1500000e18
address internal voter5 = 0xDBB5664a9DBCB98F6365804880e5b277B3155422;
bytes32 internal voter5Pool = 0x0000000000000000000000000000000000000000000000000000000000000035;
bytes32[] internal voter5_operated_poolIds = [voter5Pool];
// voting power 2291490.952353335e18
address internal voter6 = 0x9a4Eb1101C0c053505Bd71d2fFa27Ed902DEaD85;
bytes32 internal voter6Pool = 0x0000000000000000000000000000000000000000000000000000000000000029;
bytes32[] internal voter6_operated_poolIds = [voter6Pool];
// voting power 4575984.325e18
address internal voter7 = 0x9564177EC8052C92752a488a71769F710aA0A41D;
bytes32 internal voter7Pool = 0x0000000000000000000000000000000000000000000000000000000000000025;
bytes32[] internal voter7_operated_poolIds = [voter7Pool];
IERC20 internal token;
IERC20 internal maticToken;
IERC20 internal wceloToken;
IERC20 internal wyvToken;
IZeroExMock internal exchange;
IZrxTreasuryMock internal treasury;
IStakingMock internal staking;
ZRXWrappedToken internal wToken;
ZeroExVotes internal votes;
ZeroExTimelock internal protocolTimelock;
ZeroExTimelock internal treasuryTimelock;
ZeroExProtocolGovernor internal protocolGovernor;
ZeroExTreasuryGovernor internal treasuryGovernor;
function setUp() public {
mainnetFork = vm.createFork(MAINNET_RPC_URL);
vm.selectFork(mainnetFork);
token = IERC20(ZRX_TOKEN);
maticToken = IERC20(MATIC_TOKEN);
wceloToken = IERC20(WCELO_TOKEN);
wyvToken = IERC20(WYV_TOKEN);
exchange = IZeroExMock(payable(EXCHANGE_PROXY));
treasury = IZrxTreasuryMock(TREASURY);
staking = IStakingMock(STAKING);
address protocolGovernorAddress;
address treasuryGovernorAddress;
(
wToken,
votes,
protocolTimelock,
treasuryTimelock,
protocolGovernorAddress,
treasuryGovernorAddress
) = setupGovernance(token);
protocolGovernor = ZeroExProtocolGovernor(payable(protocolGovernorAddress));
treasuryGovernor = ZeroExTreasuryGovernor(payable(treasuryGovernorAddress));
}
function testProtocolGovernanceMigration() public {
// initially the zrx exchange is owned by the legacy exchange governor
assertEq(exchange.owner(), EXCHANGE_GOVERNOR);
// transfer ownership to new protocol governor
vm.prank(EXCHANGE_GOVERNOR);
exchange.transferOwnership(address(protocolGovernor));
assertEq(exchange.owner(), address(protocolGovernor));
}
function testTreasuryGovernanceMigration() public {
// Create a proposal to migrate to new governor
uint256 currentEpoch = staking.currentEpoch();
uint256 executionEpoch = currentEpoch + 2;
vm.startPrank(staker);
IZrxTreasuryMock.ProposedAction[] memory actions = new IZrxTreasuryMock.ProposedAction[](4);
// Transfer MATIC
uint256 maticBalance = maticToken.balanceOf(address(treasury));
actions[0] = IZrxTreasuryMock.ProposedAction({
target: MATIC_TOKEN,
data: abi.encodeCall(maticToken.transfer, (address(treasuryGovernor), maticBalance)),
value: 0
});
// Transfer ZRX
uint256 zrxBalance = token.balanceOf(address(treasury));
actions[1] = IZrxTreasuryMock.ProposedAction({
target: ZRX_TOKEN,
data: abi.encodeCall(token.transfer, (address(treasuryGovernor), zrxBalance)),
value: 0
});
// Transfer wCELO
uint256 wceloBalance = wceloToken.balanceOf(address(treasury));
actions[2] = IZrxTreasuryMock.ProposedAction({
target: WCELO_TOKEN,
data: abi.encodeCall(wceloToken.transfer, (address(treasuryGovernor), wceloBalance)),
value: 0
});
// Transfer WYV
uint256 wyvBalance = wyvToken.balanceOf(address(treasury));
actions[3] = IZrxTreasuryMock.ProposedAction({
target: WYV_TOKEN,
data: abi.encodeCall(wyvToken.transfer, (address(treasuryGovernor), wyvBalance)),
value: 0
});
uint256 proposalId = treasury.propose(
actions,
executionEpoch,
"Z-5 Migrate to new treasury governor",
staker_operated_poolIds
);
// Once a proposal is created, it becomes open for voting at the epoch after next (currentEpoch + 2)
// and is open for the voting period (currently set to 3 days).
uint256 epochDurationInSeconds = staking.epochDurationInSeconds(); // Currently set to 604800 seconds = 7 days
uint256 currentEpochEndTime = staking.currentEpochStartTimeInSeconds() + epochDurationInSeconds;
vm.warp(currentEpochEndTime + 1);
staking.endEpoch();
vm.warp(block.timestamp + epochDurationInSeconds + 1);
staking.endEpoch();
vm.stopPrank();
// quorum is 10,000,000e18 so reach that via the following votes
vm.prank(voter1);
treasury.castVote(proposalId, true, voter1_operated_poolIds);
vm.stopPrank();
vm.prank(voter2);
treasury.castVote(proposalId, true, voter2_operated_poolIds);
vm.stopPrank();
vm.prank(voter3);
treasury.castVote(proposalId, true, voter3_operated_poolIds);
vm.stopPrank();
vm.prank(voter4);
treasury.castVote(proposalId, true, voter4_operated_poolIds);
vm.stopPrank();
vm.prank(voter5);
treasury.castVote(proposalId, true, voter5_operated_poolIds);
vm.stopPrank();
vm.prank(voter6);
treasury.castVote(proposalId, true, voter6_operated_poolIds);
vm.stopPrank();
vm.prank(voter7);
treasury.castVote(proposalId, true, voter7_operated_poolIds);
vm.stopPrank();
vm.warp(block.timestamp + 3 days + 1);
// Execute proposal
treasury.execute(proposalId, actions);
// Assert value of treasury has correctly transferred
uint256 maticBalanceNewTreasury = maticToken.balanceOf(address(treasuryGovernor));
assertEq(maticBalanceNewTreasury, maticBalance);
uint256 zrxBalanceNewTreasury = token.balanceOf(address(treasuryGovernor));
assertEq(zrxBalanceNewTreasury, zrxBalance);
uint256 wceloBalanceNewTreasury = wceloToken.balanceOf(address(treasuryGovernor));
assertEq(wceloBalanceNewTreasury, wceloBalance);
uint256 wyvBalanceNewTreasury = wyvToken.balanceOf(address(treasuryGovernor));
assertEq(wyvBalanceNewTreasury, wyvBalance);
}
}