commit 729686df47861db2598016e36e46430e0c456d01 Author: Theo Date: Tue May 23 00:00:06 2023 +0300 Init diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7cc88f0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sol linguist-language=Solidity \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf0b572 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +out +cache \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e977ca2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "lib/forge-std"] + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std + branch = v1.5.5 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7c8bbb6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "solidity.compileUsingRemoteVersion": "v0.8.17+commit.8df45f5f", + "solidity.defaultCompiler": "remote" +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..2bb544c --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +## Requirements + +- Foundryup ([Windows](https://github.com/altugbakan/foundryup-windows), [Linux](https://book.getfoundry.sh/getting-started/installation)) +- Node 14 or higher ([Windows](https://github.com/coreybutler/nvm-windows), [Linux](https://github.com/nvm-sh/nvm)) + +## Installation + +``` +git clone --recurse-submodules https://git.tornado.ws/Theo/proposal-21-test.git +``` + +## Testing + +``` +npm run test +``` + +## Test logic + +Hacker added 1 200 000 TORN tokens to staking directly, 10 000 to 100 accounts and 200 000 to one account. +He then withdrew 483,000 TORN from the Governance Vault, however, 717,000 remained. + +We need to check, that: + +1. All attacker staked TORNs after proposal 21 will be nullified; +2. Governance Vault will be replenished from Governance for 483 000 TORN - the entire amount that he withdrew, to set the ratio of funds locked in staking contract to real tokens in Vault 1: 1 + +If all tests passed, all good. \ No newline at end of file diff --git a/foundry.toml b/foundry.toml new file mode 100644 index 0000000..cd80b65 --- /dev/null +++ b/foundry.toml @@ -0,0 +1,8 @@ +[profile.default] +solc-version = "0.8.17" +src = 'src' +out = 'out' +libs = ["node_modules", "lib"] +chain_id = 1 +optimizer = true +optimizer-runs = 10_000_000 \ No newline at end of file diff --git a/lib/forge-std b/lib/forge-std new file mode 160000 index 0000000..73d44ec --- /dev/null +++ b/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 73d44ec7d124e3831bc5f832267889ffb6f9bc3f diff --git a/package.json b/package.json new file mode 100644 index 0000000..703e157 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "proposal-19-contract", + "version": "0.1.0", + "description": "Tornado proposal #19 smart contract code & tests", + "main": "index.js", + "directories": { + "lib": "lib", + "test": "test" + }, + "scripts": { + "test": "forge test -vvv --fork-url https://rpc.mevblocker.io --block-number 17315182", + "build": "forge build --optimize" + }, + "repository": { + "type": "git", + "url": "https://git.tornado.ws/Theo/proposal-21-test" + }, + "author": "Theo", + "license": "MIT" +} diff --git a/remappings.txt b/remappings.txt new file mode 100644 index 0000000..71409b8 --- /dev/null +++ b/remappings.txt @@ -0,0 +1,6 @@ +@proprietary/=src/proprietary/ +@interfaces/=src/interfaces/ +@root/=src/ + +@forge-std/=lib/forge-std/src/ + diff --git a/src/interfaces/IERC20.sol b/src/interfaces/IERC20.sol new file mode 100644 index 0000000..f3ed318 --- /dev/null +++ b/src/interfaces/IERC20.sol @@ -0,0 +1,15 @@ +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 balanceOf(address owner) external returns (uint256); + + function approve(address spender, uint256 amount) external; +} diff --git a/src/interfaces/IGovernance.sol b/src/interfaces/IGovernance.sol new file mode 100644 index 0000000..e83c6f1 --- /dev/null +++ b/src/interfaces/IGovernance.sol @@ -0,0 +1,7 @@ +pragma solidity 0.8.17; + +interface IGovernance { + function lockedBalance(address account) external view returns (uint256); + + function execute(uint256 proposalId) external payable; +} diff --git a/src/proprietary/Parameters.sol b/src/proprietary/Parameters.sol new file mode 100644 index 0000000..4741f7c --- /dev/null +++ b/src/proprietary/Parameters.sol @@ -0,0 +1,117 @@ +pragma solidity 0.8.17; + +contract Parameters { + // Beneficary addresses + address public _governanceAddress = + 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce; + address public _governanceVaultAddress = + 0x2F50508a8a3D323B91336FA3eA6ae50E55f32185; + address public _tokenAddress = 0x77777FeDdddFfC19Ff86DB637967013e6C6A116C; + + // Attacker info - proposal, addresses + uint256 _attackerProposalId = 21; + uint256 attackerWithdrawnAmount = 483_000 ether; + address[] public _attackerAddresses = [ + 0x1C406ABB1c6a3Bb12447f933b5D4293701b6e9f2, + 0xb4d47EE99E132e441Ae3467EB7D70F06d61b10C9, + 0x57400EB021F940B258F925c57cD39F240B7366F2, + 0xbD23c3ed3DB8a2D07C52F7C6700fDf0888f4f730, + 0x548Fd6e5239e9Ce96F3B63F9EEeAd8C461609dc5, + 0x6dD8C3C6ADD0F403167bF8d2E527A544464744Bb, + 0xC883Fa52D656eBF2b665f2B0C9DC69018dB19760, + 0x1Eb70Cb3c28BE53b287C4E4770F28a3829a57242, + 0xcd280F16CE0b25f85f7520a312EB6B9D76a941D4, + 0xeFDAad217f73355Afe99bC3Ff60BA9Fa6f4Bf51D, + 0x130A2AAE6C3B2a8B0403cA6b9F4e28f3Eb59b021, + 0xf06A447EB8ebb3Afe4849fC9Ac14eA7f5FBe480a, + 0xE3339Ee951522E9C8CC28534179aBF26eF6fC390, + 0xCDcFE3Fa83e771d3CeF8AcB0Cf494B00A625Baa0, + 0x427F31Efe23C994738F79B81054351a35E020300, + 0x7b54c6424602d38c586A73237350d74d3bB1f9e3, + 0x86ab338d8f95AB08869004Fa438a0608F896cc85, + 0xe447c398F643122bAF82d2a28f0AD743Bf03810a, + 0x2026e53c38c2a6d344B20774CCE003B9c82d8db4, + 0xe2e057027215506ba37aC14b1b3F35447BCE9E00, + 0x750379A427c2e905dfb93b57Ff32Cc900B982D58, + 0xf3aBB7F9DfEC6fA5696674e434c1291BA99D5365, + 0xbDf1b3b48BC47bb400Ed3a774dde6A8a8C087B08, + 0xbB7AaF0FC95099b624f33d421A02aF2aA9dEB30b, + 0xD772cA075b0832981F907d78120BB1d2dDeA9c53, + 0xB8BC190B76066d6C36aeA266dD35997b371Bf059, + 0xd77B507176504c75e6CDcF2F18E9d5efB674C898, + 0x59783a2693E00c2e717cdF8F6AABc30F22a2EE25, + 0x2099A879c81d842CB41faE11F64C430980A2489C, + 0xe54e212b1678DD92AbA5C19c571012fD9591f79b, + 0xe8746D4Ee2E21b1952f2a299A58e26217b5C83B8, + 0xf8DD45c936A23BEC510C3F43340E96624DC64E2a, + 0xEcC13e5879a24878D391728D21908c06c49a0f35, + 0x333fA2ea687d00235C9D30Dd8d0A1Ad9be320223, + 0x39bC22EB04601d10D882b3e0Ff7BC48939468111, + 0x656c14885D5A4d9617A5338e638E9e09F8742F89, + 0xE8c82D0EDA5d845eb020b93F28B4192A485ae46F, + 0x25bC8ce97Ff49A6e4e0FF19576fdCF4930a86470, + 0xe2FAD4491D606c8dc2CCE6533BA06286B55E9e59, + 0x211Ecb06CCB94F64a199b8c0Ab50da677F0814A1, + 0x86f9EF2d46D977dd5756A145697b21A45cd482aA, + 0xb2149729d926CadF5Fd4F441D2916f32EE1117BD, + 0xFcA3B56D3fcDDd26A07B4da219D23c821464E413, + 0xf938f086deB7BF8E21e87B7F5ca695736FB72662, + 0x2aD04ec2618b937B94FAf84DE1b791ea24c421CB, + 0xddefD8c3a56B6c94aD7C99515426f35EABd6B1eb, + 0xF2Faef2A542883655d17a7E1A1F45995FFd96EbD, + 0x1f91DFE1824F686eaE52dC427725b77491BdF1fe, + 0xcE3E4F2E58536c62aB884CDf6ede3d540B3Bada4, + 0xD587e79Af0c5739E7CE2fbC61d9BD2E93905903D, + 0xd526Bf6eeD41e08f553E8C81405346cA57e5681F, + 0xB04B6457468B638F634DE5E29b5e3695219bdD07, + 0x2DC89Da10a6fECd06D1cf4cD2e300892bFb330Ad, + 0x7D98dFAD3299c1b0A64C4491E79479E25161618E, + 0x8bc8f686fb9ba1b31bc700ddf1244905F490bebE, + 0xF6B1FB511ced4Db14c6fB811c160703EE7222a9D, + 0x18Bb987538429C88364a0F06762446F5f676CD82, + 0x5A92902142cE0A9b64A63b59E8c45222Da403ADc, + 0x2a748636E9a02619B4BB517C00b01Bd554100faB, + 0x732D52E0f3c42e3FC865b0c3D56ad74bbccF012c, + 0xBaE4F977BAf53c1f4353A94467116227a36E195f, + 0x01760D5BA7507B35C24dbE0CD33eD20C6Ebc98F2, + 0xfc91b2f505d759DdB8765B2Cc87510E5aCDdbAAf, + 0x90009a669F2e2282C6264fFa371dB25e6E5266a0, + 0x1783D6610a6b8E2fF172eAA09c02F347a03679eF, + 0x53DCF5fF9804f50B395c1105785e22ae854D8F6E, + 0x7d01a7eD2f35e2232388686274b28812B1c8AF89, + 0x81cF4BcF79E85a6827D59013B91aD077c6ce58Fe, + 0xaa715EBcF8432cf5821f4Aa5E9d1481FA2Ca13B5, + 0x9ae18da8Bfb74456DcbBD23eE2F56C35A7231339, + 0xBaB434Bd4DFaA4CefA56B0B7C964facaB74caD13, + 0x6c4204b3f40dfF763307d8cd681d02e37B55fE08, + 0x4134644AdcC12841De3FC895509d82e099b7f0DF, + 0xCa79e6797953954e0817052293FE3A8710F3583d, + 0x8A6DE36E0CcEfb692355E523583b99017aadc62F, + 0xA867B662A05e6ADba6209BEe4EB8e01764f1F27d, + 0x5003997c5e8b0438fef1e6Bb2ff79D73ed68C717, + 0x335a4d0c4AaC5A5ffD644B3b4FA443679eFa88F9, + 0x6F07a83384852f22c11D132b91D8c907790911f8, + 0x32B5694222A2191142b09d6aB17c3b3f57d4e679, + 0xb99f6AACf00EBFBA50519B1A37B1Ff88E0ae3f9c, + 0x480ACEBA484e7bBB6a57c8c5F035271C5c21014E, + 0x314F40B5D640876D8c53381c66B36B55D68195cC, + 0xcBeC349Eb9ac6656393b001EfF786CDE912c50AB, + 0xBFf9cb6B8BdA67485e17dD67B450A6A49e76F4bF, + 0xfd85628806878216d93B623B2e647D1f88Cea027, + 0x5b929a832690185A150e7648f9b6476487577bd4, + 0x28bbAdF5C8CeA27636a9cA11436030337c416400, + 0x9170b1c95DAaDe6fd70E640f1F6FB2911Db62468, + 0xC73e7c6333683F25B951941759D4b6038eC51DAE, + 0xd99b4C7372cC245965Bf24A1762d76228201A4b0, + 0x67227DDE7BD55B8C2313822b2EaDB46Eda73A4bB, + 0xd4D9F6f64A5bAF9D263217EB7f5AE1444A956469, + 0xCe85fD8b7D965e807f04F51440585Fc610B061a2, + 0xd70b6B4De4afa7B0205bB93E46A994C5815fb0B4, + 0xb06F844f02695F6cfA0152B12BcfA757B31eB154, + 0x1973653486856a0420Fd92a7c5264c3d4D0319B6, + 0xA05F1956dC591b815c66e489bf2313F1Ed39dBe9, + 0xBC78138A49e5BADDBE7a125659A7b4F661D2770A, + 0x68458586990E0d48c034E49b783B08444730d44f, + 0xbfFefE62Ca8e0BE1734D267767Ad5923c23bBB05 + ]; +} diff --git a/test/Proposal.t.sol b/test/Proposal.t.sol new file mode 100644 index 0000000..445718c --- /dev/null +++ b/test/Proposal.t.sol @@ -0,0 +1,76 @@ +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 ProposalTest is Test, Parameters { + IGovernance internal governance = IGovernance(_governanceAddress); + uint256 internal currentGovernanceVaultBalance = + getGovernanceVaultBalance(); + + modifier conditionStateChecks() { + checkCurrentState(); + _; + checkResults(); + } + + function testProposal() public conditionStateChecks { + waitUntilVotingEnds(); + governance.execute(_attackerProposalId); + } + + function getAttackerLockedBalance() internal returns (uint256) { + uint256 attackerLockedBalance; + for (uint 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 waitUntilVotingEnds() internal { + vm.warp(block.timestamp + PROPOSAL_DURATION); + } + + 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 checkResults() internal { + uint256 attackerBalanceAfterProposalExecution = getAttackerLockedBalance(); + uint256 governanceVaultBalanceAfterProposalExecution = getGovernanceVaultBalance(); + 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 + ); + } +}