LCOV - code coverage report
Current view: top level - v2 - InstanceRegistry.sol (source / functions) Hit Total Coverage
Test: lcov.info Lines: 51 53 96.2 %
Date: 2023-06-20 21:04:08 Functions: 15 18 83.3 %
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             : // OZ Imports
       7             : 
       8             : import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
       9             : import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
      10             : import { Initializable } from "@openzeppelin/contracts/proxy/Initializable.sol";
      11             : 
      12             : // Tornado Imports
      13             : 
      14             : import { ITornadoInstance } from "tornado-anonymity-mining/contracts/interfaces/ITornadoInstance.sol";
      15             : 
      16             : // Local imports
      17             : 
      18             : import { ENSResolver } from "./libraries/ENSResolver.sol";
      19             : import { NameEncoder } from "./libraries/NameEncoder.sol";
      20             : import { TornadoRouter } from "./TornadoRouter.sol";
      21             : 
      22             : /**
      23             :  * @title InstanceRegistry
      24             :  * @author AlienTornadosaurusHex
      25             :  * @notice A contract which enumerates Tornado Cash pool instances, and also stores essential data regarding
      26             :  * them.
      27             :  * @dev This contract will help us layout storage properly for a proxy upgrade for the impl
      28             :  * InstanceRegistry.
      29             :  */
      30             : contract InstanceRegistryLegacyStorage {
      31             :     /* From first contract, just so right uint type is chosen */
      32             :     enum LegacyStatePlaceholder {
      33             :         DISABLED,
      34             :         ENABLED
      35             :     }
      36             : 
      37             :     /* From first contract, just if necessary to be able to properly unpack and determine value storage
      38             :     addresses and offsets */
      39             :     struct LegacyInstanceStructPlaceholder {
      40             :         bool deprecatedIsERC20;
      41             :         address deprecatedToken;
      42             :         LegacyStatePlaceholder deprecatedState;
      43             :         uint24 deprecatedUniswapPoolSwappingFee;
      44             :         uint32 deprecatedProtocolFeePercentage;
      45             :     }
      46             : 
      47             :     /**
      48             :      * @dev From Initializable.sol of first contract
      49             :      */
      50             :     bool private _deprecatedInitialized;
      51             : 
      52             :     /**
      53             :      * @dev From Initializable.sol of first contract
      54             :      */
      55             :     bool private _deprecatedInitializing;
      56             : 
      57             :     /**
      58             :      * @dev From first contract
      59             :      */
      60             :     address private _deprecatedRouterAddress;
      61             : 
      62             :     /**
      63             :      * @dev From first contract
      64             :      */
      65             :     mapping(address => LegacyInstanceStructPlaceholder) private _deprecatedInstances;
      66             : 
      67             :     /**
      68             :      * @dev From first contract
      69             :      */
      70             :     ITornadoInstance[] private _deprecatedInstanceIds;
      71             : }
      72             : 
      73             : /**
      74             :  * @dev This struct holds barebones information regarding an instance and its data location in storage.
      75             :  */
      76             : struct InstanceState {
      77             :     IERC20 token;
      78             :     uint80 index;
      79             :     bool isERC20;
      80             :     bool isEnabled;
      81             : }
      82             : 
      83             : /**
      84             :  * @title InstanceRegistry
      85             :  * @author AlienTornadosaurusHex
      86             :  * @notice A contract which enumerates Tornado Cash pool instances, and also stores essential data regarding
      87             :  * them.
      88             :  * @dev This is an improved version of the InstanceRegistry with a modified design from the original contract.
      89             :  */
      90             : contract InstanceRegistry is InstanceRegistryLegacyStorage, ENSResolver, Initializable {
      91             :     using SafeERC20 for IERC20;
      92             : 
      93             :     /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VARIABLES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
      94             : 
      95             :     /**
      96             :      * @notice The address of the Governance proxy
      97             :      */
      98             :     address public immutable governanceProxyAddress;
      99             : 
     100             :     /**
     101             :      * @notice Essential data regarding instances, see struct above
     102             :      */
     103             :     mapping(ITornadoInstance => InstanceState) public instanceData;
     104             : 
     105             :     /**
     106             :      * @notice All instances enumerable
     107             :      */
     108             :     ITornadoInstance[] public instances;
     109             : 
     110             :     /**
     111             :      * @notice The router which processes txs which we must command to approve tokens
     112             :      */
     113             :     TornadoRouter public router;
     114             : 
     115             :     /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EVENTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
     116             : 
     117             :     event RouterRegistered(address newRouterAddress);
     118             :     event InstanceAdded(address indexed instance, uint80 dataIndex, bool isERC20);
     119             :     event InstanceRemoved(address indexed instance);
     120             : 
     121             :     /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LOGIC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
     122             : 
     123             :     constructor(address _governanceProxyAddress) public {
     124             :         governanceProxyAddress = _governanceProxyAddress;
     125             :     }
     126             : 
     127             :     modifier onlyGovernance() {
     128             :         require(msg.sender == governanceProxyAddress, "InstanceRegistry: onlyGovernance");
     129             :         _;
     130             :     }
     131             : 
     132             :     function version() public pure virtual returns (string memory) {
     133           2 :         return "v2-oracle-manager";
     134             :     }
     135             : 
     136             :     function initialize(ITornadoInstance[] memory _instances, TornadoRouter _router)
     137             :         external
     138             :         onlyGovernance
     139             :         initializer
     140             :     {
     141           4 :         uint256 numInstances = _instances.length;
     142             : 
     143             :         // Router must be initialized before otherwise below will fail
     144           4 :         router = _router;
     145             : 
     146           4 :         for (uint256 i = 0; i < numInstances; i++) {
     147          68 :             addInstance(_instances[i]);
     148             :         }
     149             :     }
     150             : 
     151             :     function addInstance(ITornadoInstance _instance) public virtual onlyGovernance {
     152             :         // The instance may not already be enabled
     153             : 
     154          80 :         bool isEnabled = instanceData[_instance].isEnabled;
     155             : 
     156          80 :         require(!isEnabled, "InstanceRegistry: can't add the same instance.");
     157             : 
     158             :         // Determine whether it is an ERC20 or not
     159             : 
     160          80 :         IERC20 token = IERC20(address(0));
     161             : 
     162          80 :         bool isERC20 = false;
     163             : 
     164             :         // ETH instances do not know of a `token()` call
     165          80 :         try _instance.token() returns (address _tokenAddress) {
     166             :             token = IERC20(_tokenAddress);
     167             :             isERC20 = true;
     168             :         } catch {
     169             :             /* It's an ETH instance, do nothing */
     170             :         }
     171             : 
     172             :         // If it is ERC20 then make the router give an approval for the Tornado instance to allow the token
     173             :         // amount, if it hasn't already done so
     174          80 :         if (isERC20) {
     175          63 :             uint256 routerAllowanceForInstance = token.allowance(address(router), address(_instance));
     176             : 
     177          63 :             if (routerAllowanceForInstance == 0) {
     178          63 :                 router.approveTokenForInstance(token, address(_instance), type(uint256).max);
     179             :             }
     180             :         }
     181             : 
     182             :         // Add it to the enumerable
     183          80 :         instances.push(_instance);
     184             : 
     185             :         // Read out the index of the instance in the enumerable
     186          80 :         uint64 instanceIndex = uint64(instances.length - 1);
     187             : 
     188             :         // Store the collected data of the instance
     189          80 :         instanceData[_instance] =
     190             :             InstanceState({ token: token, index: instanceIndex, isERC20: isERC20, isEnabled: true });
     191             : 
     192             :         // Log
     193          80 :         emit InstanceAdded(address(_instance), instanceIndex, isERC20);
     194             :     }
     195             : 
     196             :     /**
     197             :      * @notice Remove an instance, only callable by Governance.
     198             :      * @dev The access modifier is in the internal call.
     199             :      * @param _instanceIndex The index of the instance to remove.
     200             :      */
     201             :     function removeInstanceByIndex(uint256 _instanceIndex) public virtual {
     202           1 :         _removeInstanceByAddress(address(instances[_instanceIndex]));
     203             :     }
     204             : 
     205             :     /**
     206             :      * @notice Remove an instance, only callable by Governance.
     207             :      * @dev The access modifier is in the internal call.
     208             :      * @param _instanceAddress The adress of the instance to remove.
     209             :      */
     210             :     function removeInstanceByAddress(address _instanceAddress) public virtual {
     211           1 :         _removeInstanceByAddress(_instanceAddress);
     212             :     }
     213             : 
     214             :     function _removeInstanceByAddress(address _instanceAddress) internal virtual onlyGovernance {
     215             :         // Grab data needed to remove the instance
     216             : 
     217           2 :         ITornadoInstance instance = ITornadoInstance(_instanceAddress);
     218           2 :         InstanceState memory data = instanceData[instance];
     219             : 
     220             :         // Checks whether already removed, so allowance can't be killed
     221             : 
     222           2 :         require(data.isEnabled, "InstanceRegistry: already removed");
     223             : 
     224             :         // Kill the allowance of the router first (arbitrary order)
     225             : 
     226           2 :         if (data.isERC20) {
     227           1 :             uint256 routerAllowanceForInstance = data.token.allowance(address(router), _instanceAddress);
     228             : 
     229           1 :             if (routerAllowanceForInstance != 0) {
     230           1 :                 router.approveTokenForInstance(data.token, _instanceAddress, 0);
     231             :             }
     232             :         }
     233             : 
     234             :         // We need to revert all changes, meaning modify position of last instance and change index in data
     235             : 
     236           2 :         uint64 lastInstanceIndex = uint64(instances.length - 1);
     237             : 
     238           2 :         ITornadoInstance lastInstance = instances[lastInstanceIndex];
     239             : 
     240             :         // Swap position of last instance with old
     241             : 
     242           2 :         instances[data.index] = lastInstance;
     243             : 
     244           2 :         instanceData[lastInstance].index = data.index;
     245             : 
     246           2 :         instances.pop();
     247             : 
     248             :         // Delete old instance data
     249             : 
     250           2 :         delete instanceData[instance];
     251             : 
     252             :         // Log
     253             : 
     254           2 :         emit InstanceRemoved(_instanceAddress);
     255             :     }
     256             : 
     257             :     /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SETTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
     258             : 
     259             :     function setTornadoRouter(address _newRouterAddress) external onlyGovernance {
     260           1 :         router = TornadoRouter(_newRouterAddress);
     261           1 :         emit RouterRegistered(_newRouterAddress);
     262             :     }
     263             : 
     264             :     /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GETTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
     265             : 
     266             :     function getAllInstances() public view virtual returns (ITornadoInstance[] memory allInstances) {
     267           5 :         return getInstances(0, instances.length - 1);
     268             :     }
     269             : 
     270             :     function getInstances(uint256 _inclusiveStartIndex, uint256 _inclusiveEndIndex)
     271             :         public
     272             :         view
     273             :         virtual
     274             :         returns (ITornadoInstance[] memory allInstances)
     275             :     {
     276           5 :         allInstances = new ITornadoInstance[](1 + _inclusiveEndIndex - _inclusiveStartIndex);
     277             : 
     278           5 :         for (uint256 i = _inclusiveStartIndex; i < _inclusiveEndIndex + 1; i++) {
     279          95 :             allInstances[i - _inclusiveStartIndex] = instances[i];
     280             :         }
     281             :     }
     282             : 
     283             :     function getAllInstanceStates() public view virtual returns (InstanceState[] memory data) {
     284           1 :         return getInstanceState(0, instances.length - 1);
     285             :     }
     286             : 
     287             :     function getInstanceState(uint256 _inclusiveStartIndex, uint256 _inclusiveEndIndex)
     288             :         public
     289             :         view
     290             :         virtual
     291             :         returns (InstanceState[] memory data)
     292             :     {
     293           2 :         data = new InstanceState[](1 + _inclusiveEndIndex - _inclusiveStartIndex);
     294             : 
     295           2 :         for (uint256 i = _inclusiveStartIndex; i < _inclusiveEndIndex + 1; i++) {
     296          26 :             data[i - _inclusiveStartIndex] = instanceData[instances[i]];
     297             :         }
     298             :     }
     299             : 
     300             :     function getInstanceState(uint256 _index) public view virtual returns (InstanceState memory data) {
     301           2 :         return instanceData[instances[_index]];
     302             :     }
     303             : 
     304             :     function getInstanceState(ITornadoInstance _instance)
     305             :         public
     306             :         view
     307             :         virtual
     308             :         returns (InstanceState memory data)
     309             :     {
     310         137 :         return instanceData[_instance];
     311             :     }
     312             : 
     313             :     function getInstanceToken(ITornadoInstance _instance) public view virtual returns (IERC20) {
     314           2 :         return instanceData[_instance].token;
     315             :     }
     316             : 
     317             :     function getInstanceIndex(ITornadoInstance _instance) public view virtual returns (uint80) {
     318           1 :         return instanceData[_instance].index;
     319             :     }
     320             : 
     321             :     function isRegisteredInstance(ITornadoInstance _instance) public view virtual returns (bool) {
     322           2 :         return isEnabledInstance(_instance);
     323             :     }
     324             : 
     325             :     function isEnabledInstance(ITornadoInstance _instance) public view virtual returns (bool) {
     326           4 :         return instanceData[_instance].isEnabled;
     327             :     }
     328             : 
     329             :     /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENS GETTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
     330             : 
     331             :     function isRegisteredInstanceByENSName(string memory _instanceENSName)
     332             :         public
     333             :         view
     334             :         virtual
     335             :         returns (bool)
     336             :     {
     337           0 :         return isEnabledInstanceByENSName(_instanceENSName);
     338             :     }
     339             : 
     340             :     function isEnabledInstanceByENSName(string memory _instanceENSName) public view virtual returns (bool) {
     341           0 :         return isEnabledInstance(getInstanceByENSName(_instanceENSName));
     342             :     }
     343             : 
     344             :     function getInstanceByENSName(string memory _instanceENSName)
     345             :         public
     346             :         view
     347             :         virtual
     348             :         returns (ITornadoInstance)
     349             :     {
     350           1 :         return ITornadoInstance(resolveByName(_instanceENSName));
     351             :     }
     352             : }

Generated by: LCOV version 1.16