Compare commits

..

9 Commits

19 changed files with 436 additions and 217 deletions

View File

@@ -1,3 +1,34 @@
# proposal-23-restore-rewards
# Proposal 25: restore old rewards
Proposal to restore old rewards value (as before hack) after redeploying Staking contract
Proposal to restore old rewards value (as before hack) after redeploying Staking contract to stakers, who did not have time to withdraw their rewards due to a bug
### Changes:
- Redeploying staking implementation contract to add new function `setReward`
- Restore rewards to 357 stakers (all stakers, who had more than 1 TORN in rewards at the time of the hack and didn't have time to withdraw them)
- Transfer 42 754 TORN from Governance to new Staking contract (so that stakers can withdraw their restored rewards)
### Requirements
- Rust ([Need only for Windows](https://doc.rust-lang.org/cargo/getting-started/installation.html))
- 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
```text
git clone --recurse-submodules https://git.tornado.ws/Theo/proposal-25-restore-rewards
cd proposal-25-restore-rewards
npm install
```
### Testing
```text
npm run test
```
### Contracts
1. New staking implementation contract: [etherscan link](https://etherscan.io/address/0x9c97be37840f0e754bb7adb1b16fd0954a2ba248#code)
2. Proposal contract: [etherscan link](https://etherscan.io/address/0xe3ea2661908d7ebdae01582ad77ab31eebffd365#code)

86
abi/MultiCallABI.json Normal file
View File

@@ -0,0 +1,86 @@
[
{
"constant": true,
"inputs": [],
"name": "getCurrentBlockTimestamp",
"outputs": [{ "name": "timestamp", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"components": [
{ "name": "target", "type": "address" },
{ "name": "callData", "type": "bytes" }
],
"name": "calls",
"type": "tuple[]"
}
],
"name": "aggregate",
"outputs": [
{ "name": "blockNumber", "type": "uint256" },
{ "name": "returnData", "type": "bytes[]" }
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getLastBlockHash",
"outputs": [{ "name": "blockHash", "type": "bytes32" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "addr", "type": "address" }],
"name": "getEthBalance",
"outputs": [{ "name": "balance", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCurrentBlockDifficulty",
"outputs": [{ "name": "difficulty", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCurrentBlockGasLimit",
"outputs": [{ "name": "gaslimit", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getCurrentBlockCoinbase",
"outputs": [{ "name": "coinbase", "type": "address" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "blockNumber", "type": "uint256" }],
"name": "getBlockHash",
"outputs": [{ "name": "blockHash", "type": "bytes32" }],
"payable": false,
"stateMutability": "view",
"type": "function"
}
]

View File

@@ -1,4 +1,4 @@
Staker[385] memory stakers = [
Staker[357] memory stakers = [
Staker(0xb2C95127308876B0dA00dCE7798412bcA95C9Fee, 261_891_050_760_386_479_981),
Staker(0x52f4B90dF9560E50389107baCCD13e8BC1e5a516, 5_519_577_581_187_935_401),
Staker(0x679959449b608AF08d9419fE66D4e985c7d64D96, 6_634_938_965_540_161_678),
@@ -11,12 +11,9 @@
Staker(0x201dD47dadA5165D792e6B4bDC2600e2FC5d7375, 3_376_734_302_476_765_689),
Staker(0x97b90FBc8904F861F76CB06BFa0A465b72C5E662, 85_583_028_288_278_705_143),
Staker(0xd3660816c68EF4DB79D2cCBFA2E6D623dfD65699, 135_764_830_626_382_535_905),
Staker(0xa3a7EAe904e92fA67c1888C6572Ac884722f5288, 63_755_633_956_332_846_740),
Staker(0xBFb910652F850F85E3F85AA0C12aE8f4037095b0, 33_237_171_239_790_116_387),
Staker(0x32f8E5d3F4039d1DF89B6A1e544288289A500Fd1, 1_536_360_162_595_381_679),
Staker(0xe2506955723C01dDd6e619dD0829e28F76328c41, 72_958_648_431_519_163_392),
Staker(0x3Df488Bd07C2082E84B1CD63F343Cf3d538342bA, 107_098_359_836_630_121_582),
Staker(0x6a90E7Ba20291CDF651A6d61ebf2371BA89EF04B, 46_595_274_664_224_710_080),
Staker(0x0b7C43AF43D76f79b6f6CfBAFb3A01ddE0468225, 18_243_581_064_710_552_362),
Staker(0x524b7c9B4cA33ba72445DFd2d6404C81d8D1F2E3, 8_414_647_798_389_006_172),
Staker(0xfDEEc44b6c63E637fA3348092A9F952A02B2E695, 1_468_551_637_230_600_353),
@@ -28,17 +25,11 @@
Staker(0xB1583e01ACA426807985FAf9438c9a4cEF73B1A7, 2_769_004_780_372_765_071),
Staker(0xcDfb26F93F2D5e0F4b76190e5bC740b3A3DA16F4, 1_986_870_853_342_994_225),
Staker(0xDbcb5D2a6c77F1a8069ff686F88FC552F2F3eFCC, 2_691_179_623_359_894_955),
Staker(0x15Ed2710d0097CE9BC352Db97287bDd9104bEC92, 517_823_661_753_566_090_385),
Staker(0x85f8BeC61f75De3Dbad1bBd4CDD168ea362bDaeA, 118_525_403_763_250_297_030),
Staker(0xac57C7A3960Ba383b94b28BF44f9cdC26B84A8e7, 766_340_829_474_823_777_721),
Staker(0xEFb7Ce1357F324a324A8EABDc443b26894A2b246, 721_114_114_180_262_809_591),
Staker(0x84781094f9B11aCb35A7Dca31D731A244B25E6a4, 389_646_430_287_742_483_283),
Staker(0xA3A89931799Ba449A7bd1658EfD9C8662dd22BcA, 4_471_048_279_368_398_062),
Staker(0x13e50a5e7D695ae729Da77623c61661B27A3b60a, 25_552_108_041_996_067_156),
Staker(0xeafA9AA6832c076D5af3d58D9224E218CA074f04, 3_278_339_837_838_322_677),
Staker(0x25713B024a8004727Ba79c43647a77c7447948dB, 16_833_083_830_815_723_474),
Staker(0x73D23cDaBBb25B0E039470ea940514Ca30744277, 6_268_058_376_469_446_863),
Staker(0x11FD8380FcEF61E7D1FC054d4Ba20D7230a5593A, 241_999_616_776_245_144_340),
Staker(0xB157ba30e3467DdBC844f14F02b4ba741f1d549F, 65_080_791_858_799_563_574),
Staker(0xB6dA1D0cac0CAC8d39125d5213E1623750525ed5, 3_582_972_520_064_518_922),
Staker(0xEBf919b0DAfb9ea4BF324108A142C64A69052D8f, 1_492_116_146_713_012_865_552),
@@ -47,7 +38,6 @@
Staker(0x076b499e9191A29Fa9210e497cBd89DABC878B6E, 4_403_836_602_105_176_579),
Staker(0x83c418D2eD6670785330B996b47a18492b61e218, 2_423_008_690_534_464_349_496),
Staker(0xcD37EF9120132F71E23982881e19B68aE3B4E871, 6_094_554_447_886_213_907),
Staker(0xe44799Ef334Df157e0F8e2855E5EbeBdBc02b299, 498_687_077_665_731_358_140),
Staker(0xff36EdACcEebADC368ea6CACA13E5f3bBD1b43AC, 1_685_473_922_303_763_108),
Staker(0x312044825EB5CD2C4Bb016a7a86ce32240Af9136, 27_126_619_039_727_679_328),
Staker(0x3035A1bBd824041B07f8Ab2297a71A81E00127c5, 14_756_069_076_031_120_181),
@@ -60,8 +50,6 @@
Staker(0xF99d1946Bf038a1205d430Ec91401E760e5F8F6F, 8_151_047_628_859_550_523_186),
Staker(0x9897Bc7231492CDf163BB81bFF10A5919a73d132, 3_388_092_111_567_580_393_688),
Staker(0x8953C798a6F54ea8907875c51e5D466DE76A1b26, 797_098_747_089_744_161_355),
Staker(0x9C42EBDf0fA6fA0274aEEBf981613Dfa9c99BFF8, 1_151_021_932_914_438_641_249),
Staker(0xD88189f7Dee6E5DBd6cbC6F06FD357f4Bf7f330b, 1_435_829_849_735_697_778_451),
Staker(0xf4DcA9B37f09D15f8dF740055cEaA860912efe2C, 2_569_990_661_510_076_867),
Staker(0xAdE9e51C9E23d64E538A7A38656B78aB6Bcc349e, 146_771_928_128_749_080_734),
Staker(0xeE1D1ac27A80De54F0ba92b2E25EBb3418495db2, 2_943_758_390_988_392_723),
@@ -147,13 +135,11 @@
Staker(0x48Ef3De608AB2304dBB0c4497d266F3BF5506e7B, 1_346_590_027_777_001_145),
Staker(0x3716905b040D5cd8a7DdE784918199117d72c3B3, 1_400_844_245_925_263_369),
Staker(0xB835b4e277094D4AF9Fbb66e9f5Db9e6E8dC65dB, 25_683_271_096_264_423_274),
Staker(0x08d19484246a987411e04a7F098E36F92cad4f24, 20_246_123_092_729_700_406),
Staker(0x42DbF634c256acd17beDDC1330488F1BEa7B8BDf, 319_523_008_529_625_373_272),
Staker(0xE7304bA0f157f2Ade94015934284b6704BC72911, 39_826_654_578_302_448_107),
Staker(0xE06bF8125273Ead3814aBDE0D548079991F5DD8a, 22_645_804_997_633_317_877),
Staker(0xaa9298F0c3e97DdA6277713fd3Ed6e2A389E7260, 3_572_475_984_033_907_702),
Staker(0xC9D32C7e16d71aF1739618356F1e3F2c69e8784a, 2_812_672_628_757_140_199),
Staker(0xFF30D836794Bfe71E888A7aa2AB62BfFb3F7a73a, 23_218_272_203_140_765_926),
Staker(0xCcC24DD1FE711d9f47A42a04b16b789669A21C98, 252_786_587_455_637_451_074),
Staker(0x0091a0aAF911A27133713028a83644224FcD7103, 4_391_483_020_114_108_858),
Staker(0x74E5B46a2A39F86ECc8CABCc409556953A688484, 3_576_335_685_734_120_104),
@@ -211,7 +197,6 @@
Staker(0xc8d51E5a9293426d678400f05fDF8395fFE34187, 1_159_086_427_507_011_821),
Staker(0x1CE7DC66CC98c61A573105514d073D64a9a8608f, 26_389_224_886_673_669_669),
Staker(0xD3069f6050A3dd4ECCc27b6A66E5C401aB59DeD5, 1_131_703_913_861_582_424_146),
Staker(0xC796A650D6e7869D1c22642Bf0a4c7D5b3bbed32, 6_099_909_659_507_227_766),
Staker(0xc6DFfE2C1C910A3E049b29638bE0286645054f3C, 29_472_347_834_775_340_843),
Staker(0x2753dEeD6Fc665ff159c94aEAFb8a19E4525831E, 25_294_315_679_682_630_786),
Staker(0x0d4E989c7620C8749c9417d2BF218896C767B606, 3_364_398_457_228_954_809_190),
@@ -224,7 +209,6 @@
Staker(0x24f04EC62597C11752c47448228B63052ED3158a, 90_815_074_343_246_091_464),
Staker(0xA11109126af2c5904fdc5b6203108Fef5770E85E, 17_491_569_071_641_631_106),
Staker(0x8904FFC6Aa039dB5941De11309a42372F3F7D2FD, 89_018_897_961_346_317_265),
Staker(0x95Be36B3F6a5DC958c59a4a81FdF0BEE671f26F3, 92_179_556_551_282_444_104),
Staker(0xa729adDeFe1fa7BCe87053ed55D55EDdDD13De60, 21_709_183_619_942_034_343),
Staker(0x409ac9C16B2CD569EC06bb9eceF97eeFDe0e8054, 15_006_870_038_073_374_755),
Staker(0xdF3c8E63677C79b24608bDed80CeD65667513BcB, 541_718_227_741_233_200_336),
@@ -257,7 +241,6 @@
Staker(0x26D3b88d464A575784Be70Edc5F9290dC5e296DB, 143_520_553_783_208_184_300),
Staker(0x4ffc1A4bD191935C603df061065Ce97C25C70687, 1_104_677_208_403_973_125),
Staker(0x7Abbdbd51813d85B448F887b946719Dd2B09D6F7, 28_496_157_399_564_678_982),
Staker(0xEb89EfE3Ed80288E310c5529e1E242b4ab56E196, 10_158_103_172_727_951_367),
Staker(0x3C7ddEB357e4341A18cfC587343a4463a280B9c5, 15_766_263_220_154_597_250),
Staker(0x8633ADAf2438703d6D7f953829A4fe0c95FbeC44, 14_574_784_535_592_207_846),
Staker(0xAD142B79f2500Bf194C174f06C7dC901A2CdA74f, 7_123_937_386_942_958_617),
@@ -285,7 +268,6 @@
Staker(0x16eb5Fbb2a5c7dAbC2c7688482378e89471d5724, 56_528_851_406_540_169_265),
Staker(0x356eE97D7D560af2E97E9f9EEe56b2e09D60e6F5, 2_357_571_123_330_435_682_004),
Staker(0x000AD8F56D3408abE29466189612d1B7B19E4420, 8_944_601_804_979_063_344),
Staker(0xc82ceD242a7c064EC0ef3742BDea830aEB46D614, 225_374_382_403_472_958_564),
Staker(0xAd412239848f37a5dDb8fAbb523D05F4FFdB2651, 1_852_483_360_172_530_551),
Staker(0x21c756E2c7B898BDa8a3b2A77e4C56D855Ab9414, 52_258_855_596_837_389_305),
Staker(0xa6Ba7cddc1c4fBfFBA96eCE341F9baA1c35fA76e, 10_324_733_292_812_452_226),
@@ -320,14 +302,12 @@
Staker(0xA103c48Dbe3E804C23a98C5f159cEb3305c28E7b, 3_039_820_725_899_735_674),
Staker(0xab03945BC97F6899902D4296Ff97cAE8dbdc1A11, 66_797_846_279_254_338_952),
Staker(0xB945e8074C3e2F758B045Cb9a30066EE33CDB87E, 8_960_852_709_660_572_526),
Staker(0xDEB1c51514ee12d9F76Eb67AfCb7B4c33B466449, 8_131_473_545_148_842_396),
Staker(0x00377B2FC0044Dec6507855eDd6531aF1755cCe4, 187_316_100_663_496_504_711),
Staker(0xDaABa4C3a3026149a7a811bcb4B4EE9F23B61800, 1_342_110_570_226_429_076),
Staker(0x10aab4B0EF76AA2AC9b5909e671517a1171B050E, 9_816_488_209_589_379_461),
Staker(0xD9D10dc5609d77F2A15FAa68414835A6ed19269B, 95_363_084_515_727_944_710),
Staker(0x71e989dC58c879D26C2efDce097edeE505A57a28, 2_088_864_348_657_925_026),
Staker(0xdF20a1124d6B44e19ad75675a622d9c9669E59B6, 88_352_293_222_343_728_212),
Staker(0xaA8B1a05dF753F54DE787a752cB9E7808f447820, 23_946_074_798_869_806_567),
Staker(0x7E5c540b343fB854782617dECc82FBc1745b5591, 14_767_739_390_099_031_589),
Staker(0x209D49fda266C0AB257648555f8459F90e154aEd, 129_761_028_103_842_230_426),
Staker(0xF4d2D64D1f9190A9daB0960c80e5C73c04710184, 20_259_718_574_398_138_635),
@@ -356,11 +336,7 @@
Staker(0xea76eE7035aF65410D290cB7E2Ed8Fc01C395266, 6_866_348_488_289_388_870),
Staker(0xC2e6B265cb965DED721566f0f9Eb5ab1A6162A21, 22_971_027_302_959_450_151),
Staker(0x4d6A11EbEC10E133A5007578Ad792F765ED724F2, 1_523_390_814_593_599_013_009),
Staker(0xaF305fEfDc439cb1CA9FAC2f9d271fD2CC7B3F05, 34_558_215_533_487_668_461),
Staker(0x164f9ECFc5Ec74fAC1Ba1ca28E71Fd57FeadCD27, 43_630_581_854_870_958_303),
Staker(0xddbc1841BE23b2ab55501Deb4d6bc39E3f8AA2d7, 57_697_184_564_150_419_473),
Staker(0x7b5edF38D955dd9deC103aF05c2D68B28e02Ad90, 990_145_869_312_977_038_005),
Staker(0xE4143f6377AEcd7193b9731d1C28815b57C4f5Ab, 794_513_313_076_462_735_653),
Staker(0x9Fd4d0dE8A3A8a8F2aC003A5ece295CE9512d9c6, 36_016_585_133_757_988_164),
Staker(0x3390937ec4D4b94002BCacf65D2F98594b4980eF, 6_453_311_584_351_983_424),
Staker(0xA207ac236dFdeE6F885d0Cc1D0C8100b46fA91EE, 1_450_736_948_351_239_615),
@@ -369,12 +345,9 @@
Staker(0xc71cB68d38dF4E2190128DCb7E39bD1e72Fc3A2F, 13_498_777_595_192_377_744),
Staker(0x3E40eCBf8eB74fB708b8cCeA28c1C9312697aFDd, 2_547_293_201_582_353_144),
Staker(0x1e4d844528F3C9890bE6c3de38Dc8c695Cd06B20, 27_853_939_827_678_230_227),
Staker(0x45a4a7b51f8691Bd52988d8ee3f01F7518f6B056, 11_167_199_970_888_954_708),
Staker(0x4BF646757dA7067E683EB20cD122AfFBc0E67e39, 4_512_233_232_588_903_004),
Staker(0xb6242d8F02bA15917A84bD83C2eeee0e45288a03, 9_403_472_182_706_909_584),
Staker(0x6f4CbC2E042ed0D1Df4bf14d00eEb52Ff1E0e5F8, 9_748_334_349_185_074_783),
Staker(0x92374BA66EE27f207F9efff0837FF6D707006304, 58_838_358_111_071_620_908),
Staker(0x6dF07d3864c5F7ee564B5920199374C0b864E7d6, 664_290_901_673_954_681_162),
Staker(0x04700e0Ef1bCD91d36e7CE63FE93d651DFB272cA, 13_074_452_933_044_923_946),
Staker(0x8a1d5F23566c802CccEF7f02d5f216c37c8e44aD, 1_481_488_396_230_202_148),
Staker(0xfa2176D82cbA00d54998E6C37616b75ceCef08a0, 8_723_821_105_751_268_318),
@@ -382,7 +355,6 @@
Staker(0x592340957eBC9e4Afb0E9Af221d06fDDDF789de9, 3_571_261_202_347_432_870),
Staker(0x000000Cd6521Ed1a65FAe0678eA15aF4EEAD74fe, 1_431_414_111_205_873_746),
Staker(0xC49415493eB3Ec64a0F13D8AA5056f1CfC4ce35c, 1_213_791_173_344_605_522),
Staker(0xa6eDC956290b7Ce416c5d8EDc67E1C32506Fe099, 366_757_732_355_918_570_636),
Staker(0xbd0fac9A19E8E19F6245eD20411E22D4786752c8, 4_355_144_205_984_655_655)
];
@@ -390,4 +362,4 @@
accrueOldReward(stakers[i].addr, stakers[i].oldRewards);
}
IERC20(tornAddress).transfer(stakingProxyAddress, 51_038_101_771_805_874_869_526);
IERC20(tornAddress).transfer(stakingProxyAddress, 42_754_780_712_309_224_285_728);

View File

@@ -0,0 +1 @@
Locked balance of stakers to who we want restore rewards: 392252226884126520706939 (~ 392252.23 TORN)

View File

@@ -5,7 +5,8 @@
"scripts": {
"computeRewards": "npx ts-node scripts/writeStakersData.ts",
"test": "forge test -vvv --fork-url https://rpc.mevblocker.io --fork-block-number 17466009",
"testGas": "forge test -vvv --fork-url https://rpc.mevblocker.io --gas-report"
"testGas": "forge test -vvv --fork-url https://rpc.mevblocker.io --gas-report",
"testStakersLocked": "npx ts-node test/stakersLockedBalanceSum.ts"
},
"repository": {
"type": "git",
@@ -23,18 +24,13 @@
"web3-utils": "^1.10.0"
},
"devDependencies": {
<<<<<<< HEAD
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@nomiclabs/hardhat-waffle": "^2.0.6",
"chai": "^4.3.7",
"ethereum-waffle": "^4.0.10",
"ethers": "^6.5.1",
=======
"ethers": "^5",
"@nomicfoundation/hardhat-foundry": "^1.0.1",
"@nomicfoundation/hardhat-verify": "^1.0.1",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"ethers": "^5",
>>>>>>> 80078475d5d09a2b730f8334120a524d069ec5b1
"hardhat": "^2.15.0",
"ts-node": "^10.9.1",
"typescript": "^5.1.3"

View File

@@ -1,28 +1,48 @@
const hre = require('hardhat')
const config = require("../config")
const { ethers } = hre
const hre = require("hardhat");
const config = require("../config");
const { ethers } = hre;
const sleep = (s) => new Promise((r) => setTimeout(r, s * 1000));
async function main() {
const factory_staking = await ethers.getContractFactory("TornadoStakingRewards")
const factory_proposal = await ethers.getContractFactory("Proposal")
const factory_staking = await ethers.getContractFactory(
"TornadoStakingRewards"
);
const factory_proposal = await ethers.getContractFactory(
"RestoreRewardsProposal"
);
const staking = await factory_staking.deploy(config.governanceProxy, config.torn, config.registryProxy)
const staking = await factory_staking.deploy(
config.governanceProxy,
config.torn,
config.registryProxy
);
await sleep(20);
console.log("\nStaking contract impl successfully deployed @ " + staking.address + '\n')
console.log(
"\nStaking contract impl successfully deployed @ " + staking.target + "\n"
);
await hre.run('verify:verify', {
address: staking.address,
constructorArguments: [config.governanceProxy, config.torn, config.registryProxy],
})
await hre.run("verify:verify", {
address: staking.target,
constructorArguments: [
config.governanceProxy,
config.torn,
config.registryProxy,
],
});
const proposal = await factory_proposal.deploy(staking.address)
const proposal = await factory_proposal.deploy(staking.target);
await sleep(20);
console.log("\nProposal 25 successfully deployed @ " + proposal.address + '\n')
console.log(
"\nProposal 25 successfully deployed @ " + proposal.target + "\n"
);
await hre.run('verify:verify', {
address: proposal.address,
constructorArguments: [staking.address],
})
await hre.run("verify:verify", {
address: proposal.target,
constructorArguments: [staking.target],
});
}
main().then((res) => console.log(res ?? "\nScript finished.\n"))
main().then((res) => console.log(res ?? "\nScript finished.\n"));

View File

@@ -1,36 +1,41 @@
import fs from 'fs';
import fs from "fs";
import path from "path";
import BigNumber from "bignumber.js";
import { getStakersWithRewardsBeforeHack } from '../utils/stakers';
import { getStakersWithRewardsBeforeHack, getStakersWithdrawedAfterHack } from "../utils/stakers";
// Format options for BigNumber printing
const fmt = {
prefix: '',
decimalSeparator: '.',
groupSeparator: '_',
prefix: "",
decimalSeparator: ".",
groupSeparator: "_",
groupSize: 3,
secondaryGroupSize: 0,
fractionGroupSeparator: ' ',
fractionGroupSeparator: " ",
fractionGroupSize: 0,
suffix: ''
}
suffix: "",
};
BigNumber.config({ FORMAT: fmt });
async function main() {
// All stakers who had more than 1 TORN in rewards at the time of the hack
const stakersWithRewardsBeforeHack = await getStakersWithRewardsBeforeHack();
// Stakers who withdrew rewards from the time of hack until the balance of the old Staking contract was nullified
const stakersWithdrawedAfterHack = await getStakersWithdrawedAfterHack();
const rewardsSum = stakersWithRewardsBeforeHack.reduce((acc, staker) => acc.plus(staker.rewardBalance), BigNumber(0));
// It makes no sense to restore awards to those who already withdrew them from the old Staking contract
const stakersToRestoreRewards = stakersWithRewardsBeforeHack.filter((staker) => !stakersWithdrawedAfterHack.includes(staker.address));
const stakersDisplayedInfo = stakersWithRewardsBeforeHack.map((staker) => {
return `${staker.address} = ${staker.rewardBalance.toString(10)} (~ ${staker.rewardBalance.div(1e18).toFixed(2)} TORN)`;
});
fs.writeFileSync(path.join("data", "rewardsBeforeHack.txt"), stakersDisplayedInfo.join("\n"));
const rewardsSum = stakersToRestoreRewards.reduce((acc, staker) => acc.plus(staker.rewardBalance), BigNumber(0));
console.log("Sum of rewards before hack:", rewardsSum.div(1e18).toFixed(2), "TORN");
const stakersDisplayedInfo = stakersWithRewardsBeforeHack.map(staker => {
return `${staker.address} = ${staker.rewardBalance.toString(10)} (~ ${staker.rewardBalance.div(1e18).toFixed(2)} TORN)`;
})
fs.writeFileSync(path.join("data", "rewardsBeforeHack.txt"), stakersDisplayedInfo.join('\n'));
const stakersData = stakersWithRewardsBeforeHack.map(staker => {
return `Staker(${staker.address}, ${staker.rewardBalance.toFormat()})`
const stakersData = stakersToRestoreRewards.map((staker) => {
return `Staker(${staker.address}, ${staker.rewardBalance.toFormat()})`;
});
const commandToAccrueRewards = `accrueOldReward(stakers[i].addr, stakers[i].oldRewards);`;
const commandToReplenishStaking = `IERC20(tornAddress).transfer(stakingProxyAddress, ${rewardsSum.toFormat()});`;
@@ -38,7 +43,7 @@ async function main() {
const codePadding3 = " ".repeat(12);
const codeToAccrueRewards =
codePadding2 +
`Staker[${stakersWithRewardsBeforeHack.length}] memory stakers = [\n` +
`Staker[${stakersToRestoreRewards.length}] memory stakers = [\n` +
codePadding3 +
stakersData.join(`,\n${codePadding3}`) +
`\n${codePadding2}];\n\n` +
@@ -50,7 +55,6 @@ async function main() {
codePadding2 +
commandToReplenishStaking;
fs.writeFileSync(path.join("data", "codeToAccrueRewards.txt"), codeToAccrueRewards);
}
main();

View File

@@ -28,7 +28,7 @@ contract RestoreRewardsProposal {
function executeProposal() external {
AdminUpgradeableProxy(payable(stakingProxyAddress)).upgradeTo(deployedStakingImplementationAddress);
Staker[385] memory stakers = [
Staker[357] memory stakers = [
Staker(0xb2C95127308876B0dA00dCE7798412bcA95C9Fee, 261_891_050_760_386_479_981),
Staker(0x52f4B90dF9560E50389107baCCD13e8BC1e5a516, 5_519_577_581_187_935_401),
Staker(0x679959449b608AF08d9419fE66D4e985c7d64D96, 6_634_938_965_540_161_678),
@@ -41,12 +41,9 @@ contract RestoreRewardsProposal {
Staker(0x201dD47dadA5165D792e6B4bDC2600e2FC5d7375, 3_376_734_302_476_765_689),
Staker(0x97b90FBc8904F861F76CB06BFa0A465b72C5E662, 85_583_028_288_278_705_143),
Staker(0xd3660816c68EF4DB79D2cCBFA2E6D623dfD65699, 135_764_830_626_382_535_905),
Staker(0xa3a7EAe904e92fA67c1888C6572Ac884722f5288, 63_755_633_956_332_846_740),
Staker(0xBFb910652F850F85E3F85AA0C12aE8f4037095b0, 33_237_171_239_790_116_387),
Staker(0x32f8E5d3F4039d1DF89B6A1e544288289A500Fd1, 1_536_360_162_595_381_679),
Staker(0xe2506955723C01dDd6e619dD0829e28F76328c41, 72_958_648_431_519_163_392),
Staker(0x3Df488Bd07C2082E84B1CD63F343Cf3d538342bA, 107_098_359_836_630_121_582),
Staker(0x6a90E7Ba20291CDF651A6d61ebf2371BA89EF04B, 46_595_274_664_224_710_080),
Staker(0x0b7C43AF43D76f79b6f6CfBAFb3A01ddE0468225, 18_243_581_064_710_552_362),
Staker(0x524b7c9B4cA33ba72445DFd2d6404C81d8D1F2E3, 8_414_647_798_389_006_172),
Staker(0xfDEEc44b6c63E637fA3348092A9F952A02B2E695, 1_468_551_637_230_600_353),
@@ -58,17 +55,11 @@ contract RestoreRewardsProposal {
Staker(0xB1583e01ACA426807985FAf9438c9a4cEF73B1A7, 2_769_004_780_372_765_071),
Staker(0xcDfb26F93F2D5e0F4b76190e5bC740b3A3DA16F4, 1_986_870_853_342_994_225),
Staker(0xDbcb5D2a6c77F1a8069ff686F88FC552F2F3eFCC, 2_691_179_623_359_894_955),
Staker(0x15Ed2710d0097CE9BC352Db97287bDd9104bEC92, 517_823_661_753_566_090_385),
Staker(0x85f8BeC61f75De3Dbad1bBd4CDD168ea362bDaeA, 118_525_403_763_250_297_030),
Staker(0xac57C7A3960Ba383b94b28BF44f9cdC26B84A8e7, 766_340_829_474_823_777_721),
Staker(0xEFb7Ce1357F324a324A8EABDc443b26894A2b246, 721_114_114_180_262_809_591),
Staker(0x84781094f9B11aCb35A7Dca31D731A244B25E6a4, 389_646_430_287_742_483_283),
Staker(0xA3A89931799Ba449A7bd1658EfD9C8662dd22BcA, 4_471_048_279_368_398_062),
Staker(0x13e50a5e7D695ae729Da77623c61661B27A3b60a, 25_552_108_041_996_067_156),
Staker(0xeafA9AA6832c076D5af3d58D9224E218CA074f04, 3_278_339_837_838_322_677),
Staker(0x25713B024a8004727Ba79c43647a77c7447948dB, 16_833_083_830_815_723_474),
Staker(0x73D23cDaBBb25B0E039470ea940514Ca30744277, 6_268_058_376_469_446_863),
Staker(0x11FD8380FcEF61E7D1FC054d4Ba20D7230a5593A, 241_999_616_776_245_144_340),
Staker(0xB157ba30e3467DdBC844f14F02b4ba741f1d549F, 65_080_791_858_799_563_574),
Staker(0xB6dA1D0cac0CAC8d39125d5213E1623750525ed5, 3_582_972_520_064_518_922),
Staker(0xEBf919b0DAfb9ea4BF324108A142C64A69052D8f, 1_492_116_146_713_012_865_552),
@@ -77,7 +68,6 @@ contract RestoreRewardsProposal {
Staker(0x076b499e9191A29Fa9210e497cBd89DABC878B6E, 4_403_836_602_105_176_579),
Staker(0x83c418D2eD6670785330B996b47a18492b61e218, 2_423_008_690_534_464_349_496),
Staker(0xcD37EF9120132F71E23982881e19B68aE3B4E871, 6_094_554_447_886_213_907),
Staker(0xe44799Ef334Df157e0F8e2855E5EbeBdBc02b299, 498_687_077_665_731_358_140),
Staker(0xff36EdACcEebADC368ea6CACA13E5f3bBD1b43AC, 1_685_473_922_303_763_108),
Staker(0x312044825EB5CD2C4Bb016a7a86ce32240Af9136, 27_126_619_039_727_679_328),
Staker(0x3035A1bBd824041B07f8Ab2297a71A81E00127c5, 14_756_069_076_031_120_181),
@@ -90,8 +80,6 @@ contract RestoreRewardsProposal {
Staker(0xF99d1946Bf038a1205d430Ec91401E760e5F8F6F, 8_151_047_628_859_550_523_186),
Staker(0x9897Bc7231492CDf163BB81bFF10A5919a73d132, 3_388_092_111_567_580_393_688),
Staker(0x8953C798a6F54ea8907875c51e5D466DE76A1b26, 797_098_747_089_744_161_355),
Staker(0x9C42EBDf0fA6fA0274aEEBf981613Dfa9c99BFF8, 1_151_021_932_914_438_641_249),
Staker(0xD88189f7Dee6E5DBd6cbC6F06FD357f4Bf7f330b, 1_435_829_849_735_697_778_451),
Staker(0xf4DcA9B37f09D15f8dF740055cEaA860912efe2C, 2_569_990_661_510_076_867),
Staker(0xAdE9e51C9E23d64E538A7A38656B78aB6Bcc349e, 146_771_928_128_749_080_734),
Staker(0xeE1D1ac27A80De54F0ba92b2E25EBb3418495db2, 2_943_758_390_988_392_723),
@@ -177,13 +165,11 @@ contract RestoreRewardsProposal {
Staker(0x48Ef3De608AB2304dBB0c4497d266F3BF5506e7B, 1_346_590_027_777_001_145),
Staker(0x3716905b040D5cd8a7DdE784918199117d72c3B3, 1_400_844_245_925_263_369),
Staker(0xB835b4e277094D4AF9Fbb66e9f5Db9e6E8dC65dB, 25_683_271_096_264_423_274),
Staker(0x08d19484246a987411e04a7F098E36F92cad4f24, 20_246_123_092_729_700_406),
Staker(0x42DbF634c256acd17beDDC1330488F1BEa7B8BDf, 319_523_008_529_625_373_272),
Staker(0xE7304bA0f157f2Ade94015934284b6704BC72911, 39_826_654_578_302_448_107),
Staker(0xE06bF8125273Ead3814aBDE0D548079991F5DD8a, 22_645_804_997_633_317_877),
Staker(0xaa9298F0c3e97DdA6277713fd3Ed6e2A389E7260, 3_572_475_984_033_907_702),
Staker(0xC9D32C7e16d71aF1739618356F1e3F2c69e8784a, 2_812_672_628_757_140_199),
Staker(0xFF30D836794Bfe71E888A7aa2AB62BfFb3F7a73a, 23_218_272_203_140_765_926),
Staker(0xCcC24DD1FE711d9f47A42a04b16b789669A21C98, 252_786_587_455_637_451_074),
Staker(0x0091a0aAF911A27133713028a83644224FcD7103, 4_391_483_020_114_108_858),
Staker(0x74E5B46a2A39F86ECc8CABCc409556953A688484, 3_576_335_685_734_120_104),
@@ -241,7 +227,6 @@ contract RestoreRewardsProposal {
Staker(0xc8d51E5a9293426d678400f05fDF8395fFE34187, 1_159_086_427_507_011_821),
Staker(0x1CE7DC66CC98c61A573105514d073D64a9a8608f, 26_389_224_886_673_669_669),
Staker(0xD3069f6050A3dd4ECCc27b6A66E5C401aB59DeD5, 1_131_703_913_861_582_424_146),
Staker(0xC796A650D6e7869D1c22642Bf0a4c7D5b3bbed32, 6_099_909_659_507_227_766),
Staker(0xc6DFfE2C1C910A3E049b29638bE0286645054f3C, 29_472_347_834_775_340_843),
Staker(0x2753dEeD6Fc665ff159c94aEAFb8a19E4525831E, 25_294_315_679_682_630_786),
Staker(0x0d4E989c7620C8749c9417d2BF218896C767B606, 3_364_398_457_228_954_809_190),
@@ -254,7 +239,6 @@ contract RestoreRewardsProposal {
Staker(0x24f04EC62597C11752c47448228B63052ED3158a, 90_815_074_343_246_091_464),
Staker(0xA11109126af2c5904fdc5b6203108Fef5770E85E, 17_491_569_071_641_631_106),
Staker(0x8904FFC6Aa039dB5941De11309a42372F3F7D2FD, 89_018_897_961_346_317_265),
Staker(0x95Be36B3F6a5DC958c59a4a81FdF0BEE671f26F3, 92_179_556_551_282_444_104),
Staker(0xa729adDeFe1fa7BCe87053ed55D55EDdDD13De60, 21_709_183_619_942_034_343),
Staker(0x409ac9C16B2CD569EC06bb9eceF97eeFDe0e8054, 15_006_870_038_073_374_755),
Staker(0xdF3c8E63677C79b24608bDed80CeD65667513BcB, 541_718_227_741_233_200_336),
@@ -287,7 +271,6 @@ contract RestoreRewardsProposal {
Staker(0x26D3b88d464A575784Be70Edc5F9290dC5e296DB, 143_520_553_783_208_184_300),
Staker(0x4ffc1A4bD191935C603df061065Ce97C25C70687, 1_104_677_208_403_973_125),
Staker(0x7Abbdbd51813d85B448F887b946719Dd2B09D6F7, 28_496_157_399_564_678_982),
Staker(0xEb89EfE3Ed80288E310c5529e1E242b4ab56E196, 10_158_103_172_727_951_367),
Staker(0x3C7ddEB357e4341A18cfC587343a4463a280B9c5, 15_766_263_220_154_597_250),
Staker(0x8633ADAf2438703d6D7f953829A4fe0c95FbeC44, 14_574_784_535_592_207_846),
Staker(0xAD142B79f2500Bf194C174f06C7dC901A2CdA74f, 7_123_937_386_942_958_617),
@@ -315,7 +298,6 @@ contract RestoreRewardsProposal {
Staker(0x16eb5Fbb2a5c7dAbC2c7688482378e89471d5724, 56_528_851_406_540_169_265),
Staker(0x356eE97D7D560af2E97E9f9EEe56b2e09D60e6F5, 2_357_571_123_330_435_682_004),
Staker(0x000AD8F56D3408abE29466189612d1B7B19E4420, 8_944_601_804_979_063_344),
Staker(0xc82ceD242a7c064EC0ef3742BDea830aEB46D614, 225_374_382_403_472_958_564),
Staker(0xAd412239848f37a5dDb8fAbb523D05F4FFdB2651, 1_852_483_360_172_530_551),
Staker(0x21c756E2c7B898BDa8a3b2A77e4C56D855Ab9414, 52_258_855_596_837_389_305),
Staker(0xa6Ba7cddc1c4fBfFBA96eCE341F9baA1c35fA76e, 10_324_733_292_812_452_226),
@@ -350,14 +332,12 @@ contract RestoreRewardsProposal {
Staker(0xA103c48Dbe3E804C23a98C5f159cEb3305c28E7b, 3_039_820_725_899_735_674),
Staker(0xab03945BC97F6899902D4296Ff97cAE8dbdc1A11, 66_797_846_279_254_338_952),
Staker(0xB945e8074C3e2F758B045Cb9a30066EE33CDB87E, 8_960_852_709_660_572_526),
Staker(0xDEB1c51514ee12d9F76Eb67AfCb7B4c33B466449, 8_131_473_545_148_842_396),
Staker(0x00377B2FC0044Dec6507855eDd6531aF1755cCe4, 187_316_100_663_496_504_711),
Staker(0xDaABa4C3a3026149a7a811bcb4B4EE9F23B61800, 1_342_110_570_226_429_076),
Staker(0x10aab4B0EF76AA2AC9b5909e671517a1171B050E, 9_816_488_209_589_379_461),
Staker(0xD9D10dc5609d77F2A15FAa68414835A6ed19269B, 95_363_084_515_727_944_710),
Staker(0x71e989dC58c879D26C2efDce097edeE505A57a28, 2_088_864_348_657_925_026),
Staker(0xdF20a1124d6B44e19ad75675a622d9c9669E59B6, 88_352_293_222_343_728_212),
Staker(0xaA8B1a05dF753F54DE787a752cB9E7808f447820, 23_946_074_798_869_806_567),
Staker(0x7E5c540b343fB854782617dECc82FBc1745b5591, 14_767_739_390_099_031_589),
Staker(0x209D49fda266C0AB257648555f8459F90e154aEd, 129_761_028_103_842_230_426),
Staker(0xF4d2D64D1f9190A9daB0960c80e5C73c04710184, 20_259_718_574_398_138_635),
@@ -386,11 +366,7 @@ contract RestoreRewardsProposal {
Staker(0xea76eE7035aF65410D290cB7E2Ed8Fc01C395266, 6_866_348_488_289_388_870),
Staker(0xC2e6B265cb965DED721566f0f9Eb5ab1A6162A21, 22_971_027_302_959_450_151),
Staker(0x4d6A11EbEC10E133A5007578Ad792F765ED724F2, 1_523_390_814_593_599_013_009),
Staker(0xaF305fEfDc439cb1CA9FAC2f9d271fD2CC7B3F05, 34_558_215_533_487_668_461),
Staker(0x164f9ECFc5Ec74fAC1Ba1ca28E71Fd57FeadCD27, 43_630_581_854_870_958_303),
Staker(0xddbc1841BE23b2ab55501Deb4d6bc39E3f8AA2d7, 57_697_184_564_150_419_473),
Staker(0x7b5edF38D955dd9deC103aF05c2D68B28e02Ad90, 990_145_869_312_977_038_005),
Staker(0xE4143f6377AEcd7193b9731d1C28815b57C4f5Ab, 794_513_313_076_462_735_653),
Staker(0x9Fd4d0dE8A3A8a8F2aC003A5ece295CE9512d9c6, 36_016_585_133_757_988_164),
Staker(0x3390937ec4D4b94002BCacf65D2F98594b4980eF, 6_453_311_584_351_983_424),
Staker(0xA207ac236dFdeE6F885d0Cc1D0C8100b46fA91EE, 1_450_736_948_351_239_615),
@@ -399,12 +375,9 @@ contract RestoreRewardsProposal {
Staker(0xc71cB68d38dF4E2190128DCb7E39bD1e72Fc3A2F, 13_498_777_595_192_377_744),
Staker(0x3E40eCBf8eB74fB708b8cCeA28c1C9312697aFDd, 2_547_293_201_582_353_144),
Staker(0x1e4d844528F3C9890bE6c3de38Dc8c695Cd06B20, 27_853_939_827_678_230_227),
Staker(0x45a4a7b51f8691Bd52988d8ee3f01F7518f6B056, 11_167_199_970_888_954_708),
Staker(0x4BF646757dA7067E683EB20cD122AfFBc0E67e39, 4_512_233_232_588_903_004),
Staker(0xb6242d8F02bA15917A84bD83C2eeee0e45288a03, 9_403_472_182_706_909_584),
Staker(0x6f4CbC2E042ed0D1Df4bf14d00eEb52Ff1E0e5F8, 9_748_334_349_185_074_783),
Staker(0x92374BA66EE27f207F9efff0837FF6D707006304, 58_838_358_111_071_620_908),
Staker(0x6dF07d3864c5F7ee564B5920199374C0b864E7d6, 664_290_901_673_954_681_162),
Staker(0x04700e0Ef1bCD91d36e7CE63FE93d651DFB272cA, 13_074_452_933_044_923_946),
Staker(0x8a1d5F23566c802CccEF7f02d5f216c37c8e44aD, 1_481_488_396_230_202_148),
Staker(0xfa2176D82cbA00d54998E6C37616b75ceCef08a0, 8_723_821_105_751_268_318),
@@ -412,7 +385,6 @@ contract RestoreRewardsProposal {
Staker(0x592340957eBC9e4Afb0E9Af221d06fDDDF789de9, 3_571_261_202_347_432_870),
Staker(0x000000Cd6521Ed1a65FAe0678eA15aF4EEAD74fe, 1_431_414_111_205_873_746),
Staker(0xC49415493eB3Ec64a0F13D8AA5056f1CfC4ce35c, 1_213_791_173_344_605_522),
Staker(0xa6eDC956290b7Ce416c5d8EDc67E1C32506Fe099, 366_757_732_355_918_570_636),
Staker(0xbd0fac9A19E8E19F6245eD20411E22D4786752c8, 4_355_144_205_984_655_655)
];
@@ -420,6 +392,6 @@ contract RestoreRewardsProposal {
accrueOldReward(stakers[i].addr, stakers[i].oldRewards);
}
IERC20(tornAddress).transfer(stakingProxyAddress, 51_038_101_771_805_874_869_526);
IERC20(tornAddress).transfer(stakingProxyAddress, 42_754_780_712_309_224_285_728);
}
}

View File

@@ -13,4 +13,8 @@ interface ITornadoStakingRewards {
function checkReward(address account) external view returns (uint256);
function accumulatedRewards(address account) external view returns (uint256);
function accumulatedRewardPerTorn() external view returns (uint256);
function addBurnRewards(uint256 amount) external;
}

View File

@@ -42,8 +42,12 @@ contract Mock {
uint16 public constant PERMIT_FUNC_SELECTOR = uint16(0x1901);
function getOldStakers() public pure returns (Staker[385] memory) {
Staker[385] memory stakers = [
uint256 public constant cheatingStakersCount = 357;
uint256 public constant summaryRestoreAmount = 42_754_780_712_309_224_285_728;
function getOldStakers() public pure returns (Staker[cheatingStakersCount] memory) {
Staker[cheatingStakersCount] memory stakers = [
Staker(0xb2C95127308876B0dA00dCE7798412bcA95C9Fee, 261_891_050_760_386_479_981),
Staker(0x52f4B90dF9560E50389107baCCD13e8BC1e5a516, 5_519_577_581_187_935_401),
Staker(0x679959449b608AF08d9419fE66D4e985c7d64D96, 6_634_938_965_540_161_678),
@@ -56,12 +60,9 @@ contract Mock {
Staker(0x201dD47dadA5165D792e6B4bDC2600e2FC5d7375, 3_376_734_302_476_765_689),
Staker(0x97b90FBc8904F861F76CB06BFa0A465b72C5E662, 85_583_028_288_278_705_143),
Staker(0xd3660816c68EF4DB79D2cCBFA2E6D623dfD65699, 135_764_830_626_382_535_905),
Staker(0xa3a7EAe904e92fA67c1888C6572Ac884722f5288, 63_755_633_956_332_846_740),
Staker(0xBFb910652F850F85E3F85AA0C12aE8f4037095b0, 33_237_171_239_790_116_387),
Staker(0x32f8E5d3F4039d1DF89B6A1e544288289A500Fd1, 1_536_360_162_595_381_679),
Staker(0xe2506955723C01dDd6e619dD0829e28F76328c41, 72_958_648_431_519_163_392),
Staker(0x3Df488Bd07C2082E84B1CD63F343Cf3d538342bA, 107_098_359_836_630_121_582),
Staker(0x6a90E7Ba20291CDF651A6d61ebf2371BA89EF04B, 46_595_274_664_224_710_080),
Staker(0x0b7C43AF43D76f79b6f6CfBAFb3A01ddE0468225, 18_243_581_064_710_552_362),
Staker(0x524b7c9B4cA33ba72445DFd2d6404C81d8D1F2E3, 8_414_647_798_389_006_172),
Staker(0xfDEEc44b6c63E637fA3348092A9F952A02B2E695, 1_468_551_637_230_600_353),
@@ -73,17 +74,11 @@ contract Mock {
Staker(0xB1583e01ACA426807985FAf9438c9a4cEF73B1A7, 2_769_004_780_372_765_071),
Staker(0xcDfb26F93F2D5e0F4b76190e5bC740b3A3DA16F4, 1_986_870_853_342_994_225),
Staker(0xDbcb5D2a6c77F1a8069ff686F88FC552F2F3eFCC, 2_691_179_623_359_894_955),
Staker(0x15Ed2710d0097CE9BC352Db97287bDd9104bEC92, 517_823_661_753_566_090_385),
Staker(0x85f8BeC61f75De3Dbad1bBd4CDD168ea362bDaeA, 118_525_403_763_250_297_030),
Staker(0xac57C7A3960Ba383b94b28BF44f9cdC26B84A8e7, 766_340_829_474_823_777_721),
Staker(0xEFb7Ce1357F324a324A8EABDc443b26894A2b246, 721_114_114_180_262_809_591),
Staker(0x84781094f9B11aCb35A7Dca31D731A244B25E6a4, 389_646_430_287_742_483_283),
Staker(0xA3A89931799Ba449A7bd1658EfD9C8662dd22BcA, 4_471_048_279_368_398_062),
Staker(0x13e50a5e7D695ae729Da77623c61661B27A3b60a, 25_552_108_041_996_067_156),
Staker(0xeafA9AA6832c076D5af3d58D9224E218CA074f04, 3_278_339_837_838_322_677),
Staker(0x25713B024a8004727Ba79c43647a77c7447948dB, 16_833_083_830_815_723_474),
Staker(0x73D23cDaBBb25B0E039470ea940514Ca30744277, 6_268_058_376_469_446_863),
Staker(0x11FD8380FcEF61E7D1FC054d4Ba20D7230a5593A, 241_999_616_776_245_144_340),
Staker(0xB157ba30e3467DdBC844f14F02b4ba741f1d549F, 65_080_791_858_799_563_574),
Staker(0xB6dA1D0cac0CAC8d39125d5213E1623750525ed5, 3_582_972_520_064_518_922),
Staker(0xEBf919b0DAfb9ea4BF324108A142C64A69052D8f, 1_492_116_146_713_012_865_552),
@@ -92,7 +87,6 @@ contract Mock {
Staker(0x076b499e9191A29Fa9210e497cBd89DABC878B6E, 4_403_836_602_105_176_579),
Staker(0x83c418D2eD6670785330B996b47a18492b61e218, 2_423_008_690_534_464_349_496),
Staker(0xcD37EF9120132F71E23982881e19B68aE3B4E871, 6_094_554_447_886_213_907),
Staker(0xe44799Ef334Df157e0F8e2855E5EbeBdBc02b299, 498_687_077_665_731_358_140),
Staker(0xff36EdACcEebADC368ea6CACA13E5f3bBD1b43AC, 1_685_473_922_303_763_108),
Staker(0x312044825EB5CD2C4Bb016a7a86ce32240Af9136, 27_126_619_039_727_679_328),
Staker(0x3035A1bBd824041B07f8Ab2297a71A81E00127c5, 14_756_069_076_031_120_181),
@@ -105,8 +99,6 @@ contract Mock {
Staker(0xF99d1946Bf038a1205d430Ec91401E760e5F8F6F, 8_151_047_628_859_550_523_186),
Staker(0x9897Bc7231492CDf163BB81bFF10A5919a73d132, 3_388_092_111_567_580_393_688),
Staker(0x8953C798a6F54ea8907875c51e5D466DE76A1b26, 797_098_747_089_744_161_355),
Staker(0x9C42EBDf0fA6fA0274aEEBf981613Dfa9c99BFF8, 1_151_021_932_914_438_641_249),
Staker(0xD88189f7Dee6E5DBd6cbC6F06FD357f4Bf7f330b, 1_435_829_849_735_697_778_451),
Staker(0xf4DcA9B37f09D15f8dF740055cEaA860912efe2C, 2_569_990_661_510_076_867),
Staker(0xAdE9e51C9E23d64E538A7A38656B78aB6Bcc349e, 146_771_928_128_749_080_734),
Staker(0xeE1D1ac27A80De54F0ba92b2E25EBb3418495db2, 2_943_758_390_988_392_723),
@@ -192,13 +184,11 @@ contract Mock {
Staker(0x48Ef3De608AB2304dBB0c4497d266F3BF5506e7B, 1_346_590_027_777_001_145),
Staker(0x3716905b040D5cd8a7DdE784918199117d72c3B3, 1_400_844_245_925_263_369),
Staker(0xB835b4e277094D4AF9Fbb66e9f5Db9e6E8dC65dB, 25_683_271_096_264_423_274),
Staker(0x08d19484246a987411e04a7F098E36F92cad4f24, 20_246_123_092_729_700_406),
Staker(0x42DbF634c256acd17beDDC1330488F1BEa7B8BDf, 319_523_008_529_625_373_272),
Staker(0xE7304bA0f157f2Ade94015934284b6704BC72911, 39_826_654_578_302_448_107),
Staker(0xE06bF8125273Ead3814aBDE0D548079991F5DD8a, 22_645_804_997_633_317_877),
Staker(0xaa9298F0c3e97DdA6277713fd3Ed6e2A389E7260, 3_572_475_984_033_907_702),
Staker(0xC9D32C7e16d71aF1739618356F1e3F2c69e8784a, 2_812_672_628_757_140_199),
Staker(0xFF30D836794Bfe71E888A7aa2AB62BfFb3F7a73a, 23_218_272_203_140_765_926),
Staker(0xCcC24DD1FE711d9f47A42a04b16b789669A21C98, 252_786_587_455_637_451_074),
Staker(0x0091a0aAF911A27133713028a83644224FcD7103, 4_391_483_020_114_108_858),
Staker(0x74E5B46a2A39F86ECc8CABCc409556953A688484, 3_576_335_685_734_120_104),
@@ -256,7 +246,6 @@ contract Mock {
Staker(0xc8d51E5a9293426d678400f05fDF8395fFE34187, 1_159_086_427_507_011_821),
Staker(0x1CE7DC66CC98c61A573105514d073D64a9a8608f, 26_389_224_886_673_669_669),
Staker(0xD3069f6050A3dd4ECCc27b6A66E5C401aB59DeD5, 1_131_703_913_861_582_424_146),
Staker(0xC796A650D6e7869D1c22642Bf0a4c7D5b3bbed32, 6_099_909_659_507_227_766),
Staker(0xc6DFfE2C1C910A3E049b29638bE0286645054f3C, 29_472_347_834_775_340_843),
Staker(0x2753dEeD6Fc665ff159c94aEAFb8a19E4525831E, 25_294_315_679_682_630_786),
Staker(0x0d4E989c7620C8749c9417d2BF218896C767B606, 3_364_398_457_228_954_809_190),
@@ -269,7 +258,6 @@ contract Mock {
Staker(0x24f04EC62597C11752c47448228B63052ED3158a, 90_815_074_343_246_091_464),
Staker(0xA11109126af2c5904fdc5b6203108Fef5770E85E, 17_491_569_071_641_631_106),
Staker(0x8904FFC6Aa039dB5941De11309a42372F3F7D2FD, 89_018_897_961_346_317_265),
Staker(0x95Be36B3F6a5DC958c59a4a81FdF0BEE671f26F3, 92_179_556_551_282_444_104),
Staker(0xa729adDeFe1fa7BCe87053ed55D55EDdDD13De60, 21_709_183_619_942_034_343),
Staker(0x409ac9C16B2CD569EC06bb9eceF97eeFDe0e8054, 15_006_870_038_073_374_755),
Staker(0xdF3c8E63677C79b24608bDed80CeD65667513BcB, 541_718_227_741_233_200_336),
@@ -302,7 +290,6 @@ contract Mock {
Staker(0x26D3b88d464A575784Be70Edc5F9290dC5e296DB, 143_520_553_783_208_184_300),
Staker(0x4ffc1A4bD191935C603df061065Ce97C25C70687, 1_104_677_208_403_973_125),
Staker(0x7Abbdbd51813d85B448F887b946719Dd2B09D6F7, 28_496_157_399_564_678_982),
Staker(0xEb89EfE3Ed80288E310c5529e1E242b4ab56E196, 10_158_103_172_727_951_367),
Staker(0x3C7ddEB357e4341A18cfC587343a4463a280B9c5, 15_766_263_220_154_597_250),
Staker(0x8633ADAf2438703d6D7f953829A4fe0c95FbeC44, 14_574_784_535_592_207_846),
Staker(0xAD142B79f2500Bf194C174f06C7dC901A2CdA74f, 7_123_937_386_942_958_617),
@@ -330,7 +317,6 @@ contract Mock {
Staker(0x16eb5Fbb2a5c7dAbC2c7688482378e89471d5724, 56_528_851_406_540_169_265),
Staker(0x356eE97D7D560af2E97E9f9EEe56b2e09D60e6F5, 2_357_571_123_330_435_682_004),
Staker(0x000AD8F56D3408abE29466189612d1B7B19E4420, 8_944_601_804_979_063_344),
Staker(0xc82ceD242a7c064EC0ef3742BDea830aEB46D614, 225_374_382_403_472_958_564),
Staker(0xAd412239848f37a5dDb8fAbb523D05F4FFdB2651, 1_852_483_360_172_530_551),
Staker(0x21c756E2c7B898BDa8a3b2A77e4C56D855Ab9414, 52_258_855_596_837_389_305),
Staker(0xa6Ba7cddc1c4fBfFBA96eCE341F9baA1c35fA76e, 10_324_733_292_812_452_226),
@@ -365,14 +351,12 @@ contract Mock {
Staker(0xA103c48Dbe3E804C23a98C5f159cEb3305c28E7b, 3_039_820_725_899_735_674),
Staker(0xab03945BC97F6899902D4296Ff97cAE8dbdc1A11, 66_797_846_279_254_338_952),
Staker(0xB945e8074C3e2F758B045Cb9a30066EE33CDB87E, 8_960_852_709_660_572_526),
Staker(0xDEB1c51514ee12d9F76Eb67AfCb7B4c33B466449, 8_131_473_545_148_842_396),
Staker(0x00377B2FC0044Dec6507855eDd6531aF1755cCe4, 187_316_100_663_496_504_711),
Staker(0xDaABa4C3a3026149a7a811bcb4B4EE9F23B61800, 1_342_110_570_226_429_076),
Staker(0x10aab4B0EF76AA2AC9b5909e671517a1171B050E, 9_816_488_209_589_379_461),
Staker(0xD9D10dc5609d77F2A15FAa68414835A6ed19269B, 95_363_084_515_727_944_710),
Staker(0x71e989dC58c879D26C2efDce097edeE505A57a28, 2_088_864_348_657_925_026),
Staker(0xdF20a1124d6B44e19ad75675a622d9c9669E59B6, 88_352_293_222_343_728_212),
Staker(0xaA8B1a05dF753F54DE787a752cB9E7808f447820, 23_946_074_798_869_806_567),
Staker(0x7E5c540b343fB854782617dECc82FBc1745b5591, 14_767_739_390_099_031_589),
Staker(0x209D49fda266C0AB257648555f8459F90e154aEd, 129_761_028_103_842_230_426),
Staker(0xF4d2D64D1f9190A9daB0960c80e5C73c04710184, 20_259_718_574_398_138_635),
@@ -401,11 +385,7 @@ contract Mock {
Staker(0xea76eE7035aF65410D290cB7E2Ed8Fc01C395266, 6_866_348_488_289_388_870),
Staker(0xC2e6B265cb965DED721566f0f9Eb5ab1A6162A21, 22_971_027_302_959_450_151),
Staker(0x4d6A11EbEC10E133A5007578Ad792F765ED724F2, 1_523_390_814_593_599_013_009),
Staker(0xaF305fEfDc439cb1CA9FAC2f9d271fD2CC7B3F05, 34_558_215_533_487_668_461),
Staker(0x164f9ECFc5Ec74fAC1Ba1ca28E71Fd57FeadCD27, 43_630_581_854_870_958_303),
Staker(0xddbc1841BE23b2ab55501Deb4d6bc39E3f8AA2d7, 57_697_184_564_150_419_473),
Staker(0x7b5edF38D955dd9deC103aF05c2D68B28e02Ad90, 990_145_869_312_977_038_005),
Staker(0xE4143f6377AEcd7193b9731d1C28815b57C4f5Ab, 794_513_313_076_462_735_653),
Staker(0x9Fd4d0dE8A3A8a8F2aC003A5ece295CE9512d9c6, 36_016_585_133_757_988_164),
Staker(0x3390937ec4D4b94002BCacf65D2F98594b4980eF, 6_453_311_584_351_983_424),
Staker(0xA207ac236dFdeE6F885d0Cc1D0C8100b46fA91EE, 1_450_736_948_351_239_615),
@@ -414,12 +394,9 @@ contract Mock {
Staker(0xc71cB68d38dF4E2190128DCb7E39bD1e72Fc3A2F, 13_498_777_595_192_377_744),
Staker(0x3E40eCBf8eB74fB708b8cCeA28c1C9312697aFDd, 2_547_293_201_582_353_144),
Staker(0x1e4d844528F3C9890bE6c3de38Dc8c695Cd06B20, 27_853_939_827_678_230_227),
Staker(0x45a4a7b51f8691Bd52988d8ee3f01F7518f6B056, 11_167_199_970_888_954_708),
Staker(0x4BF646757dA7067E683EB20cD122AfFBc0E67e39, 4_512_233_232_588_903_004),
Staker(0xb6242d8F02bA15917A84bD83C2eeee0e45288a03, 9_403_472_182_706_909_584),
Staker(0x6f4CbC2E042ed0D1Df4bf14d00eEb52Ff1E0e5F8, 9_748_334_349_185_074_783),
Staker(0x92374BA66EE27f207F9efff0837FF6D707006304, 58_838_358_111_071_620_908),
Staker(0x6dF07d3864c5F7ee564B5920199374C0b864E7d6, 664_290_901_673_954_681_162),
Staker(0x04700e0Ef1bCD91d36e7CE63FE93d651DFB272cA, 13_074_452_933_044_923_946),
Staker(0x8a1d5F23566c802CccEF7f02d5f216c37c8e44aD, 1_481_488_396_230_202_148),
Staker(0xfa2176D82cbA00d54998E6C37616b75ceCef08a0, 8_723_821_105_751_268_318),
@@ -427,7 +404,6 @@ contract Mock {
Staker(0x592340957eBC9e4Afb0E9Af221d06fDDDF789de9, 3_571_261_202_347_432_870),
Staker(0x000000Cd6521Ed1a65FAe0678eA15aF4EEAD74fe, 1_431_414_111_205_873_746),
Staker(0xC49415493eB3Ec64a0F13D8AA5056f1CfC4ce35c, 1_213_791_173_344_605_522),
Staker(0xa6eDC956290b7Ce416c5d8EDc67E1C32506Fe099, 366_757_732_355_918_570_636),
Staker(0xbd0fac9A19E8E19F6245eD20411E22D4786752c8, 4_355_144_205_984_655_655)
];

View File

@@ -16,21 +16,12 @@ contract MockProposal is Test, ProposalUtils {
_;
}
function createAndVoteProposal() public returns (uint256) {
function createAndExecuteProposal() public {
TornadoStakingRewards governanceStakingImplementation =
new TornadoStakingRewards(_governanceAddress, _tokenAddress, _relayerRegistryAddress);
RestoreRewardsProposal proposal = new RestoreRewardsProposal(address(governanceStakingImplementation));
uint256 proposalId = proposeAndVote(address(proposal));
return proposalId;
}
function createAndExecuteProposal() public {
uint256 proposalId = createAndVoteProposal();
waitUntilExecutable(proposalId);
IGovernance(_governanceAddress).execute(proposalId);
proposeAndExecute(address(proposal));
}
}

View File

@@ -13,7 +13,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract TestProposal is MockProposal {
ITornadoStakingRewards staking = ITornadoStakingRewards(_stakingAddress);
function testGovernanceBalance() internal {
function testGovernanceBalance() public {
IERC20 TORN = IERC20(_tokenAddress);
uint256 governanceBalanceBeforeExecution = TORN.balanceOf(_governanceAddress);
@@ -23,16 +23,21 @@ contract TestProposal is MockProposal {
uint256 governanceBalanceAfterExecution = TORN.balanceOf(_governanceAddress);
console2.log("Governance balance after proposal execution: %s TORN", governanceBalanceAfterExecution / _tornDecimals);
uint256 governanceBalanceDifference = governanceBalanceBeforeExecution - governanceBalanceAfterExecution;
console2.log("Governance balance difference: %s TORN, %s", governanceBalanceDifference / _tornDecimals, governanceBalanceDifference);
require(governanceBalanceDifference == summaryRestoreAmount, "Incorrect Governance balance after execution");
}
function testOtherUsersRewardUnchanged() public {
uint256 rewardsBeforeProposal = staking.checkReward(TEST_REAL_ADDRESS_WITH_BALANCE);
console2.log("Developer rewards before proposal execution: %s TORN", rewardsBeforeProposal);
console2.log("Developer rewards before proposal execution: %s TORN", rewardsBeforeProposal / _tornDecimals);
createAndExecuteProposal();
uint256 rewardsAfterProposal = staking.checkReward(TEST_REAL_ADDRESS_WITH_BALANCE);
console2.log("Developer rewards after proposal execution: %s TORN", rewardsBeforeProposal);
console2.log("Developer rewards after proposal execution: %s TORN", rewardsBeforeProposal / _tornDecimals);
require(rewardsAfterProposal == rewardsBeforeProposal, "Other stakers rewards changed");
}
@@ -53,7 +58,7 @@ contract TestProposal is MockProposal {
require(staking.checkReward(TEST_ADDRESS_ONE) == 100_000 ether, "Rewards not accrued by Governance");
}
function getStakersRewardsSum(Staker[385] memory stakers) internal returns (uint256) {
function getStakersRewardsSum(Staker[cheatingStakersCount] memory stakers) internal returns (uint256) {
uint256 rewardsSum = 0;
for (uint16 i = 0; i < stakers.length; i++) {
rewardsSum += staking.accumulatedRewards(stakers[i].addr);
@@ -63,10 +68,10 @@ contract TestProposal is MockProposal {
}
function testVerifyStakersAccrual() internal {
Staker[385] memory stakers = getOldStakers();
Staker[cheatingStakersCount] memory stakers = getOldStakers();
uint256[385] memory rewardsBefore;
uint256[385] memory rewardsAfter;
uint256[cheatingStakersCount] memory rewardsBefore;
uint256[cheatingStakersCount] memory rewardsAfter;
for (uint16 i = 0; i < stakers.length; i++) {
rewardsBefore[i] = staking.accumulatedRewards(stakers[i].addr);
@@ -89,7 +94,7 @@ contract TestProposal is MockProposal {
}
function testStakingContractReplenishedCorrect() public {
Staker[385] memory stakers = getOldStakers();
Staker[cheatingStakersCount] memory stakers = getOldStakers();
uint256 stakersRewardsSumBeforeExecution = getStakersRewardsSum(stakers);
console2.log("Old stakers rewards sum before proposal execution: %s TORN", stakersRewardsSumBeforeExecution / _tornDecimals);
@@ -116,4 +121,72 @@ contract TestProposal is MockProposal {
"Staking replenish sum doesn't match with stakers restored rewards sum"
);
}
function testAccumulatedRewardPerTornNotChanged() public {
uint256 accumulatedRewardsPerTornBeforeExecution = staking.accumulatedRewardPerTorn();
console2.log("Accumulated reward per 1 TORN before proposal execution: %s", accumulatedRewardsPerTornBeforeExecution / _tornMaximumSupply);
createAndExecuteProposal();
uint256 accumulatedRewardsPerTornAfterExecution = staking.accumulatedRewardPerTorn();
console2.log("Accumulated reward per 1 TORN after proposal execution: %s", accumulatedRewardsPerTornAfterExecution / _tornMaximumSupply);
require(accumulatedRewardsPerTornBeforeExecution == accumulatedRewardsPerTornAfterExecution, "Accumulater reward per TORN changed");
}
function testRewardAccrualsMechanismCorrect() public executeCurrentProposalBefore {
IERC20 TORN = IERC20(_tokenAddress);
uint256 toBurn = 10_000 ether;
retrieveAndLockBalance(TEST_STAKER_PRIVATE_KEY, TEST_STAKER_ADDRESS, PROPOSAL_THRESHOLD);
uint256 stakerLockedBalance = governance.lockedBalance(TEST_STAKER_ADDRESS);
require(stakerLockedBalance == PROPOSAL_THRESHOLD, "Invalid test staker locked balance");
uint256 stakerRewardsBeforeBurning = staking.checkReward(TEST_STAKER_ADDRESS);
console2.log("Staking rewards before burning: %s TORN", stakerRewardsBeforeBurning / _tornDecimals);
burnTokens(_governanceAddress, toBurn, staking);
uint256 stakerRewardsAfterBurning = staking.checkReward(TEST_STAKER_ADDRESS);
console2.log(
"Staking rewards after burning 10 000 TORN: %s TORN\n", stakerRewardsAfterBurning / _tornDecimals
);
require(stakerRewardsAfterBurning > stakerRewardsBeforeBurning, "Rewards isn't changed after burning");
// All TORN, locked by users in Governance, is on the userVault contract balance
uint256 governanceLockedAmount = TORN.balanceOf(governance.userVault());
uint256 receivedReward = stakerRewardsAfterBurning - stakerRewardsBeforeBurning;
uint256 expectedRewards = stakerLockedBalance * toBurn / governanceLockedAmount;
console2.log("Expected staking rewards: %s TORN", expectedRewards / _tornDecimals);
console2.log("Staker received rewards: %s TORN\n", receivedReward / _tornDecimals);
require(receivedReward == expectedRewards, "Expected and received rewards don't match");
}
function testAccumulatedRewardCanBeUpdated() public executeCurrentProposalBefore {
uint256 accumulatedRewardPerTornBeforeBurning =
staking.accumulatedRewardPerTorn() / _tornMaximumSupply;
console2.log(
"Accumulated reward per TORN right after proposal execution: %s TORN",
accumulatedRewardPerTornBeforeBurning / _tornDecimals
);
burnTokens(_governanceAddress, 10_000_000 ether, staking);
uint256 accumulatedRewardPerTornAfterBurning = staking.accumulatedRewardPerTorn() / _tornMaximumSupply;
console2.log(
"Accumulated reward per TORN after burning 10 000 000 TORN: ~ %s TORN",
accumulatedRewardPerTornAfterBurning / _tornDecimals
);
require(
accumulatedRewardPerTornAfterBurning > accumulatedRewardPerTornBeforeBurning,
"Staking rewards isn't updated"
);
}
}

View File

@@ -5,6 +5,8 @@ pragma experimental ABIEncoderV2;
import { Utils } from "./Utils.sol";
import { Proposal, IGovernance } from "./interfaces/IGovernance.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract ProposalUtils is Utils {
IGovernance internal governance = IGovernance(payable(_governanceAddress));
@@ -29,8 +31,7 @@ contract ProposalUtils is Utils {
}
function proposeAndVote(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);
retrieveAndLockBalance(TEST_PRIVATE_KEY_ONE, TEST_ADDRESS_ONE, PROPOSAL_THRESHOLD + 1 ether);
/* ----------PROPOSER------------ */
vm.startPrank(TEST_ADDRESS_ONE);
@@ -45,12 +46,6 @@ contract ProposalUtils is Utils {
vm.stopPrank();
/* ------------------------------ */
/* -------------VOTER-------------*/
vm.startPrank(TEST_ADDRESS_TWO);
governance.castVote(proposalId, true);
vm.stopPrank();
/* ------------------------------ */
return proposalId;
}
@@ -59,5 +54,23 @@ contract ProposalUtils is Utils {
waitUntilExecutable(proposalId);
IGovernance(_governanceAddress).execute(proposalId);
returnTokensToGovernanceAfterVoting(proposalId);
}
function returnTokensToGovernanceAfterVoting(uint256 proposalId) public {
uint256 retrievedAmount = PROPOSAL_THRESHOLD + 1 ether;
uint256 proposalExecutableTime = getProposalExecutableTime(proposalId);
uint256 tokensUnlockTime = proposalExecutableTime + 4 days + 1 seconds;
if(block.timestamp < tokensUnlockTime) vm.warp(tokensUnlockTime);
vm.startPrank(TEST_ADDRESS_ONE);
governance.unlock(retrievedAmount);
IERC20(_tokenAddress).transfer(_governanceAddress, retrievedAmount);
vm.stopPrank();
}
}

View File

@@ -7,6 +7,7 @@ import { ERC20Permit } from "torn-token/contracts/ERC20Permit.sol";
import { Test } from "@forge-std/Test.sol";
import { Parameters } from "@proprietary/Parameters.sol";
import { ITornadoStakingRewards } from "@interfaces/ITornadoStakingRewards.sol";
import { Mock } from "./Mock.sol";
import { IGovernance } from "./interfaces/IGovernance.sol";
@@ -37,4 +38,10 @@ contract Utils is Parameters, Mock, Test {
vm.stopPrank();
/* ----------------------------*/
}
function burnTokens(address caller, uint256 amount, ITornadoStakingRewards staking) internal {
vm.startPrank(caller);
staking.addBurnRewards(amount);
vm.stopPrank();
}
}

View File

@@ -41,4 +41,6 @@ interface IGovernance {
function unlock(uint256 amount) external;
function execute(uint256 proposalId) external payable;
function userVault() external view returns (address);
}

View File

@@ -0,0 +1,21 @@
import fs from "fs";
import path from "path";
import { getStakersLockedBalancesSum } from "../utils/stakers";
import { currentProposalVotingStartBlock } from "../utils/config";
async function main() {
const stakersLockedBalanceSum = await getStakersLockedBalancesSum(currentProposalVotingStartBlock);
console.log("Locked balance of stakers to who we want restore rewards:", stakersLockedBalanceSum.div(1e18).toFixed(2), "TORN");
fs.writeFileSync(
path.join("data", "stakersLockedBalanceSum.txt"),
`Locked balance of stakers to who we want restore rewards: ${stakersLockedBalanceSum.toString(10)} (~ ${stakersLockedBalanceSum
.div(1e18)
.toFixed(2)} TORN)`,
{ encoding: "utf-8" }
);
}
main();

View File

@@ -1,5 +1,8 @@
export const governanceAddress = "0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce";
export const oldStakingAddress = "0x2FC93484614a34f26F7970CBB94615bA109BB4bf";
export const multicallContractAddress = "0xeefBa1e63905eF1D7ACbA5a8513c70307C1cE441";
export const currentProposalVotingStartBlock = 17492630;
export const governanceDeployedBlock = 11474695;
export const governanceRewardsProposalBlock = 14173399;
export const hackBlock = 17299139;

View File

@@ -1,20 +1,21 @@
import Web3 from "web3";
import BigNumber from "bignumber.js"
import { AbiItem } from 'web3-utils';
import BigNumber from "bignumber.js";
import { AbiItem } from "web3-utils";
import { EthAddress, IStaker } from "./@types/staker";
import * as dotenv from "dotenv";
import { governanceAddress, governanceRewardsProposalBlock, hackBlock, oldStakingAddress } from "./config";
import { governanceAddress, governanceRewardsProposalBlock, hackBlock, oldStakingAddress, multicallContractAddress } from "./config";
import GovernanceAbi from "../abi/GovernanceAbi.json";
import StakingAbi from "../abi/StakingABI.json";
import MulticallABI from "../abi/MultiCallABI.json";
dotenv.config();
const web3 = new Web3(process.env.MAINNET_RPC_URL as string);
function getGovernanceFunctionSelector(functionName: string): string {
const lockFunctionAbi = GovernanceAbi.find(item => item.name == functionName);
const lockFunctionAbi = GovernanceAbi.find((item) => item.name == functionName);
if (!lockFunctionAbi) throw new Error(`Cannot find function ${functionName} in Governance contract ABI`);
const selector = web3.eth.abi.encodeFunctionSignature(lockFunctionAbi as AbiItem);
@@ -28,10 +29,11 @@ async function getAddressesStakersWithProssibleRewards(): Promise<Array<EthAddre
/* Don't need to fetch all "lock" or "lockAndApproval" transactions from Governance contract,
* because user rewards start updating only when RewardUpdateSuccessful events is emitted.
*/
const rewardsUpdateEvents =
await governanceContract.getPastEvents("RewardUpdateSuccessful", { fromBlock: governanceRewardsProposalBlock });
const rewardsUpdateEvents = await governanceContract.getPastEvents("RewardUpdateSuccessful", {
fromBlock: governanceRewardsProposalBlock,
});
const governanceStakers = rewardsUpdateEvents.map(event => event.returnValues.account as string);
const governanceStakers = rewardsUpdateEvents.map((event) => event.returnValues.account as string);
return [...new Set(governanceStakers)];
}
@@ -40,14 +42,59 @@ export async function getStakersWithRewardsBeforeHack(): Promise<Array<IStaker>>
const stakingContract = new web3.eth.Contract(StakingAbi as AbiItem[], oldStakingAddress);
const stakersAddresses = await getAddressesStakersWithProssibleRewards();
let stakersWithRewardsBeforeHack: Array<IStaker> = [];
for (const address of stakersAddresses) {
// Check stakers rewards on previous block before hack
const rewardsBeforeHack = await stakingContract.methods.checkReward(address).call({}, hackBlock - 1);
// Discard stakers with rewards less than 1 TORN, because accruing each reward requires paying gas
if (BigNumber(rewardsBeforeHack).div(1e18).isGreaterThan(1))
stakersWithRewardsBeforeHack.push({ address, rewardBalance: BigNumber(rewardsBeforeHack) });
const multiCallQuery: Array<[string, object]> = stakersAddresses.map((stakerAddress) =>
stakingContract.methods.checkReward(stakerAddress).encodeABI()
);
const stakersWithRewardsBeforeHackRawData = await useMultiCall(oldStakingAddress, multiCallQuery, hackBlock - 1);
const stakersWithRewardsBeforeHack: Array<IStaker> = stakersWithRewardsBeforeHackRawData.map((reward, index) => ({
address: stakersAddresses[index],
rewardBalance: BigNumber(reward),
}));
// let stakersWithRewardsBeforeHack: Array<IStaker> = [];
// for (const address of stakersAddresses) {
// // Check stakers rewards on previous block before hack
// const rewardsBeforeHack = await stakingContract.methods.checkReward(address).call({}, hackBlock - 1);
// // Discard stakers with rewards less than 1 TORN, because accruing each reward requires paying gas
// if (BigNumber(rewardsBeforeHack).div(1e18).isGreaterThan(1))
// stakersWithRewardsBeforeHack.push({ address, rewardBalance: BigNumber(rewardsBeforeHack) });
// }
return stakersWithRewardsBeforeHack.filter((staker) => staker.rewardBalance.div(1e18).isGreaterThan(1));
}
return stakersWithRewardsBeforeHack;
export async function getStakersWithdrawedAfterHack(): Promise<Array<EthAddress>> {
const stakingContract = new web3.eth.Contract(StakingAbi as AbiItem[], oldStakingAddress);
const withdrawRewardEvents = await stakingContract.getPastEvents("RewardsClaimed", { fromBlock: hackBlock });
const stakersWithdrawedAfterHack = withdrawRewardEvents.map((event) => event.returnValues.account as string);
return stakersWithdrawedAfterHack;
}
async function useMultiCall(contractAddress: EthAddress, queryArray: Array<Object>, callBlock?: number): Promise<any[]> {
const multiCallContract = new web3.eth.Contract(MulticallABI as AbiItem[], multicallContractAddress);
const multicallQueryArray = queryArray.map((query) => [contractAddress, query]);
const { returnData } = await multiCallContract.methods.aggregate(multicallQueryArray).call({}, callBlock);
return returnData;
}
export async function getStakersLockedBalancesSum(block: number): Promise<BigNumber> {
const governanceContract = new web3.eth.Contract(GovernanceAbi as AbiItem[], governanceAddress);
// All stakers who had more than 1 TORN in rewards at the time of the hack
const stakersWithRewardsBeforeHack = await getStakersWithRewardsBeforeHack();
// Stakers who withdrew rewards from the time of hack until the balance of the old Staking contract was nullified
const stakersWithdrawedAfterHack = await getStakersWithdrawedAfterHack();
// It makes no sense to restore awards to those who already withdrew them from the old Staking contract
const stakersToRestoreRewards = stakersWithRewardsBeforeHack.filter((staker) => !stakersWithdrawedAfterHack.includes(staker.address));
const lockedBalances: Array<string> = await useMultiCall(
governanceAddress,
stakersToRestoreRewards.map((staker) => governanceContract.methods.lockedBalance(staker.address).encodeABI()),
block
);
return lockedBalances.reduce((acc, cur) => acc.plus(BigNumber(cur)), BigNumber(0));
}