LCOV - code coverage report
Current view: top level - reference - RelayerRegistry.sol (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 65 0.0 %
Date: 2023-06-19 00:07:36 Functions: 0 21 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 { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
       7             : import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
       8             : import { Initializable } from "@openzeppelin/contracts/proxy/Initializable.sol";
       9             : import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
      10             : import { EnsResolve } from "torn-token/contracts/ENS.sol";
      11             : import { TORN } from "torn-token/contracts/TORN.sol";
      12             : import { TornadoStakingRewards } from "../v1/staking/TornadoStakingRewards.sol";
      13             : 
      14             : interface ITornadoInstance {
      15             :     function token() external view returns (address);
      16             : 
      17             :     function denomination() external view returns (uint256);
      18             : 
      19             :     function deposit(bytes32 commitment) external payable;
      20             : 
      21             :     function withdraw(
      22             :         bytes calldata proof,
      23             :         bytes32 root,
      24             :         bytes32 nullifierHash,
      25             :         address payable recipient,
      26             :         address payable relayer,
      27             :         uint256 fee,
      28             :         uint256 refund
      29             :     ) external payable;
      30             : }
      31             : 
      32             : interface IENS {
      33             :     function owner(bytes32 node) external view returns (address);
      34             : }
      35             : 
      36             : /*
      37             :  * @dev Solidity implementation of the ENS namehash algorithm.
      38             :  *
      39             :  * Warning! Does not normalize or validate names before hashing.
      40             :  * Original version can be found here https://github.com/JonahGroendal/ens-namehash/
      41             :  */
      42             : library ENSNamehash {
      43             :     function namehash(bytes memory domain) internal pure returns (bytes32) {
      44           0 :         return namehash(domain, 0);
      45             :     }
      46             : 
      47             :     function namehash(bytes memory domain, uint256 i) internal pure returns (bytes32) {
      48           0 :         if (domain.length <= i) return 0x0000000000000000000000000000000000000000000000000000000000000000;
      49             : 
      50           0 :         uint256 len = labelLength(domain, i);
      51             : 
      52           0 :         return keccak256(abi.encodePacked(namehash(domain, i + len + 1), keccak(domain, i, len)));
      53             :     }
      54             : 
      55             :     function labelLength(bytes memory domain, uint256 i) private pure returns (uint256) {
      56           0 :         uint256 len;
      57           0 :         while (i + len != domain.length && domain[i + len] != 0x2e) {
      58           0 :             len++;
      59             :         }
      60           0 :         return len;
      61             :     }
      62             : 
      63             :     function keccak(bytes memory data, uint256 offset, uint256 len) private pure returns (bytes32 ret) {
      64           0 :         require(offset + len <= data.length);
      65             :         assembly {
      66           0 :             ret := keccak256(add(add(data, 32), offset), len)
      67             :         }
      68             :     }
      69             : }
      70             : 
      71             : interface IFeeManager {
      72             :     function instanceFeeWithUpdate(ITornadoInstance _instance) external returns (uint160);
      73             : }
      74             : 
      75             : struct RelayerState {
      76             :     uint256 balance;
      77             :     bytes32 ensHash;
      78             : }
      79             : 
      80             : /**
      81             :  * @notice Registry contract, one of the main contracts of this protocol upgrade.
      82             :  *         The contract should store relayers' addresses and data attributed to the
      83             :  *         master address of the relayer. This data includes the relayers stake and
      84             :  *         his ensHash.
      85             :  *         A relayers master address has a number of subaddresses called "workers",
      86             :  *         these are all addresses which burn stake in communication with the proxy.
      87             :  *         If a relayer is not registered, he is not displayed on the frontend.
      88             :  * @dev CONTRACT RISKS:
      89             :  *      - if setter functions are compromised, relayer metadata would be at risk, including the noted amount
      90             :  * of his balance
      91             :  *      - if burn function is compromised, relayers run the risk of being unable to handle withdrawals
      92             :  *      - the above risk also applies to the nullify balance function
      93             :  *
      94             :  */
      95             : contract RelayerRegistry is Initializable, EnsResolve {
      96             :     using SafeMath for uint256;
      97             :     using SafeERC20 for TORN;
      98             :     using ENSNamehash for bytes;
      99             : 
     100             :     TORN public immutable torn;
     101             :     address public immutable governance;
     102             :     IENS public immutable ens;
     103             :     TornadoStakingRewards public immutable staking;
     104             :     IFeeManager public immutable feeManager;
     105             : 
     106             :     address public tornadoRouter;
     107             :     uint256 public minStakeAmount;
     108             : 
     109             :     mapping(address => RelayerState) public relayers;
     110             :     mapping(address => address) public workers;
     111             : 
     112             :     event RelayerBalanceNullified(address relayer);
     113             :     event WorkerRegistered(address relayer, address worker);
     114             :     event WorkerUnregistered(address relayer, address worker);
     115             :     event StakeAddedToRelayer(address relayer, uint256 amountStakeAdded);
     116             :     event StakeBurned(address relayer, uint256 amountBurned);
     117             :     event MinimumStakeAmount(uint256 minStakeAmount);
     118             :     event RouterRegistered(address tornadoRouter);
     119             :     event RelayerRegistered(bytes32 relayer, string ensName, address relayerAddress, uint256 stakedAmount);
     120             : 
     121             :     modifier onlyGovernance() {
     122             :         require(msg.sender == governance, "only governance");
     123             :         _;
     124             :     }
     125             : 
     126             :     modifier onlyTornadoRouter() {
     127             :         require(msg.sender == tornadoRouter, "only proxy");
     128             :         _;
     129             :     }
     130             : 
     131             :     modifier onlyRelayer(address sender, address relayer) {
     132             :         require(workers[sender] == relayer, "only relayer");
     133             :         _;
     134             :     }
     135             : 
     136             :     constructor(address _torn, address _governance, address _ens, address _staking, address _feeManager)
     137             :         public
     138             :     {
     139             :         torn = TORN(_torn);
     140             :         governance = _governance;
     141             :         ens = IENS(_ens);
     142             :         staking = TornadoStakingRewards(_staking);
     143             :         feeManager = IFeeManager(_feeManager);
     144             :     }
     145             : 
     146             :     /**
     147             :      * @notice initialize function for upgradeability
     148             :      * @dev this contract will be deployed behind a proxy and should not assign values at logic address,
     149             :      *      params left out because self explainable
     150             :      *
     151             :      */
     152             :     function initialize(bytes32 _tornadoRouter) external initializer {
     153           0 :         tornadoRouter = resolve(_tornadoRouter);
     154             :     }
     155             : 
     156             :     /**
     157             :      * @notice This function should register a master address and optionally a set of workeres for a relayer +
     158             :      * metadata
     159             :      * @dev Relayer can't steal other relayers workers since they are registered, and a wallet (msg.sender
     160             :      * check) can always unregister itself
     161             :      * @param ensName ens name of the relayer
     162             :      * @param stake the initial amount of stake in TORN the relayer is depositing
     163             :      *
     164             :      */
     165             :     function register(string calldata ensName, uint256 stake, address[] calldata workersToRegister)
     166             :         external
     167             :     {
     168           0 :         _register(msg.sender, ensName, stake, workersToRegister);
     169             :     }
     170             : 
     171             :     /**
     172             :      * @dev Register function equivalent with permit-approval instead of regular approve.
     173             :      *
     174             :      */
     175             :     function registerPermit(
     176             :         string calldata ensName,
     177             :         uint256 stake,
     178             :         address[] calldata workersToRegister,
     179             :         address relayer,
     180             :         uint256 deadline,
     181             :         uint8 v,
     182             :         bytes32 r,
     183             :         bytes32 s
     184             :     ) external {
     185           0 :         torn.permit(relayer, address(this), stake, deadline, v, r, s);
     186           0 :         _register(relayer, ensName, stake, workersToRegister);
     187             :     }
     188             : 
     189             :     function _register(
     190             :         address relayer,
     191             :         string calldata ensName,
     192             :         uint256 stake,
     193             :         address[] calldata workersToRegister
     194             :     ) internal {
     195           0 :         bytes32 ensHash = bytes(ensName).namehash();
     196           0 :         require(relayer == ens.owner(ensHash), "only ens owner");
     197           0 :         require(workers[relayer] == address(0), "cant register again");
     198           0 :         RelayerState storage metadata = relayers[relayer];
     199             : 
     200           0 :         require(metadata.ensHash == bytes32(0), "registered already");
     201           0 :         require(stake >= minStakeAmount, "!min_stake");
     202             : 
     203           0 :         torn.safeTransferFrom(relayer, address(staking), stake);
     204           0 :         emit StakeAddedToRelayer(relayer, stake);
     205             : 
     206           0 :         metadata.balance = stake;
     207           0 :         metadata.ensHash = ensHash;
     208           0 :         workers[relayer] = relayer;
     209             : 
     210           0 :         for (uint256 i = 0; i < workersToRegister.length; i++) {
     211           0 :             address worker = workersToRegister[i];
     212           0 :             _registerWorker(relayer, worker);
     213             :         }
     214             : 
     215           0 :         emit RelayerRegistered(ensHash, ensName, relayer, stake);
     216             :     }
     217             : 
     218             :     /**
     219             :      * @notice This function should allow relayers to register more workeres
     220             :      * @param relayer Relayer which should send message from any worker which is already registered
     221             :      * @param worker Address to register
     222             :      *
     223             :      */
     224             :     function registerWorker(address relayer, address worker) external onlyRelayer(msg.sender, relayer) {
     225           0 :         _registerWorker(relayer, worker);
     226             :     }
     227             : 
     228             :     function _registerWorker(address relayer, address worker) internal {
     229           0 :         require(workers[worker] == address(0), "can't steal an address");
     230           0 :         workers[worker] = relayer;
     231           0 :         emit WorkerRegistered(relayer, worker);
     232             :     }
     233             : 
     234             :     /**
     235             :      * @notice This function should allow anybody to unregister an address they own
     236             :      * @dev designed this way as to allow someone to unregister themselves in case a relayer misbehaves
     237             :      *      - this should be followed by an action like burning relayer stake
     238             :      *      - there was an option of allowing the sender to burn relayer stake in case of malicious behaviour,
     239             :      * this feature was not included in the end
     240             :      *      - reverts if trying to unregister master, otherwise contract would break. in general, there should
     241             :      * be no reason to unregister master at all
     242             :      *
     243             :      */
     244             :     function unregisterWorker(address worker) external {
     245           0 :         if (worker != msg.sender) require(workers[worker] == msg.sender, "only owner of worker");
     246           0 :         require(workers[worker] != worker, "cant unregister master");
     247           0 :         emit WorkerUnregistered(workers[worker], worker);
     248           0 :         workers[worker] = address(0);
     249             :     }
     250             : 
     251             :     /**
     252             :      * @notice This function should allow anybody to stake to a relayer more TORN
     253             :      * @param relayer Relayer main address to stake to
     254             :      * @param stake Stake to be added to relayer
     255             :      *
     256             :      */
     257             :     function stakeToRelayer(address relayer, uint256 stake) external {
     258           0 :         _stakeToRelayer(msg.sender, relayer, stake);
     259             :     }
     260             : 
     261             :     /**
     262             :      * @dev stakeToRelayer function equivalent with permit-approval instead of regular approve.
     263             :      * @param staker address from that stake is paid
     264             :      *
     265             :      */
     266             :     function stakeToRelayerPermit(
     267             :         address relayer,
     268             :         uint256 stake,
     269             :         address staker,
     270             :         uint256 deadline,
     271             :         uint8 v,
     272             :         bytes32 r,
     273             :         bytes32 s
     274             :     ) external {
     275           0 :         torn.permit(staker, address(this), stake, deadline, v, r, s);
     276           0 :         _stakeToRelayer(staker, relayer, stake);
     277             :     }
     278             : 
     279             :     function _stakeToRelayer(address staker, address relayer, uint256 stake) internal {
     280           0 :         require(workers[relayer] == relayer, "!registered");
     281           0 :         torn.safeTransferFrom(staker, address(staking), stake);
     282           0 :         relayers[relayer].balance = stake.add(relayers[relayer].balance);
     283           0 :         emit StakeAddedToRelayer(relayer, stake);
     284             :     }
     285             : 
     286             :     /**
     287             :      * @notice This function should burn some relayer stake on withdraw and notify staking of this
     288             :      * @dev IMPORTANT FUNCTION:
     289             :      *      - This should be only called by the tornado proxy
     290             :      *      - Should revert if relayer does not call proxy from valid worker
     291             :      *      - Should not overflow
     292             :      *      - Should underflow and revert (SafeMath) on not enough stake (balance)
     293             :      * @param sender worker to check sender == relayer
     294             :      * @param relayer address of relayer who's stake is being burned
     295             :      * @param pool instance to get fee for
     296             :      *
     297             :      */
     298             :     function burn(address sender, address relayer, ITornadoInstance pool) external onlyTornadoRouter {
     299           0 :         address masterAddress = workers[sender];
     300           0 :         if (masterAddress == address(0)) {
     301           0 :             require(workers[relayer] == address(0), "Only custom relayer");
     302           0 :             return;
     303             :         }
     304             : 
     305           0 :         require(masterAddress == relayer, "only relayer");
     306           0 :         uint256 toBurn = feeManager.instanceFeeWithUpdate(pool);
     307           0 :         relayers[relayer].balance = relayers[relayer].balance.sub(toBurn);
     308           0 :         staking.addBurnRewards(toBurn);
     309           0 :         emit StakeBurned(relayer, toBurn);
     310             :     }
     311             : 
     312             :     /**
     313             :      * @notice This function should allow governance to set the minimum stake amount
     314             :      * @param minAmount new minimum stake amount
     315             :      *
     316             :      */
     317             :     function setMinStakeAmount(uint256 minAmount) external onlyGovernance {
     318           0 :         minStakeAmount = minAmount;
     319           0 :         emit MinimumStakeAmount(minAmount);
     320             :     }
     321             : 
     322             :     /**
     323             :      * @notice This function should allow governance to set a new tornado proxy address
     324             :      * @param tornadoRouterAddress address of the new proxy
     325             :      *
     326             :      */
     327             :     function setTornadoRouter(address tornadoRouterAddress) external onlyGovernance {
     328           0 :         tornadoRouter = tornadoRouterAddress;
     329           0 :         emit RouterRegistered(tornadoRouterAddress);
     330             :     }
     331             : 
     332             :     /**
     333             :      * @notice This function should allow governance to nullify a relayers balance
     334             :      * @dev IMPORTANT FUNCTION:
     335             :      *      - Should nullify the balance
     336             :      *      - Adding nullified balance as rewards was refactored to allow for the flexibility of these funds
     337             :      * (for gov to operate with them)
     338             :      * @param relayer address of relayer who's balance is to nullify
     339             :      *
     340             :      */
     341             :     function nullifyBalance(address relayer) external onlyGovernance {
     342           0 :         address masterAddress = workers[relayer];
     343           0 :         require(relayer == masterAddress, "must be master");
     344           0 :         relayers[masterAddress].balance = 0;
     345           0 :         emit RelayerBalanceNullified(relayer);
     346             :     }
     347             : 
     348             :     /**
     349             :      * @notice This function should check if a worker is associated with a relayer
     350             :      * @param toResolve address to check
     351             :      * @return true if is associated
     352             :      *
     353             :      */
     354             :     function isRelayer(address toResolve) external view returns (bool) {
     355           0 :         return workers[toResolve] != address(0);
     356             :     }
     357             : 
     358             :     /**
     359             :      * @notice This function should check if a worker is registered to the relayer stated
     360             :      * @param relayer relayer to check
     361             :      * @param toResolve address to check
     362             :      * @return true if registered
     363             :      *
     364             :      */
     365             :     function isRelayerRegistered(address relayer, address toResolve) external view returns (bool) {
     366           0 :         return workers[toResolve] == relayer;
     367             :     }
     368             : 
     369             :     /**
     370             :      * @notice This function should get a relayers ensHash
     371             :      * @param relayer address to fetch for
     372             :      * @return relayer's ensHash
     373             :      *
     374             :      */
     375             :     function getRelayerEnsHash(address relayer) external view returns (bytes32) {
     376           0 :         return relayers[workers[relayer]].ensHash;
     377             :     }
     378             : 
     379             :     /**
     380             :      * @notice This function should get a relayers balance
     381             :      * @param relayer relayer who's balance is to fetch
     382             :      * @return relayer's balance
     383             :      *
     384             :      */
     385             :     function getRelayerBalance(address relayer) external view returns (uint256) {
     386           0 :         return relayers[workers[relayer]].balance;
     387             :     }
     388             : }

Generated by: LCOV version 1.16