// SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { Initializable } from "@openzeppelin/contracts/proxy/Initializable.sol"; import "@openzeppelin/contracts/proxy/Clones.sol"; import "./instances/ERC20TornadoCloneable.sol"; import "./instances/ETHTornadoCloneable.sol"; contract MinimalInstanceFactory { using Clones for address; using Address for address; address public immutable ERC20Impl; address public immutable nativeCurImpl; address public immutable verifier; address public immutable hasher; uint32 public immutable merkleTreeHeight; event NewTreeHeightSet(uint32 indexed newTreeHeight); event NewImplementationSet(address indexed ERC20Impl, address indexed nativeCurImpl, address verifier, address hasher); event NewInstanceCloneCreated(address indexed clone); /** * @notice This instance factory is NOT permissioned. It is designed to always be able to print * new Tornado Instances if necessary. * @dev Creates new Tornado instance. */ constructor(address _verifier, address _hasher, uint32 _merkleTreeHeight) public { verifier = _verifier; hasher = _hasher; merkleTreeHeight = _merkleTreeHeight; ERC20TornadoCloneable ERC20ImplContract = new ERC20TornadoCloneable(_verifier, _hasher); ERC20Impl = address(ERC20ImplContract); ETHTornadoCloneable nativeCurImplContract = new ETHTornadoCloneable(_verifier, _hasher); nativeCurImpl = address(nativeCurImplContract); } /** * @notice Creates new Tornado instance. * @param _denomination denomination of new Tornado instance * @param _token address of ERC20 token for a new instance, if zero address, then it will be ETH */ function createInstanceClone(uint256 _denomination, address _token) public virtual returns (address clone) { bytes32 salt = keccak256(abi.encodePacked(_denomination, _token)); if (_token == address(0)) { clone = nativeCurImpl.predictDeterministicAddress(salt); if (!clone.isContract()) { nativeCurImpl.cloneDeterministic(salt); emit NewInstanceCloneCreated(clone); ETHTornadoCloneable(clone).init(_denomination, merkleTreeHeight); } } else { clone = ERC20Impl.predictDeterministicAddress(salt); if (!clone.isContract()) { ERC20Impl.cloneDeterministic(salt); emit NewInstanceCloneCreated(clone); ERC20TornadoCloneable(clone).init(_denomination, merkleTreeHeight, _token); } } return clone; } function getInstanceAddress(uint256 _denomination, address _token) public view returns (address) { bytes32 salt = keccak256(abi.encodePacked(_denomination, _token)); if (_token == address(0)) { return nativeCurImpl.predictDeterministicAddress(salt); } else { return ERC20Impl.predictDeterministicAddress(salt); } } }