Line data Source code
1 : // SPDX-License-Identifier: MIT 2 : 3 : pragma solidity ^0.6.12; 4 : pragma experimental ABIEncoderV2; 5 : 6 : import { Initializable } from "@openzeppelin/contracts/proxy/Initializable.sol"; 7 : import { EnsResolve } from "torn-token/contracts/ENS.sol"; 8 : import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 9 : import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; 10 : import "tornado-anonymity-mining/contracts/interfaces/ITornadoInstance.sol"; 11 : import "./FeeManager.sol"; 12 : import "./TornadoRouter.sol"; 13 : 14 : contract InstanceRegistry is Initializable, EnsResolve { 15 : using SafeERC20 for IERC20; 16 : 17 : enum InstanceState { 18 : DISABLED, 19 : ENABLED 20 : } 21 : 22 : struct Instance { 23 : bool isERC20; 24 : IERC20 token; 25 : InstanceState state; 26 : // the fee of the uniswap pool which will be used to get a TWAP 27 : uint24 uniswapPoolSwappingFee; 28 : // the fee the protocol takes from relayer, it should be multiplied by PROTOCOL_FEE_DIVIDER from FeeManager.sol 29 : uint32 protocolFeePercentage; 30 : } 31 : 32 : struct Tornado { 33 : ITornadoInstance addr; 34 : Instance instance; 35 : } 36 : 37 : address public immutable governance; 38 : TornadoRouter public router; 39 : 40 : mapping(ITornadoInstance => Instance) public instances; 41 : ITornadoInstance[] public instanceIds; 42 : 43 : event InstanceStateUpdated(ITornadoInstance indexed instance, InstanceState state); 44 : event RouterRegistered(address tornadoRouter); 45 : 46 : modifier onlyGovernance() { 47 : require(msg.sender == governance, "Not authorized"); 48 : _; 49 : } 50 : 51 : constructor(address _governance) public { 52 : governance = _governance; 53 : } 54 : 55 : function initialize(Tornado[] memory _instances, bytes32 _router) external initializer { 56 0 : router = TornadoRouter(resolve(_router)); 57 0 : for (uint256 i = 0; i < _instances.length; i++) { 58 0 : _updateInstance(_instances[i]); 59 0 : instanceIds.push(_instances[i].addr); 60 : } 61 : } 62 : 63 : /** 64 : * @dev Add or update an instance. 65 : */ 66 : function updateInstance(Tornado calldata _tornado) external virtual onlyGovernance { 67 0 : require(_tornado.instance.state != InstanceState.DISABLED, "Use removeInstance() for remove"); 68 0 : if (instances[_tornado.addr].state == InstanceState.DISABLED) { 69 0 : instanceIds.push(_tornado.addr); 70 : } 71 0 : _updateInstance(_tornado); 72 : } 73 : 74 : /** 75 : * @dev Remove an instance. 76 : * @param _instanceId The instance id in `instanceIds` mapping to remove. 77 : */ 78 : function removeInstance(uint256 _instanceId) external virtual onlyGovernance { 79 0 : ITornadoInstance _instance = instanceIds[_instanceId]; 80 0 : (bool isERC20, IERC20 token) = (instances[_instance].isERC20, instances[_instance].token); 81 : 82 0 : if (isERC20) { 83 0 : uint256 allowance = token.allowance(address(router), address(_instance)); 84 0 : if (allowance != 0) { 85 0 : router.approveExactToken(token, address(_instance), 0); 86 : } 87 : } 88 : 89 0 : delete instances[_instance]; 90 0 : instanceIds[_instanceId] = instanceIds[instanceIds.length - 1]; 91 0 : instanceIds.pop(); 92 0 : emit InstanceStateUpdated(_instance, InstanceState.DISABLED); 93 : } 94 : 95 : /** 96 : * @notice This function should allow governance to set a new protocol fee for relayers 97 : * @param instance the to update 98 : * @param newFee the new fee to use 99 : * */ 100 : function setProtocolFee(ITornadoInstance instance, uint32 newFee) external onlyGovernance { 101 0 : instances[instance].protocolFeePercentage = newFee; 102 : } 103 : 104 : /** 105 : * @notice This function should allow governance to set a new tornado proxy address 106 : * @param routerAddress address of the new proxy 107 : * */ 108 : function setTornadoRouter(address routerAddress) external onlyGovernance { 109 0 : router = TornadoRouter(routerAddress); 110 0 : emit RouterRegistered(routerAddress); 111 : } 112 : 113 : function _updateInstance(Tornado memory _tornado) internal virtual { 114 0 : instances[_tornado.addr] = _tornado.instance; 115 0 : if (_tornado.instance.isERC20) { 116 0 : IERC20 token = IERC20(_tornado.addr.token()); 117 0 : require(token == _tornado.instance.token, "Incorrect token"); 118 0 : uint256 allowance = token.allowance(address(router), address(_tornado.addr)); 119 : 120 0 : if (allowance == 0) { 121 0 : router.approveExactToken(token, address(_tornado.addr), type(uint256).max); 122 : } 123 : } 124 0 : emit InstanceStateUpdated(_tornado.addr, _tornado.instance.state); 125 : } 126 : 127 : /** 128 : * @dev Returns all instance configs 129 : */ 130 : function getAllInstances() public view returns (Tornado[] memory result) { 131 0 : result = new Tornado[](instanceIds.length); 132 0 : for (uint256 i = 0; i < instanceIds.length; i++) { 133 0 : ITornadoInstance _instance = instanceIds[i]; 134 0 : result[i] = Tornado({ addr: _instance, instance: instances[_instance] }); 135 : } 136 : } 137 : 138 : /** 139 : * @dev Returns all instance addresses 140 : */ 141 : function getAllInstanceAddresses() public view returns (ITornadoInstance[] memory result) { 142 0 : result = new ITornadoInstance[](instanceIds.length); 143 0 : for (uint256 i = 0; i < instanceIds.length; i++) { 144 0 : result[i] = instanceIds[i]; 145 : } 146 : } 147 : 148 : /// @notice get erc20 tornado instance token 149 : /// @param instance the interface (contract) key to the instance data 150 : function getPoolToken(ITornadoInstance instance) external view returns (address) { 151 0 : return address(instances[instance].token); 152 : } 153 : }