generated from defi-wonderland/solidity-foundry-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: 0xRaccoon <[email protected]>
- Loading branch information
Showing
12 changed files
with
361 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,5 @@ GOERLI_RPC= | |
GOERLI_DEPLOYER_PK= | ||
|
||
ETHERSCAN_API_KEY= | ||
|
||
OPTIMISM_RPC= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
import './IntegrationBase.t.sol'; | ||
Check warning on line 4 in solidity/test/integration/Delegation.t.sol GitHub Actions / Run Linters (18.x)
|
||
|
||
import {WonderVotes} from 'contracts/governance/utils/WonderVotes.sol'; | ||
import {WonderGovernor} from 'contracts/governance/WonderGovernor.sol'; | ||
|
||
contract Integration_Delegation is IntegrationBase { | ||
function test_AllVotersDelegateToProposer() public { | ||
// AllVoters delegates to proposer | ||
for (uint256 _i = 0; _i < VOTERS_NUMBER; _i++) { | ||
address holder = holders[_i]; | ||
vm.prank(holder); | ||
rabbitToken.delegate(proposer); | ||
} | ||
|
||
for (uint256 _i = 0; _i < VOTERS_NUMBER; _i++) { | ||
address holder = holders[_i]; | ||
|
||
for (uint256 _j = 0; _j < governor.proposalTypes().length; _j++) { | ||
uint8 proposalType = governor.proposalTypes()[_j]; | ||
assertEq(rabbitToken.getVotes(holder, proposalType), 0); | ||
} | ||
} | ||
|
||
for (uint256 _j = 0; _j < governor.proposalTypes().length; _j++) { | ||
uint8 proposalType = governor.proposalTypes()[_j]; | ||
assertEq(rabbitToken.getVotes(proposer, proposalType), INITIAL_VOTERS_BALANCE * VOTERS_NUMBER); | ||
} | ||
} | ||
|
||
function test_AllVotersDelegateByProposalType() public { | ||
uint8[] memory proposalTypes = governor.proposalTypes(); | ||
|
||
for (uint256 _i = 0; _i < proposalTypes.length; _i++) { | ||
address _holder = holders[_i]; | ||
vm.prank(_holder); | ||
rabbitToken.delegate(proposer, proposalTypes[_i]); | ||
} | ||
|
||
for (uint256 _i = 0; _i < proposalTypes.length; _i++) { | ||
address _holder = holders[_i]; | ||
assertEq(rabbitToken.getVotes(_holder, proposalTypes[_i]), 0); | ||
assertEq(rabbitToken.getVotes(proposer, proposalTypes[_i]), INITIAL_VOTERS_BALANCE); | ||
} | ||
} | ||
|
||
function test_AllVotersDelegatePartially() public { | ||
uint8[] memory proposalTypes = governor.proposalTypes(); | ||
|
||
// 50% of votes | ||
uint256 _weight = rabbitToken.weightNormalizer() / 2; | ||
|
||
IWonderVotes.Delegate memory _delegate = IWonderVotes.Delegate({account: proposer, weight: _weight}); | ||
IWonderVotes.Delegate memory _delegate2 = IWonderVotes.Delegate({account: proposer2, weight: _weight}); | ||
|
||
IWonderVotes.Delegate[] memory _delegates = new IWonderVotes.Delegate[](2); | ||
_delegates[0] = _delegate; | ||
_delegates[1] = _delegate2; | ||
|
||
for (uint256 _i = 0; _i < proposalTypes.length; _i++) { | ||
for (uint256 _j = 0; _j < VOTERS_NUMBER; _j++) { | ||
address _holder = holders[_j]; | ||
vm.prank(_holder); | ||
rabbitToken.delegate(_delegates, proposalTypes[_i]); | ||
} | ||
} | ||
|
||
for (uint256 _i = 0; _i < proposalTypes.length; _i++) { | ||
assertEq(rabbitToken.getVotes(proposer, proposalTypes[_i]), INITIAL_VOTERS_BALANCE * VOTERS_NUMBER / 2); | ||
assertEq(rabbitToken.getVotes(proposer2, proposalTypes[_i]), INITIAL_VOTERS_BALANCE * VOTERS_NUMBER / 2); | ||
|
||
for (uint256 _j = 0; _j < VOTERS_NUMBER; _j++) { | ||
address _holder = holders[_j]; | ||
assertEq(rabbitToken.getVotes(_holder, proposalTypes[_i]), 0); | ||
} | ||
} | ||
} | ||
|
||
function test_ProposeWithDelegatedVotes() public { | ||
address _voter1 = holders[0]; | ||
|
||
vm.prank(proposer); | ||
rabbitToken.delegate(proposer); | ||
|
||
// delegate to proposer | ||
vm.prank(_voter1); | ||
rabbitToken.delegate(proposer); | ||
|
||
address[] memory _targets = new address[](1); | ||
_targets[0] = address(governor); | ||
|
||
uint256[] memory _values = new uint256[](1); | ||
_values[0] = 1; | ||
|
||
bytes[] memory _calldatas = new bytes[](1); | ||
_calldatas[0] = abi.encode(0); | ||
|
||
string memory _description = 'test proposal'; | ||
|
||
// To propose Governor controls the proposal threshold calling getPastVotes, so we need to mine a block to be able to propose | ||
_mineBlock(); | ||
|
||
uint8[] memory _proposalTypes = governor.proposalTypes(); | ||
|
||
vm.startPrank(proposer); | ||
for (uint256 _i = 0; _i < _proposalTypes.length; _i++) { | ||
uint8 _proposalType = _proposalTypes[_i]; | ||
|
||
uint256 _precomputedProposalId = | ||
governor.hashProposal(_proposalType, _targets, _values, _calldatas, keccak256(bytes(_description))); | ||
_expectEmit(address(governor)); | ||
|
||
emit ProposalCreated( | ||
_precomputedProposalId, | ||
_proposalType, | ||
address(proposer), | ||
_targets, | ||
_values, | ||
new string[](1), | ||
_calldatas, | ||
block.number + 1, | ||
block.number + governor.votingPeriod() + 1, | ||
_description | ||
); | ||
governor.propose(_proposalType, _targets, _values, _calldatas, _description); | ||
} | ||
vm.stopPrank(); | ||
} | ||
|
||
function test_AllVotersChangeDelegation() public { | ||
uint8[] memory _proposalTypes = governor.proposalTypes(); | ||
|
||
for (uint256 _i = 0; _i < VOTERS_NUMBER; _i++) { | ||
address _holder = holders[_i]; | ||
vm.prank(_holder); | ||
rabbitToken.delegate(proposer); | ||
} | ||
|
||
for (uint256 _i = 0; _i < VOTERS_NUMBER; _i++) { | ||
address _holder = holders[_i]; | ||
vm.prank(_holder); | ||
rabbitToken.delegate(proposer2); | ||
} | ||
|
||
for (uint8 i = 0; i < _proposalTypes.length; i++) { | ||
assertEq(rabbitToken.getVotes(proposer, _proposalTypes[i]), 0); | ||
assertEq(rabbitToken.getVotes(proposer2, _proposalTypes[i]), INITIAL_VOTERS_BALANCE * VOTERS_NUMBER); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
// solhint-disable no-unused-import | ||
// solhint-disable-next-line no-console | ||
import {console} from 'forge-std/console.sol'; | ||
|
||
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; | ||
|
||
import {IWonderVotes} from 'interfaces/governance/utils/IWonderVotes.sol'; | ||
import {IWonderGovernor} from 'interfaces/governance/IWonderGovernor.sol'; | ||
|
||
import {AliceGovernor} from 'examples/AliceGovernor.sol'; | ||
import {RabbitToken} from 'examples/RabbitToken.sol'; | ||
|
||
import {TestExtended} from '../utils/TestExtended.sol'; | ||
|
||
contract IntegrationBase is TestExtended { | ||
uint256 public constant FORK_BLOCK = 111_361_902; | ||
|
||
uint256 internal _initialBalance = 100_000 ether; | ||
|
||
address public deployer = makeAddr('deployer'); | ||
address public proposer = makeAddr('proposer'); | ||
address public proposer2 = makeAddr('proposer2'); | ||
|
||
address[] public holders; | ||
|
||
IWonderVotes public rabbitToken; | ||
IWonderGovernor public governor; | ||
|
||
uint256 public constant INITIAL_VOTERS_BALANCE = 100_000e18; | ||
uint8 public constant VOTERS_NUMBER = 10; | ||
|
||
function setUp() public virtual { | ||
vm.createSelectFork(vm.rpcUrl('optimism'), FORK_BLOCK); | ||
|
||
// Deploy the governance contracts | ||
vm.startPrank(deployer); | ||
|
||
address tokenAddress = vm.computeCreateAddress(deployer, vm.getNonce(deployer) + 1); | ||
governor = new AliceGovernor(tokenAddress); | ||
rabbitToken = new RabbitToken(AliceGovernor(payable(address(governor)))); | ||
|
||
vm.stopPrank(); | ||
|
||
for (uint256 i = 0; i < VOTERS_NUMBER; i++) { | ||
address holder = makeAddr(string(abi.encodePacked('holder', i))); | ||
holders.push(holder); | ||
deal(tokenAddress, holder, INITIAL_VOTERS_BALANCE); | ||
vm.prank(holder); | ||
|
||
// start tracking votes | ||
rabbitToken.delegate(holder); | ||
} | ||
|
||
_mineBlock(); | ||
} | ||
|
||
event ProposalCreated( | ||
uint256 proposalId, | ||
uint8 proposalType, | ||
address proposer, | ||
address[] targets, | ||
uint256[] values, | ||
string[] signatures, | ||
bytes[] calldatas, | ||
uint256 voteStart, | ||
uint256 voteEnd, | ||
string description | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
import './IntegrationBase.t.sol'; | ||
|
||
import {WonderVotes} from 'contracts/governance/utils/WonderVotes.sol'; | ||
import {WonderGovernor} from 'contracts/governance/WonderGovernor.sol'; | ||
|
||
contract Integration_Propose is IntegrationBase { | ||
function _propose() internal returns (uint256 _proposalId) { | ||
address[] memory _targets = new address[](1); | ||
_targets[0] = address(governor); | ||
|
||
uint256[] memory _values = new uint256[](1); | ||
_values[0] = 1; | ||
|
||
bytes[] memory _calldatas = new bytes[](1); | ||
_calldatas[0] = abi.encode(0); | ||
|
||
string memory _description = 'test proposal'; | ||
|
||
vm.prank(holders[0]); | ||
|
||
// Propose | ||
return governor.propose(0, _targets, _values, _calldatas, _description); | ||
} | ||
|
||
function _vote(uint256 _proposalId, uint256 _forVoters) internal { | ||
for (uint256 _i = 0; _i < VOTERS_NUMBER; _i++) { | ||
address _holder = holders[_i]; | ||
vm.prank(_holder); | ||
|
||
// for 60% , against 40% | ||
uint8 _vote = _forVoters > _i ? 1 : 0; | ||
// Vote | ||
governor.castVote(_proposalId, _vote); | ||
} | ||
} | ||
|
||
function test_ProposalSucceeded() public { | ||
uint256 _proposalId = _propose(); | ||
|
||
_mineBlocks(governor.votingDelay() + 1); | ||
|
||
uint256 _forVoters = VOTERS_NUMBER / 2 + 1; | ||
uint256 _againstVoters = VOTERS_NUMBER - _forVoters; | ||
|
||
_vote(_proposalId, _forVoters); | ||
|
||
(uint256 _id, uint256 _votes, uint256 _forVotes, uint256 _againstVotes, uint256 _abstainVotes) = | ||
AliceGovernor(payable(address(governor))).proposalTracks(_proposalId); | ||
|
||
assertEq(_forVotes, INITIAL_VOTERS_BALANCE * _forVoters); | ||
assertEq(_againstVotes, INITIAL_VOTERS_BALANCE * _againstVoters); | ||
assertEq(_abstainVotes, 0); | ||
assertEq(_votes, INITIAL_VOTERS_BALANCE * VOTERS_NUMBER); | ||
|
||
// End voting period | ||
_mineBlocks(governor.votingPeriod()); | ||
|
||
assertEq(uint256(governor.state(_proposalId)), 4); | ||
} | ||
|
||
function test_ProposalDefeated() public { | ||
uint256 _proposalId = _propose(); | ||
|
||
_mineBlocks(governor.votingDelay() + 1); | ||
|
||
uint256 _againstVoters = VOTERS_NUMBER / 2 + 1; | ||
uint256 _forVoters = VOTERS_NUMBER - _againstVoters; | ||
|
||
_vote(_proposalId, _forVoters); | ||
|
||
(uint256 _id, uint256 _votes, uint256 _forVotes, uint256 _againstVotes, uint256 _abstainVotes) = | ||
AliceGovernor(payable(address(governor))).proposalTracks(_proposalId); | ||
|
||
assertEq(_forVotes, INITIAL_VOTERS_BALANCE * _forVoters); | ||
assertEq(_againstVotes, INITIAL_VOTERS_BALANCE * _againstVoters); | ||
assertEq(_abstainVotes, 0); | ||
assertEq(_votes, INITIAL_VOTERS_BALANCE * VOTERS_NUMBER); | ||
|
||
// End voting period | ||
_mineBlocks(governor.votingPeriod()); | ||
|
||
assertEq(uint256(governor.state(_proposalId)), 3); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.