tornado-nova/contracts/TornadoPool.sol

274 lines
9.4 KiB
Solidity
Raw Normal View History

2021-06-06 19:31:32 +02:00
// SPDX-License-Identifier: MIT
2020-04-08 11:41:12 +02:00
// https://tornado.cash
/*
2021-06-16 02:31:31 +02:00
* d888888P dP a88888b. dP
* 88 88 d8' `88 88
* 88 .d8888b. 88d888b. 88d888b. .d8888b. .d888b88 .d8888b. 88 .d8888b. .d8888b. 88d888b.
* 88 88' `88 88' `88 88' `88 88' `88 88' `88 88' `88 88 88' `88 Y8ooooo. 88' `88
* 88 88. .88 88 88 88 88. .88 88. .88 88. .88 dP Y8. .88 88. .88 88 88 88
* dP `88888P' dP dP dP `88888P8 `88888P8 `88888P' 88 Y88888P' `88888P8 `88888P' dP dP
* ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
*/
2020-04-08 11:41:12 +02:00
2021-07-06 23:10:18 +02:00
pragma solidity ^0.7.0;
2021-06-07 12:12:15 +02:00
pragma experimental ABIEncoderV2;
2021-09-29 21:39:30 +02:00
import "@openzeppelin/contracts/contracts/token/ERC20/IERC20.sol";
2021-10-05 14:12:39 +02:00
import "@openzeppelin/contracts/contracts/cryptography/ECDSA.sol";
2021-09-26 18:14:05 +02:00
import "./MerkleTreeWithHistory.sol";
2020-04-08 11:41:12 +02:00
2021-09-29 21:39:30 +02:00
interface IERC6777 is IERC20 {
function transferAndCall(
address,
uint256,
bytes calldata
) external returns (bool);
}
2021-06-06 19:31:32 +02:00
interface IVerifier {
2021-09-26 18:14:05 +02:00
function verifyProof(bytes memory _proof, uint256[7] memory _input) external view returns (bool);
2021-06-16 02:31:31 +02:00
2021-09-26 18:14:05 +02:00
function verifyProof(bytes memory _proof, uint256[21] memory _input) external view returns (bool);
2020-04-08 11:41:12 +02:00
}
2021-09-27 10:55:14 +02:00
interface IERC20Receiver {
function onTokenBridged(
2021-09-29 21:39:30 +02:00
IERC6777 token,
2021-09-27 10:55:14 +02:00
uint256 value,
bytes calldata data
) external;
}
2021-09-29 18:41:56 +02:00
contract TornadoPool is MerkleTreeWithHistory, IERC20Receiver {
2021-08-16 21:17:07 +02:00
int256 public constant MAX_EXT_AMOUNT = 2**248;
2021-08-16 18:53:18 +02:00
uint256 public constant MAX_FEE = 2**248;
2021-10-05 14:12:39 +02:00
bytes32 public constant ACCOUNT_TYPEHASH = keccak256("TornadoAccount(address owner,bytes publicKey)");
uint256 public immutable L1_CHAIN_ID;
2020-04-08 11:41:12 +02:00
2021-06-16 13:01:29 +02:00
IVerifier public immutable verifier2;
IVerifier public immutable verifier16;
2021-09-29 21:39:30 +02:00
IERC6777 public immutable token;
address public immutable omniBridge;
2021-09-30 17:34:07 +02:00
address public immutable l1Unwrapper;
2020-04-08 11:41:12 +02:00
uint256 public totalDeposited;
mapping(bytes32 => bool) public nullifierHashes;
2021-06-07 12:12:15 +02:00
struct ExtData {
2021-09-29 21:39:30 +02:00
address recipient;
2021-08-16 18:53:18 +02:00
int256 extAmount;
2021-09-29 21:39:30 +02:00
address relayer;
uint256 fee;
2021-06-07 12:12:15 +02:00
bytes encryptedOutput1;
bytes encryptedOutput2;
2021-09-30 17:34:07 +02:00
bool isL1Withdrawal;
2021-06-07 12:12:15 +02:00
}
2021-07-22 16:01:22 +02:00
struct Proof {
bytes proof;
bytes32 root;
bytes32[] inputNullifiers;
bytes32[2] outputCommitments;
uint256 publicAmount;
2021-07-22 16:01:22 +02:00
bytes32 extDataHash;
}
2021-10-04 18:28:08 +02:00
struct Account {
address owner;
bytes publicKey;
}
2021-06-16 02:31:31 +02:00
event NewCommitment(bytes32 commitment, uint256 index, bytes encryptedOutput);
2020-04-08 11:41:12 +02:00
event NewNullifier(bytes32 nullifier);
2021-06-21 19:05:36 +02:00
event PublicKey(address indexed owner, bytes key);
2020-04-08 11:41:12 +02:00
/**
@dev The constructor
2021-06-16 10:28:39 +02:00
@param _verifier2 the address of SNARK verifier for 2 inputs
@param _verifier16 the address of SNARK verifier for 16 inputs
2020-04-08 11:41:12 +02:00
*/
2021-09-26 18:14:05 +02:00
constructor(
IVerifier _verifier2,
IVerifier _verifier16,
uint32 _levels,
2021-09-29 18:41:56 +02:00
address _hasher,
2021-09-29 21:39:30 +02:00
IERC6777 _token,
2021-09-30 17:34:07 +02:00
address _omniBridge,
2021-10-05 14:12:39 +02:00
address _l1Unwrapper,
uint256 _l1ChainId
2021-09-26 18:14:05 +02:00
) MerkleTreeWithHistory(_levels, _hasher) {
verifier2 = _verifier2;
verifier16 = _verifier16;
2021-09-27 10:55:14 +02:00
token = _token;
2021-09-29 21:39:30 +02:00
omniBridge = _omniBridge;
2021-09-30 17:34:07 +02:00
l1Unwrapper = _l1Unwrapper;
2021-10-05 14:12:39 +02:00
L1_CHAIN_ID = _l1ChainId;
2021-08-05 09:29:49 +02:00
}
2021-09-29 21:39:30 +02:00
function transact(Proof memory _args, ExtData memory _extData) public {
if (_extData.extAmount > 0) {
// for deposits from L2
token.transferFrom(msg.sender, address(this), uint256(_extData.extAmount));
totalDeposited += uint256(_extData.extAmount);
2021-09-29 21:39:30 +02:00
}
_transact(_args, _extData);
}
function _transact(Proof memory _args, ExtData memory _extData) internal {
2021-09-26 18:14:05 +02:00
require(isKnownRoot(_args.root), "Invalid merkle root");
2021-07-22 16:01:22 +02:00
for (uint256 i = 0; i < _args.inputNullifiers.length; i++) {
require(!isSpent(_args.inputNullifiers[i]), "Input is already spent");
2021-06-15 13:47:54 +02:00
}
2021-07-22 16:01:22 +02:00
require(uint256(_args.extDataHash) == uint256(keccak256(abi.encode(_extData))) % FIELD_SIZE, "Incorrect external data hash");
2021-08-16 21:17:07 +02:00
require(_args.publicAmount == calculatePublicAmount(_extData.extAmount, _extData.fee), "Invalid public amount");
2021-07-22 16:01:22 +02:00
require(verifyProof(_args), "Invalid transaction proof");
for (uint256 i = 0; i < _args.inputNullifiers.length; i++) {
nullifierHashes[_args.inputNullifiers[i]] = true;
2021-06-16 10:28:39 +02:00
}
2021-09-29 21:39:30 +02:00
if (_extData.extAmount < 0) {
2021-06-16 10:28:39 +02:00
require(_extData.recipient != address(0), "Can't withdraw to zero address");
2021-09-30 17:34:07 +02:00
if (_extData.isL1Withdrawal) {
token.transferAndCall(omniBridge, uint256(-_extData.extAmount), abi.encodePacked(l1Unwrapper, _extData.recipient));
2021-09-29 21:39:30 +02:00
} else {
token.transfer(_extData.recipient, uint256(-_extData.extAmount));
}
totalDeposited -= uint256(-_extData.extAmount);
2021-06-16 10:28:39 +02:00
}
if (_extData.fee > 0) {
2021-09-27 10:55:14 +02:00
token.transfer(_extData.relayer, _extData.fee);
2021-06-16 10:28:39 +02:00
}
2021-09-26 18:14:05 +02:00
_insert(_args.outputCommitments[0], _args.outputCommitments[1]);
emit NewCommitment(_args.outputCommitments[0], nextIndex - 2, _extData.encryptedOutput1);
emit NewCommitment(_args.outputCommitments[1], nextIndex - 1, _extData.encryptedOutput2);
2021-07-22 16:01:22 +02:00
for (uint256 i = 0; i < _args.inputNullifiers.length; i++) {
emit NewNullifier(_args.inputNullifiers[i]);
2021-06-16 10:28:39 +02:00
}
}
2021-08-19 12:31:58 +02:00
function calculatePublicAmount(int256 _extAmount, uint256 _fee) public pure returns (uint256) {
2021-08-16 21:17:07 +02:00
require(_fee < MAX_FEE, "Invalid fee");
require(_extAmount > -MAX_EXT_AMOUNT && _extAmount < MAX_EXT_AMOUNT, "Invalid ext amount");
int256 publicAmount = _extAmount - int256(_fee);
return (publicAmount >= 0) ? uint256(publicAmount) : FIELD_SIZE - uint256(-publicAmount);
2021-06-16 10:28:39 +02:00
}
/** @dev whether a note is already spent */
function isSpent(bytes32 _nullifierHash) public view returns (bool) {
return nullifierHashes[_nullifierHash];
}
2021-09-27 10:55:14 +02:00
function verifyProof(Proof memory _args) public view returns (bool) {
2021-07-22 16:01:22 +02:00
if (_args.inputNullifiers.length == 2) {
2021-06-16 10:28:39 +02:00
return
2021-06-16 02:31:31 +02:00
verifier2.verifyProof(
2021-07-22 16:01:22 +02:00
_args.proof,
2021-06-16 02:31:31 +02:00
[
2021-07-22 16:01:22 +02:00
uint256(_args.root),
_args.publicAmount,
2021-07-22 16:01:22 +02:00
uint256(_args.extDataHash),
uint256(_args.inputNullifiers[0]),
uint256(_args.inputNullifiers[1]),
uint256(_args.outputCommitments[0]),
2021-09-26 18:14:05 +02:00
uint256(_args.outputCommitments[1])
2021-06-16 02:31:31 +02:00
]
2021-06-16 10:28:39 +02:00
);
2021-07-22 16:01:22 +02:00
} else if (_args.inputNullifiers.length == 16) {
2021-06-16 10:28:39 +02:00
return
2021-06-16 02:31:31 +02:00
verifier16.verifyProof(
2021-07-22 16:01:22 +02:00
_args.proof,
2021-06-16 02:31:31 +02:00
[
2021-07-22 16:01:22 +02:00
uint256(_args.root),
_args.publicAmount,
2021-07-22 16:01:22 +02:00
uint256(_args.extDataHash),
uint256(_args.inputNullifiers[0]),
uint256(_args.inputNullifiers[1]),
uint256(_args.inputNullifiers[2]),
uint256(_args.inputNullifiers[3]),
uint256(_args.inputNullifiers[4]),
uint256(_args.inputNullifiers[5]),
uint256(_args.inputNullifiers[6]),
uint256(_args.inputNullifiers[7]),
uint256(_args.inputNullifiers[8]),
uint256(_args.inputNullifiers[9]),
uint256(_args.inputNullifiers[10]),
uint256(_args.inputNullifiers[11]),
uint256(_args.inputNullifiers[12]),
uint256(_args.inputNullifiers[13]),
uint256(_args.inputNullifiers[14]),
uint256(_args.inputNullifiers[15]),
uint256(_args.outputCommitments[0]),
2021-09-26 18:14:05 +02:00
uint256(_args.outputCommitments[1])
2021-06-16 02:31:31 +02:00
]
2021-06-16 10:28:39 +02:00
);
2021-06-15 13:47:54 +02:00
} else {
revert("unsupported input count");
}
2020-04-08 11:41:12 +02:00
}
2021-06-21 19:05:36 +02:00
2021-10-04 18:28:08 +02:00
function register(Account memory _account) public {
require(_account.owner == msg.sender, "only owner can be registered");
_register(_account);
}
function _register(Account memory _account) internal {
emit PublicKey(_account.owner, _account.publicKey);
2021-07-22 16:01:22 +02:00
}
function registerAndTransact(
2021-10-04 18:28:08 +02:00
Account memory _account,
2021-09-27 10:55:14 +02:00
Proof memory _proofArgs,
ExtData memory _extData
2021-09-29 21:39:30 +02:00
) public {
2021-10-04 18:28:08 +02:00
register(_account);
2021-09-29 21:39:30 +02:00
transact(_proofArgs, _extData);
2021-06-21 19:05:36 +02:00
}
2021-09-27 10:55:14 +02:00
function onTokenBridged(
2021-09-29 21:39:30 +02:00
IERC6777 _token,
uint256 _amount,
2021-09-27 10:55:14 +02:00
bytes calldata _data
) external override {
2021-10-05 14:12:39 +02:00
(Account memory _account, Proof memory _args, ExtData memory _extData, bytes memory _signature) = abi.decode(
_data,
(Account, Proof, ExtData, bytes)
);
require(isValidSignature(_account, _signature), "Invalid account signature");
2021-09-27 10:55:14 +02:00
require(_token == token, "provided token is not supported");
require(msg.sender == omniBridge, "only omni bridge");
require(_amount == uint256(_extData.extAmount), "amount from bridge is incorrect");
require(uint256(_extData.extAmount) + totalDeposited >= token.balanceOf(address(this)), "bridge did not send enough tokens");
totalDeposited += uint256(_extData.extAmount);
2021-09-29 21:39:30 +02:00
2021-10-04 18:28:08 +02:00
if (_account.owner != address(0) && _account.publicKey.length > 0) {
_register(_account);
2021-09-27 10:55:14 +02:00
}
2021-09-29 21:39:30 +02:00
_transact(_args, _extData);
2021-09-27 10:55:14 +02:00
}
2021-10-05 14:12:39 +02:00
function isValidSignature(Account memory _account, bytes memory _signature) public view returns (bool) {
bytes32 hashStruct = keccak256(abi.encode(ACCOUNT_TYPEHASH, _account.owner, keccak256(_account.publicKey)));
bytes32 hash = keccak256(abi.encodePacked(uint16(0x1901), domainSeparator(), hashStruct));
address signer = ECDSA.recover(hash, _signature);
return signer == _account.owner;
}
function domainSeparator() public view returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes("TornadoPool")),
keccak256(bytes("1")), // Version
L1_CHAIN_ID,
address(this)
)
);
}
2020-04-08 11:41:12 +02:00
}