Context
After the Tornado hack, which occurred after proposal 20, in addition to the main losses associated with the hacker withdrawing 483 000 TORN from the Governance Vault, another problem arose - a broken Governance Staking contract and the withdrawal (via bug) of more than 130 000 TORN.
This happened for a very simple reason: when calculating the total reward for the withdrawal commission paid by the relayer in the staking contract, the addBurnRewards function and the accumulatedRewardPerTorn variable are responsible. The calculated reward per 1 TORN of staker funds depends, of course, on the total locked tokens - and Staking contract, since all staker funds must be in the Governance Vault, it simply checks the balance of the Vault contract.
Since almost all of the tokens in the Vault contract were withdrawn by the cracker, the few TORNs left in the Vault contract led to the emergence of a huge rewards out of nowhere from each relayer fee payment, which led to an increase in staker rewards to millions or even billions of TORNs. Since it was no longer possible to fix what had happened by changing the data in the contract, I had to create a new staking proxy contract and a logical contract (implementation), which was done in proposal 22. Since the old state (data on rewards and so on) remained in the previous proxy contract , after the execution of proposal 22, the rewards of all users were reset to zero - especially those who had honestly earned rewards before the hack and did not have time to withdraw them suffered.
Changes description
To restore rewards, needed:
- Change the logical contract (implementation) of Governance Staking by adding the setReward function, which will allow you to directly set rewards for stakers (of course, it can only be called using the proposal, on behalf of the Governance contract);
- Return the old rewards to the stakers - of course, only those who did not have time to withdraw them after the hack, and only those who had more than 1 TORN rewards - since we are limited by the commission and the maximum size of the contract compiled bytecode;
- Transfer the total amount of rewards returned to stakers (42 754 TORN) from the Governance contract to the Staking contract so that they can take the tokens without disturbing the balance of funds in the contract.
Proposal
https://git.tornado.ws/Theo/proposal-25-restore-rewards
The code includes the main proposal contract, all the functional code of which, except updating the Staking implementation contract, is automatically generated by a specific TS script.
This script first gets the addresses of all stakers, then checks their rewards before the hack, filters those who managed to withdraw from the moment of the hack to the moment the new Staking contract was created, calculates the total amount of returned tokens and generates a Solidity code that is written to the codeToAccrueRewards file .txt without a single change and then copied into the code of the main proposal contract. Anyone can run this code again by running npm run computeRewards
in the repository directory and compare it to the code in the proposal’s main contract.
Information about all stakers with balances over 1 TORN before the hack is in this file - you can check the details of any address yourself.
I also suggest that everyone compare the modified implementation of the Staking contract with the verified code of the actual implementation on etherscan - the difference is only in the new added setReward function.
New deployed & verified contracts
- Governance Staking Rewards implementation contract: etherscan code
- Proposal contract: etherscan code