mirror of
https://github.com/tornadocash/tornado-anonymity-mining.git
synced 2024-11-22 09:47:15 +01:00
133 lines
4.7 KiB
Solidity
133 lines
4.7 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
|
|
pragma solidity ^0.6.0;
|
|
pragma experimental ABIEncoderV2;
|
|
|
|
import "torn-token/contracts/ENS.sol";
|
|
import "./utils/OwnableMerkleTree.sol";
|
|
import "./interfaces/ITornadoTrees.sol";
|
|
import "./interfaces/IHasher.sol";
|
|
|
|
contract TornadoTrees is ITornadoTrees, EnsResolve {
|
|
OwnableMerkleTree public immutable depositTree;
|
|
OwnableMerkleTree public immutable withdrawalTree;
|
|
IHasher public immutable hasher;
|
|
address public immutable tornadoProxy;
|
|
|
|
bytes32[] public deposits;
|
|
uint256 public lastProcessedDepositLeaf;
|
|
|
|
bytes32[] public withdrawals;
|
|
uint256 public lastProcessedWithdrawalLeaf;
|
|
|
|
event DepositData(address instance, bytes32 indexed hash, uint256 block, uint256 index);
|
|
event WithdrawalData(address instance, bytes32 indexed hash, uint256 block, uint256 index);
|
|
|
|
struct TreeLeaf {
|
|
address instance;
|
|
bytes32 hash;
|
|
uint256 block;
|
|
}
|
|
|
|
modifier onlyTornadoProxy {
|
|
require(msg.sender == tornadoProxy, "Not authorized");
|
|
_;
|
|
}
|
|
|
|
constructor(
|
|
bytes32 _tornadoProxy,
|
|
bytes32 _hasher2,
|
|
bytes32 _hasher3,
|
|
uint32 _levels
|
|
) public {
|
|
tornadoProxy = resolve(_tornadoProxy);
|
|
hasher = IHasher(resolve(_hasher3));
|
|
depositTree = new OwnableMerkleTree(_levels, IHasher(resolve(_hasher2)));
|
|
withdrawalTree = new OwnableMerkleTree(_levels, IHasher(resolve(_hasher2)));
|
|
}
|
|
|
|
function registerDeposit(address _instance, bytes32 _commitment) external override onlyTornadoProxy {
|
|
deposits.push(keccak256(abi.encode(_instance, _commitment, blockNumber())));
|
|
}
|
|
|
|
function registerWithdrawal(address _instance, bytes32 _nullifier) external override onlyTornadoProxy {
|
|
withdrawals.push(keccak256(abi.encode(_instance, _nullifier, blockNumber())));
|
|
}
|
|
|
|
function updateRoots(TreeLeaf[] calldata _deposits, TreeLeaf[] calldata _withdrawals) external {
|
|
if (_deposits.length > 0) updateDepositTree(_deposits);
|
|
if (_withdrawals.length > 0) updateWithdrawalTree(_withdrawals);
|
|
}
|
|
|
|
function updateDepositTree(TreeLeaf[] calldata _deposits) public {
|
|
bytes32[] memory leaves = new bytes32[](_deposits.length);
|
|
uint256 offset = lastProcessedDepositLeaf;
|
|
|
|
for (uint256 i = 0; i < _deposits.length; i++) {
|
|
TreeLeaf memory deposit = _deposits[i];
|
|
bytes32 leafHash = keccak256(abi.encode(deposit.instance, deposit.hash, deposit.block));
|
|
require(deposits[offset + i] == leafHash, "Incorrect deposit");
|
|
|
|
leaves[i] = hasher.poseidon([bytes32(uint256(deposit.instance)), deposit.hash, bytes32(deposit.block)]);
|
|
delete deposits[offset + i];
|
|
|
|
emit DepositData(deposit.instance, deposit.hash, deposit.block, offset + i);
|
|
}
|
|
|
|
lastProcessedDepositLeaf = offset + _deposits.length;
|
|
depositTree.bulkInsert(leaves);
|
|
}
|
|
|
|
function updateWithdrawalTree(TreeLeaf[] calldata _withdrawals) public {
|
|
bytes32[] memory leaves = new bytes32[](_withdrawals.length);
|
|
uint256 offset = lastProcessedWithdrawalLeaf;
|
|
|
|
for (uint256 i = 0; i < _withdrawals.length; i++) {
|
|
TreeLeaf memory withdrawal = _withdrawals[i];
|
|
bytes32 leafHash = keccak256(abi.encode(withdrawal.instance, withdrawal.hash, withdrawal.block));
|
|
require(withdrawals[offset + i] == leafHash, "Incorrect withdrawal");
|
|
|
|
leaves[i] = hasher.poseidon([bytes32(uint256(withdrawal.instance)), withdrawal.hash, bytes32(withdrawal.block)]);
|
|
delete withdrawals[offset + i];
|
|
|
|
emit WithdrawalData(withdrawal.instance, withdrawal.hash, withdrawal.block, offset + i);
|
|
}
|
|
|
|
lastProcessedWithdrawalLeaf = offset + _withdrawals.length;
|
|
withdrawalTree.bulkInsert(leaves);
|
|
}
|
|
|
|
function validateRoots(bytes32 _depositRoot, bytes32 _withdrawalRoot) public view {
|
|
require(depositTree.isKnownRoot(_depositRoot), "Incorrect deposit tree root");
|
|
require(withdrawalTree.isKnownRoot(_withdrawalRoot), "Incorrect withdrawal tree root");
|
|
}
|
|
|
|
function depositRoot() external view returns (bytes32) {
|
|
return depositTree.getLastRoot();
|
|
}
|
|
|
|
function withdrawalRoot() external view returns (bytes32) {
|
|
return withdrawalTree.getLastRoot();
|
|
}
|
|
|
|
function getRegisteredDeposits() external view returns (bytes32[] memory _deposits) {
|
|
uint256 count = deposits.length - lastProcessedDepositLeaf;
|
|
_deposits = new bytes32[](count);
|
|
for (uint256 i = 0; i < count; i++) {
|
|
_deposits[i] = deposits[lastProcessedDepositLeaf + i];
|
|
}
|
|
}
|
|
|
|
function getRegisteredWithdrawals() external view returns (bytes32[] memory _withdrawals) {
|
|
uint256 count = withdrawals.length - lastProcessedWithdrawalLeaf;
|
|
_withdrawals = new bytes32[](count);
|
|
for (uint256 i = 0; i < count; i++) {
|
|
_withdrawals[i] = withdrawals[lastProcessedWithdrawalLeaf + i];
|
|
}
|
|
}
|
|
|
|
function blockNumber() public view virtual returns (uint256) {
|
|
return block.number;
|
|
}
|
|
}
|