protocol/contracts/governance/test/unit/ZRXWrappedTokenTest.t.sol
Elena b7bf5b5dfe
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
2023-04-05 09:35:08 +03:00

316 lines
11 KiB
Solidity

// 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 "../BaseTest.t.sol";
import "../../src/ZRXWrappedToken.sol";
import "@openzeppelin/token/ERC20/ERC20.sol";
contract ZRXWrappedTokenTest is BaseTest {
IERC20 private token;
ZRXWrappedToken private wToken;
ZeroExVotes private votes;
function setUp() public {
token = mockZRXToken();
(wToken, votes, , , , ) = setupGovernance(token);
vm.startPrank(account1);
token.transfer(account2, 100e18);
token.transfer(account3, 200e18);
vm.stopPrank();
}
function testShouldReturnCorrectSymbol() public {
string memory wZRXSymbol = wToken.symbol();
assertEq(wZRXSymbol, "wZRX");
}
function testShouldReturnCorrectName() public {
string memory wZRXName = wToken.name();
assertEq(wZRXName, "Wrapped ZRX");
}
function testShouldReturnCorrectNumberOfDecimals() public {
uint8 wZRXDecimals = wToken.decimals();
assertEq(wZRXDecimals, 18);
}
function testShouldBeAbleToWrapZRX() public {
vm.startPrank(account2);
// Approve the wrapped token and deposit 1e18 ZRX
token.approve(address(wToken), 1e18);
wToken.depositFor(account2, 1e18);
// Check the token balances even out
uint256 wTokenBalance = wToken.balanceOf(account2);
assertEq(wTokenBalance, 1e18);
uint256 tokenBalance = token.balanceOf(account2);
assertEq(tokenBalance, 100e18 - wTokenBalance);
}
function testShouldBeAbleToUnwrapToZRX() public {
vm.startPrank(account2);
// Approve the wrapped token and deposit 1e18 ZRX
token.approve(address(wToken), 1e18);
wToken.depositFor(account2, 1e18);
// Withdraw 1e6 wZRX back to ZRX to own account
wToken.withdrawTo(account2, 1e6);
// Check token balances even out
uint256 wTokenBalance = wToken.balanceOf(account2);
assertEq(wTokenBalance, 1e18 - 1e6);
uint256 tokenBalance = token.balanceOf(account2);
assertEq(tokenBalance, 100e18 - wTokenBalance);
}
function testShouldBeAbleToUnwrapToZRXToAnotherAccount() public {
vm.startPrank(account2);
// Approve the wrapped token and deposit 1e18 ZRX
token.approve(address(wToken), 1e18);
wToken.depositFor(account2, 1e18);
// Withdraw 1e7 wZRX back to ZRX to account4 (which owns no tokens to start with)
wToken.withdrawTo(account4, 1e7);
// Check token balances even out
uint256 wTokenBalance2 = wToken.balanceOf(account2);
assertEq(wTokenBalance2, 1e18 - 1e7);
uint256 tokenBalance4 = token.balanceOf(account4);
assertEq(tokenBalance4, 1e7);
uint256 tokenBalance2 = token.balanceOf(account2);
assertEq(tokenBalance2, 100e18 - wTokenBalance2 - tokenBalance4);
}
function testWrappedZRXTotalsAreCorrect() public {
// Wrap 1e18 and check total supply is correct
vm.startPrank(account2);
token.approve(address(wToken), 1e18);
wToken.depositFor(account2, 1e18);
vm.stopPrank();
uint256 wTokenBalance = wToken.totalSupply();
assertEq(wTokenBalance, 1e18);
// Wrap 2e18 more and check total supply is correct
vm.startPrank(account3);
token.approve(address(wToken), 2e18);
wToken.depositFor(account3, 2e18);
vm.stopPrank();
wTokenBalance = wToken.totalSupply();
assertEq(wTokenBalance, 1e18 + 2e18);
// Unwrap 1e7 and check total supply is correct
vm.startPrank(account2);
wToken.withdrawTo(account2, 1e7);
vm.stopPrank();
wTokenBalance = wToken.totalSupply();
assertEq(wTokenBalance, 3e18 - 1e7);
// Unwrap 8e17 and check total supply is correct
vm.startPrank(account2);
wToken.withdrawTo(account2, 8e17);
vm.stopPrank();
wTokenBalance = wToken.totalSupply();
assertEq(wTokenBalance, 3e18 - 1e7 - 8e17);
// We are not keeping record of total balances so check they are zero
assertEq(votes.getPastTotalSupply(0), 0);
assertEq(votes.getPastQuadraticTotalSupply(0), 0);
}
function testWhenMintingFirstTimeForAccountTotalSupplyCheckpointsAreCorrect() public {
vm.startPrank(account2);
// Approve the wrapped token and deposit 1e18 ZRX
token.approve(address(wToken), 1e18);
vm.roll(2);
wToken.depositFor(account2, 1e18);
vm.roll(3);
// Check the totals are correct
uint256 totalSupplyVotes = votes.getPastTotalSupply(2);
uint256 totalSupplyQuadraticVotes = votes.getPastQuadraticTotalSupply(2);
assertEq(totalSupplyVotes, 1e18);
assertEq(totalSupplyQuadraticVotes, 1e18);
}
function testWhenMintingForAccountWithExistingBalanceTotalSupplyCheckpointsAreCorrect() public {
vm.startPrank(account2);
// Approve the wrapped token and deposit 1e18 ZRX
token.approve(address(wToken), 5e18);
wToken.depositFor(account2, 1e18);
vm.roll(2);
// Depost 3e18 more for the same account
wToken.depositFor(account2, 3e18);
vm.roll(3);
// Check the totals are correct
uint256 totalSupplyVotes = votes.getPastTotalSupply(2);
uint256 totalSupplyQuadraticVotes = votes.getPastQuadraticTotalSupply(2);
assertEq(totalSupplyVotes, 4e18);
assertEq(totalSupplyQuadraticVotes, 4e18);
}
function testWhenMintingForMultipleAccountsTotalSupplyCheckpointsAreCorrect() public {
// Deposit 1e18 ZRX by account2
vm.startPrank(account2);
token.approve(address(wToken), 5e18);
wToken.depositFor(account2, 1e18);
vm.stopPrank();
// Deposit 2e18 ZRX by account3
vm.startPrank(account3);
token.approve(address(wToken), 2e18);
wToken.depositFor(account3, 2e18);
vm.stopPrank();
// Deposit 4e18 ZRX by account2
vm.startPrank(account2);
vm.roll(2);
wToken.depositFor(account2, 4e18);
vm.stopPrank();
vm.roll(3);
// Check the totals are correct
uint256 totalSupplyVotes = votes.getPastTotalSupply(2);
uint256 totalSupplyQuadraticVotes = votes.getPastQuadraticTotalSupply(2);
assertEq(totalSupplyVotes, 7e18);
assertEq(totalSupplyQuadraticVotes, 5e18 + 2e18);
}
function testWhenBurningForMultipleAccountsTotalSupplyCheckpointsAreCorrect() public {
// Deposit 5e18 ZRX by account2
vm.startPrank(account2);
token.approve(address(wToken), 5e18);
wToken.depositFor(account2, 5e18);
vm.stopPrank();
// Deposit 2e18 ZRX by account3
vm.startPrank(account3);
token.approve(address(wToken), 2e18);
wToken.depositFor(account3, 2e18);
vm.stopPrank();
// Burn 4e18 ZRX by account2
vm.startPrank(account2);
vm.roll(2);
wToken.withdrawTo(account2, 4e18);
vm.stopPrank();
vm.roll(3);
// Check the totals are correct
uint256 totalSupplyVotes = votes.getPastTotalSupply(2);
uint256 totalSupplyQuadraticVotes = votes.getPastQuadraticTotalSupply(2);
assertEq(totalSupplyVotes, 3e18);
assertEq(totalSupplyQuadraticVotes, 1e18 + 2e18);
}
function testShouldBeAbleToTransferCorrectly() public {
assertEq(wToken.balanceOf(account4), 0);
vm.startPrank(account2);
token.approve(address(wToken), 1e18);
wToken.depositFor(account2, 1e18);
wToken.transfer(account4, 1e17);
vm.stopPrank();
assertEq(wToken.balanceOf(account4), 1e17);
}
function testShouldTransferVotingPowerWhenTransferringTokens() public {
// Account 2 wraps ZRX and delegates voting power to itself
vm.startPrank(account2);
token.approve(address(wToken), 10e18);
wToken.depositFor(account2, 10e18);
wToken.delegate(account2);
wToken.transfer(account3, 3e18);
assertEq(wToken.balanceOf(account2), 7e18);
assertEq(wToken.balanceOf(account3), 3e18);
assertEq(votes.getVotes(account2), 7e18);
assertEq(votes.getQuadraticVotes(account2), 7e18);
// Since account3 is not delegating to anyone, they should have no voting power
assertEq(votes.getVotes(account3), 0);
assertEq(votes.getQuadraticVotes(account3), 0);
}
function testShouldUpdateVotingPowerWhenDepositing() public {
// Account 2 wraps ZRX and delegates voting power to itself
vm.startPrank(account2);
token.approve(address(wToken), 10e18);
wToken.depositFor(account2, 7e18);
wToken.delegate(account2);
assertEq(votes.getVotes(account2), 7e18);
assertEq(votes.getQuadraticVotes(account2), 7e18);
wToken.depositFor(account2, 2e18);
assertEq(votes.getVotes(account2), 9e18);
assertEq(votes.getQuadraticVotes(account2), 9e18);
}
function testShouldUpdateVotingPowerWhenWithdrawing() public {
// Account 2 wraps ZRX and delegates voting power to itself
vm.startPrank(account2);
token.approve(address(wToken), 10e18);
wToken.depositFor(account2, 10e18);
wToken.delegate(account2);
assertEq(votes.getVotes(account2), 10e18);
assertEq(votes.getQuadraticVotes(account2), 10e18);
wToken.withdrawTo(account2, 2e18);
assertEq(votes.getVotes(account2), 8e18);
assertEq(votes.getQuadraticVotes(account2), 8e18);
}
function testShouldSetDelegateBalanceLastUpdatedOnTransfer() public {
ZRXWrappedToken.DelegateInfo memory account2DelegateInfo = wToken.delegateInfo(account2);
assertEq(account2DelegateInfo.delegate, address(0));
assertEq(account2DelegateInfo.balanceLastUpdated, 0);
// Account 2 wraps ZRX and delegates voting power to account3
vm.startPrank(account2);
token.approve(address(wToken), 10e18);
wToken.depositFor(account2, 10e18);
wToken.delegate(account3);
account2DelegateInfo = wToken.delegateInfo(account2);
assertEq(account2DelegateInfo.delegate, account3);
assertEq(account2DelegateInfo.balanceLastUpdated, 1); // Set to the block.number
vm.roll(3);
wToken.transfer(account3, 3e18);
account2DelegateInfo = wToken.delegateInfo(account2);
assertEq(account2DelegateInfo.delegate, account3);
assertEq(account2DelegateInfo.balanceLastUpdated, 3);
}
}