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