Miner.sol 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.6.0;
  3. pragma experimental ABIEncoderV2;
  4. import "./interfaces/IVerifier.sol";
  5. import "./interfaces/IRewardSwap.sol";
  6. import "tornado-trees/contracts/TornadoTrees.sol";
  7. import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
  8. import "@openzeppelin/contracts/math/SafeMath.sol";
  9. import "torn-token/contracts/ENS.sol";
  10. contract Miner is EnsResolve {
  11. using SafeMath for uint256;
  12. IVerifier public rewardVerifier;
  13. IVerifier public withdrawVerifier;
  14. IVerifier public treeUpdateVerifier;
  15. IRewardSwap public immutable rewardSwap;
  16. address public immutable governance;
  17. TornadoTrees public tornadoTrees;
  18. mapping(bytes32 => bool) public accountNullifiers;
  19. mapping(bytes32 => bool) public rewardNullifiers;
  20. mapping(address => uint256) public rates;
  21. uint256 public accountCount;
  22. uint256 public constant ACCOUNT_ROOT_HISTORY_SIZE = 100;
  23. bytes32[ACCOUNT_ROOT_HISTORY_SIZE] public accountRoots;
  24. event NewAccount(bytes32 commitment, bytes32 nullifier, bytes encryptedAccount, uint256 index);
  25. event RateChanged(address instance, uint256 value);
  26. event VerifiersUpdated(address reward, address withdraw, address treeUpdate);
  27. struct TreeUpdateArgs {
  28. bytes32 oldRoot;
  29. bytes32 newRoot;
  30. bytes32 leaf;
  31. uint256 pathIndices;
  32. }
  33. struct AccountUpdate {
  34. bytes32 inputRoot;
  35. bytes32 inputNullifierHash;
  36. bytes32 outputRoot;
  37. uint256 outputPathIndices;
  38. bytes32 outputCommitment;
  39. }
  40. struct RewardExtData {
  41. address relayer;
  42. bytes encryptedAccount;
  43. }
  44. struct RewardArgs {
  45. uint256 rate;
  46. uint256 fee;
  47. address instance;
  48. bytes32 rewardNullifier;
  49. bytes32 extDataHash;
  50. bytes32 depositRoot;
  51. bytes32 withdrawalRoot;
  52. RewardExtData extData;
  53. AccountUpdate account;
  54. }
  55. struct WithdrawExtData {
  56. uint256 fee;
  57. address recipient;
  58. address relayer;
  59. bytes encryptedAccount;
  60. }
  61. struct WithdrawArgs {
  62. uint256 amount;
  63. bytes32 extDataHash;
  64. WithdrawExtData extData;
  65. AccountUpdate account;
  66. }
  67. struct Rate {
  68. bytes32 instance;
  69. uint256 value;
  70. }
  71. modifier onlyGovernance() {
  72. require(msg.sender == governance, "Only governance can perform this action");
  73. _;
  74. }
  75. constructor(
  76. bytes32 _rewardSwap,
  77. bytes32 _governance,
  78. bytes32 _tornadoTrees,
  79. bytes32[3] memory _verifiers,
  80. bytes32 _accountRoot,
  81. Rate[] memory _rates
  82. ) public {
  83. rewardSwap = IRewardSwap(resolve(_rewardSwap));
  84. governance = resolve(_governance);
  85. tornadoTrees = TornadoTrees(resolve(_tornadoTrees));
  86. // insert empty tree root without incrementing accountCount counter
  87. accountRoots[0] = _accountRoot;
  88. _setRates(_rates);
  89. // prettier-ignore
  90. _setVerifiers([
  91. IVerifier(resolve(_verifiers[0])),
  92. IVerifier(resolve(_verifiers[1])),
  93. IVerifier(resolve(_verifiers[2]))
  94. ]);
  95. }
  96. function reward(bytes memory _proof, RewardArgs memory _args) public {
  97. reward(_proof, _args, new bytes(0), TreeUpdateArgs(0, 0, 0, 0));
  98. }
  99. function batchReward(bytes[] calldata _rewardArgs) external {
  100. for (uint256 i = 0; i < _rewardArgs.length; i++) {
  101. (bytes memory proof, RewardArgs memory args) = abi.decode(_rewardArgs[i], (bytes, RewardArgs));
  102. reward(proof, args);
  103. }
  104. }
  105. function reward(
  106. bytes memory _proof,
  107. RewardArgs memory _args,
  108. bytes memory _treeUpdateProof,
  109. TreeUpdateArgs memory _treeUpdateArgs
  110. ) public {
  111. validateAccountUpdate(_args.account, _treeUpdateProof, _treeUpdateArgs);
  112. tornadoTrees.validateRoots(_args.depositRoot, _args.withdrawalRoot);
  113. require(_args.extDataHash == keccak248(abi.encode(_args.extData)), "Incorrect external data hash");
  114. require(_args.fee < 2**248, "Fee value out of range");
  115. require(_args.rate == rates[_args.instance] && _args.rate > 0, "Invalid reward rate");
  116. require(!rewardNullifiers[_args.rewardNullifier], "Reward has been already spent");
  117. require(
  118. rewardVerifier.verifyProof(
  119. _proof,
  120. [
  121. uint256(_args.rate),
  122. uint256(_args.fee),
  123. uint256(_args.instance),
  124. uint256(_args.rewardNullifier),
  125. uint256(_args.extDataHash),
  126. uint256(_args.account.inputRoot),
  127. uint256(_args.account.inputNullifierHash),
  128. uint256(_args.account.outputRoot),
  129. uint256(_args.account.outputPathIndices),
  130. uint256(_args.account.outputCommitment),
  131. uint256(_args.depositRoot),
  132. uint256(_args.withdrawalRoot)
  133. ]
  134. ),
  135. "Invalid reward proof"
  136. );
  137. accountNullifiers[_args.account.inputNullifierHash] = true;
  138. rewardNullifiers[_args.rewardNullifier] = true;
  139. insertAccountRoot(_args.account.inputRoot == getLastAccountRoot() ? _args.account.outputRoot : _treeUpdateArgs.newRoot);
  140. if (_args.fee > 0) {
  141. rewardSwap.swap(_args.extData.relayer, _args.fee);
  142. }
  143. emit NewAccount(
  144. _args.account.outputCommitment,
  145. _args.account.inputNullifierHash,
  146. _args.extData.encryptedAccount,
  147. accountCount - 1
  148. );
  149. }
  150. function withdraw(bytes memory _proof, WithdrawArgs memory _args) public {
  151. withdraw(_proof, _args, new bytes(0), TreeUpdateArgs(0, 0, 0, 0));
  152. }
  153. function withdraw(
  154. bytes memory _proof,
  155. WithdrawArgs memory _args,
  156. bytes memory _treeUpdateProof,
  157. TreeUpdateArgs memory _treeUpdateArgs
  158. ) public {
  159. validateAccountUpdate(_args.account, _treeUpdateProof, _treeUpdateArgs);
  160. require(_args.extDataHash == keccak248(abi.encode(_args.extData)), "Incorrect external data hash");
  161. require(_args.amount < 2**248, "Amount value out of range");
  162. require(
  163. withdrawVerifier.verifyProof(
  164. _proof,
  165. [
  166. uint256(_args.amount),
  167. uint256(_args.extDataHash),
  168. uint256(_args.account.inputRoot),
  169. uint256(_args.account.inputNullifierHash),
  170. uint256(_args.account.outputRoot),
  171. uint256(_args.account.outputPathIndices),
  172. uint256(_args.account.outputCommitment)
  173. ]
  174. ),
  175. "Invalid withdrawal proof"
  176. );
  177. insertAccountRoot(_args.account.inputRoot == getLastAccountRoot() ? _args.account.outputRoot : _treeUpdateArgs.newRoot);
  178. accountNullifiers[_args.account.inputNullifierHash] = true;
  179. // allow submitting noop withdrawals (amount == 0)
  180. uint256 amount = _args.amount.sub(_args.extData.fee, "Amount should be greater than fee");
  181. if (amount > 0) {
  182. rewardSwap.swap(_args.extData.recipient, amount);
  183. }
  184. // Note. The relayer swap rate always will be worse than estimated
  185. if (_args.extData.fee > 0) {
  186. rewardSwap.swap(_args.extData.relayer, _args.extData.fee);
  187. }
  188. emit NewAccount(
  189. _args.account.outputCommitment,
  190. _args.account.inputNullifierHash,
  191. _args.extData.encryptedAccount,
  192. accountCount - 1
  193. );
  194. }
  195. function setRates(Rate[] memory _rates) external onlyGovernance {
  196. _setRates(_rates);
  197. }
  198. function setVerifiers(IVerifier[3] calldata _verifiers) external onlyGovernance {
  199. _setVerifiers(_verifiers);
  200. }
  201. function setTornadoTreesContract(TornadoTrees _tornadoTrees) external onlyGovernance {
  202. tornadoTrees = _tornadoTrees;
  203. }
  204. function setPoolWeight(uint256 _newWeight) external onlyGovernance {
  205. rewardSwap.setPoolWeight(_newWeight);
  206. }
  207. // ------VIEW-------
  208. /**
  209. @dev Whether the root is present in the root history
  210. */
  211. function isKnownAccountRoot(bytes32 _root, uint256 _index) public view returns (bool) {
  212. return _root != 0 && accountRoots[_index % ACCOUNT_ROOT_HISTORY_SIZE] == _root;
  213. }
  214. /**
  215. @dev Returns the last root
  216. */
  217. function getLastAccountRoot() public view returns (bytes32) {
  218. return accountRoots[accountCount % ACCOUNT_ROOT_HISTORY_SIZE];
  219. }
  220. // -----INTERNAL-------
  221. function keccak248(bytes memory _data) internal pure returns (bytes32) {
  222. return keccak256(_data) & 0x00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
  223. }
  224. function validateTreeUpdate(
  225. bytes memory _proof,
  226. TreeUpdateArgs memory _args,
  227. bytes32 _commitment
  228. ) internal view {
  229. require(_proof.length > 0, "Outdated account merkle root");
  230. require(_args.oldRoot == getLastAccountRoot(), "Outdated tree update merkle root");
  231. require(_args.leaf == _commitment, "Incorrect commitment inserted");
  232. require(_args.pathIndices == accountCount, "Incorrect account insert index");
  233. require(
  234. treeUpdateVerifier.verifyProof(
  235. _proof,
  236. [uint256(_args.oldRoot), uint256(_args.newRoot), uint256(_args.leaf), uint256(_args.pathIndices)]
  237. ),
  238. "Invalid tree update proof"
  239. );
  240. }
  241. function validateAccountUpdate(
  242. AccountUpdate memory _account,
  243. bytes memory _treeUpdateProof,
  244. TreeUpdateArgs memory _treeUpdateArgs
  245. ) internal view {
  246. require(!accountNullifiers[_account.inputNullifierHash], "Outdated account state");
  247. if (_account.inputRoot != getLastAccountRoot()) {
  248. // _account.outputPathIndices (= last tree leaf index) is always equal to root index in the history mapping
  249. // because we always generate a new root for each new leaf
  250. require(isKnownAccountRoot(_account.inputRoot, _account.outputPathIndices), "Invalid account root");
  251. validateTreeUpdate(_treeUpdateProof, _treeUpdateArgs, _account.outputCommitment);
  252. } else {
  253. require(_account.outputPathIndices == accountCount, "Incorrect account insert index");
  254. }
  255. }
  256. function insertAccountRoot(bytes32 _root) internal {
  257. accountRoots[++accountCount % ACCOUNT_ROOT_HISTORY_SIZE] = _root;
  258. }
  259. function _setRates(Rate[] memory _rates) internal {
  260. for (uint256 i = 0; i < _rates.length; i++) {
  261. require(_rates[i].value < 2**128, "Incorrect rate");
  262. address instance = resolve(_rates[i].instance);
  263. rates[instance] = _rates[i].value;
  264. emit RateChanged(instance, _rates[i].value);
  265. }
  266. }
  267. function _setVerifiers(IVerifier[3] memory _verifiers) internal {
  268. rewardVerifier = _verifiers[0];
  269. withdrawVerifier = _verifiers[1];
  270. treeUpdateVerifier = _verifiers[2];
  271. emit VerifiersUpdated(address(_verifiers[0]), address(_verifiers[1]), address(_verifiers[2]));
  272. }
  273. }