LCOV - code coverage report
Current view: top level - v1/staking - TornadoStakingRewards.sol (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 19 0.0 %
Date: 2023-06-20 21:04:08 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // SPDX-License-Identifier: MIT
       2             : 
       3             : pragma solidity ^0.6.12;
       4             : pragma experimental ABIEncoderV2;
       5             : 
       6             : import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
       7             : import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
       8             : import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
       9             : import { Initializable } from "@openzeppelin/contracts/proxy/Initializable.sol";
      10             : import { EnsResolve } from "torn-token/contracts/ENS.sol";
      11             : import { ITornadoGovernance } from "../interfaces/ITornadoGovernance.sol";
      12             : 
      13             : /**
      14             :  * @notice This is the staking contract of the governance staking upgrade.
      15             :  *         This contract should hold the staked funds which are received upon relayer registration,
      16             :  *         and properly attribute rewards to addresses without security issues.
      17             :  * @dev CONTRACT RISKS:
      18             :  *      - Relayer staked TORN at risk if contract is compromised.
      19             :  * */
      20             : contract TornadoStakingRewards is Initializable, EnsResolve {
      21             :   using SafeMath for uint256;
      22             :   using SafeERC20 for IERC20;
      23             : 
      24             :   /// @notice 1e25
      25             :   uint256 public immutable ratioConstant;
      26             :   ITornadoGovernance public immutable Governance;
      27             :   IERC20 public immutable torn;
      28             :   address public immutable relayerRegistry;
      29             : 
      30             :   /// @notice the sum torn_burned_i/locked_amount_i*coefficient where i is incremented at each burn
      31             :   uint256 public accumulatedRewardPerTorn;
      32             :   /// @notice notes down accumulatedRewardPerTorn for an address on a lock/unlock/claim
      33             :   mapping(address => uint256) public accumulatedRewardRateOnLastUpdate;
      34             :   /// @notice notes down how much an account may claim
      35             :   mapping(address => uint256) public accumulatedRewards;
      36             : 
      37             :   event RewardsUpdated(address indexed account, uint256 rewards);
      38             :   event RewardsClaimed(address indexed account, uint256 rewardsClaimed);
      39             : 
      40             :   modifier onlyGovernance() {
      41             :     require(msg.sender == address(Governance), "only governance");
      42             :     _;
      43             :   }
      44             : 
      45             :   constructor(
      46             :     address governanceAddress,
      47             :     address tornAddress,
      48             :     bytes32 _relayerRegistry
      49             :   ) public {
      50             :     Governance = ITornadoGovernance(governanceAddress);
      51             :     torn = IERC20(tornAddress);
      52             :     relayerRegistry = resolve(_relayerRegistry);
      53             :     ratioConstant = IERC20(tornAddress).totalSupply();
      54             :   }
      55             : 
      56             :   /**
      57             :    * @notice This function should safely send a user his rewards.
      58             :    * @dev IMPORTANT FUNCTION:
      59             :    *      We know that rewards are going to be updated every time someone locks or unlocks
      60             :    *      so we know that this function can't be used to falsely increase the amount of
      61             :    *      lockedTorn by locking in governance and subsequently calling it.
      62             :    *      - set rewards to 0 greedily
      63             :    */
      64             :   function getReward() external {
      65           0 :     uint256 rewards = _updateReward(msg.sender, Governance.lockedBalance(msg.sender));
      66           0 :     rewards = rewards.add(accumulatedRewards[msg.sender]);
      67           0 :     accumulatedRewards[msg.sender] = 0;
      68           0 :     torn.safeTransfer(msg.sender, rewards);
      69           0 :     emit RewardsClaimed(msg.sender, rewards);
      70             :   }
      71             : 
      72             :   /**
      73             :    * @notice This function should increment the proper amount of rewards per torn for the contract
      74             :    * @dev IMPORTANT FUNCTION:
      75             :    *      - calculation must not overflow with extreme values
      76             :    *        (amount <= 1e25) * 1e25 / (balance of vault <= 1e25) -> (extreme values)
      77             :    * @param amount amount to add to the rewards
      78             :    */
      79             :   function addBurnRewards(uint256 amount) external {
      80           0 :     require(msg.sender == address(Governance) || msg.sender == relayerRegistry, "unauthorized");
      81           0 :     accumulatedRewardPerTorn = accumulatedRewardPerTorn.add(
      82             :       amount.mul(ratioConstant).div(torn.balanceOf(address(Governance.userVault())))
      83             :     );
      84             :   }
      85             : 
      86             :   /**
      87             :    * @notice This function should allow governance to properly update the accumulated rewards rate for an account
      88             :    * @param account address of account to update data for
      89             :    * @param amountLockedBeforehand the balance locked beforehand in the governance contract
      90             :    * */
      91             :   function updateRewardsOnLockedBalanceChange(address account, uint256 amountLockedBeforehand) external onlyGovernance {
      92           0 :     uint256 claimed = _updateReward(account, amountLockedBeforehand);
      93           0 :     accumulatedRewards[account] = accumulatedRewards[account].add(claimed);
      94             :   }
      95             : 
      96             :   /**
      97             :    * @notice This function should allow governance rescue tokens from the staking rewards contract
      98             :    * */
      99             :   function withdrawTorn(uint256 amount) external onlyGovernance {
     100           0 :     if (amount == type(uint256).max) amount = torn.balanceOf(address(this));
     101           0 :     torn.safeTransfer(address(Governance), amount);
     102             :   }
     103             : 
     104             :   /**
     105             :    * @notice This function should calculated the proper amount of rewards attributed to user since the last update
     106             :    * @dev IMPORTANT FUNCTION:
     107             :    *      - calculation must not overflow with extreme values
     108             :    *        (accumulatedReward <= 1e25) * (lockedBeforehand <= 1e25) / 1e25
     109             :    *      - result may go to 0, since this implies on 1 TORN locked => accumulatedReward <= 1e7, meaning a very small reward
     110             :    * @param account address of account to calculate rewards for
     111             :    * @param amountLockedBeforehand the balance locked beforehand in the governance contract
     112             :    * @return claimed the rewards attributed to user since the last update
     113             :    */
     114             :   function _updateReward(address account, uint256 amountLockedBeforehand) private returns (uint256 claimed) {
     115           0 :     if (amountLockedBeforehand != 0)
     116           0 :       claimed = (accumulatedRewardPerTorn.sub(accumulatedRewardRateOnLastUpdate[account])).mul(amountLockedBeforehand).div(
     117             :         ratioConstant
     118             :       );
     119           0 :     accumulatedRewardRateOnLastUpdate[account] = accumulatedRewardPerTorn;
     120           0 :     emit RewardsUpdated(account, claimed);
     121             :   }
     122             : 
     123             :   /**
     124             :    * @notice This function should show a user his rewards.
     125             :    * @param account address of account to calculate rewards for
     126             :    */
     127             :   function checkReward(address account) external view returns (uint256 rewards) {
     128           0 :     uint256 amountLocked = Governance.lockedBalance(account);
     129           0 :     if (amountLocked != 0)
     130           0 :       rewards = (accumulatedRewardPerTorn.sub(accumulatedRewardRateOnLastUpdate[account])).mul(amountLocked).div(ratioConstant);
     131           0 :     rewards = rewards.add(accumulatedRewards[account]);
     132             :   }
     133             : }

Generated by: LCOV version 1.16