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 { Initializable } from "@openzeppelin/contracts/proxy/Initializable.sol";
10 : import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
11 : import { Address } from "@openzeppelin/contracts/utils/Address.sol";
12 : import { Math } from "@openzeppelin/contracts/math/Math.sol";
13 :
14 : // Tornado Imports
15 :
16 : import { ITornadoInstance } from "tornado-anonymity-mining/contracts/interfaces/ITornadoInstance.sol";
17 :
18 : // Local imports
19 :
20 : import { RelayerRegistry } from "./RelayerRegistry.sol";
21 : import { FeeOracleManager } from "./FeeOracleManager.sol";
22 : import { TornadoStakingRewards } from "./TornadoStakingRewards.sol";
23 : import { InstanceRegistry, InstanceState } from "./InstanceRegistry.sol";
24 :
25 : /**
26 : * @title TornadoRouter
27 : * @author AlienTornadosaurusHex
28 : * @notice This contract is a router for all Tornado Cash deposits and withdrawals
29 : * @dev This is an improved version of the TornadoRouter with a modified design from the original contract.
30 : */
31 : contract TornadoRouter is Initializable {
32 : using SafeERC20 for IERC20;
33 :
34 : /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VARIABLES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
35 :
36 : /**
37 : * @notice The address of the Governance proxy
38 : */
39 : address public immutable governanceProxyAddress;
40 :
41 : /**
42 : * @notice The Instance Registry
43 : */
44 : InstanceRegistry public instanceRegistry;
45 :
46 : /**
47 : * @notice The Relayer Registry
48 : */
49 : RelayerRegistry public relayerRegistry;
50 :
51 : /**
52 : * @notice The Fee Oracle Manager
53 : */
54 : FeeOracleManager public feeOracleManager;
55 :
56 : /**
57 : * @notice The Staking Rewards contract
58 : */
59 : TornadoStakingRewards public stakingRewards;
60 :
61 : /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EVENTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
62 :
63 : event EncryptedNote(address indexed sender, bytes encryptedNote);
64 : event TokenApproved(address indexed spender, uint256 amount);
65 :
66 : event WithdrawalWithRelayer(
67 : address sender, address relayer, address instanceAddress, bytes32 nullifierHash
68 : );
69 :
70 : event InstanceRegistryUpdated(address newInstanceRegistryProxyAddress);
71 : event RelayerRegistryUpdated(address newRelayerRegistryProxyAddress);
72 : event FeeOracleManagerUpdated(address newFeeOracleManagerProxyAddress);
73 : event StakingRewardsUpdated(address newStakingRewardsProxyAddress);
74 :
75 : /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LOGIC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
76 :
77 : constructor(address _governanceProxyAddress) public {
78 : governanceProxyAddress = _governanceProxyAddress;
79 : }
80 :
81 : modifier onlyInstanceRegistry() {
82 : require(msg.sender == address(instanceRegistry), "TornadoRouter: onlyInstanceRegistry");
83 : _;
84 : }
85 :
86 : modifier onlyGovernance() {
87 : require(msg.sender == governanceProxyAddress, "TornadoRouter: onlyGovernance");
88 : _;
89 : }
90 :
91 : function version() public pure virtual returns (string memory) {
92 2 : return "v2-oracle-manager";
93 : }
94 :
95 : function initialize(
96 : address _instanceRegistryProxyAddress,
97 : address _relayerRegistryProxyAddress,
98 : address _feeOracleManagerProxyAddress,
99 : address _stakingRewardsProxyAddress
100 : ) external onlyGovernance initializer {
101 4 : instanceRegistry = InstanceRegistry(_instanceRegistryProxyAddress);
102 4 : relayerRegistry = RelayerRegistry(_relayerRegistryProxyAddress);
103 4 : feeOracleManager = FeeOracleManager(_feeOracleManagerProxyAddress);
104 4 : stakingRewards = TornadoStakingRewards(_stakingRewardsProxyAddress);
105 : }
106 :
107 : /**
108 : * @notice Function to deposit into a Tornado instance. We don't really case if an external contract
109 : * breaks for deposit since deposits can go through the instances too if need be.
110 : * @param _tornado The instance to deposit into (address).
111 : * @param _commitment The commitment which will be added to the Merkle Tree.
112 : * @param _encryptedNote An encrypted note tied to the commitment which may be logged.
113 : */
114 : function deposit(ITornadoInstance _tornado, bytes32 _commitment, bytes calldata _encryptedNote)
115 : public
116 : payable
117 : virtual
118 : {
119 1 : (IERC20 token,, bool isERC20, bool isEnabled) = instanceRegistry.instanceData(_tornado);
120 :
121 : // Better than having it revert at safeTransferFrom
122 1 : require(isEnabled, "TornadoRouter: instance not enabled");
123 :
124 1 : if (isERC20) {
125 1 : token.safeTransferFrom(msg.sender, address(this), _tornado.denomination());
126 : }
127 :
128 1 : _tornado.deposit{ value: msg.value }(_commitment);
129 :
130 1 : emit EncryptedNote(msg.sender, _encryptedNote);
131 : }
132 :
133 : /**
134 : * @notice Withdraw from a Tornado Instance. The registry proxy will be set to 0, this will then
135 : * guarantee that the contract is not upgradeable and thus that it will never be able to block
136 : * withdrawals via the `isWorker` function. In any case, both manual users, Governance relayers
137 : * and non-Governance relayers may use this function to process a withdrawal. Only withdrawals
138 : * which include a `_relayer` field in the proof which belongs to a registered relayer, but which
139 : * attempt to withdraw via an unregistered worker are not allowed to withdraw.
140 : * @param _tornado The Tornado instance to withdraw from.
141 : * @param _proof Bytes proof data.
142 : * @param _root A current or historical bytes32 root of the Merkle Tree within the proofs context.
143 : * @param _nullifierHash The bytes32 nullifierHash for the deposit.
144 : * @param _recipient The address of recipient for withdrawn funds.
145 : * @param _relayer The address of the relayer which will be making the withdrawal.
146 : * @param _fee The fee in bips to pay the relayer.
147 : * @param _refund If swapping into ETH on the other side, use this to specify how much should be paid for
148 : * it.
149 : */
150 : function withdraw(
151 : ITornadoInstance _tornado,
152 : bytes calldata _proof,
153 : bytes32 _root,
154 : bytes32 _nullifierHash,
155 : address payable _recipient,
156 : address payable _relayer,
157 : uint256 _fee,
158 : uint256 _refund
159 : ) public payable virtual {
160 : // The registry proxy admin has been tossed meaning that below function can't be
161 : // upgraded to break withdrawals from the instances
162 : //
163 : // The next check confirms that `_relayer` is registered with Governance
164 1 : if (relayerRegistry.isWorker(_relayer)) {
165 : // Check whether someone is impersonating a relayer or a relayer is avoiding
166 1 : require(relayerRegistry.isWorkerOfRelayer(_relayer, msg.sender), "TornadoRouter: invalid relayer");
167 :
168 : // Check whether the instance is enabled
169 1 : require(instanceRegistry.isEnabledInstance(_tornado), "TornadoRouter: instance not enabled");
170 :
171 : // Get the fee for the instance
172 1 : uint256 fee = feeOracleManager.updateFee(_tornado, true);
173 :
174 : // Deduct the relayers balance
175 1 : relayerRegistry.deductBalance(msg.sender, _relayer, fee);
176 :
177 : // Add burn rewards
178 1 : stakingRewards.addBurnRewards(fee);
179 : }
180 :
181 : // In any case withdraw, again, can't break, above logic is based on an "immutable conditional"
182 1 : _tornado.withdraw{ value: msg.value }(
183 : _proof, _root, _nullifierHash, _recipient, _relayer, _fee, _refund
184 : );
185 : }
186 :
187 : function backupNotes(bytes[] calldata _encryptedNotes) public virtual {
188 1 : for (uint256 i = 0; i < _encryptedNotes.length; i++) {
189 1 : emit EncryptedNote(msg.sender, _encryptedNotes[i]);
190 : }
191 : }
192 :
193 : /**
194 : * @notice Note that this contract doesn't leave dust unless someone sends dust to it.
195 : */
196 : function rescueTokens(IERC20 _token, address payable _to, uint256 _amount)
197 : public
198 : virtual
199 : onlyGovernance
200 : {
201 2 : require(_to != address(0), "TORN: can not send to zero address");
202 :
203 2 : if (_token == IERC20(0)) {
204 : // For Ether
205 1 : uint256 totalBalance = address(this).balance;
206 1 : uint256 balance = Math.min(totalBalance, _amount);
207 1 : _to.transfer(balance);
208 : } else {
209 : // For any other ERC20
210 1 : uint256 totalBalance = _token.balanceOf(address(this));
211 1 : uint256 balance = Math.min(totalBalance, _amount);
212 1 : require(balance > 0, "TORN: trying to send 0 balance");
213 1 : _token.safeTransfer(_to, balance);
214 : }
215 : }
216 :
217 : /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SETTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
218 :
219 : function approveTokenForInstance(IERC20 _token, address _spender, uint256 _amount)
220 : external
221 : onlyInstanceRegistry
222 : {
223 64 : _token.safeApprove(_spender, _amount);
224 64 : emit TokenApproved(_spender, _amount);
225 : }
226 :
227 : function setInstanceRegistry(address _newInstanceRegistryProxyAddress) external onlyGovernance {
228 1 : instanceRegistry = InstanceRegistry(_newInstanceRegistryProxyAddress);
229 1 : emit InstanceRegistryUpdated(_newInstanceRegistryProxyAddress);
230 : }
231 :
232 : function setFeeOracleManager(address _newFeeOracleManagerProxyAddress) external onlyGovernance {
233 1 : feeOracleManager = FeeOracleManager(_newFeeOracleManagerProxyAddress);
234 1 : emit FeeOracleManagerUpdated(_newFeeOracleManagerProxyAddress);
235 : }
236 :
237 : function setStakingRewards(address _newStakingRewardsProxyAddress) external onlyGovernance {
238 1 : stakingRewards = TornadoStakingRewards(_newStakingRewardsProxyAddress);
239 1 : emit StakingRewardsUpdated(_newStakingRewardsProxyAddress);
240 : }
241 : }
|