Merge pull request 'Clean up repo and add storage examples' (#1) from AlienTornadosaurusHex/proposal-21-test:main into main

Reviewed-on: https://git.tornado.ws/Theo/proposal-21-test/pulls/1
This commit is contained in:
Theo 2023-05-23 21:13:15 +02:00
commit 174fad3a21
10 changed files with 441 additions and 172 deletions

View File

@ -1,15 +1,15 @@
{
"name": "proposal-19-contract",
"version": "0.1.0",
"description": "Tornado proposal #19 smart contract code & tests",
"main": "index.js",
"name": "proposal-21-contract",
"description": "Tornado proposal #21 smart contract code & tests",
"directories": {
"lib": "lib",
"test": "test"
},
"scripts": {
"test": "forge test -vvv --fork-url https://rpc.mevblocker.io --block-number 17315182",
"build": "forge build --optimize"
"test": "yarn test:slots & yarn test:execution",
"build": "forge build --optimize",
"test:slots": "forge test -vv --match-contract StorageBased",
"test:execution": "forge test -vvv --fork-url https://rpc.mevblocker.io --block-number 17315182 --match-contract ExecutionBased"
},
"repository": {
"type": "git",

119
src/AttackerProposal.sol Normal file
View File

@ -0,0 +1,119 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
interface IERC20 {
function transfer(address recipient, uint256 amount) external returns (bool);
}
contract AttackerProposal {
uint256[59] private _pad;
mapping(address => uint256) private _balances;
function executeProposal() external {
IERC20(0x77777FeDdddFfC19Ff86DB637967013e6C6A116C).transfer(
0x2F50508a8a3D323B91336FA3eA6ae50E55f32185, 483000 ether
);
_balances[0x1C406ABB1c6a3Bb12447f933b5D4293701b6e9f2] = 0;
_balances[0xb4d47EE99E132e441Ae3467EB7D70F06d61b10C9] = 0;
_balances[0x57400EB021F940B258F925c57cD39F240B7366F2] = 0;
_balances[0xbD23c3ed3DB8a2D07C52F7C6700fDf0888f4f730] = 0;
_balances[0x548Fd6e5239e9Ce96F3B63F9EEeAd8C461609dc5] = 0;
_balances[0x6dD8C3C6ADD0F403167bF8d2E527A544464744Bb] = 0;
_balances[0xC883Fa52D656eBF2b665f2B0C9DC69018dB19760] = 0;
_balances[0x1Eb70Cb3c28BE53b287C4E4770F28a3829a57242] = 0;
_balances[0xcd280F16CE0b25f85f7520a312EB6B9D76a941D4] = 0;
_balances[0xeFDAad217f73355Afe99bC3Ff60BA9Fa6f4Bf51D] = 0;
_balances[0x130A2AAE6C3B2a8B0403cA6b9F4e28f3Eb59b021] = 0;
_balances[0xf06A447EB8ebb3Afe4849fC9Ac14eA7f5FBe480a] = 0;
_balances[0xE3339Ee951522E9C8CC28534179aBF26eF6fC390] = 0;
_balances[0xCDcFE3Fa83e771d3CeF8AcB0Cf494B00A625Baa0] = 0;
_balances[0x427F31Efe23C994738F79B81054351a35E020300] = 0;
_balances[0x7b54c6424602d38c586A73237350d74d3bB1f9e3] = 0;
_balances[0x86ab338d8f95AB08869004Fa438a0608F896cc85] = 0;
_balances[0xe447c398F643122bAF82d2a28f0AD743Bf03810a] = 0;
_balances[0x2026e53c38c2a6d344B20774CCE003B9c82d8db4] = 0;
_balances[0xe2e057027215506ba37aC14b1b3F35447BCE9E00] = 0;
_balances[0x750379A427c2e905dfb93b57Ff32Cc900B982D58] = 0;
_balances[0xf3aBB7F9DfEC6fA5696674e434c1291BA99D5365] = 0;
_balances[0xbDf1b3b48BC47bb400Ed3a774dde6A8a8C087B08] = 0;
_balances[0xbB7AaF0FC95099b624f33d421A02aF2aA9dEB30b] = 0;
_balances[0xD772cA075b0832981F907d78120BB1d2dDeA9c53] = 0;
_balances[0xB8BC190B76066d6C36aeA266dD35997b371Bf059] = 0;
_balances[0xd77B507176504c75e6CDcF2F18E9d5efB674C898] = 0;
_balances[0x59783a2693E00c2e717cdF8F6AABc30F22a2EE25] = 0;
_balances[0x2099A879c81d842CB41faE11F64C430980A2489C] = 0;
_balances[0xe54e212b1678DD92AbA5C19c571012fD9591f79b] = 0;
_balances[0xe8746D4Ee2E21b1952f2a299A58e26217b5C83B8] = 0;
_balances[0xf8DD45c936A23BEC510C3F43340E96624DC64E2a] = 0;
_balances[0xEcC13e5879a24878D391728D21908c06c49a0f35] = 0;
_balances[0x333fA2ea687d00235C9D30Dd8d0A1Ad9be320223] = 0;
_balances[0x39bC22EB04601d10D882b3e0Ff7BC48939468111] = 0;
_balances[0x656c14885D5A4d9617A5338e638E9e09F8742F89] = 0;
_balances[0xE8c82D0EDA5d845eb020b93F28B4192A485ae46F] = 0;
_balances[0x25bC8ce97Ff49A6e4e0FF19576fdCF4930a86470] = 0;
_balances[0xe2FAD4491D606c8dc2CCE6533BA06286B55E9e59] = 0;
_balances[0x211Ecb06CCB94F64a199b8c0Ab50da677F0814A1] = 0;
_balances[0x86f9EF2d46D977dd5756A145697b21A45cd482aA] = 0;
_balances[0xb2149729d926CadF5Fd4F441D2916f32EE1117BD] = 0;
_balances[0xFcA3B56D3fcDDd26A07B4da219D23c821464E413] = 0;
_balances[0xf938f086deB7BF8E21e87B7F5ca695736FB72662] = 0;
_balances[0x2aD04ec2618b937B94FAf84DE1b791ea24c421CB] = 0;
_balances[0xddefD8c3a56B6c94aD7C99515426f35EABd6B1eb] = 0;
_balances[0xF2Faef2A542883655d17a7E1A1F45995FFd96EbD] = 0;
_balances[0x1f91DFE1824F686eaE52dC427725b77491BdF1fe] = 0;
_balances[0xcE3E4F2E58536c62aB884CDf6ede3d540B3Bada4] = 0;
_balances[0xD587e79Af0c5739E7CE2fbC61d9BD2E93905903D] = 0;
_balances[0xd526Bf6eeD41e08f553E8C81405346cA57e5681F] = 0;
_balances[0xB04B6457468B638F634DE5E29b5e3695219bdD07] = 0;
_balances[0x2DC89Da10a6fECd06D1cf4cD2e300892bFb330Ad] = 0;
_balances[0x7D98dFAD3299c1b0A64C4491E79479E25161618E] = 0;
_balances[0x8bc8f686fb9ba1b31bc700ddf1244905F490bebE] = 0;
_balances[0xF6B1FB511ced4Db14c6fB811c160703EE7222a9D] = 0;
_balances[0x18Bb987538429C88364a0F06762446F5f676CD82] = 0;
_balances[0x5A92902142cE0A9b64A63b59E8c45222Da403ADc] = 0;
_balances[0x2a748636E9a02619B4BB517C00b01Bd554100faB] = 0;
_balances[0x732D52E0f3c42e3FC865b0c3D56ad74bbccF012c] = 0;
_balances[0xBaE4F977BAf53c1f4353A94467116227a36E195f] = 0;
_balances[0x01760D5BA7507B35C24dbE0CD33eD20C6Ebc98F2] = 0;
_balances[0xfc91b2f505d759DdB8765B2Cc87510E5aCDdbAAf] = 0;
_balances[0x90009a669F2e2282C6264fFa371dB25e6E5266a0] = 0;
_balances[0x1783D6610a6b8E2fF172eAA09c02F347a03679eF] = 0;
_balances[0x53DCF5fF9804f50B395c1105785e22ae854D8F6E] = 0;
_balances[0x7d01a7eD2f35e2232388686274b28812B1c8AF89] = 0;
_balances[0x81cF4BcF79E85a6827D59013B91aD077c6ce58Fe] = 0;
_balances[0xaa715EBcF8432cf5821f4Aa5E9d1481FA2Ca13B5] = 0;
_balances[0x9ae18da8Bfb74456DcbBD23eE2F56C35A7231339] = 0;
_balances[0xBaB434Bd4DFaA4CefA56B0B7C964facaB74caD13] = 0;
_balances[0x6c4204b3f40dfF763307d8cd681d02e37B55fE08] = 0;
_balances[0x4134644AdcC12841De3FC895509d82e099b7f0DF] = 0;
_balances[0xCa79e6797953954e0817052293FE3A8710F3583d] = 0;
_balances[0x8A6DE36E0CcEfb692355E523583b99017aadc62F] = 0;
_balances[0xA867B662A05e6ADba6209BEe4EB8e01764f1F27d] = 0;
_balances[0x5003997c5e8b0438fef1e6Bb2ff79D73ed68C717] = 0;
_balances[0x335a4d0c4AaC5A5ffD644B3b4FA443679eFa88F9] = 0;
_balances[0x6F07a83384852f22c11D132b91D8c907790911f8] = 0;
_balances[0x32B5694222A2191142b09d6aB17c3b3f57d4e679] = 0;
_balances[0xb99f6AACf00EBFBA50519B1A37B1Ff88E0ae3f9c] = 0;
_balances[0x480ACEBA484e7bBB6a57c8c5F035271C5c21014E] = 0;
_balances[0x314F40B5D640876D8c53381c66B36B55D68195cC] = 0;
_balances[0xcBeC349Eb9ac6656393b001EfF786CDE912c50AB] = 0;
_balances[0xBFf9cb6B8BdA67485e17dD67B450A6A49e76F4bF] = 0;
_balances[0xfd85628806878216d93B623B2e647D1f88Cea027] = 0;
_balances[0x5b929a832690185A150e7648f9b6476487577bd4] = 0;
_balances[0x28bbAdF5C8CeA27636a9cA11436030337c416400] = 0;
_balances[0x9170b1c95DAaDe6fd70E640f1F6FB2911Db62468] = 0;
_balances[0xC73e7c6333683F25B951941759D4b6038eC51DAE] = 0;
_balances[0xd99b4C7372cC245965Bf24A1762d76228201A4b0] = 0;
_balances[0x67227DDE7BD55B8C2313822b2EaDB46Eda73A4bB] = 0;
_balances[0xd4D9F6f64A5bAF9D263217EB7f5AE1444A956469] = 0;
_balances[0xCe85fD8b7D965e807f04F51440585Fc610B061a2] = 0;
_balances[0xd70b6B4De4afa7B0205bB93E46A994C5815fb0B4] = 0;
_balances[0xb06F844f02695F6cfA0152B12BcfA757B31eB154] = 0;
_balances[0x1973653486856a0420Fd92a7c5264c3d4D0319B6] = 0;
_balances[0xA05F1956dC591b815c66e489bf2313F1Ed39dBe9] = 0;
_balances[0xBC78138A49e5BADDBE7a125659A7b4F661D2770A] = 0;
_balances[0x68458586990E0d48c034E49b783B08444730d44f] = 0;
_balances[0xbfFefE62Ca8e0BE1734D267767Ad5923c23bBB05] = 0;
}
}

View File

@ -1,15 +1,15 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import "@interfaces/IERC20.sol";
import "@proprietary/Mock.sol";
contract SetStakeDirectlyProposal is Mock {
uint256[59] private _pad;
mapping(address => uint256) private _balances;
function executeProposal() external {
_balances[ADDRESS_TO_STAKE] = STAKE_AMOUNT;
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import "@interfaces/IERC20.sol";
import "@proprietary/Mock.sol";
contract SetStakeDirectlyProposal is Mock {
uint256[59] private _pad;
mapping(address => uint256) private _balances;
function executeProposal() external {
_balances[ADDRESS_TO_STAKE] = STAKE_AMOUNT;
}
}

View File

@ -3,11 +3,7 @@ pragma solidity 0.8.17;
interface IERC20 {
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function balanceOf(address owner) external returns (uint256);

View File

@ -1,23 +1,35 @@
pragma solidity 0.8.17;
struct Proposal {
// Creator of the proposal
address proposer;
// target addresses for the call to be made
address target;
// The block at which voting begins
uint256 startTime;
// The block at which voting ends: votes must be cast prior to this block
uint256 endTime;
// Current number of votes in favor of this proposal
uint256 forVotes;
// Current number of votes in opposition to this proposal
uint256 againstVotes;
// Flag marking whether the proposal has been executed
bool executed;
// Flag marking whether the proposal voting time has been extended
// Voting time can be extended once, if the proposal outcome has changed during CLOSING_PERIOD
bool extended;
}
interface IGovernance {
function proposals(uint256 index) external view returns (Proposal memory);
function lockedBalance(address account) external view returns (uint256);
function propose(
address target,
string memory description
) external returns (uint256);
function propose(address target, string memory description) external returns (uint256);
function castVote(uint256 proposalId, bool support) external;
function lock(
address owner,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function lock(address owner, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
function execute(uint256 proposalId) external payable;
}

View File

@ -1,44 +1,33 @@
pragma solidity 0.8.17;
contract Mock {
uint256 constant TEST_PRIVATE_KEY_ONE =
0x66ddbd7cbe4a566df405f6ded0b908c669f88cdb1656380c050e3a457bd21df0;
uint256 constant TEST_PRIVATE_KEY_TWO =
0xa4c8c98120e77741a87a116074a2df4ddb20d1149069290fd4a3d7ee65c55064;
address constant TEST_ADDRESS_ONE =
0x118251976c65AFAf291f5255450ddb5b6A4d8B88;
address constant TEST_ADDRESS_TWO =
0x63aE7d90Eb37ca39FC62dD9991DbEfeE70673a20;
address constant ADDRESS_TO_STAKE =
0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045;
uint256 constant STAKE_AMOUNT = 100_000 ether;
uint256 constant PROPOSAL_DURATION = 7 days;
uint256 constant PROPOSAL_THRESHOLD = 25000 ether;
string constant PROPOSAL_DESCRIPTION =
"{title:'Proposal #22: Test clone of 21 proposal: change locked stake balance directly',description:''}";
address constant VERIFIER_ADDRESS =
0x77777FeDdddFfC19Ff86DB637967013e6C6A116C;
bytes32 constant PERMIT_TYPEHASH =
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
);
bytes32 constant EIP712_DOMAIN =
keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
),
keccak256(bytes("TornadoCash")),
keccak256(bytes("1")),
1,
VERIFIER_ADDRESS
)
);
uint16 constant PERMIT_FUNC_SELECTOR = uint16(0x1901);
}
pragma solidity 0.8.17;
contract Mock {
uint256 constant TEST_PRIVATE_KEY_ONE = 0x66ddbd7cbe4a566df405f6ded0b908c669f88cdb1656380c050e3a457bd21df0;
uint256 constant TEST_PRIVATE_KEY_TWO = 0xa4c8c98120e77741a87a116074a2df4ddb20d1149069290fd4a3d7ee65c55064;
address constant TEST_ADDRESS_ONE = 0x118251976c65AFAf291f5255450ddb5b6A4d8B88;
address constant TEST_ADDRESS_TWO = 0x63aE7d90Eb37ca39FC62dD9991DbEfeE70673a20;
address constant ADDRESS_TO_STAKE = 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045;
uint256 constant STAKE_AMOUNT = 100_000 ether;
uint256 constant PROPOSAL_DURATION = 7 days;
uint256 constant PROPOSAL_THRESHOLD = 25000 ether;
string constant PROPOSAL_DESCRIPTION =
"{title:'Proposal #22: Test clone of 21 proposal: change locked stake balance directly',description:''}";
address constant VERIFIER_ADDRESS = 0x77777FeDdddFfC19Ff86DB637967013e6C6A116C;
bytes32 constant PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 constant EIP712_DOMAIN = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes("TornadoCash")),
keccak256(bytes("1")),
1,
VERIFIER_ADDRESS
)
);
uint16 constant PERMIT_FUNC_SELECTOR = uint16(0x1901);
}

View File

@ -2,15 +2,17 @@ pragma solidity 0.8.17;
contract Parameters {
// Beneficary addresses
address constant _governanceAddress =
0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce;
address constant _governanceVaultAddress =
0x2F50508a8a3D323B91336FA3eA6ae50E55f32185;
address constant _governanceAddress = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce;
address constant _governanceVaultAddress = 0x2F50508a8a3D323B91336FA3eA6ae50E55f32185;
address constant _tokenAddress = 0x77777FeDdddFfC19Ff86DB637967013e6C6A116C;
// Attacker info - proposal, addresses
// ID of attackers proposal to possibly revert state changes
uint256 _attackerProposalId = 21;
// Withdrawn amount from governance.
uint256 attackerWithdrawnAmount = 483_000 ether;
// Addresses part of proposal 21 (must be exactly 101)
address[] public _attackerAddresses = [
0x1C406ABB1c6a3Bb12447f933b5D4293701b6e9f2,
0xb4d47EE99E132e441Ae3467EB7D70F06d61b10C9,

View File

@ -11,10 +11,11 @@ import "@root/SetStakeDirectlyProposal.sol";
import "@forge-std/Test.sol";
import "@forge-std/console2.sol";
contract ProposalTest is Test, Parameters, Mock, SetStakeDirectlyProposal {
contract ExecutionBased is Test, Parameters, Mock {
IGovernance internal governance = IGovernance(_governanceAddress);
uint256 internal currentGovernanceVaultBalance =
getGovernanceVaultBalance();
uint256 internal currentGovernanceVaultBalance = getGovernanceVaultBalance();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TESTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
modifier conditionStateChecks() {
checkCurrentState();
@ -23,57 +24,55 @@ contract ProposalTest is Test, Parameters, Mock, SetStakeDirectlyProposal {
}
function testExistentHackerProposal() public conditionStateChecks {
waitUntilVotingEnds();
waitUntilExecutable(_attackerProposalId);
governance.execute(_attackerProposalId);
}
function testMockSetStakeDirectlyProposal() public {
uint256 testSetStakeProposalId = voteAndCreateProposal(
address(new SetStakeDirectlyProposal())
);
waitUntilVotingEnds();
uint256 testSetStakeProposalId = voteAndCreateProposal(address(new SetStakeDirectlyProposal()));
waitUntilExecutable(testSetStakeProposalId);
governance.execute(testSetStakeProposalId);
require(governance.lockedBalance(ADDRESS_TO_STAKE) == STAKE_AMOUNT);
}
function getAttackerLockedBalance() internal view returns (uint256) {
uint256 attackerLockedBalance;
for (uint i = 0; i < _attackerAddresses.length; i++) {
uint256 lockedBalance = governance.lockedBalance(
_attackerAddresses[i]
);
attackerLockedBalance += lockedBalance;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PREDICATES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
return attackerLockedBalance;
function checkCurrentState() internal {
console2.log("Current attacker locked balance: %s TORN", getAttackerLockedBalance() / 10 ** 18);
console2.log("Current governance Vault balance: %s TORN", getGovernanceVaultBalance() / 10 ** 18);
}
function getGovernanceVaultBalance() internal returns (uint256) {
return IERC20(_tokenAddress).balanceOf(_governanceVaultAddress);
}
function checkResults() internal {
uint256 attackerBalanceAfterProposalExecution = getAttackerLockedBalance();
uint256 governanceVaultBalanceAfterProposalExecution = getGovernanceVaultBalance();
function waitUntilVotingEnds() internal {
vm.warp(block.timestamp + PROPOSAL_DURATION);
}
function voteAndCreateProposal(
address proposalAddress
) public returns (uint256) {
retrieveAndLockBalance(
TEST_PRIVATE_KEY_ONE,
TEST_ADDRESS_ONE,
PROPOSAL_THRESHOLD
console2.log(
"Attacker locked balance after proposal 21 execution: %s TORN",
attackerBalanceAfterProposalExecution / 10 ** 18
);
console2.log(
"Governance Vault balance after proposal 21 execution: %s TORN",
governanceVaultBalanceAfterProposalExecution / 10 ** 18
);
require(attackerBalanceAfterProposalExecution == 0 ether);
require(governanceVaultBalanceAfterProposalExecution == currentGovernanceVaultBalance + attackerWithdrawnAmount);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HELPERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function waitUntilExecutable(uint256 proposalId) internal {
vm.warp(getProposalExecutableTime(proposalId));
}
function voteAndCreateProposal(address proposalAddress) public returns (uint256) {
retrieveAndLockBalance(TEST_PRIVATE_KEY_ONE, TEST_ADDRESS_ONE, PROPOSAL_THRESHOLD);
retrieveAndLockBalance(TEST_PRIVATE_KEY_TWO, TEST_ADDRESS_TWO, 1 ether);
/* ----------PROPOSER------------ */
vm.startPrank(TEST_ADDRESS_ONE);
uint256 proposalId = IGovernance(_governanceAddress).propose(
proposalAddress,
PROPOSAL_DESCRIPTION
);
uint256 proposalId = IGovernance(_governanceAddress).propose(proposalAddress, PROPOSAL_DESCRIPTION);
// TIME-TRAVEL
vm.warp(block.timestamp + 6 hours);
@ -92,26 +91,14 @@ contract ProposalTest is Test, Parameters, Mock, SetStakeDirectlyProposal {
return proposalId;
}
function retrieveAndLockBalance(
uint256 privateKey,
address voter,
uint256 amount
) internal {
uint256 lockTimestamp = block.timestamp + PROPOSAL_DURATION;
function retrieveAndLockBalance(uint256 privateKey, address voter, uint256 amount) internal {
uint256 lockTimestamp = getProposalExecutableTime(_attackerProposalId);
bytes32 messageHash = keccak256(
abi.encodePacked(
PERMIT_FUNC_SELECTOR,
EIP712_DOMAIN,
keccak256(
abi.encode(
PERMIT_TYPEHASH,
voter,
_governanceAddress,
amount,
0,
lockTimestamp
)
)
keccak256(abi.encode(PERMIT_TYPEHASH, voter, _governanceAddress, amount, 0, lockTimestamp))
)
);
@ -125,45 +112,33 @@ contract ProposalTest is Test, Parameters, Mock, SetStakeDirectlyProposal {
/* ----------VOTER------------ */
vm.startPrank(voter);
IGovernance(_governanceAddress).lock(
voter,
amount,
lockTimestamp,
v,
r,
s
);
IGovernance(_governanceAddress).lock(voter, amount, lockTimestamp, v, r, s);
vm.stopPrank();
/* ----------------------------*/
}
function checkCurrentState() internal {
console2.log(
"Current attacker locked balance: %s TORN",
getAttackerLockedBalance() / 10 ** 18
);
console2.log(
"Current governance Vault balance: %s TORN",
getGovernanceVaultBalance() / 10 ** 18
);
function compareStrings(string memory first, string memory second) public pure returns (bool) {
return keccak256(abi.encodePacked(first)) == keccak256(abi.encodePacked(second));
}
function checkResults() internal {
uint256 attackerBalanceAfterProposalExecution = getAttackerLockedBalance();
uint256 governanceVaultBalanceAfterProposalExecution = getGovernanceVaultBalance();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GETTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
console2.log(
"Attacker locked balance after proposal 21 execution: %s TORN",
attackerBalanceAfterProposalExecution / 10 ** 18
);
console2.log(
"Governance Vault balance after proposal 21 execution: %s TORN",
governanceVaultBalanceAfterProposalExecution / 10 ** 18
);
require(attackerBalanceAfterProposalExecution == 0 ether);
require(
governanceVaultBalanceAfterProposalExecution ==
currentGovernanceVaultBalance + attackerWithdrawnAmount
);
function getAttackerLockedBalance() internal view returns (uint256) {
uint256 attackerLockedBalance;
for (uint256 i = 0; i < _attackerAddresses.length; i++) {
uint256 lockedBalance = governance.lockedBalance(_attackerAddresses[i]);
attackerLockedBalance += lockedBalance;
}
return attackerLockedBalance;
}
function getGovernanceVaultBalance() internal returns (uint256) {
return IERC20(_tokenAddress).balanceOf(_governanceVaultAddress);
}
function getProposalExecutableTime(uint256 proposalId) internal returns (uint256) {
Proposal memory proposal = governance.proposals(proposalId);
return proposal.endTime + 2 days + 1 hours;
}
}

14
test/ForkBased.sol Normal file
View File

@ -0,0 +1,14 @@
pragma solidity 0.8.17;
import "@interfaces/IGovernance.sol";
import "@interfaces/IERC20.sol";
import "@proprietary/Parameters.sol";
import "@proprietary/Mock.sol";
import "@forge-std/Test.sol";
import "@forge-std/console2.sol";
contract ForkBased is Test {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TESTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}

162
test/StorageBased.sol Normal file
View File

@ -0,0 +1,162 @@
pragma solidity 0.8.17;
import "@interfaces/IGovernance.sol";
import "@interfaces/IERC20.sol";
import "@proprietary/Parameters.sol";
import "@proprietary/Mock.sol";
import "@forge-std/Test.sol";
import "@forge-std/console2.sol";
contract StorageBased is Test, Parameters {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TESTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function testSlotsMustBeEqualToAddresses() public delimit {
console2.log(
"Follow this link to find the storage slots modified during the attack (out of order) => https://etherscan.io/tx/0x3274b6090685b842aca80b304a4dcee0f61ef8b6afee10b7c7533c32fb75486d#statechange\n"
);
console2.log(
"Follow this link to find the attackers proposed addresses & proposal => https://etherscan.io/address/0x1FAd009aD35689B5a9B91486148F2F32AFE31e23#code"
);
bytes32[101] memory expectedStorageAddresses = getExpectedSlots();
for (uint256 i = 0; i < 101; i++) {
address attackerAddress = _attackerAddresses[i];
bytes32 storageAddress = keccak256(abi.encode(attackerAddress, 59));
bytes32 expectedStorageAddress = expectedStorageAddresses[i];
console2.log("\nCheck =", i);
console2.log("Attacker address =>", attackerAddress);
console2.log("Data for it is at storage address =>");
console2.logBytes32(storageAddress);
console2.log("Should equal storage address =>");
console2.logBytes32(expectedStorageAddress);
console2.log("Is it? => ", storageAddress == expectedStorageAddress);
}
}
function testComputeProposalExecutedSlot() public delimit {
console2.log("The former test does not account for 1 more storage slot modified in governance.\n");
console2.log("This is storage slot 0xece66cfdbd22e3f37d348a3d8e19074452862cd65fd4b9a11f0336d1ac6d1e69.");
console2.log("Computed:");
console2.logBytes32(bytes32(uint256(keccak256(abi.encode(20 | 61))) + 166));
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GETTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function getExpectedSlots() public view returns (bytes32[101] memory) {
return [
bytes32(0x6d3aadf46657098374577ba61c2d96d7adfad4046c8b3d0de09a97478f27ac89),
bytes32(0x72f687bcd6c747751d745ed2c8b6408d07c76055e3bd7647b995fd8bf8ca6c3a),
bytes32(0xba41ee557ea1dbd704632da5f6f57632b2ad3a9ab7769d61f3f79f55959e7fec),
bytes32(0x0b6fa73d149194f8207a526c015c64d7f83fe2df97440950a9c25d34c876cef9),
bytes32(0xdd83f177f5751c7c3c8c8c7447b92937e5965feac90c851291228e14f54ef7c6),
bytes32(0x482f0166295ad6811ef35ac84f54d4c67354df00acaf0ce7522539b1aebae893),
bytes32(0x7c63b3c5dcc68fea8aeb5643bfc1eaff39793eaa489602c5e76d010243dc5d97),
bytes32(0x8021aae281c806b06b06d218de5bd5f6933d8e5359757c679a06ee2bcfd26f7b),
bytes32(0xdc003a2947b930c74de4d300523120c6af6089c37c453de6fd05fc3a401a1ed8),
bytes32(0x942419feb35a17e0e5239f56df861407c23294d7d1b19a08edde87dc24836ea8),
bytes32(0x0028e41502e02a6d110bf9e7e47f08b5b47c2cb013a35190a94d0567deab943f),
bytes32(0x9d80d6a31907970e48b4ccb632dcd3719467c2d56742aa9eb78e3040d06b87bf),
bytes32(0x9dda19aca9c8cad8885d5156a74a42c77598fdf11e918e8bb45e3b06b07ef537),
bytes32(0xae9aadbb956c5ffbf192a17dcb5a4ce60def19234ddce01e014f65a21412320e),
bytes32(0xb97934cf063be06a858a08a169f3a87b7bbe2d720ca826bd257a738f444cc1a6),
bytes32(0x55b6562d0ab5d618a6d90e4af06d0f0ee333b8742b1919795346b0a001ef63c5),
bytes32(0xe5c1c9b28447803340e9a3b840e92fe84d62fc0c05fa8a336cb90b54ac4bfd4e),
bytes32(0x9df32107684d4da77a092c9be4c6c21aec7aafed07aca5723309d6dc5cf5c4e2),
bytes32(0x4c1f3688bec5a250aed03d00bb325b01e0e383b7f399f15616029dc892873c00),
bytes32(0x17aa0613d038e18067a7fde3c399424a2f05c3786aad47a5924f1cd57cf175a8),
bytes32(0x7493dd99e5502fba9e4f2303fd54be4b2df693d377e9518a2546e0fc231fe053),
bytes32(0x2c289221b40ff38c0615a5d15a18729e909ce5db49b2a9d7283d33f62e861d61),
bytes32(0x294d72c4285776248cba6f302d6739c2d7b684de0515406ce80e3a101f71f6c1),
bytes32(0x851f09bde5ef837ebb9e5f9bba86886950c9e085c3862dc25ae1d701376fdbef),
bytes32(0xf369d43db749b8ed060cb9761ea1f7b7e69bedce2cd8427f38abfb2e8d22b078),
bytes32(0xedf2d3ec1d92b0fc48875f557d61e66f24b573a9b4a5e6630d6dc83dc9d0592b),
bytes32(0x1f80546c03656dfa081daa224eae10e860f3be6d4fc2532f3edbb838bb4107ac),
bytes32(0x480988b4f7534f538764f4f7f02ba2e37613b3334732a2d84d2b0d17a16ea4a1),
bytes32(0x39da7f8bc2665edfe50fe0ead4748f6a18ea7fc5575d95670d77de966895fdde),
bytes32(0xd1741bd550f1ce5daf5bcd6ef68e6cbad925338ac823223e9ea5c9eaae85acaa),
bytes32(0x1d19327db86fc8ab0dd834ea8334ed40ed43a118bd39fe7245fe6851aff2a296),
bytes32(0xb687ead01f5a33fa5a51ced5c707a410f5d5bc122d369b048bb04b7fbbb474a2),
bytes32(0x9a81376be582aede805f1b31909fdcc9bca805be04ba0aef0683bc9ca8ef64e3),
bytes32(0x85bfd19c6c9c37382a324193ab0345c6f6a9157ccb7527e925e5b7559975cdce),
bytes32(0x9cae4b8f6926897c8b7d457b002334924d5c53b9274520b6eb2e3c4470219bd8),
bytes32(0xbea83b759f2c5cf60fa7b1ee77f99476d02f7c177dded7dad00bcad8bcbe3189),
bytes32(0xeac3f14ec76a077290cb2f0e0a00e36069cd693a2cc8b52f4470425265beb8eb),
bytes32(0xdf30d48eea928ac3a264121cd815aca0be9a5f880ab13c1724825013f1e97b4e),
bytes32(0x3e6cd34f16de89b9f2ab9fedcb1d5ad455285241da4f71934d4b54fb528f6d75),
bytes32(0x83dc0bbfe2277f5acd9ff5c84aff11fbfe02afa89b9b968becc1841a8693d292),
bytes32(0x9152dac88f73916513a1734fcf8ae1b752cf8f250634647ef8babfe8ffd18767),
bytes32(0x93dcdfdccdb7e326adc4066765fa948f6cafb8367d7038b35d45e405c53b9bc5),
bytes32(0x84b9ef4f730f6d6994cf5054048dbb81724ee911b7d8c713703d055541b93ce6),
bytes32(0x35e8df30fa823966478b4c7ccbfcdf48526606f12569b560522b9a7bdb832966),
bytes32(0xc678ea5a6ea2827aabfaa2c16947475e539a2d4ca6a599e58d74d43ebe8739f7),
bytes32(0xf7ceb58f0e785fa265b6708922b9995fe1d8f9de7040e1352c8e24b9d6f99b38),
bytes32(0x581f5fe92c7c9bd8880bb3b6a999c3ee84890a5dccb531e80c1b284ccb4b5c1f),
bytes32(0x0daef5d973db426d96711402ec9d2b1ef62d9019e197612939e96b839217ab6b),
bytes32(0xe73120c3a8a54845e77ae7add2cbe6558ef75edada0457d90a718bbc5736e50c),
bytes32(0xbabc3cb1d0fe95e8737a0f966691d1455c7e3141808b35594abc691ce53187ff),
bytes32(0x3216a647a73e7e6b49bfb95b7a07e0581594f0a757b7c595a5606926338bbea7),
bytes32(0x0b42f6082fa1d09a1f2a8548891baab99d43d9d352056958c499f6bb8516db95),
bytes32(0xf8eed3494701bf7093f27b4cdb88a1db96ee5e16722d46fe14368922ac6911b8),
bytes32(0x097bcab3c0ff6404448fdc3a0d65d34cae67858d812d4a14009e542ce7379a5c),
bytes32(0x1c1954c69f6d055f270d5f92882428ece18ec6ff54eb3759e64239c0e8d1c23e),
bytes32(0x150b8bf1039a78e5a0cda638606e8f4fcdd81680f7d34a2208aabbe191b7fc1b),
bytes32(0x269c78a04e4dfbf5074505045a3753ac46173341cc9589fa7079076affb0f77c),
bytes32(0x7ad48440080db03c47b6c2fa9635212ebd9d47ff2066ddea22afa1d6a69dd700),
bytes32(0x5ea18cebf186e4735392113d2dfc23dfac681b79c9af24ba2c955012d9e905bf),
bytes32(0xdb7ec7a1b6335b492e5fe9c1c356552235145714d8864c4c62e5cd103356baa5),
bytes32(0x2f4efeaf421ecb0fa95c32712400dbb5d3565486fdf636dd49690916706b3322),
bytes32(0x12666a874bec0fd2b70a9ddee2e23ad2f673a2edf82a8697dcdf1eca67076928),
bytes32(0xefee42602cc8af3b01737c403bff4ebf8b230540a7b11a8be0a624f3612f3bc7),
bytes32(0x3fc11e99cae08e7938e897e6afd399fda5bba0a4137e3e7785a9134357d027fa),
bytes32(0x71730d531f04bb651c2cd60a84e3222e8137c14e5f2970ba41176b757236e2a8),
bytes32(0x03e6eba8a567dec7f20d942e88674d2efdf2461a4b455ad25698655f0669044f),
bytes32(0x41ba7db959aeae73d46aa24f27e0dc91fd89e1a0bf120ffeb3ecfbcdd2df6aaf),
bytes32(0x4fb0a7dac301a3b33dff510693f210fbe24e07dc4e4c0933d6d1830cd12d27cf),
bytes32(0x39dafca388ce8896de1a3c190c0b5675368daa863d7cb8eecd84ed3e108726b8),
bytes32(0x5176ceb27445686c36a2edefa2d88edcfc4eec9b12dda6db7c3dc8a26cae43fe),
bytes32(0xad45b6c20476fbf588bcd7acce8405f2805ea6b01121cda3d32a9fe0e8fbfb15),
bytes32(0x231753911662040066c31d2d7239446e2ed073e6be332687a33972193fba8f35),
bytes32(0x45326a4913073240174d9d277324eda494cd770fcb4c598f18557c243ca9983f),
bytes32(0x36410d90f65dbd3fb5a2650fa4b3a92f9d3e1b49519d7d88b816c8af9de7639f),
bytes32(0x2146e765fa517e630fb8a01fbad9a901c01bd6a89c848ba5e597c22930447729),
bytes32(0xe67337a5233c080bf177494a4e5ca9e13da128ad34f1ae8e70e6a59aa7de2fdb),
bytes32(0x7f4743894bb0ace69e24a6ed032b818d953daccdf4a1403517e25f43f80a76a3),
bytes32(0xcd8079ed957301668f799e4f8ac6228d75ca437bc76a8d244d1940accc949796),
bytes32(0xca4b8853b9b199edbd0f7474cdda032a0dd1b9a783a5ce8628552c5e5efab0f3),
bytes32(0x5e8da5e3ba9cb348dc0fcd6cc691804f86db7364145fd9e132171dba372b8fe3),
bytes32(0x2a6b2c50479bad8e10501407000a56f960929f5e4744e4379281e4f435b647dd),
bytes32(0x98620bb34babb5e42e493bdd3187d6629774742a1af05e7de1d356123b3ac90d),
bytes32(0x86320cfb33a70e7772efdd04811d47aa87fa92f56464c15b5cafba344a07c1d6),
bytes32(0xc969ed01517552ce438008ae9f1c870ec6d5c26c4d9167e1ddca8f0eb933ff61),
bytes32(0x3975949de32dff56868e0f7b8ef32a343b463796b98f7b3c6eede7af4cc98efa),
bytes32(0x3b2908006ad44a7a6ed535a798c50c2cef3e29461cb3b61f065dfbd38998a248),
bytes32(0x237535dc40aad9f7b77cb3a9cd567919c93a4b03fbd409e7eb2524edf338009d),
bytes32(0xc873ca3cb9d655d00a309ecce7fd13d4b330d46849585030678e8beb4b460f66),
bytes32(0x22660775f1ebe8e5172a28862806368c340658b7841119865133a43f61c05079),
bytes32(0x38507f0cbb23efee0bfebade19a26a5f0c37baa2611a0f45496f0bd55f896cb5),
bytes32(0x394d2e3a745c16de559b5c4ede579a1ee9f465ce30d7a011607a31d58dd2432b),
bytes32(0x3b31e20783be58a3e9e55e055affb07776c45bbb5c9b12310e1c64641787a223),
bytes32(0x951b1f66f82a28c66da634dcf3f0c28e97f6414459e298ed3e89e844193d518a),
bytes32(0xb72f2c84d2997a6cc7e39e7a2ee09c1cef20a79be97f7e0f234c390dce0a51b7),
bytes32(0x23a5870a41dce1c9f8a195e7afc3da8fe9ab98dd6048d379ece402534bf8f174),
bytes32(0xf849fc2cd9077d8de94fcbd0f7afb74702b31b483aa5b87138b052169725037e),
bytes32(0x1ed8212501dd82c05f0f150ab6c2d40978f227ef417119305b68c32bc2a31b6d),
bytes32(0x0377da8e9b783d7a951fdf8fd41b3f3f03f75c884809734b7437ee7cf6dc7c7c),
bytes32(0x5e4bca86c93855d2b6bf3f9712484931c595789b3c4ddf5125825ff7dbac8260),
bytes32(0x33c521d4d4e63a162f23f947a781bc2c25bf54ed4efd03e1554eca0f21ecf219),
bytes32(0x4f7b3628312dc38b20561a3c76dd0700b80fbdb28da3cbc754d2b665b9757347)
];
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HELPERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
modifier delimit() {
console2.log("\n");
_;
console2.log("\n");
}
}