diff --git a/.env.example b/.env.example index 48a8535..166127c 100644 --- a/.env.example +++ b/.env.example @@ -1,13 +1,4 @@ -etherscan_api_key= -goerli_rpc_key= -mainnet_rpc_key= -goerli_account_pk= -mainnet_account_pk= -use_latest_block=false - -PROXY=0x722122dF12D4e14e13Ac3b6895a86e84145b6967 -DEPLOYER=0xCEe71753C9820f063b38FDbE4cFDAf1d3D928A80 -HASHER=0x83584f83f26aF4eDDA9CBe8C730bc87C364b28fe -VERIFIER=0xce172ce1F20EC0B3728c9965470eaf994A03557A -SALT=0x0000000000000000000000000000000000000000000000000000000047941987 -COMP_ADDRESS=0xc00e94Cb662C3520282E6f5717214004A7f26888 \ No newline at end of file +ETHERSCAN_KEY= +ALCHEMY_KEY= +PRIVATE_KEY= +INFURA_API_KEY= diff --git a/.env.example.workflow b/.env.example.workflow deleted file mode 100644 index 50fdc29..0000000 --- a/.env.example.workflow +++ /dev/null @@ -1,8 +0,0 @@ -use_latest_block=false - -PROXY=0x722122dF12D4e14e13Ac3b6895a86e84145b6967 -DEPLOYER=0xCEe71753C9820f063b38FDbE4cFDAf1d3D928A80 -HASHER=0x83584f83f26aF4eDDA9CBe8C730bc87C364b28fe -VERIFIER=0xce172ce1F20EC0B3728c9965470eaf994A03557A -SALT=0x0000000000000000000000000000000000000000000000000000000047941987 -COMP_ADDRESS=0xc00e94Cb662C3520282E6f5717214004A7f26888 \ No newline at end of file diff --git a/.github/workflows/build.js.yml b/.github/workflows/build.js.yml index 7440c01..c6aca03 100644 --- a/.github/workflows/build.js.yml +++ b/.github/workflows/build.js.yml @@ -3,34 +3,22 @@ name: build on: push: branches: ['*'] + tags: ['v[0-9]+.[0-9]+.[0-9]+'] pull_request: jobs: build: runs-on: ubuntu-latest - environment: secrets - env: - etherscan_api_key: ${{ secrets.ETHERSCAN_API_KEY }} - goerli_rpc_key: ${{ secrets.GOERLI_RPC_KEY }} - mainnet_rpc_key: ${{ secrets.MAINNET_RPC_KEY }} - goerli_account_pk: ${{ secrets.GOERLI_ACCOUNT_PK }} - mainnet_account_pk: ${{ secrets.MAINNET_ACCOUNT_PK }} steps: - - name: Tests and setup + - name: Checkout uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: 12 - - run: yarn install - - run: cp .env.example.workflow .env - - run: yarn prettier:fix + node-version: 14 + - run: yarn cache clean --all + - run: yarn install --network-concurrency 1 - run: yarn lint + - run: yarn compile - run: yarn test - - - name: Generate coverage - run: yarn coverage - - - name: Coveralls - uses: coverallsapp/github-action@master - with: - github-token: ${{ secrets.GITHUB_TOKEN }} + env: + ALCHEMY_KEY: ${{ secrets.ALCHEMY_KEY }} diff --git a/.gitignore b/.gitignore index 376909a..02e59cc 100644 --- a/.gitignore +++ b/.gitignore @@ -106,4 +106,6 @@ dist artifacts cache coverage -coverage.json \ No newline at end of file +coverage.json + +.vscode \ No newline at end of file diff --git a/.solcover.js b/.solcover.js index db331df..ba8ea30 100644 --- a/.solcover.js +++ b/.solcover.js @@ -1,14 +1,3 @@ module.exports = { - skipFiles: [ - 'tornado_proxy/TornadoProxy.sol', - 'tornado_proxy/ITornadoTrees.sol', - 'tornado_proxy/ITornadoInstance.sol', - 'ERC20TornadoVirtual.sol', - 'denomination_templates/Add1Instance.sol', - 'denomination_templates/Add2Instances.sol', - 'denomination_templates/Add3Instances.sol', - 'denomination_templates/Add4Instances.sol', - 'denomination_templates/Add5Instances.sol', - 'denomination_templates/Add6Instances.sol', - ], + skipFiles: [], } diff --git a/README.md b/README.md index 38b585e..0f7c102 100644 --- a/README.md +++ b/README.md @@ -1,87 +1,90 @@ -# Tornado Instances - -[![build](https://img.shields.io/github/workflow/status/mirru2532/tornado-instances/build)](https://github.com/h-ivor/tornado-instances/actions) [![Coveralls](https://img.shields.io/coveralls/github/mirru2532/tornado-instances)](https://coveralls.io/github/mirru2532/tornado-instances) +# Tornado Instances Factory ## About -This repository serves as a general template repository for deploying proposals for governance for the addition of new tornado ERC20 instances to the tornado proxy. +This repository contains: -The contracts offer a template for the addition of 4 new instances for an ERC20 token (the standard way to add new instances) and can also be slightly modified to add a custom amount. The scripts deploy the contracts. +1. `InstanceFactory` - instance factory for the creation new Tornado ERC20 pools +2. `InstanceFactoryWithRegistry` - governance proposal factory for the addition of new Tornado ERC20 instances to the Tornado router -The resources folder contains data necessary for the instances to be deployed and must be filled out. They are initially filled out with the RAI instance data. +### InstanceFactory -### How-To: +Anyone can create a new ERC20 instance by calling `createInstanceClone` method of the factory with parameters: + +1. `address token` - address of ERC20 token for a new instance +2. `uint256 denomination` - denomination for new instance (tokens can only be deposited in certain denominations into instances) + +### InstanceFactoryWithRegistry + +Anyone can create governance proposal for the addition of a new ERC20 instance by calling `createProposalApprove/createProposalPermit` method of the factory with parameters (proposal creation fee in TORN is charged from sender): + +1. `address token` - address of ERC20 token for a new instance +2. `uint24 uniswapPoolSwappingFee` - fee value of Uniswap instance which will be used for `TORN/token` price determination. `3000` means 0.3% fee Uniswap pool. +3. `uint256[] denominations` - list of denominations for each new instance (tokens can only be deposited in certain denominations into instances). +4. `uint32[] protocolFees` - list of protocol fees for each new instance (this fee is only charged from registrated relayer during withdrawal process). `100` means 1% of instance denomination fee for withdrawal throw registrated relayer. + +## Factory parameters + +### InstanceFactoryWithRegistry + +1. `max number of new instances in one proposal` - the current version supports the addition of a maximum of 4 instances at once. +2. `proposal creation fee` - this fee is charged from creator of proposal during `createProposalApprove/createProposalPermit` factory method execution. It can be changed by governance. Default value is stored in `config.js`. +3. `TWAPSlotsMin` - minimum number of TWAP slots for Uniswap pool that is chosen during `createProposalApprove/createProposalPermit` factory method call. It can be changed by governance. Default value is stored in `config.js`. + +## Warnings + +1. This version of the factory creates a proposal for **immutable** Tornado instance initialization. +2. For `InstanceFactoryWithRegistry` users should manually propose a proposal after its creation using the factory (in governance UI for example). As `propose()` method caller must have 1000 TORN locked in the governance. Moreover, the proposer can't propose more than one proposal simultaneously. + +## Tests Setting up the repository: ```bash -git clone https://github.com/mirru2532/tornado-instances.git -cd tornado-instances -yarn -cp .env.example .env + yarn + cp .env.example .env ``` Please fill out .env according to the template provided in it. Please ensure that all of the example values are set to the correct addresses. -### Testing and running scripts: - To run test scripts: ```bash -yarn test + yarn test ``` -Test scripts cover instance factory deployment, proposal deployment and executing proposal (RAI instances). +Test scripts cover instance factory deployment, proposal deployment and executing proposal. -Running **tasks:** +## Deploy -```bash -# a list of yarn scripts specifically for instance deployment -"deploy:proposal": "yarn hardhat --network mainnet deploy_proposal --factory-address", -"deploy:proposal:test": "yarn hardhat --network goerli deploy_proposal --factory-address", -"deploy:proposal:factory": "yarn hardhat --network mainnet deploy_factory_proposal", -"deploy:proposal:factory:test": "yarn hardhat --network goerli deploy_factory_proposal", -"propose": "yarn hardhat --network mainnet propose_proposal --proposal-address", +Check config.js for actual values. -# as an example -yarn deploy:proposal:factory +With `salt` = `0x0000000000000000000000000000000000000000000000000000000047941987` address must be: -# to call a specific task -yarn hardhat --network +1. `InstanceFactory` - `0x09110e04d5AEF747bcf7A3585D8FFC892Ab9D1Cf` +2. `InstanceFactoryWithRegistry` - `0xC01D57d83E9Fe35E0Fb900F9D384EFcA679DF4bD` + +Check addresses with current config: + +```shell + yarn compile + node -e 'require("./src/generateAddresses").generateWithLog()' ``` -## Deploying a proposal for an instance update +Deploy InstanceFactory: -Open `resources/instances.js`, a single object which generates an instance contains the following fields (RAI as an example): - -```js -{ - tokenAddress: "0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919", - denomination: "33333333333333333333", - symbol: "RAI", - decimals: 18 -} +```shell + yarn hardhat run scripts/deployInstanceFactory.js --network mainnet ``` -`denomination` - tokens can only be deposited in certain denominations into instances, the above considers this instance to have a 100$ denomination, assuming RAI at 3$. -Fill out each of these fields for your own token in the `instance.js` file. This repo supports the addition of a maximum of 6 instances at once. It will automatically detect how many instances are to use. +Deploy InstanceFactoryWithRegistry: -Now find the factory contract address: - -```bash -yarn deploy:proposal +```shell + yarn hardhat run scripts/deployInstanceFactoryWithRegistry.js --network mainnet ``` -If testing: +Verify InstanceFactory on Etherscan: -```bash -yarn deploy:proposal:test ``` - -The last step, or first depending on if you are simply proposing the proposal, is taking the address of the deployed proposal and calling: - -```bash -yarn propose + yarn hardhat verify --network ``` - -There is not test implementation for this. diff --git a/config.js b/config.js new file mode 100644 index 0000000..58fed34 --- /dev/null +++ b/config.js @@ -0,0 +1,21 @@ +module.exports = { + verifier: '0xce172ce1F20EC0B3728c9965470eaf994A03557A', + hasher: '0x83584f83f26aF4eDDA9CBe8C730bc87C364b28fe', + governance: '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce', + instanceRegistry: '0xB20c66C4DE72433F3cE747b58B86830c459CA911', + router: '0xd90e2f925DA726b50C4Ed8D0Fb90Ad053324F31b', + merkleTreeHeight: 20, + singletonFactory: '0xce0042B868300000d44A59004Da54A005ffdcf9f', + singletonFactoryVerboseWrapper: '0xCEe71753C9820f063b38FDbE4cFDAf1d3D928A80', + salt: '0x0000000000000000000000000000000000000000000000000000000047941987', + COMP: '0xc00e94Cb662C3520282E6f5717214004A7f26888', + TORN: '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C', + tornWhale: '0xF977814e90dA44bFA03b6295A0616a897441aceC', + compWhale: '0xF977814e90dA44bFA03b6295A0616a897441aceC', + creationFee: '200000000000000000000', // 200 TORN + deployGasLimit: 7000000, + owner: '0xBAE5aBfa98466Dbe68836763B087f2d189f4D28f', + WETH: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + UniswapV3Factory: '0x1F98431c8aD98523631AE4a59f267346ea31F984', + TWAPSlotsMin: 50, +} diff --git a/contracts/AddInstanceProposal.sol b/contracts/AddInstanceProposal.sol new file mode 100644 index 0000000..96cf6de --- /dev/null +++ b/contracts/AddInstanceProposal.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.7.6; +pragma abicoder v2; + +import "./interfaces/IInstanceRegistry.sol"; +import "./InstanceFactory.sol"; + +contract AddInstanceProposal { + InstanceFactory public immutable instanceFactory; + IInstanceRegistry public immutable instanceRegistry; + address public immutable token; + uint24 public immutable uniswapPoolSwappingFee; + + uint256 public immutable numInstances; + uint256 internal immutable denomination0; + uint256 internal immutable denomination1; + uint256 internal immutable denomination2; + uint256 internal immutable denomination3; + uint32 internal immutable protocolFee0; + uint32 internal immutable protocolFee1; + uint32 internal immutable protocolFee2; + uint32 internal immutable protocolFee3; + + event AddInstanceForRegistry(address instance, address token, uint256 denomination); + + constructor( + address _instanceFactory, + address _instanceRegistry, + address _token, + uint24 _uniswapPoolSwappingFee, + uint256[] memory _denominations, + uint32[] memory _protocolFees + ) { + instanceFactory = InstanceFactory(_instanceFactory); + instanceRegistry = IInstanceRegistry(_instanceRegistry); + token = _token; + uniswapPoolSwappingFee = _uniswapPoolSwappingFee; + + require(_denominations.length == _protocolFees.length, "Incorrect denominations/fees length"); + uint256 _numInstances = _denominations.length; + require(_numInstances > 0 && _numInstances <= 4, "incorrect instances number"); + numInstances = _numInstances; + + denomination0 = _numInstances > 0 ? _denominations[0] : 0; + denomination1 = _numInstances > 1 ? _denominations[1] : 0; + denomination2 = _numInstances > 2 ? _denominations[2] : 0; + denomination3 = _numInstances > 3 ? _denominations[3] : 0; + protocolFee0 = _numInstances > 0 ? _protocolFees[0] : 0; + protocolFee1 = _numInstances > 1 ? _protocolFees[1] : 0; + protocolFee2 = _numInstances > 2 ? _protocolFees[2] : 0; + protocolFee3 = _numInstances > 3 ? _protocolFees[3] : 0; + } + + function executeProposal() external { + for (uint256 i = 0; i < numInstances; i++) { + address instance = instanceFactory.createInstanceClone(denominationByIndex(i), token); + + IInstanceRegistry.Instance memory newInstanceData = IInstanceRegistry.Instance( + true, + IERC20(token), + IInstanceRegistry.InstanceState.ENABLED, + uniswapPoolSwappingFee, + protocolFeeByIndex(i) + ); + + IInstanceRegistry.Tornado memory tornadoForUpdate = IInstanceRegistry.Tornado(instance, newInstanceData); + + instanceRegistry.updateInstance(tornadoForUpdate); + + emit AddInstanceForRegistry(address(instance), token, denominationByIndex(i)); + } + } + + function denominationByIndex(uint256 _index) public view returns (uint256) { + if (_index == 0) { + return denomination0; + } else if (_index == 1) { + return denomination1; + } else if (_index == 2) { + return denomination2; + } else if (_index == 3) { + return denomination3; + } else { + revert("Invalid instance index"); + } + } + + function protocolFeeByIndex(uint256 _index) public view returns (uint32) { + if (_index == 0) { + return protocolFee0; + } else if (_index == 1) { + return protocolFee1; + } else if (_index == 2) { + return protocolFee2; + } else if (_index == 3) { + return protocolFee3; + } else { + revert("Invalid instance index"); + } + } +} diff --git a/contracts/CreateFactoryAndAddInstancesProposal.sol b/contracts/CreateFactoryAndAddInstancesProposal.sol deleted file mode 100644 index 68886ec..0000000 --- a/contracts/CreateFactoryAndAddInstancesProposal.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.6; -pragma abicoder v2; - -import "./TornadoInstanceCloneFactory.sol"; -import "./tornado_proxy/TornadoProxy.sol"; - -contract CreateFactoryAndAddInstancesProposal { - address public constant verifier = 0xce172ce1F20EC0B3728c9965470eaf994A03557A; - address public constant hasher = 0x83584f83f26aF4eDDA9CBe8C730bc87C364b28fe; - address public constant governance = 0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce; - - TornadoInstanceCloneFactory public immutable instanceFactory; - address public immutable token; - address public immutable proxyAddress; - - uint256 public immutable denomination1; - uint256 public immutable denomination2; - uint256 public immutable denomination3; - uint256 public immutable denomination4; - - event UpdatedInstanceForProxy(address indexed instance, address indexed token, uint256 indexed denomination); - - constructor( - address _proxyAddress, - uint256[4] memory _denominations, - address _token - ) { - TornadoInstanceCloneFactory cachedFactory = new TornadoInstanceCloneFactory(verifier, hasher, 20); - cachedFactory.transferOwnership(governance); - instanceFactory = cachedFactory; - - token = _token; - proxyAddress = _proxyAddress; - - denomination1 = _denominations[0]; - denomination2 = _denominations[1]; - denomination3 = _denominations[2]; - denomination4 = _denominations[3]; - } - - function executeProposal() external { - TornadoProxy tornadoProxy = TornadoProxy(proxyAddress); - - for (uint256 i = 0; i < 4; i++) { - ITornadoInstance instance = ITornadoInstance(instanceFactory.createInstanceClone(denominations(i), token)); - TornadoProxy.Instance memory newInstanceData = TornadoProxy.Instance( - true, - IERC20(token), - TornadoProxy.InstanceState.ENABLED - ); - TornadoProxy.Tornado memory tornadoForUpdate = TornadoProxy.Tornado(instance, newInstanceData); - - tornadoProxy.updateInstance(tornadoForUpdate); - - emit UpdatedInstanceForProxy(address(instance), instance.token(), instance.denomination()); - } - } - - function denominations(uint256 index) private view returns (uint256) { - if (index > 2) { - return denomination4; - } else if (index > 1) { - return denomination3; - } else if (index > 0) { - return denomination2; - } else { - return denomination1; - } - } -} diff --git a/contracts/ERC20TornadoCloneable.sol b/contracts/ERC20TornadoCloneable.sol index d9abb7d..45fde4d 100644 --- a/contracts/ERC20TornadoCloneable.sol +++ b/contracts/ERC20TornadoCloneable.sol @@ -1,5 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.7.6; + +pragma solidity 0.7.6; pragma abicoder v2; import "tornado-core/contracts/ERC20Tornado.sol"; @@ -13,12 +14,10 @@ contract ERC20TornadoCloneable is ERC20Tornado { address _token ) external { require(denomination == 0 && levels == 0, "already initialized"); - /// In Constructor: ERC20Tornado + token = IERC20(_token); - /// In Constructor: Tornado require(_denomination > 0, "denomination should be greater than 0"); denomination = _denomination; - /// In Constructor: MerkleTreeWithHistory require(_merkleTreeHeight > 0, "_levels should be greater than zero"); require(_merkleTreeHeight < 32, "_levels should be less than 32"); levels = _merkleTreeHeight; diff --git a/contracts/ERC20TornadoVirtual.sol b/contracts/ERC20TornadoVirtual.sol deleted file mode 100644 index 18974d6..0000000 --- a/contracts/ERC20TornadoVirtual.sol +++ /dev/null @@ -1,337 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.6; -pragma abicoder v2; - -// https://tornado.cash -/* - * 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 - */ - -interface IHasher { - function MiMCSponge(uint256 in_xL, uint256 in_xR) external pure returns (uint256 xL, uint256 xR); -} - -contract MerkleTreeWithHistory { - uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - uint256 public constant ZERO_VALUE = 21663839004416932945382355908790599225266501822907911457504978515578255421292; // = keccak256("tornado") % FIELD_SIZE - - IHasher public hasher; - uint32 public levels; - - // the following variables are made public for easier testing and debugging and - // are not supposed to be accessed in regular code - - // filledSubtrees and roots could be bytes32[size], but using mappings makes it cheaper because - // it removes index range check on every interaction - mapping(uint256 => bytes32) public filledSubtrees; - mapping(uint256 => bytes32) public roots; - uint32 public constant ROOT_HISTORY_SIZE = 30; - uint32 public currentRootIndex = 0; - uint32 public nextIndex = 0; - - constructor(uint32 _levels, IHasher _hasher) { - require(_levels > 0, "_levels should be greater than zero"); - require(_levels < 32, "_levels should be less than 32"); - levels = _levels; - hasher = _hasher; - - for (uint32 i = 0; i < _levels; i++) { - filledSubtrees[i] = zeros(i); - } - - roots[0] = zeros(_levels - 1); - } - - /** - @dev Hash 2 tree leaves, returns MiMC(_left, _right) - */ - function hashLeftRight( - IHasher _hasher, - bytes32 _left, - bytes32 _right - ) public pure returns (bytes32) { - require(uint256(_left) < FIELD_SIZE, "_left should be inside the field"); - require(uint256(_right) < FIELD_SIZE, "_right should be inside the field"); - uint256 R = uint256(_left); - uint256 C = 0; - (R, C) = _hasher.MiMCSponge(R, C); - R = addmod(R, uint256(_right), FIELD_SIZE); - (R, C) = _hasher.MiMCSponge(R, C); - return bytes32(R); - } - - function _insert(bytes32 _leaf) internal returns (uint32 index) { - uint32 _nextIndex = nextIndex; - require(_nextIndex != uint32(2)**levels, "Merkle tree is full. No more leaves can be added"); - uint32 currentIndex = _nextIndex; - bytes32 currentLevelHash = _leaf; - bytes32 left; - bytes32 right; - - for (uint32 i = 0; i < levels; i++) { - if (currentIndex % 2 == 0) { - left = currentLevelHash; - right = zeros(i); - filledSubtrees[i] = currentLevelHash; - } else { - left = filledSubtrees[i]; - right = currentLevelHash; - } - currentLevelHash = hashLeftRight(hasher, left, right); - currentIndex /= 2; - } - - uint32 newRootIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE; - currentRootIndex = newRootIndex; - roots[newRootIndex] = currentLevelHash; - nextIndex = _nextIndex + 1; - return _nextIndex; - } - - /** - @dev Whether the root is present in the root history - */ - function isKnownRoot(bytes32 _root) public view returns (bool) { - if (_root == 0) { - return false; - } - uint32 _currentRootIndex = currentRootIndex; - uint32 i = _currentRootIndex; - do { - if (_root == roots[i]) { - return true; - } - if (i == 0) { - i = ROOT_HISTORY_SIZE; - } - i--; - } while (i != _currentRootIndex); - return false; - } - - /** - @dev Returns the last root - */ - function getLastRoot() public view returns (bytes32) { - return roots[currentRootIndex]; - } - - /// @dev provides Zero (Empty) elements for a MiMC MerkleTree. Up to 32 levels - function zeros(uint256 i) public pure returns (bytes32) { - if (i == 0) return bytes32(0x2fe54c60d3acabf3343a35b6eba15db4821b340f76e741e2249685ed4899af6c); - else if (i == 1) return bytes32(0x256a6135777eee2fd26f54b8b7037a25439d5235caee224154186d2b8a52e31d); - else if (i == 2) return bytes32(0x1151949895e82ab19924de92c40a3d6f7bcb60d92b00504b8199613683f0c200); - else if (i == 3) return bytes32(0x20121ee811489ff8d61f09fb89e313f14959a0f28bb428a20dba6b0b068b3bdb); - else if (i == 4) return bytes32(0x0a89ca6ffa14cc462cfedb842c30ed221a50a3d6bf022a6a57dc82ab24c157c9); - else if (i == 5) return bytes32(0x24ca05c2b5cd42e890d6be94c68d0689f4f21c9cec9c0f13fe41d566dfb54959); - else if (i == 6) return bytes32(0x1ccb97c932565a92c60156bdba2d08f3bf1377464e025cee765679e604a7315c); - else if (i == 7) return bytes32(0x19156fbd7d1a8bf5cba8909367de1b624534ebab4f0f79e003bccdd1b182bdb4); - else if (i == 8) return bytes32(0x261af8c1f0912e465744641409f622d466c3920ac6e5ff37e36604cb11dfff80); - else if (i == 9) return bytes32(0x0058459724ff6ca5a1652fcbc3e82b93895cf08e975b19beab3f54c217d1c007); - else if (i == 10) return bytes32(0x1f04ef20dee48d39984d8eabe768a70eafa6310ad20849d4573c3c40c2ad1e30); - else if (i == 11) return bytes32(0x1bea3dec5dab51567ce7e200a30f7ba6d4276aeaa53e2686f962a46c66d511e5); - else if (i == 12) return bytes32(0x0ee0f941e2da4b9e31c3ca97a40d8fa9ce68d97c084177071b3cb46cd3372f0f); - else if (i == 13) return bytes32(0x1ca9503e8935884501bbaf20be14eb4c46b89772c97b96e3b2ebf3a36a948bbd); - else if (i == 14) return bytes32(0x133a80e30697cd55d8f7d4b0965b7be24057ba5dc3da898ee2187232446cb108); - else if (i == 15) return bytes32(0x13e6d8fc88839ed76e182c2a779af5b2c0da9dd18c90427a644f7e148a6253b6); - else if (i == 16) return bytes32(0x1eb16b057a477f4bc8f572ea6bee39561098f78f15bfb3699dcbb7bd8db61854); - else if (i == 17) return bytes32(0x0da2cb16a1ceaabf1c16b838f7a9e3f2a3a3088d9e0a6debaa748114620696ea); - else if (i == 18) return bytes32(0x24a3b3d822420b14b5d8cb6c28a574f01e98ea9e940551d2ebd75cee12649f9d); - else if (i == 19) return bytes32(0x198622acbd783d1b0d9064105b1fc8e4d8889de95c4c519b3f635809fe6afc05); - else if (i == 20) return bytes32(0x29d7ed391256ccc3ea596c86e933b89ff339d25ea8ddced975ae2fe30b5296d4); - else if (i == 21) return bytes32(0x19be59f2f0413ce78c0c3703a3a5451b1d7f39629fa33abd11548a76065b2967); - else if (i == 22) return bytes32(0x1ff3f61797e538b70e619310d33f2a063e7eb59104e112e95738da1254dc3453); - else if (i == 23) return bytes32(0x10c16ae9959cf8358980d9dd9616e48228737310a10e2b6b731c1a548f036c48); - else if (i == 24) return bytes32(0x0ba433a63174a90ac20992e75e3095496812b652685b5e1a2eae0b1bf4e8fcd1); - else if (i == 25) return bytes32(0x019ddb9df2bc98d987d0dfeca9d2b643deafab8f7036562e627c3667266a044c); - else if (i == 26) return bytes32(0x2d3c88b23175c5a5565db928414c66d1912b11acf974b2e644caaac04739ce99); - else if (i == 27) return bytes32(0x2eab55f6ae4e66e32c5189eed5c470840863445760f5ed7e7b69b2a62600f354); - else if (i == 28) return bytes32(0x002df37a2642621802383cf952bf4dd1f32e05433beeb1fd41031fb7eace979d); - else if (i == 29) return bytes32(0x104aeb41435db66c3e62feccc1d6f5d98d0a0ed75d1374db457cf462e3a1f427); - else if (i == 30) return bytes32(0x1f3c6fd858e9a7d4b0d1f38e256a09d81d5a5e3c963987e2d4b814cfab7c6ebb); - else if (i == 31) return bytes32(0x2c7a07d20dff79d01fecedc1134284a8d08436606c93693b67e333f671bf69cc); - else revert("Index out of bounds"); - } -} - -// https://tornado.cash -/* - * 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 - */ - -import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; - -interface IVerifier { - function verifyProof(bytes memory _proof, uint256[6] memory _input) external returns (bool); -} - -abstract contract Tornado is MerkleTreeWithHistory, ReentrancyGuard { - IVerifier public verifier; - uint256 public denomination; - - mapping(bytes32 => bool) public nullifierHashes; - // we store all commitments just to prevent accidental deposits with the same commitment - mapping(bytes32 => bool) public commitments; - - event Deposit(bytes32 indexed commitment, uint32 leafIndex, uint256 timestamp); - event Withdrawal(address to, bytes32 nullifierHash, address indexed relayer, uint256 fee); - - /** - @dev The constructor - @param _verifier the address of SNARK verifier for this contract - @param _hasher the address of MiMC hash contract - @param _denomination transfer amount for each deposit - @param _merkleTreeHeight the height of deposits' Merkle Tree - */ - constructor( - IVerifier _verifier, - IHasher _hasher, - uint256 _denomination, - uint32 _merkleTreeHeight - ) MerkleTreeWithHistory(_merkleTreeHeight, _hasher) { - require(_denomination > 0, "denomination should be greater than 0"); - verifier = _verifier; - denomination = _denomination; - } - - /** - @dev Deposit funds into the contract. The caller must send (for ETH) or approve (for ERC20) value equal to or `denomination` of this instance. - @param _commitment the note commitment, which is PedersenHash(nullifier + secret) - */ - function deposit(bytes32 _commitment) external payable nonReentrant { - require(!commitments[_commitment], "The commitment has been submitted"); - - uint32 insertedIndex = _insert(_commitment); - commitments[_commitment] = true; - _processDeposit(); - - emit Deposit(_commitment, insertedIndex, block.timestamp); - } - - /** @dev this function is defined in a child contract */ - function _processDeposit() internal virtual; - - /** - @dev Withdraw a deposit from the contract. `proof` is a zkSNARK proof data, and input is an array of circuit public inputs - `input` array consists of: - - merkle root of all deposits in the contract - - hash of unique deposit nullifier to prevent double spends - - the recipient of funds - - optional fee that goes to the transaction sender (usually a relay) - */ - function withdraw( - bytes calldata _proof, - bytes32 _root, - bytes32 _nullifierHash, - address payable _recipient, - address payable _relayer, - uint256 _fee, - uint256 _refund - ) external payable nonReentrant { - require(_fee <= denomination, "Fee exceeds transfer value"); - require(!nullifierHashes[_nullifierHash], "The note has been already spent"); - require(isKnownRoot(_root), "Cannot find your merkle root"); // Make sure to use a recent one - require( - verifier.verifyProof( - _proof, - [uint256(_root), uint256(_nullifierHash), uint256(_recipient), uint256(_relayer), _fee, _refund] - ), - "Invalid withdraw proof" - ); - - nullifierHashes[_nullifierHash] = true; - _processWithdraw(_recipient, _relayer, _fee, _refund); - emit Withdrawal(_recipient, _nullifierHash, _relayer, _fee); - } - - /** @dev this function is defined in a child contract */ - function _processWithdraw( - address payable _recipient, - address payable _relayer, - uint256 _fee, - uint256 _refund - ) internal virtual; - - /** @dev whether a note is already spent */ - function isSpent(bytes32 _nullifierHash) public view returns (bool) { - return nullifierHashes[_nullifierHash]; - } - - /** @dev whether an array of notes is already spent */ - function isSpentArray(bytes32[] calldata _nullifierHashes) external view returns (bool[] memory spent) { - spent = new bool[](_nullifierHashes.length); - for (uint256 i = 0; i < _nullifierHashes.length; i++) { - if (isSpent(_nullifierHashes[i])) { - spent[i] = true; - } - } - } -} - -// https://tornado.cash -/* - * 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 - */ - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; - -contract ERC20Tornado is Tornado { - using SafeERC20 for IERC20; - IERC20 public token; - - constructor( - IVerifier _verifier, - IHasher _hasher, - uint256 _denomination, - uint32 _merkleTreeHeight, - IERC20 _token - ) Tornado(_verifier, _hasher, _denomination, _merkleTreeHeight) { - token = _token; - } - - function _processDeposit() internal override { - require(msg.value == 0, "ETH value is supposed to be 0 for ERC20 instance"); - token.safeTransferFrom(msg.sender, address(this), denomination); - } - - function _processWithdraw( - address payable _recipient, - address payable _relayer, - uint256 _fee, - uint256 _refund - ) internal override { - require(msg.value == _refund, "Incorrect refund amount received by the contract"); - - token.safeTransfer(_recipient, denomination - _fee); - if (_fee > 0) { - token.safeTransfer(_relayer, _fee); - } - - if (_refund > 0) { - (bool success, ) = _recipient.call{ value: _refund }(""); - if (!success) { - // let's return _refund back to the relayer - _relayer.transfer(_refund); - } - } - } -} diff --git a/contracts/TornadoInstanceCloneFactory.sol b/contracts/InstanceFactory.sol similarity index 69% rename from contracts/TornadoInstanceCloneFactory.sol rename to contracts/InstanceFactory.sol index 944913a..f3e5a80 100644 --- a/contracts/TornadoInstanceCloneFactory.sol +++ b/contracts/InstanceFactory.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.7.6; + +pragma solidity 0.7.6; pragma abicoder v2; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; - import "@openzeppelin/contracts/proxy/Clones.sol"; import "./ERC20TornadoCloneable.sol"; -contract TornadoInstanceCloneFactory is Ownable { +contract InstanceFactory is Ownable { using Clones for address; using Address for address; @@ -17,52 +17,35 @@ contract TornadoInstanceCloneFactory is Ownable { address public hasher; uint32 public merkleTreeHeight; - event NewVerifierSet(address indexed newVerifier); - event NewHasherSet(address indexed newHasher); event NewTreeHeightSet(uint32 indexed newTreeHeight); - event NewImplementationSet(address indexed newImplemenentation); + event NewImplementationSet(address indexed newImplemenentation, address verifier, address hasher); event NewInstanceCloneCreated(address indexed clone); constructor( address _verifier, address _hasher, - uint32 _merkleTreeHeight + uint32 _merkleTreeHeight, + address _owner ) { verifier = _verifier; hasher = _hasher; merkleTreeHeight = _merkleTreeHeight; + ERC20TornadoCloneable implContract = new ERC20TornadoCloneable(_verifier, _hasher); implementation = address(implContract); + + transferOwnership(_owner); } - function setVerifier(address _verifier) external onlyOwner { - verifier = _verifier; - emit NewVerifierSet(verifier); - } - - function setHasher(address _hasher) external onlyOwner { - hasher = _hasher; - emit NewHasherSet(hasher); - } - - function setMerkleTreeHeight(uint32 _merkleTreeHeight) external onlyOwner { - merkleTreeHeight = _merkleTreeHeight; - emit NewTreeHeightSet(merkleTreeHeight); - } - - function setImplementation(address _newImplementation) external onlyOwner { - implementation = _newImplementation; - emit NewImplementationSet(implementation); - } - - function generateNewImplementation() external onlyOwner { - implementation = address(new ERC20TornadoCloneable(verifier, hasher)); - } - - function createInstanceClone(uint256 _denomination, address _token) external onlyOwner returns (address) { + /** + * @dev Creates new Tornado instance. + * @param _denomination denomination of new Tornado instance + * @param _token address of ERC20 token for a new instance + */ + function createInstanceClone(uint256 _denomination, address _token) public virtual returns (address) { bytes32 salt = keccak256(abi.encodePacked(_denomination, _token)); - require(!implementation.predictDeterministicAddress(salt).isContract(), "Instance for this denomination already exists"); + require(!implementation.predictDeterministicAddress(salt).isContract(), "Instance already exists"); address newClone = implementation.cloneDeterministic(salt); @@ -75,4 +58,16 @@ contract TornadoInstanceCloneFactory is Ownable { bytes32 salt = keccak256(abi.encodePacked(_denomination, _token)); return implementation.predictDeterministicAddress(salt); } + + function setMerkleTreeHeight(uint32 _merkleTreeHeight) external onlyOwner { + merkleTreeHeight = _merkleTreeHeight; + emit NewTreeHeightSet(merkleTreeHeight); + } + + function generateNewImplementation(address _verifier, address _hasher) external onlyOwner { + verifier = _verifier; + hasher = _hasher; + implementation = address(new ERC20TornadoCloneable(_verifier, _hasher)); + emit NewImplementationSet(implementation, _verifier, _hasher); + } } diff --git a/contracts/InstanceFactoryWithRegistry.sol b/contracts/InstanceFactoryWithRegistry.sol new file mode 100644 index 0000000..c9e2b9e --- /dev/null +++ b/contracts/InstanceFactoryWithRegistry.sol @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.7.6; +pragma abicoder v2; + +import { Address } from "@openzeppelin/contracts/utils/Address.sol"; +import "./AddInstanceProposal.sol"; +import "./InstanceFactory.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { IERC20Permit } from "@openzeppelin/contracts/drafts/IERC20Permit.sol"; +import { IUniswapV3Factory } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol"; +import { IUniswapV3PoolState } from "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol"; + +contract InstanceFactoryWithRegistry is InstanceFactory { + using Address for address; + + address public immutable governance; + address public immutable torn; + address public immutable instanceRegistry; + IUniswapV3Factory public immutable UniswapV3Factory; + address public immutable WETH; + uint16 public TWAPSlotsMin; + uint256 public creationFee; + + event NewCreationFeeSet(uint256 newCreationFee); + event NewTWAPSlotsMinSet(uint256 newTWAPSlotsMin); + event NewGovernanceProposalCreated(address indexed proposal); + + /** + * @dev Throws if called by any account other than the Governance. + */ + modifier onlyGovernance() { + require(owner() == _msgSender(), "Caller is not the Governance"); + _; + } + + constructor( + address _verifier, + address _hasher, + uint32 _merkleTreeHeight, + address _governance, + address _instanceRegistry, + address _torn, + address _UniswapV3Factory, + address _WETH, + uint16 _TWAPSlotsMin, + uint256 _creationFee + ) InstanceFactory(_verifier, _hasher, _merkleTreeHeight, _governance) { + governance = _governance; + instanceRegistry = _instanceRegistry; + torn = _torn; + UniswapV3Factory = IUniswapV3Factory(_UniswapV3Factory); + WETH = _WETH; + TWAPSlotsMin = _TWAPSlotsMin; + creationFee = _creationFee; + } + + /** + * @dev Throws if called by any account other than the Governance. + * @param _denomination denomination of new Tornado instance + * @param _token address of ERC20 token for a new instance + */ + function createInstanceClone(uint256 _denomination, address _token) public override onlyGovernance returns (address) { + return super.createInstanceClone(_denomination, _token); + } + + /** + * @dev Creates AddInstanceProposal with approve. + * @param _token address of ERC20 token for a new instance + * @param _uniswapPoolSwappingFee fee value of Uniswap instance which will be used for `TORN/token` price determination. + * `3000` means 0.3% fee Uniswap pool. + * @param _denominations list of denominations for each new instance + * @param _protocolFees list of protocol fees for each new instance. + * `100` means that instance withdrawal fee is 1% of denomination. + */ + function createProposalApprove( + address _token, + uint24 _uniswapPoolSwappingFee, + uint256[] memory _denominations, + uint32[] memory _protocolFees + ) external returns (address) { + require(IERC20(torn).transferFrom(msg.sender, governance, creationFee)); + return _createProposal(_token, _uniswapPoolSwappingFee, _denominations, _protocolFees); + } + + /** + * @dev Creates AddInstanceProposal with permit. + * @param _token address of ERC20 token for a new instance + * @param _uniswapPoolSwappingFee fee value of Uniswap instance which will be used for `TORN/token` price determination. + * `3000` means 0.3% fee Uniswap pool. + * @param _denominations list of denominations for each new instance + * @param _protocolFees list of protocol fees for each new instance. + * `100` means that instance withdrawal fee is 1% of denomination. + */ + function createProposalPermit( + address _token, + uint24 _uniswapPoolSwappingFee, + uint256[] memory _denominations, + uint32[] memory _protocolFees, + address creater, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external returns (address) { + IERC20Permit(torn).permit(creater, address(this), creationFee, deadline, v, r, s); + require(IERC20(torn).transferFrom(creater, governance, creationFee)); + return _createProposal(_token, _uniswapPoolSwappingFee, _denominations, _protocolFees); + } + + function _createProposal( + address _token, + uint24 _uniswapPoolSwappingFee, + uint256[] memory _denominations, + uint32[] memory _protocolFees + ) internal returns (address) { + require(_token.isContract(), "Token is not contract"); + require(_denominations.length > 0, "Empty denominations"); + require(_denominations.length == _protocolFees.length, "Incorrect denominations/fees length"); + + // check Uniswap Pool + for (uint8 i = 0; i < _protocolFees.length; i++) { + if (_protocolFees[i] > 0) { + // pool exists + address poolAddr = UniswapV3Factory.getPool(_token, WETH, _uniswapPoolSwappingFee); + require(poolAddr != address(0), "Uniswap pool is not exist"); + // TWAP slots + (, , , , uint16 observationCardinalityNext, , ) = IUniswapV3PoolState(poolAddr).slot0(); + require(observationCardinalityNext >= TWAPSlotsMin, "Uniswap pool TWAP slots number is low"); + break; + } + } + + address proposal = address( + new AddInstanceProposal(address(this), instanceRegistry, _token, _uniswapPoolSwappingFee, _denominations, _protocolFees) + ); + emit NewGovernanceProposalCreated(proposal); + + return proposal; + } + + function setCreationFee(uint256 _creationFee) external onlyGovernance { + creationFee = _creationFee; + emit NewCreationFeeSet(_creationFee); + } + + function setTWAPSlotsMin(uint16 _TWAPSlotsMin) external onlyGovernance { + TWAPSlotsMin = _TWAPSlotsMin; + emit NewTWAPSlotsMinSet(_TWAPSlotsMin); + } +} diff --git a/contracts/denomination_templates/Add1Instance.sol b/contracts/denomination_templates/Add1Instance.sol deleted file mode 100644 index a369ba1..0000000 --- a/contracts/denomination_templates/Add1Instance.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.6; -pragma abicoder v2; - -import "../TornadoInstanceCloneFactory.sol"; -import "../tornado_proxy/TornadoProxy.sol"; - -contract Add1Instance { - TornadoInstanceCloneFactory public immutable instanceFactory; - address public immutable token; - address public immutable proxyAddress; - uint256 public immutable denomination; - - event UpdatedInstanceForProxy(address instance, address token, uint256 denomination); - - constructor( - address _proxyAddress, - address _instanceFactory, - uint256 _denomination, - address _token - ) { - instanceFactory = TornadoInstanceCloneFactory(_instanceFactory); - token = _token; - proxyAddress = _proxyAddress; - denomination = _denomination; - } - - function executeProposal() external { - TornadoProxy tornadoProxy = TornadoProxy(proxyAddress); - - ITornadoInstance instance = ITornadoInstance(instanceFactory.createInstanceClone(denomination, token)); - - TornadoProxy.Instance memory newInstanceData = TornadoProxy.Instance(true, IERC20(token), TornadoProxy.InstanceState.ENABLED); - - TornadoProxy.Tornado memory tornadoForUpdate = TornadoProxy.Tornado(instance, newInstanceData); - - tornadoProxy.updateInstance(tornadoForUpdate); - - emit UpdatedInstanceForProxy(address(instance), instance.token(), instance.denomination()); - } -} diff --git a/contracts/denomination_templates/Add2Instances.sol b/contracts/denomination_templates/Add2Instances.sol deleted file mode 100644 index bbc27fb..0000000 --- a/contracts/denomination_templates/Add2Instances.sol +++ /dev/null @@ -1,59 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.6; -pragma abicoder v2; - -import "../TornadoInstanceCloneFactory.sol"; -import "../tornado_proxy/TornadoProxy.sol"; - -contract Add2Instances { - TornadoInstanceCloneFactory public immutable instanceFactory; - address public immutable token; - address public immutable proxyAddress; - - uint256 public immutable denomination1; - uint256 public immutable denomination2; - - event UpdatedInstanceForProxy(address instance, address token, uint256 denomination); - - constructor( - address _proxyAddress, - address _instanceFactory, - uint256[2] memory _denominations, - address _token - ) { - instanceFactory = TornadoInstanceCloneFactory(_instanceFactory); - token = _token; - proxyAddress = _proxyAddress; - - denomination1 = _denominations[0]; - denomination2 = _denominations[1]; - } - - function executeProposal() external { - TornadoProxy tornadoProxy = TornadoProxy(proxyAddress); - - for (uint256 i = 0; i < 2; i++) { - ITornadoInstance instance = ITornadoInstance(instanceFactory.createInstanceClone(denominations(i), token)); - - TornadoProxy.Instance memory newInstanceData = TornadoProxy.Instance( - true, - IERC20(token), - TornadoProxy.InstanceState.ENABLED - ); - - TornadoProxy.Tornado memory tornadoForUpdate = TornadoProxy.Tornado(instance, newInstanceData); - - tornadoProxy.updateInstance(tornadoForUpdate); - - emit UpdatedInstanceForProxy(address(instance), instance.token(), instance.denomination()); - } - } - - function denominations(uint256 index) private view returns (uint256) { - if (index > 0) { - return denomination2; - } else { - return denomination1; - } - } -} diff --git a/contracts/denomination_templates/Add3Instances.sol b/contracts/denomination_templates/Add3Instances.sol deleted file mode 100644 index b4c7b35..0000000 --- a/contracts/denomination_templates/Add3Instances.sol +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.6; -pragma abicoder v2; - -import "../TornadoInstanceCloneFactory.sol"; -import "../tornado_proxy/TornadoProxy.sol"; - -contract Add3Instances { - TornadoInstanceCloneFactory public immutable instanceFactory; - address public immutable token; - address public immutable proxyAddress; - - uint256 public immutable denomination1; - uint256 public immutable denomination2; - uint256 public immutable denomination3; - - event UpdatedInstanceForProxy(address instance, address token, uint256 denomination); - - constructor( - address _proxyAddress, - address _instanceFactory, - uint256[3] memory _denominations, - address _token - ) { - instanceFactory = TornadoInstanceCloneFactory(_instanceFactory); - token = _token; - proxyAddress = _proxyAddress; - - denomination1 = _denominations[0]; - denomination2 = _denominations[1]; - denomination3 = _denominations[2]; - } - - function executeProposal() external { - TornadoProxy tornadoProxy = TornadoProxy(proxyAddress); - - for (uint256 i = 0; i < 3; i++) { - ITornadoInstance instance = ITornadoInstance(instanceFactory.createInstanceClone(denominations(i), token)); - - TornadoProxy.Instance memory newInstanceData = TornadoProxy.Instance( - true, - IERC20(token), - TornadoProxy.InstanceState.ENABLED - ); - - TornadoProxy.Tornado memory tornadoForUpdate = TornadoProxy.Tornado(instance, newInstanceData); - - tornadoProxy.updateInstance(tornadoForUpdate); - - emit UpdatedInstanceForProxy(address(instance), instance.token(), instance.denomination()); - } - } - - function denominations(uint256 index) private view returns (uint256) { - if (index > 1) { - return denomination3; - } else if (index > 0) { - return denomination2; - } else { - return denomination1; - } - } -} diff --git a/contracts/denomination_templates/Add4Instances.sol b/contracts/denomination_templates/Add4Instances.sol deleted file mode 100644 index a6178aa..0000000 --- a/contracts/denomination_templates/Add4Instances.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.6; -pragma abicoder v2; - -import "../TornadoInstanceCloneFactory.sol"; -import "../tornado_proxy/TornadoProxy.sol"; - -contract Add4Instances { - TornadoInstanceCloneFactory public immutable instanceFactory; - address public immutable token; - address public immutable proxyAddress; - - uint256 public immutable denomination1; - uint256 public immutable denomination2; - uint256 public immutable denomination3; - uint256 public immutable denomination4; - - event UpdatedInstanceForProxy(address instance, address token, uint256 denomination); - - constructor( - address _proxyAddress, - address _instanceFactory, - uint256[4] memory _denominations, - address _token - ) { - instanceFactory = TornadoInstanceCloneFactory(_instanceFactory); - token = _token; - proxyAddress = _proxyAddress; - - denomination1 = _denominations[0]; - denomination2 = _denominations[1]; - denomination3 = _denominations[2]; - denomination4 = _denominations[3]; - } - - function executeProposal() external { - TornadoProxy tornadoProxy = TornadoProxy(proxyAddress); - - for (uint256 i = 0; i < 4; i++) { - ITornadoInstance instance = ITornadoInstance(instanceFactory.createInstanceClone(denominations(i), token)); - - TornadoProxy.Instance memory newInstanceData = TornadoProxy.Instance( - true, - IERC20(token), - TornadoProxy.InstanceState.ENABLED - ); - - TornadoProxy.Tornado memory tornadoForUpdate = TornadoProxy.Tornado(instance, newInstanceData); - - tornadoProxy.updateInstance(tornadoForUpdate); - - emit UpdatedInstanceForProxy(address(instance), instance.token(), instance.denomination()); - } - } - - function denominations(uint256 index) private view returns (uint256) { - if (index > 2) { - return denomination4; - } else if (index > 1) { - return denomination3; - } else if (index > 0) { - return denomination2; - } else { - return denomination1; - } - } -} diff --git a/contracts/denomination_templates/Add5Instances.sol b/contracts/denomination_templates/Add5Instances.sol deleted file mode 100644 index 195a953..0000000 --- a/contracts/denomination_templates/Add5Instances.sol +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.6; -pragma abicoder v2; - -import "../TornadoInstanceCloneFactory.sol"; -import "../tornado_proxy/TornadoProxy.sol"; - -contract Add5Instances { - TornadoInstanceCloneFactory public immutable instanceFactory; - address public immutable token; - address public immutable proxyAddress; - - uint256 public immutable denomination1; - uint256 public immutable denomination2; - uint256 public immutable denomination3; - uint256 public immutable denomination4; - uint256 public immutable denomination5; - - event UpdatedInstanceForProxy(address instance, address token, uint256 denomination); - - constructor( - address _proxyAddress, - address _instanceFactory, - uint256[5] memory _denominations, - address _token - ) { - instanceFactory = TornadoInstanceCloneFactory(_instanceFactory); - token = _token; - proxyAddress = _proxyAddress; - - denomination1 = _denominations[0]; - denomination2 = _denominations[1]; - denomination3 = _denominations[2]; - denomination4 = _denominations[3]; - denomination5 = _denominations[4]; - } - - function executeProposal() external { - TornadoProxy tornadoProxy = TornadoProxy(proxyAddress); - - for (uint256 i = 0; i < 5; i++) { - ITornadoInstance instance = ITornadoInstance(instanceFactory.createInstanceClone(denominations(i), token)); - - TornadoProxy.Instance memory newInstanceData = TornadoProxy.Instance( - true, - IERC20(token), - TornadoProxy.InstanceState.ENABLED - ); - - TornadoProxy.Tornado memory tornadoForUpdate = TornadoProxy.Tornado(instance, newInstanceData); - - tornadoProxy.updateInstance(tornadoForUpdate); - - emit UpdatedInstanceForProxy(address(instance), instance.token(), instance.denomination()); - } - } - - function denominations(uint256 index) private view returns (uint256) { - if (index > 3) { - return denomination5; - } else if (index > 2) { - return denomination4; - } else if (index > 1) { - return denomination3; - } else if (index > 0) { - return denomination2; - } else { - return denomination1; - } - } -} diff --git a/contracts/denomination_templates/Add6Instances.sol b/contracts/denomination_templates/Add6Instances.sol deleted file mode 100644 index 79640ad..0000000 --- a/contracts/denomination_templates/Add6Instances.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.7.6; -pragma abicoder v2; - -import "../TornadoInstanceCloneFactory.sol"; -import "../tornado_proxy/TornadoProxy.sol"; - -contract Add6Instances { - TornadoInstanceCloneFactory public immutable instanceFactory; - address public immutable token; - address public immutable proxyAddress; - - uint256 public immutable denomination1; - uint256 public immutable denomination2; - uint256 public immutable denomination3; - uint256 public immutable denomination4; - uint256 public immutable denomination5; - uint256 public immutable denomination6; - - event UpdatedInstanceForProxy(address instance, address token, uint256 denomination); - - constructor( - address _proxyAddress, - address _instanceFactory, - uint256[6] memory _denominations, - address _token - ) { - instanceFactory = TornadoInstanceCloneFactory(_instanceFactory); - token = _token; - proxyAddress = _proxyAddress; - - denomination1 = _denominations[0]; - denomination2 = _denominations[1]; - denomination3 = _denominations[2]; - denomination4 = _denominations[3]; - denomination5 = _denominations[4]; - denomination6 = _denominations[5]; - } - - function executeProposal() external { - TornadoProxy tornadoProxy = TornadoProxy(proxyAddress); - - for (uint256 i = 0; i < 6; i++) { - ITornadoInstance instance = ITornadoInstance(instanceFactory.createInstanceClone(denominations(i), token)); - - TornadoProxy.Instance memory newInstanceData = TornadoProxy.Instance( - true, - IERC20(token), - TornadoProxy.InstanceState.ENABLED - ); - - TornadoProxy.Tornado memory tornadoForUpdate = TornadoProxy.Tornado(instance, newInstanceData); - - tornadoProxy.updateInstance(tornadoForUpdate); - - emit UpdatedInstanceForProxy(address(instance), instance.token(), instance.denomination()); - } - } - - function denominations(uint256 index) private view returns (uint256) { - if (index > 4) { - return denomination6; - } else if (index > 3) { - return denomination5; - } else if (index > 2) { - return denomination4; - } else if (index > 1) { - return denomination3; - } else if (index > 0) { - return denomination2; - } else { - return denomination1; - } - } -} diff --git a/contracts/interfaces/IInstanceRegistry.sol b/contracts/interfaces/IInstanceRegistry.sol new file mode 100644 index 0000000..e5d37df --- /dev/null +++ b/contracts/interfaces/IInstanceRegistry.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.7.6; +pragma abicoder v2; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +interface IInstanceRegistry { + enum InstanceState { + DISABLED, + ENABLED + } + + struct Instance { + bool isERC20; + IERC20 token; + InstanceState state; + // the fee of the uniswap pool which will be used to get a TWAP + uint24 uniswapPoolSwappingFee; + // the fee the protocol takes from relayer, it should be multiplied by PROTOCOL_FEE_DIVIDER from FeeManager.sol + uint32 protocolFeePercentage; + } + + struct Tornado { + address addr; + Instance instance; + } + + function updateInstance(Tornado calldata _tornado) external; +} diff --git a/contracts/libraries/SingletonFactory.sol b/contracts/libraries/SingletonFactory.sol new file mode 100644 index 0000000..13653e5 --- /dev/null +++ b/contracts/libraries/SingletonFactory.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +/** + *Submitted for verification at Etherscan.io on 2020-03-30 + */ + +pragma solidity 0.6.2; + +/** + * @title Singleton Factory (EIP-2470) + * @notice Exposes CREATE2 (EIP-1014) to deploy bytecode on deterministic addresses based on initialization code and salt. + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + */ +contract SingletonFactory { + /** + * @notice Deploys `_initCode` using `_salt` for defining the deterministic address. + * @param _initCode Initialization code. + * @param _salt Arbitrary value to modify resulting address. + * @return createdContract Created contract address. + */ + function deploy(bytes memory _initCode, bytes32 _salt) public returns (address payable createdContract) { + assembly { + createdContract := create2(0, add(_initCode, 0x20), mload(_initCode), _salt) + } + } +} +// IV is a value changed to generate the vanity address. +// IV: 6583047 diff --git a/contracts/mock/CompileDummy.sol b/contracts/mock/CompileDummy.sol index 05e7374..b69bca4 100644 --- a/contracts/mock/CompileDummy.sol +++ b/contracts/mock/CompileDummy.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.6.12; -import { Governance } from "tornado-governance/contracts/Governance.sol"; +pragma solidity 0.6.12||0.7.6; + +import { Governance } from "tornado-governance/contracts/v1/Governance.sol"; +import { InstanceRegistry } from "tornado-relayer-registry/contracts/tornado-proxy/InstanceRegistry.sol"; contract CompileDummy {} diff --git a/contracts/tornado_proxy/ITornadoInstance.sol b/contracts/tornado_proxy/ITornadoInstance.sol deleted file mode 100644 index 07cf927..0000000 --- a/contracts/tornado_proxy/ITornadoInstance.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.7.6; - -interface ITornadoInstance { - function token() external view returns (address); - - function denomination() external view returns (uint256); - - function deposit(bytes32 commitment) external payable; - - function withdraw( - bytes calldata proof, - bytes32 root, - bytes32 nullifierHash, - address payable recipient, - address payable relayer, - uint256 fee, - uint256 refund - ) external payable; -} diff --git a/contracts/tornado_proxy/ITornadoTrees.sol b/contracts/tornado_proxy/ITornadoTrees.sol deleted file mode 100644 index 9b4d3e0..0000000 --- a/contracts/tornado_proxy/ITornadoTrees.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.7.6; - -interface ITornadoTrees { - function registerDeposit(address instance, bytes32 commitment) external; - - function registerWithdrawal(address instance, bytes32 nullifier) external; -} diff --git a/contracts/tornado_proxy/TornadoProxy.sol b/contracts/tornado_proxy/TornadoProxy.sol deleted file mode 100644 index c546405..0000000 --- a/contracts/tornado_proxy/TornadoProxy.sol +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.7.6; -pragma experimental ABIEncoderV2; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; -import "@openzeppelin/contracts/math/Math.sol"; -import "./ITornadoInstance.sol"; -import "./ITornadoTrees.sol"; - -contract TornadoProxy { - using SafeERC20 for IERC20; - - event EncryptedNote(address indexed sender, bytes encryptedNote); - event InstanceStateUpdated(ITornadoInstance indexed instance, InstanceState state); - event TornadoTreesUpdated(ITornadoTrees addr); - - enum InstanceState { - DISABLED, - ENABLED, - MINEABLE - } - - struct Instance { - bool isERC20; - IERC20 token; - InstanceState state; - } - - struct Tornado { - ITornadoInstance addr; - Instance instance; - } - - ITornadoTrees public tornadoTrees; - address public immutable governance; - mapping(ITornadoInstance => Instance) public instances; - - modifier onlyGovernance() { - require(msg.sender == governance, "Not authorized"); - _; - } - - constructor( - address _tornadoTrees, - address _governance, - Tornado[] memory _instances - ) public { - tornadoTrees = ITornadoTrees(_tornadoTrees); - governance = _governance; - - for (uint256 i = 0; i < _instances.length; i++) { - _updateInstance(_instances[i]); - } - } - - function deposit( - ITornadoInstance _tornado, - bytes32 _commitment, - bytes calldata _encryptedNote - ) external payable { - Instance memory instance = instances[_tornado]; - require(instance.state != InstanceState.DISABLED, "The instance is not supported"); - - if (instance.isERC20) { - instance.token.safeTransferFrom(msg.sender, address(this), _tornado.denomination()); - } - _tornado.deposit{ value: msg.value }(_commitment); - - if (instance.state == InstanceState.MINEABLE) { - tornadoTrees.registerDeposit(address(_tornado), _commitment); - } - emit EncryptedNote(msg.sender, _encryptedNote); - } - - function withdraw( - ITornadoInstance _tornado, - bytes calldata _proof, - bytes32 _root, - bytes32 _nullifierHash, - address payable _recipient, - address payable _relayer, - uint256 _fee, - uint256 _refund - ) external payable { - Instance memory instance = instances[_tornado]; - require(instance.state != InstanceState.DISABLED, "The instance is not supported"); - - _tornado.withdraw{ value: msg.value }(_proof, _root, _nullifierHash, _recipient, _relayer, _fee, _refund); - if (instance.state == InstanceState.MINEABLE) { - tornadoTrees.registerWithdrawal(address(_tornado), _nullifierHash); - } - } - - function backupNotes(bytes[] calldata _encryptedNotes) external { - for (uint256 i = 0; i < _encryptedNotes.length; i++) { - emit EncryptedNote(msg.sender, _encryptedNotes[i]); - } - } - - function updateInstance(Tornado calldata _tornado) external onlyGovernance { - _updateInstance(_tornado); - } - - function setTornadoTreesContract(ITornadoTrees _tornadoTrees) external onlyGovernance { - tornadoTrees = _tornadoTrees; - emit TornadoTreesUpdated(_tornadoTrees); - } - - /// @dev Method to claim junk and accidentally sent tokens - function rescueTokens( - IERC20 _token, - address payable _to, - uint256 _amount - ) external onlyGovernance { - require(_to != address(0), "TORN: can not send to zero address"); - - if (_token == IERC20(0)) { - // for Ether - uint256 totalBalance = address(this).balance; - uint256 balance = Math.min(totalBalance, _amount); - _to.transfer(balance); - } else { - // any other erc20 - uint256 totalBalance = _token.balanceOf(address(this)); - uint256 balance = Math.min(totalBalance, _amount); - require(balance > 0, "TORN: trying to send 0 balance"); - _token.safeTransfer(_to, balance); - } - } - - function _updateInstance(Tornado memory _tornado) internal { - instances[_tornado.addr] = _tornado.instance; - if (_tornado.instance.isERC20) { - IERC20 token = IERC20(_tornado.addr.token()); - require(token == _tornado.instance.token, "Incorrect token"); - uint256 allowance = token.allowance(address(this), address(_tornado.addr)); - - if (_tornado.instance.state != InstanceState.DISABLED && allowance == 0) { - token.safeApprove(address(_tornado.addr), uint256(-1)); - } else if (_tornado.instance.state == InstanceState.DISABLED && allowance != 0) { - token.safeApprove(address(_tornado.addr), 0); - } - } - emit InstanceStateUpdated(_tornado.addr, _tornado.instance.state); - } -} diff --git a/hardhat.config.js b/hardhat.config.js index 0b39c3c..cec68c9 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -1,25 +1,30 @@ require('dotenv').config() -require('@nomiclabs/hardhat-ethers') -require('@nomiclabs/hardhat-etherscan') require('@nomiclabs/hardhat-waffle') +require('@nomiclabs/hardhat-etherscan') require('hardhat-log-remover') require('solidity-coverage') -require('./tasks/deploy_proposal.js') -require('./tasks/deploy_factory_proposal.js') -require('./tasks/propose_proposal.js') /** * @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: { compilers: [ + { + version: '0.6.2', + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, { version: '0.6.12', settings: { optimizer: { enabled: true, - runs: 2000, + runs: 200, }, }, }, @@ -28,7 +33,7 @@ module.exports = { settings: { optimizer: { enabled: true, - runs: 2000, + runs: 200, }, }, }, @@ -37,24 +42,26 @@ module.exports = { networks: { hardhat: { forking: { - url: `https://mainnet.infura.io/v3/${process.env.mainnet_rpc_key}`, - blockNumber: process.env.use_latest_block == 'true' ? undefined : 13017436, + url: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`, + blockNumber: 14250000, }, + chainId: 1, + initialBaseFeePerGas: 5, loggingEnabled: false, + allowUnlimitedContractSize: false, + blockGasLimit: 50000000, }, - localhost: { - url: 'http://localhost:8545', - timeout: 120000, + rinkeby: { + url: `https://rinkeby.infura.io/v3/${process.env.INFURA_API_KEY}`, + accounts: process.env.PRIVATE_KEY + ? [process.env.PRIVATE_KEY] + : { mnemonic: 'test test test test test junk' }, }, mainnet: { - url: `https://mainnet.infura.io/v3/${process.env.mainnet_rpc_key}`, - accounts: [`${process.env.mainnet_account_pk}`], - timeout: 2147483647, - }, - goerli: { - url: `https://goerli.infura.io/v3/${process.env.goerli_rpc_key}`, - accounts: [`${process.env.goerli_account_pk}`], - timeout: 2147483647, + url: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`, + accounts: process.env.PRIVATE_KEY + ? [process.env.PRIVATE_KEY] + : { mnemonic: 'test test test test test junk' }, }, }, mocha: { timeout: 9999999999 }, @@ -63,6 +70,6 @@ module.exports = { runOnCompile: true, }, etherscan: { - apiKey: `${process.env.etherscan_api_key}`, + apiKey: `${process.env.ETHERSCAN_KEY}`, }, } diff --git a/package.json b/package.json index 8e01431..3b3705f 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,26 @@ { "name": "tornado-instances", "version": "1.0.0", - "main": "index.js", "license": "MIT", "scripts": { - "start": "node src/index.js", "eslint": "eslint --ext .js --ignore-path .gitignore .", "prettier:check": "prettier --check . --config .prettierrc", "prettier:fix": "prettier --write . --config .prettierrc", "lint": "yarn eslint && yarn prettier:check", - "deploy:proposal": "yarn hardhat --network mainnet deploy_proposal --factory-address", - "deploy:proposal:test": "yarn hardhat --network goerli deploy_proposal --factory-address", - "deploy:proposal:factory": "yarn hardhat --network mainnet deploy_factory_proposal", - "deploy:proposal:factory:test": "yarn hardhat --network goerli deploy_factory_proposal", - "propose": "yarn hardhat --network mainnet propose_proposal --proposal-address", + "compile": "yarn hardhat compile", "test": "yarn hardhat test", - "f:test": "yarn test && yarn clean", "clean": "yarn prettier:fix && yarn lint", "coverage": "yarn hardhat coverage --testfiles \"test/*.js\"" }, + "dependencies": { + "@openzeppelin/contracts": "3.4.2", + "@openzeppelin/upgrades-core": "^1.0.1", + "torn-token": "^1.0.4", + "tornado-cli": "^0.0.1", + "tornado-core": "https://github.com/tornadocash/tornado-core.git", + "tornado-governance": "2.0.0", + "tornado-relayer-registry": "https://github.com/Rezan-vm/tornado-relayer-registry.git" + }, "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.0.2", "@nomiclabs/hardhat-etherscan": "^2.1.4", @@ -39,13 +41,5 @@ "solhint-plugin-prettier": "^0.0.5", "solidity-coverage": "^0.7.17", "websnark": "^0.0.5" - }, - "dependencies": { - "@openzeppelin/contracts": "3.4.2", - "@openzeppelin/upgrades-core": "^1.0.1", - "torn-token": "^1.0.4", - "tornado-cli": "^0.0.1", - "tornado-core": "https://github.com/tornadocash/tornado-core.git", - "tornado-governance": "^1.0.2" } } diff --git a/resources/instances.js b/resources/instances.js deleted file mode 100644 index 52b2995..0000000 --- a/resources/instances.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = [ - { - tokenAddress: '0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919', - denomination: '33333333333333333333', - symbol: 'RAI', - decimals: 18, - }, - { - tokenAddress: '0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919', - denomination: '333333333333333333333', - symbol: 'RAI', - decimals: 18, - }, - { - tokenAddress: '0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919', - denomination: '3333333333333333333333', - symbol: 'RAI', - decimals: 18, - }, - { - tokenAddress: '0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919', - denomination: '33333333333333333333333', - symbol: 'RAI', - decimals: 18, - }, -] diff --git a/scripts/deployInstanceFactory.js b/scripts/deployInstanceFactory.js new file mode 100644 index 0000000..60d639a --- /dev/null +++ b/scripts/deployInstanceFactory.js @@ -0,0 +1,26 @@ +const { ethers } = require('hardhat') +const config = require('../config') +const { generate } = require('../src/generateAddresses') + +async function deploy({ address, bytecode, singletonFactory }) { + const contractCode = await ethers.provider.getCode(address) + if (contractCode !== '0x') { + console.log(`Contract ${address} already deployed. Skipping...`) + return + } + await singletonFactory.deploy(bytecode, config.salt, { gasLimit: config.deployGasLimit }) +} + +async function main() { + const singletonFactory = await ethers.getContractAt('SingletonFactory', config.singletonFactory) + const contracts = await generate() + await deploy({ ...contracts.factoryContract, singletonFactory }) + console.log(`Instance factory contract have been deployed on ${contracts.factoryContract.address} address`) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/scripts/deployInstanceFactoryWithRegistry.js b/scripts/deployInstanceFactoryWithRegistry.js new file mode 100644 index 0000000..bc24b52 --- /dev/null +++ b/scripts/deployInstanceFactoryWithRegistry.js @@ -0,0 +1,28 @@ +const { ethers } = require('hardhat') +const config = require('../config') +const { generate } = require('../src/generateAddresses') + +async function deploy({ address, bytecode, singletonFactory }) { + const contractCode = await ethers.provider.getCode(address) + if (contractCode !== '0x') { + console.log(`Contract ${address} already deployed. Skipping...`) + return + } + await singletonFactory.deploy(bytecode, config.salt, { gasLimit: config.deployGasLimit }) +} + +async function main() { + const singletonFactory = await ethers.getContractAt('SingletonFactory', config.singletonFactory) + const contracts = await generate() + await deploy({ ...contracts.factoryWithRegistryContract, singletonFactory }) + console.log( + `Instance factory with registry contract have been deployed on ${contracts.factoryWithRegistryContract.address} address`, + ) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/scripts/helper/propose_proposal.js b/scripts/helper/propose_proposal.js deleted file mode 100644 index f29cc86..0000000 --- a/scripts/helper/propose_proposal.js +++ /dev/null @@ -1,22 +0,0 @@ -require('dotenv').config() -const { ethers } = require('hardhat') - -// THIS IS ASSUMING YOU HAVE ENOUGH LOCKED TORN TO PROPOSE -async function propose(proposalArgs) { - const proposer = proposalArgs[0] - const ProposalContract = proposalArgs[1] - - let GovernanceContract = await ethers.getContractAt( - '../artifacts/tornado-governance/contracts/Governance.sol:Governance', - '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce', - ) - GovernanceContract = await GovernanceContract.connect(proposer) - - const response = await GovernanceContract.propose(ProposalContract.address, proposalArgs[2]) - - const id = await GovernanceContract.latestProposalIds(proposer.address) - const state = await GovernanceContract.state(id) - - return [response, id, state] -} -module.exports.propose = propose diff --git a/src/generateAddresses.js b/src/generateAddresses.js new file mode 100644 index 0000000..c6a57c7 --- /dev/null +++ b/src/generateAddresses.js @@ -0,0 +1,68 @@ +const { ethers } = require('hardhat') +const defaultConfig = require('../config') + +async function generate(config = defaultConfig) { + const FactoryFactory = await ethers.getContractFactory('InstanceFactory') + const deploymentBytecodeFactory = + FactoryFactory.bytecode + + FactoryFactory.interface + .encodeDeploy([config.verifier, config.hasher, config.merkleTreeHeight, config.owner]) + .slice(2) + + const factoryAddress = ethers.utils.getCreate2Address( + config.singletonFactory, + config.salt, + ethers.utils.keccak256(deploymentBytecodeFactory), + ) + + const FactoryWithRegistryFactory = await ethers.getContractFactory('InstanceFactoryWithRegistry') + const deploymentBytecodeFactoryWithRegistry = + FactoryWithRegistryFactory.bytecode + + FactoryWithRegistryFactory.interface + .encodeDeploy([ + config.verifier, + config.hasher, + config.merkleTreeHeight, + config.governance, + config.instanceRegistry, + config.TORN, + config.UniswapV3Factory, + config.WETH, + config.TWAPSlotsMin, + config.creationFee, + ]) + .slice(2) + + const factoryWithRegistryAddress = ethers.utils.getCreate2Address( + config.singletonFactory, + config.salt, + ethers.utils.keccak256(deploymentBytecodeFactoryWithRegistry), + ) + + const result = { + factoryContract: { + address: factoryAddress, + bytecode: deploymentBytecodeFactory, + isProxy: false, + }, + factoryWithRegistryContract: { + address: factoryWithRegistryAddress, + bytecode: deploymentBytecodeFactoryWithRegistry, + isProxy: false, + }, + } + + return result +} + +async function generateWithLog() { + const contracts = await generate() + console.log('Instance factory contract: ', contracts.factoryContract.address) + console.log('Instance factory with registry contract: ', contracts.factoryWithRegistryContract.address) + return contracts +} + +module.exports = { + generate, + generateWithLog, +} diff --git a/src/permit.js b/src/permit.js new file mode 100644 index 0000000..36ce381 --- /dev/null +++ b/src/permit.js @@ -0,0 +1,44 @@ +const { EIP712Signer } = require('@ticket721/e712') + +const Permit = [ + { name: 'owner', type: 'address' }, + { name: 'spender', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint256' }, +] + +class PermitSigner extends EIP712Signer { + constructor(_domain, _permitArgs) { + super(_domain, ['Permit', Permit]) + this.permitArgs = _permitArgs + } + + // Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline) + setPermitInfo(_permitArgs) { + this.permitArgs = _permitArgs + } + + getPayload() { + return this.generatePayload(this.permitArgs, 'Permit') + } + + async getSignature(privateKey) { + let payload = this.getPayload() + payload.message.owner = payload.message.owner.address + const { hex, v, r, s } = await this.sign(privateKey, payload) + return { + hex, + v, + r: '0x' + r, + s: '0x' + s, + } + } + + getSignerAddress(permitArgs, signature) { + const original_payload = this.generatePayload(permitArgs, 'Permit') + return this.verify(original_payload, signature) + } +} + +module.exports = { PermitSigner } diff --git a/tasks/deploy_factory_proposal.js b/tasks/deploy_factory_proposal.js deleted file mode 100644 index 1e0381b..0000000 --- a/tasks/deploy_factory_proposal.js +++ /dev/null @@ -1,27 +0,0 @@ -require('dotenv').config() -const { task } = require('hardhat/config') -const { BigNumber } = require('@ethersproject/bignumber') -const instancesData = require('../resources/instances') - -task('deploy_factory_proposal', 'deploy the proposal that creates the factory').setAction( - async (taskArgs, hre) => { - const ProposalFactory = await hre.ethers.getContractFactory('CreateFactoryAndAddInstancesProposal') - - let denominations = [] - for (let i = 0; i < 4; i++) { - denominations[i] = BigNumber.from(instancesData[i].denomination) - } - const tokenAddress = instancesData[0].tokenAddress - - const ProposalContract = await ProposalFactory.deploy(`${process.env.PROXY}`, denominations, tokenAddress) - - await ProposalContract.deployTransaction.wait(5) - - await hre.run('verify:verify', { - address: ProposalContract.address, - constructorArguments: [`${process.env.PROXY}`, denominations, tokenAddress], - }) - - console.log('Verified CreateFactoryAndAddInstancesProposal deployed at: ', ProposalContract.address) - }, -) diff --git a/tasks/deploy_proposal.js b/tasks/deploy_proposal.js deleted file mode 100644 index 7d39b79..0000000 --- a/tasks/deploy_proposal.js +++ /dev/null @@ -1,40 +0,0 @@ -require('dotenv').config() -const { task } = require('hardhat/config') -const { BigNumber } = require('@ethersproject/bignumber') -const instancesData = require('../resources/instances') - -task('deploy_proposal', 'deploy proposal that uses factory') - .addParam('factoryAddress', 'address of factory') - .setAction(async (taskArgs, hre) => { - const contractName = `Add${instancesData.length}Instance${instancesData.length == 1 ? '' : 's'}` - - const ProposalFactory = await hre.ethers.getContractFactory(contractName) - - let denominations = [] - for (let i = 0; i < instancesData.length; i++) { - denominations[i] = BigNumber.from(instancesData[i].denomination) - } - - const tokenAddress = instancesData[0].tokenAddress - - const ProposalContract = await ProposalFactory.deploy( - `${process.env.PROXY}`, - taskArgs.factoryAddress, - denominations.length == 1 ? denominations[0] : denominations, - tokenAddress, - ) - - await ProposalContract.deployTransaction.wait(5) - - await hre.run('verify:verify', { - address: ProposalContract.address, - constructorArguments: [ - `${process.env.PROXY}`, - taskArgs.factoryAddress, - denominations.length == 1 ? denominations[0] : denominations, - tokenAddress, - ], - }) - - console.log(`Verified ${contractName} deployed at: `, ProposalContract.address) - }) diff --git a/tasks/propose_proposal.js b/tasks/propose_proposal.js deleted file mode 100644 index 8284af8..0000000 --- a/tasks/propose_proposal.js +++ /dev/null @@ -1,20 +0,0 @@ -require('dotenv').config() -const { task } = require('hardhat/config') -const instancesData = require('../resources/instances') - -task('propose_proposal', 'propose proposal that uses factory') - .addParam('proposalAddress', 'address of proposal') - .setAction(async (taskArgs, hre) => { - const proposalName = `add-${instancesData[0].symbol}-instances` - - const GovernanceContract = await hre.ethers.getContractAt( - '../artifacts/tornado-governance/contracts/Governance.sol:Governance', - '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce', - ) - await GovernanceContract.propose(taskArgs.proposalAddress, proposalName) - - const id = await GovernanceContract.latestProposalIds((await hre.ethers.getSigners())[0].address) - const state = await GovernanceContract.state(id) - - console.log('Proposal with name: ', proposalName, ' proposed with id: ', id, ', has state: ', state) - }) diff --git a/test/factory.test.js b/test/factory.test.js new file mode 100644 index 0000000..0201c63 --- /dev/null +++ b/test/factory.test.js @@ -0,0 +1,156 @@ +const hre = require('hardhat') +const { ethers, waffle } = hre +const { loadFixture } = waffle +const { expect } = require('chai') +const { BigNumber } = require('@ethersproject/bignumber') +const config = require('../config') +const { getSignerFromAddress } = require('./utils') +const { generate } = require('../src/generateAddresses') +const { rbigint, createDeposit, toHex, generateProof, initialize } = require('tornado-cli') + +describe('Instance Factory Tests', () => { + const addressZero = ethers.constants.AddressZero + + async function fixture() { + const [sender, deployer] = await ethers.getSigners() + + const owner = await getSignerFromAddress(config.owner) + + await sender.sendTransaction({ + to: config.owner, + value: ethers.utils.parseEther('1'), + }) + + const compWhale = await getSignerFromAddress(config.compWhale) + + const compToken = await ethers.getContractAt( + '@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20', + config.COMP, + ) + + // deploy InstanceFactory with CREATE2 + const singletonFactory = await ethers.getContractAt( + 'SingletonFactory', + config.singletonFactoryVerboseWrapper, + ) + const contracts = await generate() + if ((await ethers.provider.getCode(contracts.factoryContract.address)) == '0x') { + await singletonFactory.deploy(contracts.factoryContract.bytecode, config.salt, { + gasLimit: config.deployGasLimit, + }) + } + const instanceFactory = await ethers.getContractAt('InstanceFactory', contracts.factoryContract.address) + + return { + sender, + deployer, + owner, + compToken, + compWhale, + instanceFactory, + } + } + + it('Should have initialized all successfully', async function () { + const { sender, compToken, instanceFactory } = await loadFixture(fixture) + expect(sender.address).to.exist + expect(compToken.address).to.exist + expect(instanceFactory.address).to.exist + }) + + it('Should set correct params for factory', async function () { + const { instanceFactory } = await loadFixture(fixture) + + expect(await instanceFactory.verifier()).to.be.equal(config.verifier) + expect(await instanceFactory.hasher()).to.be.equal(config.hasher) + expect(await instanceFactory.merkleTreeHeight()).to.be.equal(config.merkleTreeHeight) + expect(await instanceFactory.implementation()).to.exist + }) + + it('Governance should be able to set factory params', async function () { + let { instanceFactory, owner } = await loadFixture(fixture) + + await expect(instanceFactory.setMerkleTreeHeight(1)).to.be.reverted + + instanceFactory = await instanceFactory.connect(owner) + + await instanceFactory.generateNewImplementation(addressZero, addressZero) + await instanceFactory.setMerkleTreeHeight(1) + + expect(await instanceFactory.verifier()).to.be.equal(addressZero) + expect(await instanceFactory.hasher()).to.be.equal(addressZero) + expect(await instanceFactory.merkleTreeHeight()).to.be.equal(1) + + await instanceFactory.generateNewImplementation(config.verifier, config.hasher) + await instanceFactory.setMerkleTreeHeight(config.merkleTreeHeight) + + expect(await instanceFactory.verifier()).to.be.equal(config.verifier) + expect(await instanceFactory.hasher()).to.be.equal(config.hasher) + expect(await instanceFactory.merkleTreeHeight()).to.be.equal(config.merkleTreeHeight) + }) + + it('Should successfully add instance', async function () { + let { sender, instanceFactory } = await loadFixture(fixture) + + // deploy instance + await instanceFactory.connect(sender).createInstanceClone(ethers.utils.parseEther('1000'), config.COMP) + + // check instance initialization + let logs = await instanceFactory.queryFilter('NewInstanceCloneCreated') + const instance = await ethers.getContractAt( + 'ERC20TornadoCloneable', + ethers.utils.getAddress('0x' + logs[logs.length - 1].topics[1].slice(-40)), + ) + + expect(await instance.token()).to.be.equal(config.COMP) + expect(await instance.verifier()).to.be.equal(config.verifier) + expect(await instance.hasher()).to.be.equal(config.hasher) + expect(await instance.levels()).to.be.equal(config.merkleTreeHeight) + expect(await instance.denomination()).to.equal(ethers.utils.parseEther('1000')) + }) + + it('Should deposit and withdraw into the new instance', async function () { + let { sender, instanceFactory, compToken, compWhale } = await loadFixture(fixture) + + // deploy instance + await instanceFactory.connect(sender).createInstanceClone(ethers.utils.parseEther('100'), config.COMP) + + let logs = await instanceFactory.queryFilter('NewInstanceCloneCreated') + const instance = await ethers.getContractAt( + 'ERC20TornadoCloneable', + ethers.utils.getAddress('0x' + logs[logs.length - 1].topics[1].slice(-40)), + ) + + // check instance work ------------------------------------------ + const depo = createDeposit({ + nullifier: rbigint(31), + secret: rbigint(31), + }) + + const value = ethers.utils.parseEther('100') + + await compToken.connect(compWhale).transfer(sender.address, value) + await compToken.connect(sender).approve(instance.address, value) + + await expect(() => instance.deposit(toHex(depo.commitment), [])).to.changeTokenBalances( + compToken, + [sender, instance], + [BigNumber.from(0).sub(value), value], + ) + + let pevents = await instance.queryFilter('Deposit') + await initialize({ merkleTreeHeight: 20 }) + + const { proof, args } = await generateProof({ + deposit: depo, + recipient: sender.address, + events: pevents, + }) + + await expect(() => instance.withdraw(proof, ...args)).to.changeTokenBalances( + compToken, + [instance, sender], + [BigNumber.from(0).sub(value), value], + ) + }) +}) diff --git a/test/factory.with.registry.test.js b/test/factory.with.registry.test.js new file mode 100644 index 0000000..6fce033 --- /dev/null +++ b/test/factory.with.registry.test.js @@ -0,0 +1,496 @@ +const hre = require('hardhat') +const { ethers, waffle } = hre +const { loadFixture } = waffle +const { expect } = require('chai') +const { BigNumber } = require('@ethersproject/bignumber') +const config = require('../config') +const { getSignerFromAddress, minewait } = require('./utils') +const { PermitSigner } = require('../src/permit.js') +const { generate } = require('../src/generateAddresses') +const { rbigint, createDeposit, toHex, generateProof, initialize } = require('tornado-cli') + +describe('Instance Factory With Registry Tests', () => { + const ProposalState = { + Pending: 0, + Active: 1, + Defeated: 2, + Timelocked: 3, + AwaitingExecution: 4, + Executed: 5, + Expired: 6, + } + + const addressZero = ethers.constants.AddressZero + + async function fixture() { + const [sender, deployer, multisig] = await ethers.getSigners() + + const tornWhale = await getSignerFromAddress(config.tornWhale) + + const compWhale = await getSignerFromAddress(config.compWhale) + + const gov = await ethers.getContractAt('Governance', config.governance) + + const router = await ethers.getContractAt( + 'tornado-relayer-registry/contracts/tornado-proxy/TornadoRouter.sol:TornadoRouter', + config.router, + ) + + const tornToken = await ethers.getContractAt( + '@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20', + config.TORN, + ) + + const compToken = await ethers.getContractAt( + '@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20', + config.COMP, + ) + + const instanceRegistry = await ethers.getContractAt( + 'tornado-relayer-registry/contracts/tornado-proxy/InstanceRegistry.sol:InstanceRegistry', + config.instanceRegistry, + ) + + // deploy InstanceFactoryWithRegistry with CREATE2 + const singletonFactory = await ethers.getContractAt( + 'SingletonFactory', + config.singletonFactoryVerboseWrapper, + ) + const contracts = await generate() + if ((await ethers.provider.getCode(contracts.factoryWithRegistryContract.address)) == '0x') { + await singletonFactory.deploy(contracts.factoryWithRegistryContract.bytecode, config.salt, { + gasLimit: config.deployGasLimit, + }) + } + const instanceFactory = await ethers.getContractAt( + 'InstanceFactoryWithRegistry', + contracts.factoryWithRegistryContract.address, + ) + + return { + sender, + deployer, + multisig, + tornWhale, + compWhale, + router, + gov, + tornToken, + compToken, + instanceRegistry, + instanceFactory, + } + } + + it('Should have initialized all successfully', async function () { + const { sender, gov, tornToken, instanceRegistry, instanceFactory } = await loadFixture(fixture) + expect(sender.address).to.exist + expect(gov.address).to.exist + expect(tornToken.address).to.exist + expect(instanceRegistry.address).to.exist + expect(instanceFactory.address).to.exist + }) + + it('Should set correct params for factory', async function () { + const { instanceFactory } = await loadFixture(fixture) + + expect(await instanceFactory.governance()).to.be.equal(config.governance) + expect(await instanceFactory.verifier()).to.be.equal(config.verifier) + expect(await instanceFactory.hasher()).to.be.equal(config.hasher) + expect(await instanceFactory.merkleTreeHeight()).to.be.equal(config.merkleTreeHeight) + expect(await instanceFactory.implementation()).to.exist + expect(await instanceFactory.creationFee()).to.be.equal(config.creationFee) + expect(await instanceFactory.torn()).to.be.equal(config.TORN) + expect(await instanceFactory.TWAPSlotsMin()).to.be.equal(config.TWAPSlotsMin) + expect(await instanceFactory.WETH()).to.be.equal(config.WETH) + expect(await instanceFactory.UniswapV3Factory()).to.be.equal(config.UniswapV3Factory) + }) + + it('Governance should be able to set factory params', async function () { + let { instanceFactory, gov } = await loadFixture(fixture) + + await expect(instanceFactory.setMerkleTreeHeight(1)).to.be.reverted + + const govSigner = await getSignerFromAddress(gov.address) + instanceFactory = await instanceFactory.connect(govSigner) + + await instanceFactory.generateNewImplementation(addressZero, addressZero) + await instanceFactory.setMerkleTreeHeight(1) + await instanceFactory.setCreationFee(0) + await instanceFactory.setTWAPSlotsMin(0) + + expect(await instanceFactory.verifier()).to.be.equal(addressZero) + expect(await instanceFactory.hasher()).to.be.equal(addressZero) + expect(await instanceFactory.merkleTreeHeight()).to.be.equal(1) + expect(await instanceFactory.creationFee()).to.be.equal(0) + expect(await instanceFactory.TWAPSlotsMin()).to.be.equal(0) + + await instanceFactory.generateNewImplementation(config.verifier, config.hasher) + await instanceFactory.setMerkleTreeHeight(config.merkleTreeHeight) + await instanceFactory.setCreationFee(config.creationFee) + await instanceFactory.setTWAPSlotsMin(config.TWAPSlotsMin) + + expect(await instanceFactory.verifier()).to.be.equal(config.verifier) + expect(await instanceFactory.hasher()).to.be.equal(config.hasher) + expect(await instanceFactory.merkleTreeHeight()).to.be.equal(config.merkleTreeHeight) + expect(await instanceFactory.creationFee()).to.be.equal(config.creationFee) + expect(await instanceFactory.TWAPSlotsMin()).to.be.equal(config.TWAPSlotsMin) + }) + + it('Should successfully deploy/propose/execute proposal - add instance', async function () { + let { sender, instanceFactory, gov, instanceRegistry, tornWhale, tornToken } = await loadFixture(fixture) + + // deploy proposal ---------------------------------------------- + await tornToken.connect(tornWhale).transfer(sender.address, config.creationFee) + await tornToken.approve(instanceFactory.address, config.creationFee) + + await expect(() => + instanceFactory + .connect(sender) + .createProposalApprove(config.COMP, 3000, [ethers.utils.parseEther('100')], [30]), + ).to.changeTokenBalances( + tornToken, + [sender, gov], + [BigNumber.from(0).sub(config.creationFee), config.creationFee], + ) + + let logs = await instanceFactory.queryFilter('NewGovernanceProposalCreated') + const proposal = await ethers.getContractAt( + 'AddInstanceProposal', + ethers.utils.getAddress('0x' + logs[logs.length - 1].topics[1].slice(-40)), + ) + + expect(await proposal.instanceFactory()).to.be.equal(instanceFactory.address) + expect(await proposal.instanceRegistry()).to.be.equal(instanceRegistry.address) + expect(await proposal.token()).to.be.equal(config.COMP) + expect(await proposal.uniswapPoolSwappingFee()).to.be.equal(3000) + expect(await proposal.numInstances()).to.be.equal(1) + expect(await proposal.protocolFeeByIndex(0)).to.be.equal(30) + expect(await proposal.denominationByIndex(0)).to.be.equal(ethers.utils.parseEther('100')) + + // propose proposal --------------------------------------------- + let response, id, state + gov = await gov.connect(tornWhale) + await tornToken.connect(tornWhale).approve(gov.address, ethers.utils.parseEther('26000')) + await gov.lockWithApproval(ethers.utils.parseEther('26000')) + + response = await gov.propose(proposal.address, 'COMP token instance proposal') + id = await gov.latestProposalIds(tornWhale.address) + state = await gov.state(id) + + const { events } = await response.wait() + const args = events.find(({ event }) => event == 'ProposalCreated').args + expect(args.id).to.be.equal(id) + expect(args.proposer).to.be.equal(tornWhale.address) + expect(args.target).to.be.equal(proposal.address) + expect(args.description).to.be.equal('COMP token instance proposal') + expect(state).to.be.equal(ProposalState.Pending) + + // execute proposal --------------------------------------------- + await minewait((await gov.VOTING_DELAY()).add(1).toNumber()) + await expect(gov.castVote(id, true)).to.not.be.reverted + expect(await gov.state(id)).to.be.equal(ProposalState.Active) + await minewait( + ( + await gov.VOTING_PERIOD() + ) + .add(await gov.EXECUTION_DELAY()) + .add(96400) + .toNumber(), + ) + expect(await gov.state(id)).to.be.equal(ProposalState.AwaitingExecution) + + let tx = await gov.execute(id) + + expect(await gov.state(id)).to.be.equal(ProposalState.Executed) + + // check instance initialization -------------------------------- + let receipt = await tx.wait() + const instanceAddr = '0x' + receipt.events[0].topics[1].toString().slice(-40) + const instance = await ethers.getContractAt('ERC20TornadoCloneable', instanceAddr) + + expect(await instance.token()).to.be.equal(config.COMP) + expect(await instance.verifier()).to.be.equal(config.verifier) + expect(await instance.hasher()).to.be.equal(config.hasher) + expect(await instance.levels()).to.be.equal(config.merkleTreeHeight) + expect(await instance.denomination()).to.equal(ethers.utils.parseEther('100')) + + const instanceData = await instanceRegistry.instances(instance.address) + expect(instanceData.isERC20).to.be.equal(true) + expect(instanceData.token).to.be.equal(config.COMP) + expect(instanceData.state).to.be.equal(1) + expect(instanceData.uniswapPoolSwappingFee).to.be.equal(3000) + expect(instanceData.protocolFeePercentage).to.be.equal(30) + }) + + it('Should successfully deploy/propose/execute proposal - add instances', async function () { + let { sender, instanceFactory, gov, instanceRegistry, tornWhale, tornToken } = await loadFixture(fixture) + + const denominations = [ + ethers.utils.parseEther('1'), + ethers.utils.parseEther('10'), + ethers.utils.parseEther('100'), + ethers.utils.parseEther('1000'), + ] + const numInstances = denominations.length + + const protocolFees = [30, 30, 30, 30] + + // deploy proposal ---------------------------------------------- + await tornToken.connect(tornWhale).transfer(sender.address, config.creationFee) + await tornToken.approve(instanceFactory.address, config.creationFee) + + await expect(() => + instanceFactory.connect(sender).createProposalApprove(config.COMP, 3000, denominations, protocolFees), + ).to.changeTokenBalances( + tornToken, + [sender, gov], + [BigNumber.from(0).sub(config.creationFee), config.creationFee], + ) + + let logs = await instanceFactory.queryFilter('NewGovernanceProposalCreated') + const proposal = await ethers.getContractAt( + 'AddInstanceProposal', + ethers.utils.getAddress('0x' + logs[logs.length - 1].topics[1].slice(-40)), + ) + + expect(await proposal.instanceFactory()).to.be.equal(instanceFactory.address) + expect(await proposal.instanceRegistry()).to.be.equal(instanceRegistry.address) + expect(await proposal.token()).to.be.equal(config.COMP) + expect(await proposal.uniswapPoolSwappingFee()).to.be.equal(3000) + expect(await proposal.numInstances()).to.be.equal(numInstances) + for (let i = 0; i < numInstances; i++) { + expect(await proposal.protocolFeeByIndex(i)).to.be.equal(protocolFees[i]) + expect(await proposal.denominationByIndex(i)).to.be.equal(denominations[i]) + } + + // propose proposal --------------------------------------------- + let response, id, state + gov = await gov.connect(tornWhale) + await tornToken.connect(tornWhale).approve(gov.address, ethers.utils.parseEther('26000')) + await gov.lockWithApproval(ethers.utils.parseEther('26000')) + + response = await gov.propose(proposal.address, 'COMP token instances proposal') + id = await gov.latestProposalIds(tornWhale.address) + state = await gov.state(id) + + const { events } = await response.wait() + const args = events.find(({ event }) => event == 'ProposalCreated').args + expect(args.id).to.be.equal(id) + expect(args.proposer).to.be.equal(tornWhale.address) + expect(args.target).to.be.equal(proposal.address) + expect(args.description).to.be.equal('COMP token instances proposal') + expect(state).to.be.equal(ProposalState.Pending) + + // execute proposal --------------------------------------------- + await minewait((await gov.VOTING_DELAY()).add(1).toNumber()) + await expect(gov.castVote(id, true)).to.not.be.reverted + expect(await gov.state(id)).to.be.equal(ProposalState.Active) + await minewait( + ( + await gov.VOTING_PERIOD() + ) + .add(await gov.EXECUTION_DELAY()) + .add(96400) + .toNumber(), + ) + expect(await gov.state(id)).to.be.equal(ProposalState.AwaitingExecution) + + await gov.execute(id) + + expect(await gov.state(id)).to.be.equal(ProposalState.Executed) + + // check instances initialization ------------------------------- + logs = await instanceFactory.queryFilter('NewInstanceCloneCreated') + for (let i = 0; i < numInstances; i++) { + let instanceAddr = '0x' + logs[logs.length - numInstances + i].topics[1].slice(-40) + let instance = await ethers.getContractAt('ERC20TornadoCloneable', instanceAddr) + + expect(await instance.token()).to.be.equal(config.COMP) + expect(await instance.verifier()).to.be.equal(config.verifier) + expect(await instance.hasher()).to.be.equal(config.hasher) + expect(await instance.levels()).to.be.equal(config.merkleTreeHeight) + expect(await instance.denomination()).to.equal(denominations[i]) + + let instanceData = await instanceRegistry.instances(instance.address) + expect(instanceData.isERC20).to.be.equal(true) + expect(instanceData.token).to.be.equal(config.COMP) + expect(instanceData.state).to.be.equal(1) + expect(instanceData.uniswapPoolSwappingFee).to.be.equal(3000) + expect(instanceData.protocolFeePercentage).to.be.equal(protocolFees[i]) + } + }) + + it('Should successfully deploy proposal with permit', async function () { + let { instanceFactory, gov, instanceRegistry, tornWhale, tornToken } = await loadFixture(fixture) + + const privateKey = '0xc87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3' + const publicKey = '0x' + ethers.utils.computeAddress(Buffer.from(privateKey.slice(2), 'hex')) + const sender = await ethers.getSigner(publicKey.slice(2)) + + await expect(() => + tornToken.connect(tornWhale).transfer(sender.address, config.creationFee), + ).to.changeTokenBalances( + tornToken, + [tornWhale, sender], + [BigNumber.from(0).sub(config.creationFee), config.creationFee], + ) + + // prepare permit data + const domain = { + name: await tornToken.name(), + version: '1', + chainId: 1, + verifyingContract: tornToken.address, + } + + const curTimestamp = Math.trunc(new Date().getTime() / 1000) + const args = { + owner: sender, + spender: instanceFactory.address, + value: config.creationFee, + nonce: 0, + deadline: curTimestamp + 1000, + } + + const permitSigner = new PermitSigner(domain, args) + const signature = await permitSigner.getSignature(privateKey) + const signer = await permitSigner.getSignerAddress(args, signature.hex) + expect(signer).to.equal(sender.address) + + await expect(() => + instanceFactory.createProposalPermit( + config.COMP, + 3000, + [ethers.utils.parseEther('100')], + [30], + sender.address, + args.deadline.toString(), + signature.v, + signature.r, + signature.s, + ), + ).to.changeTokenBalances( + tornToken, + [sender, gov], + [BigNumber.from(0).sub(config.creationFee), config.creationFee], + ) + + let logs = await instanceFactory.queryFilter('NewGovernanceProposalCreated') + const proposal = await ethers.getContractAt( + 'AddInstanceProposal', + ethers.utils.getAddress('0x' + logs[logs.length - 1].topics[1].slice(-40)), + ) + + expect(await proposal.instanceFactory()).to.be.equal(instanceFactory.address) + expect(await proposal.instanceRegistry()).to.be.equal(instanceRegistry.address) + expect(await proposal.token()).to.be.equal(config.COMP) + expect(await proposal.uniswapPoolSwappingFee()).to.be.equal(3000) + expect(await proposal.numInstances()).to.be.equal(1) + expect(await proposal.protocolFeeByIndex(0)).to.be.equal(30) + expect(await proposal.denominationByIndex(0)).to.be.equal(ethers.utils.parseEther('100')) + }) + + it('Should deposit and withdraw into the new instance', async function () { + let { sender, instanceFactory, gov, tornWhale, tornToken, router, compToken, compWhale } = + await loadFixture(fixture) + + // deploy proposal ---------------------------------------------- + await tornToken.connect(tornWhale).transfer(sender.address, config.creationFee) + await tornToken.approve(instanceFactory.address, config.creationFee) + + await expect(() => + instanceFactory + .connect(sender) + .createProposalApprove(config.COMP, 3000, [ethers.utils.parseEther('100')], [30]), + ).to.changeTokenBalances( + tornToken, + [sender, gov], + [BigNumber.from(0).sub(config.creationFee), config.creationFee], + ) + + let logs = await instanceFactory.queryFilter('NewGovernanceProposalCreated') + const proposal = await ethers.getContractAt( + 'AddInstanceProposal', + ethers.utils.getAddress('0x' + logs[logs.length - 1].topics[1].slice(-40)), + ) + + // propose proposal --------------------------------------------- + let id + gov = await gov.connect(tornWhale) + await tornToken.connect(tornWhale).approve(gov.address, ethers.utils.parseEther('26000')) + await gov.lockWithApproval(ethers.utils.parseEther('26000')) + + await gov.propose(proposal.address, 'COMP token instance proposal') + id = await gov.latestProposalIds(tornWhale.address) + + // execute proposal --------------------------------------------- + await minewait((await gov.VOTING_DELAY()).add(1).toNumber()) + await expect(gov.castVote(id, true)).to.not.be.reverted + await minewait( + ( + await gov.VOTING_PERIOD() + ) + .add(await gov.EXECUTION_DELAY()) + .add(96400) + .toNumber(), + ) + + let tx = await gov.execute(id) + let receipt = await tx.wait() + const instanceAddr = '0x' + receipt.events[0].topics[1].toString().slice(-40) + const instance = await ethers.getContractAt('ERC20TornadoCloneable', instanceAddr) + + // check instance work ------------------------------------------ + const depo = createDeposit({ + nullifier: rbigint(31), + secret: rbigint(31), + }) + + const value = ethers.utils.parseEther('100') + + await compToken.connect(compWhale).transfer(sender.address, value) + await compToken.connect(sender).approve(router.address, value) + + await expect(() => router.deposit(instance.address, toHex(depo.commitment), [])).to.changeTokenBalances( + compToken, + [sender, instance], + [BigNumber.from(0).sub(value), value], + ) + + let pevents = await instance.queryFilter('Deposit') + await initialize({ merkleTreeHeight: 20 }) + + const { proof, args } = await generateProof({ + deposit: depo, + recipient: sender.address, + events: pevents, + }) + + await expect(() => router.withdraw(instance.address, proof, ...args)).to.changeTokenBalances( + compToken, + [instance, sender], + [BigNumber.from(0).sub(value), value], + ) + }) + + it('Should not deploy proposal with incorrect Uniswap pool', async function () { + let { sender, instanceFactory, tornWhale, tornToken } = await loadFixture(fixture) + + // deploy proposal ---------------------------------------------- + await tornToken.connect(tornWhale).transfer(sender.address, config.creationFee) + await tornToken.approve(instanceFactory.address, config.creationFee) + + await expect( + instanceFactory + .connect(sender) + .createProposalApprove(config.COMP, 4000, [ethers.utils.parseEther('100')], [30]), + ).to.be.revertedWith('Uniswap pool is not exist') + + await expect( + instanceFactory + .connect(sender) + .createProposalApprove(config.COMP, 10000, [ethers.utils.parseEther('100')], [30]), + ).to.be.revertedWith('Uniswap pool TWAP slots number is low') + }) +}) diff --git a/test/instance.factory.proposal.test.js b/test/instance.factory.proposal.test.js deleted file mode 100644 index 9bfe6cb..0000000 --- a/test/instance.factory.proposal.test.js +++ /dev/null @@ -1,346 +0,0 @@ -require('dotenv').config() -const { ethers } = require('hardhat') -const { expect } = require('chai') -const { BigNumber } = require('@ethersproject/bignumber') -const { rbigint, createDeposit, toHex, generateProof, initialize } = require('tornado-cli') - -const { propose } = require('../scripts/helper/propose_proposal.js') - -const MixerContractABI = require('tornado-cli/build/contracts/Mixer.abi.json') - -describe('Deployments test setup', () => { - const Verifier = `${process.env.VERIFIER}` - const Hasher = `${process.env.HASHER}` - const Proxy = `${process.env.PROXY}` - - //// IMPERSONATED ACCOUNTS - let accounts - let whale - let impGov - - //// CONTRACTS / FACTORIES - let ProposalFactory - let ProposalContract - - let GovernanceContract - let TornToken - let RAIToken - let TornadoProxy - - let TornadoInstanceFactoryContract - - /// HARDCODED - let denominations = [ - '33333333333333333333', - '333333333333333333333', - '3333333333333333333333', - '33333333333333333333333', - ] - let tokenAddress = '0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919' - - let minewait = async (time) => { - await ethers.provider.send('evm_increaseTime', [time]) - await ethers.provider.send('evm_mine', []) - } - - let sendr = async (method, params) => { - return await ethers.provider.send(method, params) - } - - let clog = (...x) => { - console.log(x) - } - - let pE = (x) => { - return ethers.utils.parseEther(`${x}`) - } - - const ProposalState = { - Pending: 0, - Active: 1, - Defeated: 2, - Timelocked: 3, - AwaitingExecution: 4, - Executed: 5, - Expired: 6, - } - - before(async () => { - accounts = await ethers.getSigners() - ProposalFactory = await ethers.getContractFactory('CreateFactoryAndAddInstancesProposal') - GovernanceContract = await ethers.getContractAt( - 'Governance', - '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce', - ) - TornToken = await ethers.getContractAt( - '@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20', - '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C', - ) - TornadoProxy = await ethers.getContractAt('TornadoProxy', '0x722122dF12D4e14e13Ac3b6895a86e84145b6967') - }) - - describe('Test instance deployment', () => { - let snapshotId - - it('Should have initialized all successfully', () => { - expect(accounts[0].address).to.exist - expect(GovernanceContract.address).to.exist - expect(TornToken.address).to.exist - expect(TornadoProxy.address).to.exist - }) - - it('Should successfully imitate whale', async () => { - await sendr('hardhat_impersonateAccount', ['0xA2b2fBCaC668d86265C45f62dA80aAf3Fd1dEde3']) - whale = await ethers.getSigner('0xA2b2fBCaC668d86265C45f62dA80aAf3Fd1dEde3') - GovernanceContract = await GovernanceContract.connect(whale) - - let balance = await TornToken.balanceOf(whale.address) - TornToken = await TornToken.connect(whale) - - await TornToken.approve(GovernanceContract.address, ethers.utils.parseEther('8000000000')) - await expect(GovernanceContract.lockWithApproval(balance)).to.not.be.reverted - - expect((await GovernanceContract.lockedBalance(whale.address)).toString()).to.equal(balance.toString()) - }) - - it('Should successfully deploy proposal', async () => { - ProposalContract = await ProposalFactory.deploy(Proxy, denominations, tokenAddress) - expect(await ProposalContract.token()).to.equal(tokenAddress) - expect(await ProposalContract.denomination1()).to.equal(denominations[0]) - expect(await ProposalContract.denomination2()).to.equal(denominations[1]) - expect(await ProposalContract.denomination3()).to.equal(denominations[2]) - expect(await ProposalContract.denomination4()).to.equal(denominations[3]) - - TornadoInstanceFactoryContract = await ethers.getContractAt( - 'TornadoInstanceCloneFactory', - await ProposalContract.instanceFactory(), - ) - }) - - it('Should successfully pass the proposal', async () => { - let response, id, state - ;[response, id, state] = await propose([whale, ProposalContract, 'Instances']) - - let { events } = await response.wait() - let args = events.find(({ event }) => event == 'ProposalCreated').args - expect(args.id).to.be.equal(id) - expect(args.proposer).to.be.equal(whale.address) - expect(args.target).to.be.equal(ProposalContract.address) - expect(args.description).to.be.equal('Instances') - expect(state).to.be.equal(ProposalState.Pending) - - await minewait((await GovernanceContract.VOTING_DELAY()).add(1).toNumber()) - await expect(GovernanceContract.castVote(id, true)).to.not.be.reverted - state = await GovernanceContract.state(id) - expect(state).to.be.equal(ProposalState.Active) - await minewait( - ( - await GovernanceContract.VOTING_PERIOD() - ) - .add(await GovernanceContract.EXECUTION_DELAY()) - .add(86400) - .toNumber(), - ) - const overrides = { - gasLimit: BigNumber.from('30000000'), - } - await GovernanceContract.execute(id, overrides) - }) - - it('Should set correct params for factory', async () => { - expect(await TornadoInstanceFactoryContract.verifier()).to.equal(Verifier) - expect(await TornadoInstanceFactoryContract.hasher()).to.equal(Hasher) - expect(await TornadoInstanceFactoryContract.merkleTreeHeight()).to.equal(20) - clog(await TornadoInstanceFactoryContract.implementation()) - }) - - it('Factory should be able to generate an instance without reverting', async () => { - const OHMAddress = '0x383518188C0C6d7730D91b2c03a03C837814a899' - - await sendr('hardhat_impersonateAccount', [GovernanceContract.address]) - await sendr('hardhat_setBalance', [GovernanceContract.address, '0xDE0B6B3A764000000']) - impGov = await ethers.getSigner(GovernanceContract.address) - - const factory = await TornadoInstanceFactoryContract.connect(impGov) - - await factory.createInstanceClone(333, OHMAddress) - const instanceAddress = await TornadoInstanceFactoryContract.getInstanceAddress(333, OHMAddress) - - const instance = await ethers.getContractAt('ERC20TornadoCloneable', instanceAddress) - - const token = await instance.token() - const denomination = await instance.denomination() - const verifier = await instance.verifier() - const hasher = await instance.hasher() - const levels = await instance.levels() - - expect(token).to.equal(OHMAddress) - expect(denomination).to.equal(333) - expect(verifier).to.equal(Verifier) - expect(hasher).to.equal(Hasher) - expect(levels).to.equal(20) - }) - - it('Governance should be able to set factory params', async () => { - const zeroAddress = '0x0000000000000000000000000000000000000000' - - const factory = await TornadoInstanceFactoryContract.connect(impGov) - await factory.setVerifier(zeroAddress) - await factory.setHasher(zeroAddress) - await factory.setMerkleTreeHeight(25) - - let fverifier = await factory.verifier() - let fhasher = await factory.hasher() - let merkleTreeHeight = await factory.merkleTreeHeight() - - expect(fverifier).to.equal(zeroAddress) - expect(fhasher).to.equal(zeroAddress) - expect(merkleTreeHeight).to.equal(25) - - await factory.setVerifier(Verifier) - await factory.setHasher(Hasher) - await factory.setMerkleTreeHeight(20) - - fverifier = await factory.verifier() - fhasher = await factory.hasher() - merkleTreeHeight = await factory.merkleTreeHeight() - - expect(fverifier).to.equal(Verifier) - expect(fhasher).to.equal(Hasher) - expect(merkleTreeHeight).to.equal(20) - }) - - let whaleRAI, whaleRAIBalance, TornadoInstance, mixerContract, instanceAddresses - instanceAddresses = [] - - it('Should prepare data for instance deposit/withdraw tests', async () => { - const RAITokenAddress = '0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919' - await sendr('hardhat_impersonateAccount', ['0x46a0B4Fa58141ABa23185e79f7047A7dFd0FF100']) - RAIToken = await ethers.getContractAt( - '@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20', - RAITokenAddress, - ) - whaleRAI = await ethers.getSigner('0x46a0B4Fa58141ABa23185e79f7047A7dFd0FF100') - - const tx = { - to: whaleRAI.address, - value: pE(50), - } - await accounts[0].sendTransaction(tx) - - whaleRAIBalance = await RAIToken.balanceOf(whaleRAI.address) - RAIToken = await RAIToken.connect(whaleRAI) - TornadoProxy = await TornadoProxy.connect(whaleRAI) - - for (let i = 0; i < 4; i++) { - instanceAddresses[i] = await TornadoInstanceFactoryContract.getInstanceAddress( - denominations[i], - RAIToken.address, - ) - } - - mixerContract = await ethers.getContractAt(MixerContractABI, instanceAddresses[0]) - mixerContract = await mixerContract.connect(whaleRAI) - - snapshotId = await sendr('evm_snapshot', []) - }) - - it('Should test depositing and withdrawing into the new instance over proxy', async () => { - const depo = createDeposit({ - nullifier: rbigint(31), - secret: rbigint(31), - }) - - const note = toHex(depo.preimage, 62) - const noteString = `tornado-RAI-33-1-${note}` - clog('Note: ', note) - clog('Note string: ', noteString) - clog('Commitment: ', toHex(depo.commitment)) - - await expect(RAIToken.approve(TornadoProxy.address, pE(5000000))).to.not.be.reverted - TornadoInstance = await ethers.getContractAt( - 'contracts/tornado_proxy/ITornadoInstance.sol:ITornadoInstance', - instanceAddresses[0], - ) - - await expect(() => - TornadoProxy.deposit(instanceAddresses[0], toHex(depo.commitment), []), - ).to.changeTokenBalance(RAIToken, whaleRAI, BigNumber.from(0).sub(await TornadoInstance.denomination())) - - let pevents = await mixerContract.queryFilter('Deposit') - await initialize({ merkleTreeHeight: 20 }) - - const { proof, args } = await generateProof({ - deposit: depo, - recipient: whaleRAI.address, - events: pevents, - }) - - await expect(() => - TornadoProxy.withdraw(TornadoInstance.address, proof, ...args), - ).to.changeTokenBalance(RAIToken, whaleRAI, await TornadoInstance.denomination()) - - await sendr('evm_revert', [snapshotId]) - snapshotId = await sendr('evm_snapshot', []) - }) - - it('Should prepare for multiple account deposits', async () => { - let toSend = whaleRAIBalance.div(5) - - for (let i = 0; i < 3; i++) { - await RAIToken.transfer(accounts[i].address, toSend) - const rai = await RAIToken.connect(accounts[i]) - await rai.approve(TornadoProxy.address, pE(600000)) - } - }) - - it('Should test depositing with multiple accounts over proxy', async () => { - for (let i = 0; i < 3; i++) { - const depo = createDeposit({ - nullifier: rbigint(31), - secret: rbigint(31), - }) - const note = toHex(depo.preimage, 62) - const noteString = `tornado-RAI-33-1-${note}` - clog('Note: ', note) - clog('Note string: ', noteString) - clog('Commitment: ', toHex(depo.commitment)) - const proxy = await TornadoProxy.connect(accounts[i]) - - await expect(() => - proxy.deposit(TornadoInstance.address, toHex(depo.commitment), []), - ).to.changeTokenBalance( - RAIToken, - accounts[i], - BigNumber.from(0).sub(await TornadoInstance.denomination()), - ) - - let pevents = await mixerContract.queryFilter('Deposit') - await initialize({ merkleTreeHeight: 20 }) - - const { proof, args } = await generateProof({ - deposit: depo, - recipient: accounts[i].address, - events: pevents, - }) - - await expect(() => proxy.withdraw(TornadoInstance.address, proof, ...args)).to.changeTokenBalance( - RAIToken, - accounts[i], - await TornadoInstance.denomination(), - ) - } - }) - }) - - after(async function () { - await ethers.provider.send('hardhat_reset', [ - { - forking: { - jsonRpcUrl: `https://mainnet.infura.io/v3/${process.env.mainnet_rpc_key}`, - blockNumber: process.env.use_latest_block == 'true' ? undefined : 13017436, - }, - }, - ]) - }) -}) diff --git a/test/instance.proposal.test.js b/test/instance.proposal.test.js deleted file mode 100644 index 12692b0..0000000 --- a/test/instance.proposal.test.js +++ /dev/null @@ -1,355 +0,0 @@ -require('dotenv').config() -const { ethers } = require('hardhat') -const { expect } = require('chai') -const { BigNumber } = require('@ethersproject/bignumber') -const { rbigint, createDeposit, toHex, generateProof, initialize } = require('tornado-cli') - -const { propose } = require('../scripts/helper/propose_proposal.js') - -const MixerContractABI = require('tornado-cli/build/contracts/Mixer.abi.json') - -describe('Deployments test setup', () => { - const Verifier = `${process.env.VERIFIER}` - const Hasher = `${process.env.HASHER}` - const Proxy = `${process.env.PROXY}` - - //// IMPERSONATED ACCOUNTS - let accounts - let whale - let impGov - - //// CONTRACTS / FACTORIES - let ProposalFactory - let ProposalContract - - let GovernanceContract - let TornToken - let RAIToken - let TornadoProxy - - let TornadoInstanceFactoryFactory - let TornadoInstanceFactoryContract - - /// HARDCODED - let denominations = [ - '33333333333333333333', - '333333333333333333333', - '3333333333333333333333', - '33333333333333333333333', - ] - let tokenAddress = '0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919' - - let minewait = async (time) => { - await ethers.provider.send('evm_increaseTime', [time]) - await ethers.provider.send('evm_mine', []) - } - - let sendr = async (method, params) => { - return await ethers.provider.send(method, params) - } - - let clog = (...x) => { - console.log(x) - } - - let pE = (x) => { - return ethers.utils.parseEther(`${x}`) - } - - const ProposalState = { - Pending: 0, - Active: 1, - Defeated: 2, - Timelocked: 3, - AwaitingExecution: 4, - Executed: 5, - Expired: 6, - } - - before(async () => { - accounts = await ethers.getSigners() - ProposalFactory = await ethers.getContractFactory('Add4Instances') - GovernanceContract = await ethers.getContractAt( - 'Governance', - '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce', - ) - TornToken = await ethers.getContractAt( - '@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20', - '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C', - ) - TornadoProxy = await ethers.getContractAt('TornadoProxy', '0x722122dF12D4e14e13Ac3b6895a86e84145b6967') - TornadoInstanceFactoryFactory = await ethers.getContractFactory('TornadoInstanceCloneFactory') - }) - - describe('Test instance deployment', () => { - let snapshotId - - it('Should have initialized all successfully', () => { - expect(accounts[0].address).to.exist - expect(GovernanceContract.address).to.exist - expect(TornToken.address).to.exist - expect(TornadoProxy.address).to.exist - }) - - it('Should set correct params for factory', async () => { - TornadoInstanceFactoryContract = await TornadoInstanceFactoryFactory.deploy( - Verifier, - Hasher, - BigNumber.from(20), - ) - await TornadoInstanceFactoryContract.transferOwnership(GovernanceContract.address) - expect(await TornadoInstanceFactoryContract.verifier()).to.equal(Verifier) - expect(await TornadoInstanceFactoryContract.hasher()).to.equal(Hasher) - expect(await TornadoInstanceFactoryContract.merkleTreeHeight()).to.equal(20) - clog(await TornadoInstanceFactoryContract.implementation()) - }) - - it('Factory should be able to generate an instance without reverting', async () => { - const OHMAddress = '0x383518188C0C6d7730D91b2c03a03C837814a899' - - await sendr('hardhat_impersonateAccount', [GovernanceContract.address]) - await sendr('hardhat_setBalance', [GovernanceContract.address, '0xDE0B6B3A764000000']) - impGov = await ethers.getSigner(GovernanceContract.address) - - const factory = await TornadoInstanceFactoryContract.connect(impGov) - - await factory.createInstanceClone(333, OHMAddress) - const instanceAddress = await TornadoInstanceFactoryContract.getInstanceAddress(333, OHMAddress) - - const instance = await ethers.getContractAt('ERC20TornadoCloneable', instanceAddress) - - const token = await instance.token() - const denomination = await instance.denomination() - const verifier = await instance.verifier() - const hasher = await instance.hasher() - const levels = await instance.levels() - - expect(token).to.equal(OHMAddress) - expect(denomination).to.equal(333) - expect(verifier).to.equal(Verifier) - expect(hasher).to.equal(Hasher) - expect(levels).to.equal(20) - }) - - it('Governance should be able to set factory params', async () => { - const zeroAddress = '0x0000000000000000000000000000000000000000' - - const factory = await TornadoInstanceFactoryContract.connect(impGov) - await factory.setVerifier(zeroAddress) - await factory.setHasher(zeroAddress) - await factory.setMerkleTreeHeight(25) - - let fverifier = await factory.verifier() - let fhasher = await factory.hasher() - let merkleTreeHeight = await factory.merkleTreeHeight() - - expect(fverifier).to.equal(zeroAddress) - expect(fhasher).to.equal(zeroAddress) - expect(merkleTreeHeight).to.equal(25) - - await factory.setVerifier(Verifier) - await factory.setHasher(Hasher) - await factory.setMerkleTreeHeight(20) - - fverifier = await factory.verifier() - fhasher = await factory.hasher() - merkleTreeHeight = await factory.merkleTreeHeight() - - expect(fverifier).to.equal(Verifier) - expect(fhasher).to.equal(Hasher) - expect(merkleTreeHeight).to.equal(20) - }) - - it('Should successfully imitate whale', async () => { - await sendr('hardhat_impersonateAccount', ['0xA2b2fBCaC668d86265C45f62dA80aAf3Fd1dEde3']) - whale = await ethers.getSigner('0xA2b2fBCaC668d86265C45f62dA80aAf3Fd1dEde3') - GovernanceContract = await GovernanceContract.connect(whale) - - let balance = await TornToken.balanceOf(whale.address) - TornToken = await TornToken.connect(whale) - - await TornToken.approve(GovernanceContract.address, ethers.utils.parseEther('8000000000')) - await expect(GovernanceContract.lockWithApproval(balance)).to.not.be.reverted - - expect((await GovernanceContract.lockedBalance(whale.address)).toString()).to.equal(balance.toString()) - }) - - it('Should successfully deploy proposal', async () => { - ProposalContract = await ProposalFactory.deploy( - Proxy, - TornadoInstanceFactoryContract.address, - denominations, - tokenAddress, - ) - expect(await ProposalContract.token()).to.equal(tokenAddress) - expect(await ProposalContract.instanceFactory()).to.equal(TornadoInstanceFactoryContract.address) - expect(await ProposalContract.denomination1()).to.equal(denominations[0]) - expect(await ProposalContract.denomination2()).to.equal(denominations[1]) - expect(await ProposalContract.denomination3()).to.equal(denominations[2]) - expect(await ProposalContract.denomination4()).to.equal(denominations[3]) - }) - - it('Should successfully pass the proposal', async () => { - let response, id, state - ;[response, id, state] = await propose([whale, ProposalContract, 'Instances']) - - let { events } = await response.wait() - let args = events.find(({ event }) => event == 'ProposalCreated').args - expect(args.id).to.be.equal(id) - expect(args.proposer).to.be.equal(whale.address) - expect(args.target).to.be.equal(ProposalContract.address) - expect(args.description).to.be.equal('Instances') - expect(state).to.be.equal(ProposalState.Pending) - - await minewait((await GovernanceContract.VOTING_DELAY()).add(1).toNumber()) - await expect(GovernanceContract.castVote(id, true)).to.not.be.reverted - state = await GovernanceContract.state(id) - expect(state).to.be.equal(ProposalState.Active) - await minewait( - ( - await GovernanceContract.VOTING_PERIOD() - ) - .add(await GovernanceContract.EXECUTION_DELAY()) - .add(86400) - .toNumber(), - ) - const overrides = { - gasLimit: BigNumber.from('30000000'), - } - await GovernanceContract.execute(id, overrides) - }) - - let whaleRAI, whaleRAIBalance, TornadoInstance, mixerContract, instanceAddresses - instanceAddresses = [] - - it('Should prepare data for instance deposit/withdraw tests', async () => { - const RAITokenAddress = '0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919' - await sendr('hardhat_impersonateAccount', ['0x46a0B4Fa58141ABa23185e79f7047A7dFd0FF100']) - RAIToken = await ethers.getContractAt( - '@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20', - RAITokenAddress, - ) - whaleRAI = await ethers.getSigner('0x46a0B4Fa58141ABa23185e79f7047A7dFd0FF100') - - const tx = { - to: whaleRAI.address, - value: pE(50), - } - await accounts[0].sendTransaction(tx) - - whaleRAIBalance = await RAIToken.balanceOf(whaleRAI.address) - RAIToken = await RAIToken.connect(whaleRAI) - TornadoProxy = await TornadoProxy.connect(whaleRAI) - - for (let i = 0; i < 4; i++) { - instanceAddresses[i] = await TornadoInstanceFactoryContract.getInstanceAddress( - denominations[i], - RAIToken.address, - ) - } - - mixerContract = await ethers.getContractAt(MixerContractABI, instanceAddresses[0]) - mixerContract = await mixerContract.connect(whaleRAI) - - snapshotId = await sendr('evm_snapshot', []) - }) - - it('Should test depositing and withdrawing into the new instance over proxy', async () => { - const depo = createDeposit({ - nullifier: rbigint(31), - secret: rbigint(31), - }) - - const note = toHex(depo.preimage, 62) - const noteString = `tornado-RAI-33-1-${note}` - clog('Note: ', note) - clog('Note string: ', noteString) - clog('Commitment: ', toHex(depo.commitment)) - - await expect(RAIToken.approve(TornadoProxy.address, pE(5000000))).to.not.be.reverted - TornadoInstance = await ethers.getContractAt( - 'contracts/tornado_proxy/ITornadoInstance.sol:ITornadoInstance', - instanceAddresses[0], - ) - - await expect(() => - TornadoProxy.deposit(instanceAddresses[0], toHex(depo.commitment), []), - ).to.changeTokenBalance(RAIToken, whaleRAI, BigNumber.from(0).sub(await TornadoInstance.denomination())) - - let pevents = await mixerContract.queryFilter('Deposit') - await initialize({ merkleTreeHeight: 20 }) - - const { proof, args } = await generateProof({ - deposit: depo, - recipient: whaleRAI.address, - events: pevents, - }) - - await expect(() => - TornadoProxy.withdraw(TornadoInstance.address, proof, ...args), - ).to.changeTokenBalance(RAIToken, whaleRAI, await TornadoInstance.denomination()) - - await sendr('evm_revert', [snapshotId]) - snapshotId = await sendr('evm_snapshot', []) - }) - - it('Should prepare for multiple account deposits', async () => { - let toSend = whaleRAIBalance.div(5) - - for (let i = 0; i < 3; i++) { - await RAIToken.transfer(accounts[i].address, toSend) - const rai = await RAIToken.connect(accounts[i]) - await rai.approve(TornadoProxy.address, pE(600000)) - } - }) - - it('Should test depositing with multiple accounts over proxy', async () => { - for (let i = 0; i < 3; i++) { - const depo = createDeposit({ - nullifier: rbigint(31), - secret: rbigint(31), - }) - const note = toHex(depo.preimage, 62) - const noteString = `tornado-RAI-33-1-${note}` - clog('Note: ', note) - clog('Note string: ', noteString) - clog('Commitment: ', toHex(depo.commitment)) - const proxy = await TornadoProxy.connect(accounts[i]) - - await expect(() => - proxy.deposit(TornadoInstance.address, toHex(depo.commitment), []), - ).to.changeTokenBalance( - RAIToken, - accounts[i], - BigNumber.from(0).sub(await TornadoInstance.denomination()), - ) - - let pevents = await mixerContract.queryFilter('Deposit') - await initialize({ merkleTreeHeight: 20 }) - - const { proof, args } = await generateProof({ - deposit: depo, - recipient: accounts[i].address, - events: pevents, - }) - - await expect(() => proxy.withdraw(TornadoInstance.address, proof, ...args)).to.changeTokenBalance( - RAIToken, - accounts[i], - await TornadoInstance.denomination(), - ) - } - }) - }) - - after(async function () { - await ethers.provider.send('hardhat_reset', [ - { - forking: { - jsonRpcUrl: `https://mainnet.infura.io/v3/${process.env.mainnet_rpc_key}`, - blockNumber: process.env.use_latest_block == 'true' ? undefined : 13017436, - }, - }, - ]) - }) -}) diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 0000000..7745595 --- /dev/null +++ b/test/utils.js @@ -0,0 +1,43 @@ +/* global ethers, network */ + +async function setTime(timestamp) { + await ethers.provider.send('evm_setNextBlockTimestamp', [timestamp]) +} + +async function takeSnapshot() { + return await ethers.provider.send('evm_snapshot', []) +} + +async function revertSnapshot(id) { + await ethers.provider.send('evm_revert', [id]) +} + +async function advanceTime(sec) { + const now = (await ethers.provider.getBlock('latest')).timestamp + await setTime(now + sec) +} + +async function getSignerFromAddress(address) { + await network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [address], + }) + + let signer = await ethers.provider.getSigner(address) + signer.address = signer._address + return signer +} + +async function minewait(time) { + await ethers.provider.send('evm_increaseTime', [time]) + await ethers.provider.send('evm_mine', []) +} + +module.exports = { + setTime, + advanceTime, + takeSnapshot, + revertSnapshot, + getSignerFromAddress, + minewait, +} diff --git a/yarn.lock b/yarn.lock index 6510af4..69b1d7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1232,6 +1232,13 @@ dependencies: "@ethersproject/logger" "^5.5.0" +"@ethersproject/networks@5.5.2": + version "5.5.2" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.5.2.tgz#784c8b1283cd2a931114ab428dae1bd00c07630b" + integrity sha512-NEqPxbGBfy6O3x4ZTISb90SjEDkWYDUbEeIFhJly0F7sZjoQMnj5KYzMSkMkLKZ+1fGpx00EDpHQCy6PrDupkQ== + dependencies: + "@ethersproject/logger" "^5.5.0" + "@ethersproject/networks@^5.4.0": version "5.4.2" resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.4.2.tgz#2247d977626e97e2c3b8ee73cd2457babde0ce35" @@ -1319,6 +1326,31 @@ bech32 "1.1.4" ws "7.4.6" +"@ethersproject/providers@5.5.3": + version "5.5.3" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.5.3.tgz#56c2b070542ac44eb5de2ed3cf6784acd60a3130" + integrity sha512-ZHXxXXXWHuwCQKrgdpIkbzMNJMvs+9YWemanwp1fA7XZEv7QlilseysPvQe0D7Q7DlkJX/w/bGA1MdgK2TbGvA== + dependencies: + "@ethersproject/abstract-provider" "^5.5.0" + "@ethersproject/abstract-signer" "^5.5.0" + "@ethersproject/address" "^5.5.0" + "@ethersproject/basex" "^5.5.0" + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/constants" "^5.5.0" + "@ethersproject/hash" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/networks" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + "@ethersproject/random" "^5.5.0" + "@ethersproject/rlp" "^5.5.0" + "@ethersproject/sha2" "^5.5.0" + "@ethersproject/strings" "^5.5.0" + "@ethersproject/transactions" "^5.5.0" + "@ethersproject/web" "^5.5.0" + bech32 "1.1.4" + ws "7.4.6" + "@ethersproject/random@5.4.0", "@ethersproject/random@^5.4.0": version "5.4.0" resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.4.0.tgz#9cdde60e160d024be39cc16f8de3b9ce39191e16" @@ -1335,6 +1367,14 @@ "@ethersproject/bytes" "^5.5.0" "@ethersproject/logger" "^5.5.0" +"@ethersproject/random@5.5.1": + version "5.5.1" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.5.1.tgz#7cdf38ea93dc0b1ed1d8e480ccdaf3535c555415" + integrity sha512-YaU2dQ7DuhL5Au7KbcQLHxcRHfgyNgvFV4sQOo0HrtW3Zkrc9ctWNz8wXQ4uCSfSDsqX2vcjhroxU5RQRV0nqA== + dependencies: + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/rlp@5.4.0", "@ethersproject/rlp@^5.4.0": version "5.4.0" resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.4.0.tgz#de61afda5ff979454e76d3b3310a6c32ad060931" @@ -1546,6 +1586,17 @@ "@ethersproject/properties" "^5.5.0" "@ethersproject/strings" "^5.5.0" +"@ethersproject/web@5.5.1": + version "5.5.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.5.1.tgz#cfcc4a074a6936c657878ac58917a61341681316" + integrity sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg== + dependencies: + "@ethersproject/base64" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + "@ethersproject/strings" "^5.5.0" + "@ethersproject/wordlists@5.4.0", "@ethersproject/wordlists@^5.4.0": version "5.4.0" resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.4.0.tgz#f34205ec3bbc9e2c49cadaee774cf0b07e7573d7" @@ -1568,6 +1619,37 @@ "@ethersproject/properties" "^5.5.0" "@ethersproject/strings" "^5.5.0" +"@gnosis.pm/ido-contracts@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@gnosis.pm/ido-contracts/-/ido-contracts-0.5.0.tgz#83de88dece517d5f1069ec32bd2eebd1857ef3ac" + integrity sha512-4q7bB4c+7zFvIlolg/Xo1rRFcecAO+zLdIQ2am5zXKnii0Txz3Ki4yXzg7/nbBHMPZZANLmVgXe0ZDiGS5OsIw== + dependencies: + "@gnosis.pm/solidity-data-structures" "^1.3.4" + "@types/yargs" "^15.0.10" + argv "^0.0.2" + axios "^0.21.1" + bn.js "^5.1.1" + dotenv "^8.2.0" + ethers "^5.0.22" + solc "0.6.8" + yargs "^16.1.1" + +"@gnosis.pm/solidity-data-structures@^1.3.4": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@gnosis.pm/solidity-data-structures/-/solidity-data-structures-1.3.5.tgz#a38cab984a5a4c7d379454d5e82a2ac2f1a6b65e" + integrity sha512-qU32sUlH1cE26uhSSTbCYpskYzMm4KBXaIZdpu9v2xsO6jjedgfg9rKxJcor1V4ZRBp4EQyFqWzPx7fPTTPoUQ== + dependencies: + "@gnosis.pm/util-contracts" "^2.0.4" + ethereumjs-util "^6.1.0" + merkletreejs "0.0.22" + +"@gnosis.pm/util-contracts@^2.0.4": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@gnosis.pm/util-contracts/-/util-contracts-2.0.7.tgz#b28073890a6a6be8458a7d7952c8541788fd020f" + integrity sha512-+8V0C/E4aGMudeMQBNDLidE3GwfM4XSySuT39wON8wpj9ocNyIsV4U+4YTfEOyUQ9PafKloWr78W5OhkOX9eqQ== + dependencies: + "@truffle/hdwallet-provider" "^1.0.42" + "@graphql-tools/batch-delegate@^6.2.4", "@graphql-tools/batch-delegate@^6.2.6": version "6.2.6" resolved "https://registry.yarnpkg.com/@graphql-tools/batch-delegate/-/batch-delegate-6.2.6.tgz#fbea98dc825f87ef29ea5f3f371912c2a2aa2f2c" @@ -1914,6 +1996,19 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== +"@iden3/bigarray@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@iden3/bigarray/-/bigarray-0.0.2.tgz#6fc4ba5be18daf8a26ee393f2fb62b80d98c05e9" + integrity sha512-Xzdyxqm1bOFF6pdIsiHLLl3HkSLjbhqJHVyqaTxXt3RqXBEnmsUmEW47H7VOi/ak7TdkRpNkxjyK5Zbkm+y52g== + +"@iden3/binfileutils@0.0.8": + version "0.0.8" + resolved "https://registry.yarnpkg.com/@iden3/binfileutils/-/binfileutils-0.0.8.tgz#d1d349bdbaa9f0a99644232c7d75ea0db98ea1c7" + integrity sha512-/GqTsujUssGuQY+sd/XaLrA+OiCwzm+6yH28C57QQDWCHET2Logry9fGxU10n6XKdhCQBjZ7T/YMQkLwwkpRTQ== + dependencies: + fastfile "0.0.19" + ffjavascript "^0.2.30" + "@improbable-eng/grpc-web@^0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@improbable-eng/grpc-web/-/grpc-web-0.12.0.tgz#9b10a7edf2a1d7672f8997e34a60e7b70e49738f" @@ -2051,7 +2146,22 @@ "@types/sinon-chai" "^3.2.3" "@types/web3" "1.0.19" -"@openzeppelin/contracts@3.4.2", "@openzeppelin/contracts@^3.2.0-rc.0", "@openzeppelin/contracts@^3.4.1": +"@openzeppelin/contracts@3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.2.0.tgz#3e6b3a7662d8ed64271ade96ef42655db983fd9d" + integrity sha512-bUOmkSoPkjnUyMiKo6RYnb0VHBk5D9KKDAgNLzF41aqAM3TeE0yGdFF5dVRcV60pZdJLlyFT/jjXIZCWyyEzAQ== + +"@openzeppelin/contracts@3.2.0-rc.0": + version "3.2.0-rc.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.2.0-rc.0.tgz#1f39e49df5f7a7b42fd49343ac1d758bbd24b826" + integrity sha512-EcEho5UFNZN1ZUHuD5ka38qgs+XWlzBM1FFfpu4YNVoo0xtwWeg7X52jm8pK+NYq8tJAI8ySjGYPM+4S5+N8iA== + +"@openzeppelin/contracts@3.4.1-solc-0.7-2": + version "3.4.1-solc-0.7-2" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.1-solc-0.7-2.tgz#371c67ebffe50f551c3146a9eec5fe6ffe862e92" + integrity sha512-tAG9LWg8+M2CMu7hIsqHPaTyG4uDzjr6mhvH96LvOpLZZj6tgzTluBt+LsCf1/QaYrlis6pITvpIaIhE+iZB+Q== + +"@openzeppelin/contracts@3.4.2", "@openzeppelin/contracts@^3.2.0-rc.0", "@openzeppelin/contracts@^3.4.0", "@openzeppelin/contracts@^3.4.1": version "3.4.2" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2.tgz#d81f786fda2871d1eb8a8c5a73e455753ba53527" integrity sha512-z0zMCjyhhp4y7XKAcDAi3Vgms4T2PstwBdahiO0+9NaGICQKjynK3wduSRplTgk4LXmoO1yfDGO5RbjKYxtuxA== @@ -2061,6 +2171,13 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.1.tgz#03c891fec7f93be0ae44ed74e57a122a38732ce7" integrity sha512-cUriqMauq1ylzP2TxePNdPqkwI7Le3Annh4K9rrpvKfSBB/bdW+Iu1ihBaTIABTAAJ85LmKL5SSPPL9ry8d1gQ== +"@openzeppelin/hardhat-upgrades@1.10.0": + version "1.10.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-1.10.0.tgz#e7751e3b9a005ccc9cef4e0de190628b181b59b6" + integrity sha512-iGe058iV7Ba/g11RxlbqBG47nbqbZn1FRdg1FCQq7xPmvjRhXmFsoI/5gGw5el0aZlLDRtpFOBZbzMZvI/S7iw== + dependencies: + "@openzeppelin/upgrades-core" "^1.9.0" + "@openzeppelin/upgrades-core@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@openzeppelin/upgrades-core/-/upgrades-core-1.0.1.tgz#2a3d81e3d3bdf5805b5492c47cdb21941ef57fdc" @@ -2077,6 +2194,20 @@ proper-lockfile "^4.1.1" solidity-ast "^0.4.1" +"@openzeppelin/upgrades-core@^1.5.1", "@openzeppelin/upgrades-core@^1.9.0": + version "1.12.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/upgrades-core/-/upgrades-core-1.12.0.tgz#847aeeba38780040672f8288795c824a4c9d97e6" + integrity sha512-gu/ijQW+RJqGlniNkpNmiwBus3R1cuJNT0/MEJASWRFNr4Qvn0d7LZONaAkhnvlBpxdiiPenMcFIrRlwvZL4iw== + dependencies: + bn.js "^5.1.2" + cbor "^8.0.0" + chalk "^4.1.0" + compare-versions "^4.0.0" + debug "^4.1.1" + ethereumjs-util "^7.0.3" + proper-lockfile "^4.1.1" + solidity-ast "^0.4.15" + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -2591,6 +2722,14 @@ event-iterator "^2.0.0" loglevel "^1.7.0" +"@ticket721/e712@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@ticket721/e712/-/e712-0.4.1.tgz#b9be3f5d9d01a8468e0a49eeed67fe4454c87582" + integrity sha512-JHqyb2HntsmLJ4PtlXQ2AoU+s42X1itRtxeCAlA1AxOMORXQudbhly9wvGhN/Hbcl8VYpfgLJKp4hK3AT6xDiw== + dependencies: + bn.js "5.1.1" + ethers "4.0.41" + "@truffle/abi-utils@^0.1.0": version "0.1.6" resolved "https://registry.yarnpkg.com/@truffle/abi-utils/-/abi-utils-0.1.6.tgz#d754a54caec2577efaa05f0ca66c58e73676884e" @@ -2818,6 +2957,20 @@ ethereumjs-util "^6.1.0" ethereumjs-wallet "^1.0.1" +"@truffle/hdwallet-provider@^1.0.42": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@truffle/hdwallet-provider/-/hdwallet-provider-1.7.0.tgz#5cfa8bc67c2a30b3943d3dab78f74c6a191cde02" + integrity sha512-nT7BPJJ2jPCLJc5uZdVtRnRMny5he5d3kO9Hi80ZSqe5xlnK905grBptM/+CwOfbeqHKQirI1btwm6r3wIBM8A== + dependencies: + "@ethereumjs/common" "^2.4.0" + "@ethereumjs/tx" "^3.3.0" + "@trufflesuite/web3-provider-engine" "15.0.14" + eth-sig-util "^3.0.1" + ethereum-cryptography "^0.1.3" + ethereum-protocol "^1.0.1" + ethereumjs-util "^6.1.0" + ethereumjs-wallet "^1.0.1" + "@truffle/interface-adapter@^0.5.8": version "0.5.8" resolved "https://registry.yarnpkg.com/@truffle/interface-adapter/-/interface-adapter-0.5.8.tgz#76cfd34374d85849e1164de1a3d5a3dce0dc5d01" @@ -3014,6 +3167,34 @@ xhr "^2.2.0" xtend "^4.0.1" +"@trufflesuite/web3-provider-engine@15.0.14": + version "15.0.14" + resolved "https://registry.yarnpkg.com/@trufflesuite/web3-provider-engine/-/web3-provider-engine-15.0.14.tgz#8f9696f434585cc0ab2e57c312090c1f138bc471" + integrity sha512-6/LoWvNMxYf0oaYzJldK2a9AdnkAdIeJhHW4nuUBAeO29eK9xezEaEYQ0ph1QRTaICxGxvn+1Azp4u8bQ8NEZw== + dependencies: + "@ethereumjs/tx" "^3.3.0" + "@trufflesuite/eth-json-rpc-filters" "^4.1.2-1" + "@trufflesuite/eth-json-rpc-infura" "^4.0.3-0" + "@trufflesuite/eth-json-rpc-middleware" "^4.4.2-1" + "@trufflesuite/eth-sig-util" "^1.4.2" + async "^2.5.0" + backoff "^2.5.0" + clone "^2.0.0" + cross-fetch "^2.1.0" + eth-block-tracker "^4.4.2" + eth-json-rpc-errors "^2.0.2" + ethereumjs-block "^1.2.2" + ethereumjs-util "^5.1.5" + ethereumjs-vm "^2.3.4" + json-stable-stringify "^1.0.1" + promise-to-callback "^1.0.0" + readable-stream "^2.2.9" + request "^2.85.0" + semaphore "^1.0.3" + ws "^5.1.1" + xhr "^2.2.0" + xtend "^4.0.1" + "@typechain/ethers-v5@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-2.0.0.tgz#cd3ca1590240d587ca301f4c029b67bfccd08810" @@ -3354,11 +3535,53 @@ dependencies: "@types/node" "*" +"@types/yargs-parser@*": + version "20.2.1" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" + integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== + +"@types/yargs@^15.0.10": + version "15.0.14" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" + integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== + dependencies: + "@types/yargs-parser" "*" + "@types/zen-observable@0.8.3": version "0.8.3" resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + +"@uniswap/lib@^4.0.1-alpha": + version "4.0.1-alpha" + resolved "https://registry.yarnpkg.com/@uniswap/lib/-/lib-4.0.1-alpha.tgz#2881008e55f075344675b3bca93f020b028fbd02" + integrity sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA== + +"@uniswap/v2-core@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@uniswap/v2-core/-/v2-core-1.0.1.tgz#af8f508bf183204779938969e2e54043e147d425" + integrity sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q== + +"@uniswap/v3-core@1.0.0", "@uniswap/v3-core@https://github.com/Tisamenus/uniswap-v3-core": + version "1.0.0" + resolved "https://github.com/Tisamenus/uniswap-v3-core#08bec74e0b902f97f34bdd47229ca4e61fbea1bd" + +"@uniswap/v3-periphery@https://github.com/Tisamenus/uniswap-v3-periphery": + version "1.1.1" + resolved "https://github.com/Tisamenus/uniswap-v3-periphery#928c03c5d67a4d6c9032fb000cf861c8b659d941" + dependencies: + "@openzeppelin/contracts" "3.4.1-solc-0.7-2" + "@uniswap/lib" "^4.0.1-alpha" + "@uniswap/v2-core" "1.0.1" + "@uniswap/v3-core" "1.0.0" + base64-sol "1.0.1" + hardhat-watcher "^2.1.1" + "@wry/context@^0.6.0": version "0.6.1" resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.6.1.tgz#c3c29c0ad622adb00f6a53303c4f965ee06ebeb2" @@ -3966,11 +4189,21 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + argsarray@0.0.1, argsarray@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/argsarray/-/argsarray-0.0.1.tgz#6e7207b4ecdb39b0af88303fa5ae22bda8df61cb" integrity sha1-bnIHtOzbObCviDA/pa4ivajfYcs= +argv@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" + integrity sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas= + arr-diff@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" @@ -4141,6 +4374,11 @@ async-retry@^1.2.1: dependencies: retry "0.13.1" +async@0.9.x: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= + async@1.x, async@^1.4.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -4214,6 +4452,13 @@ axios@^0.20.0: dependencies: follow-redirects "^1.10.0" +axios@^0.21.1: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -4855,6 +5100,11 @@ base64-js@^1.0.2, base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +base64-sol@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/base64-sol/-/base64-sol-1.0.1.tgz#91317aa341f0bc763811783c5729f1c2574600f6" + integrity sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -4908,6 +5158,11 @@ big-integer@^1.6.32, big-integer@^1.6.42, big-integer@^1.6.43: resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e" integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w== +big-integer@^1.6.48: + version "1.6.51" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" + integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -5020,6 +5275,12 @@ blake2b-wasm@^1.1.0: dependencies: nanoassert "^1.0.0" +"blake2b-wasm@https://github.com/jbaylina/blake2b-wasm.git": + version "2.1.0" + resolved "https://github.com/jbaylina/blake2b-wasm.git#0d5f024b212429c7f50a7f533aa3a2406b5b42b3" + dependencies: + nanoassert "^1.0.0" + blake2b@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/blake2b/-/blake2b-2.1.3.tgz#f5388be424768e7c6327025dad0c3c6d83351bca" @@ -5060,7 +5321,12 @@ bn.js@4.11.8, bn.js@=4.11.8: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.1, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.8.0: +bn.js@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.1.tgz#48efc4031a9c4041b9c99c6941d903463ab62eb5" + integrity sha512-IUTD/REb78Z2eodka1QZyyEk66pciRcP6Sroka0aI3tG/iwIdYLrBD62RsubR7vqdt3WyX8p4jxeatzmRSphtA== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.1, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.4.0, bn.js@^4.8.0: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== @@ -5377,6 +5643,11 @@ buffer-pipe@0.0.3: dependencies: safe-buffer "^5.1.2" +buffer-reverse@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-reverse/-/buffer-reverse-1.0.1.tgz#49283c8efa6f901bc01fa3304d06027971ae2f60" + integrity sha1-SSg8jvpvkBvAH6MwTQYCeXGuL2A= + buffer-to-arraybuffer@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" @@ -5569,6 +5840,11 @@ camelcase@^5.0.0, camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + caniuse-lite@^1.0.30000844: version "1.0.30001246" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001246.tgz#fe17d9919f87124d6bb416ef7b325356d69dc76c" @@ -5592,6 +5868,13 @@ cbor@^5.0.2, cbor@^5.1.0: bignumber.js "^9.0.1" nofilter "^1.0.4" +cbor@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-8.1.0.tgz#cfc56437e770b73417a2ecbfc9caf6b771af60d5" + integrity sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg== + dependencies: + nofilter "^3.1.0" + center-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" @@ -5775,6 +6058,21 @@ chokidar@3.4.2: optionalDependencies: fsevents "~2.1.2" +chokidar@3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" + integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.5.0" + optionalDependencies: + fsevents "~2.3.1" + chokidar@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" @@ -5809,6 +6107,21 @@ chokidar@^3.4.0, chokidar@^3.4.1: optionalDependencies: fsevents "~2.3.2" +chokidar@^3.4.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chownr@^1.1.1, chownr@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -5857,6 +6170,69 @@ circom@0.0.35, circom@^0.0.35: optimist "^0.6.1" yargs "^12.0.2" +circom@0.5.33: + version "0.5.33" + resolved "https://registry.yarnpkg.com/circom/-/circom-0.5.33.tgz#6943d5799adf5388989bfbb3ef8f502fb1b4f662" + integrity sha512-UdL8fr6GckhQ4VoWjIvuYwCHneJe8z/AyJpDxgKLyuaX51ijd4gBP6jlwHDbQJsha2aU2GR9qgDsxd0jfari1Q== + dependencies: + chai "^4.2.0" + circom_runtime "0.1.8" + fastfile "0.0.18" + ffiasm "0.1.1" + ffjavascript "0.2.22" + ffwasm "0.0.7" + fnv-plus "^1.3.1" + r1csfile "0.0.16" + tmp-promise "^2.0.2" + wasmbuilder "0.0.10" + +circom@0.5.42: + version "0.5.42" + resolved "https://registry.yarnpkg.com/circom/-/circom-0.5.42.tgz#96a456f9538f4425654df091d15e3158e9da2acc" + integrity sha512-v6+f9g3z2ia17NQvQmyZjvh8cE8O3GtxRE36KfJfx/a+s58Y7aEDWsUG+GFRJhp1ajiQELdj3NehY9vHSf5Rkg== + dependencies: + chai "^4.2.0" + circom_runtime "0.1.12" + fastfile "0.0.18" + ffiasm "0.1.1" + ffjavascript "0.2.22" + ffwasm "0.0.7" + fnv-plus "^1.3.1" + r1csfile "0.0.16" + tmp-promise "^2.0.2" + wasmbuilder "0.0.10" + +circom_runtime@0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/circom_runtime/-/circom_runtime-0.1.12.tgz#e1a302c6fe8cec390f035c2e7a8496cfa7cfb4a2" + integrity sha512-R+QT9HS9w71cmGmWIn+PSyD3aHyR5JZBiVvxOjCfn12wwnpuFwBjdMG7he+v8h/oQD1mDRAu2KrBeL4mAt5s4A== + dependencies: + ffjavascript "0.2.34" + fnv-plus "^1.3.1" + +circom_runtime@0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/circom_runtime/-/circom_runtime-0.1.13.tgz#90f86f35d989c48d4c27595b94664ea6918fbede" + integrity sha512-vmv19/0p5OTe5uCI7PWqPtB5vPoYWjczqKYnabaC5HOxX99R4K1MuNqEXsNEAoEfZrmfAQd7vXLcATN9NVnsPA== + dependencies: + ffjavascript "0.2.35" + fnv-plus "^1.3.1" + +circom_runtime@0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/circom_runtime/-/circom_runtime-0.1.8.tgz#d967a1618fe5290849f9c0bbffb6b97b95c0f1c8" + integrity sha512-5ZmzCyidkNPb1zZsJGRXTuWcJ6kW6+gRBtHgf2tFqTh5dUyWVVPH0Zg7AsU2ijPr1AmYZUlme0yORUZK5HrjOA== + dependencies: + ffjavascript "0.2.10" + fnv-plus "^1.3.1" + +circom_runtime@^0.1.12: + version "0.1.17" + resolved "https://registry.yarnpkg.com/circom_runtime/-/circom_runtime-0.1.17.tgz#9360017d6b5d9291128da4fe05830384ef293ec1" + integrity sha512-FCOCPz7ZbqL4TpzBlISRZ7/fcYHkdZz0DMfju1DYHiRU/+ZzJQfDS8JYENlnb9PO+HsLTr6/QtzphqvnEBp9AQ== + dependencies: + ffjavascript "0.2.48" + "circomlib@git+https://github.com/tornadocash/circomlib.git#3b492f9801573eebcfe1b6c584afe8a3beecf2b4": version "0.0.20" resolved "git+https://github.com/tornadocash/circomlib.git#3b492f9801573eebcfe1b6c584afe8a3beecf2b4" @@ -5887,6 +6263,15 @@ circom@0.0.35, circom@^0.0.35: typedarray-to-buffer "^3.1.5" web3 "^1.0.0-beta.55" +"circomlib@git+https://github.com/tornadocash/circomlib.git#d20d53411d1bef61f38c99a8b36d5d0cc4836aa1": + version "0.4.1" + resolved "git+https://github.com/tornadocash/circomlib.git#d20d53411d1bef61f38c99a8b36d5d0cc4836aa1" + dependencies: + blake-hash "^1.1.0" + blake2b "^2.1.3" + circom "0.5.33" + ffjavascript "0.1.0" + circular-json@^0.5.9: version "0.5.9" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" @@ -5976,6 +6361,15 @@ cliui@^6.0.0: strip-ansi "^6.0.0" wrap-ansi "^6.2.0" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + clone-buffer@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" @@ -6121,6 +6515,11 @@ compare-versions@^3.6.0: resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== +compare-versions@^4.0.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-4.1.3.tgz#8f7b8966aef7dc4282b45dfa6be98434fc18a1a4" + integrity sha512-WQfnbDcrYnGr55UwbxKiQKASnTtNnaAWVi8jZyy8NTpVAXWACSne8lMD1iaIo9AiU6mnuLvSVshCzewVuWxHUg== + component-emitter@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" @@ -6429,6 +6828,11 @@ crypto-browserify@3.12.0, crypto-browserify@^3.0.0, crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +crypto-js@^3.1.9-1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.3.0.tgz#846dd1cce2f68aacfa156c8578f926a609b7976b" + integrity sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q== + css-select@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" @@ -6568,6 +6972,13 @@ debug@4.1.1: dependencies: ms "^2.1.1" +debug@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + debug@^3.1.0, debug@^3.2.6: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -6580,6 +6991,16 @@ decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +decimal.js@^10.2.0: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -6821,6 +7242,11 @@ diff@4.0.2: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -7022,6 +7448,13 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= +ejs@^3.0.1: + version "3.1.6" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.6.tgz#5bfd0a0689743bb5268b3550cceeebbc1702822a" + integrity sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw== + dependencies: + jake "^10.6.1" + electron-fetch@^1.7.2: version "1.7.4" resolved "https://registry.yarnpkg.com/electron-fetch/-/electron-fetch-1.7.4.tgz#af975ab92a14798bfaa025f88dcd2e54a7b0b769" @@ -7039,6 +7472,19 @@ electron-to-chromium@^1.3.878: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.879.tgz#4aba9700cfb241fb95c6ed69e31785e3d1605a43" integrity sha512-zJo+D9GwbJvM31IdFmwcGvychhk4KKbKYo2GWlsn+C/dxz2NwmbhGJjWwTfFSF2+eFH7VvfA8MCZ8SOqTrlnpw== +elliptic@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" + integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" @@ -8147,6 +8593,21 @@ ethereumjs-wallet@^1.0.1: utf8 "^3.0.0" uuid "^8.3.2" +ethers@4.0.41: + version "4.0.41" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.41.tgz#a0cff526f08c2e08c525cf82ef4483f6333b8000" + integrity sha512-QpW2CPZajquwiA7rVDozMksOuvdUBKIruamAakt0++EKBB/VWtLB9zSRZDInLDpp9fZYgOT/0trPD38r6CzLIg== + dependencies: + aes-js "3.0.0" + bn.js "^4.4.0" + elliptic "6.5.2" + hash.js "1.1.3" + js-sha3 "0.5.7" + scrypt-js "2.0.4" + setimmediate "1.0.4" + uuid "2.0.1" + xmlhttprequest "1.8.0" + ethers@^4.0.32: version "4.0.49" resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894" @@ -8234,6 +8695,42 @@ ethers@^5.0.13: "@ethersproject/web" "5.5.0" "@ethersproject/wordlists" "5.5.0" +ethers@^5.0.22, ethers@^5.5.1: + version "5.5.4" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.5.4.tgz#e1155b73376a2f5da448e4a33351b57a885f4352" + integrity sha512-N9IAXsF8iKhgHIC6pquzRgPBJEzc9auw3JoRkaKe+y4Wl/LFBtDDunNe7YmdomontECAcC5APaAgWZBiu1kirw== + dependencies: + "@ethersproject/abi" "5.5.0" + "@ethersproject/abstract-provider" "5.5.1" + "@ethersproject/abstract-signer" "5.5.0" + "@ethersproject/address" "5.5.0" + "@ethersproject/base64" "5.5.0" + "@ethersproject/basex" "5.5.0" + "@ethersproject/bignumber" "5.5.0" + "@ethersproject/bytes" "5.5.0" + "@ethersproject/constants" "5.5.0" + "@ethersproject/contracts" "5.5.0" + "@ethersproject/hash" "5.5.0" + "@ethersproject/hdnode" "5.5.0" + "@ethersproject/json-wallets" "5.5.0" + "@ethersproject/keccak256" "5.5.0" + "@ethersproject/logger" "5.5.0" + "@ethersproject/networks" "5.5.2" + "@ethersproject/pbkdf2" "5.5.0" + "@ethersproject/properties" "5.5.0" + "@ethersproject/providers" "5.5.3" + "@ethersproject/random" "5.5.1" + "@ethersproject/rlp" "5.5.0" + "@ethersproject/sha2" "5.5.0" + "@ethersproject/signing-key" "5.5.0" + "@ethersproject/solidity" "5.5.0" + "@ethersproject/strings" "5.5.0" + "@ethersproject/transactions" "5.5.0" + "@ethersproject/units" "5.5.0" + "@ethersproject/wallet" "5.5.0" + "@ethersproject/web" "5.5.1" + "@ethersproject/wordlists" "5.5.0" + ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -8549,6 +9046,16 @@ fastestsmallesttextencoderdecoder@^1.0.22: resolved "https://registry.yarnpkg.com/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz#59b47e7b965f45258629cc6c127bf783281c5e93" integrity sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw== +fastfile@0.0.18: + version "0.0.18" + resolved "https://registry.yarnpkg.com/fastfile/-/fastfile-0.0.18.tgz#2b69bbbfd2fcccc9bc8099c27de1379b89756a4b" + integrity sha512-q03PTKc+wptis4WmuFOwPNQx2p5myFUrl/dMgRlW9mymc1Egyc14JPHgiGnWK+sJ0+dBl2Vwtfh5GfSQltYOpw== + +fastfile@0.0.19: + version "0.0.19" + resolved "https://registry.yarnpkg.com/fastfile/-/fastfile-0.0.19.tgz#02cef9ade123b0a74adb794f4a1abcfa5719fd46" + integrity sha512-tz9nWR5KYb6eR2odFQ7oxqEkx8F3YQZ6NBJoJR92YEG3DqYOqyxMck8PKvTVNKx3uwvOqGnLXNScnqpdHRdHGQ== + fastq@^1.6.0: version "1.13.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" @@ -8603,6 +9110,86 @@ fetch-ponyfill@^4.0.0: dependencies: node-fetch "~1.7.1" +ffiasm@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ffiasm/-/ffiasm-0.1.1.tgz#34ca6a00a875b5a926f66fd46e79530194e9c312" + integrity sha512-irMMHiR9JJ7BVBrAhtliUawxVdPYSdyl81taUYJ4C1mJ0iw2ueThE/qtr0J8B83tsIY8HJvh0lg5F+6ClK4xpA== + dependencies: + big-integer "^1.6.48" + ejs "^3.0.1" + yargs "^15.3.1" + +ffiasm@^0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/ffiasm/-/ffiasm-0.1.4.tgz#d84b6d656e6b28b1aff1eefbc3d31609c07127a3" + integrity sha512-3WmLCxWAr9n/lyvMJuB+rXXnQ4C0Md9UxQIL6ZT3a+Ux9OcMR0+Qj6UE0LfOYny0Lq7KuvyYtDCZL9+wwMNGUg== + dependencies: + big-integer "^1.6.48" + ejs "^3.0.1" + yargs "^15.3.1" + +ffjavascript@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.1.0.tgz#456256c259654cc1ce864c6762b0e76ee1714100" + integrity sha512-dmKlUasSfvUcxBm8nCSKl2x7EFJsXA7OVP8XLFA03T2+6mAc3IiVLC2ambEVOcMOhyhl0vJfVZjM9f9d38D1rw== + dependencies: + big-integer "^1.6.48" + +ffjavascript@0.2.10: + version "0.2.10" + resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.10.tgz#b0bf88d69be0b51e0bd28e1966c4a6fb29a86682" + integrity sha512-GQI6gHYYG5/iD4Kt3VzezzK7fARJzP0zkc82V/+JAdjfeKBXhDSo5rpKFuK3cDcrdW0Fu2emuYNMEAuFqhEQvQ== + dependencies: + big-integer "^1.6.48" + wasmcurves "0.0.5" + worker-threads "^1.0.0" + +ffjavascript@0.2.22: + version "0.2.22" + resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.22.tgz#101f33db330b0f6a0c10dec22ebf5725618a8a7d" + integrity sha512-EsVqap2Txm17bKW0z/jXCX3M7rQ++nQUAJY8alWDpyhjRj90xjl6GLeVSKZQ8rOFDQ/SFFXcEB8w9X8Boxid+w== + dependencies: + big-integer "^1.6.48" + wasmcurves "0.0.12" + worker-threads "^1.0.0" + +ffjavascript@0.2.34: + version "0.2.34" + resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.34.tgz#e0607d1635ad06e8519268af475bc90deac60fbd" + integrity sha512-fq/qfJluC4spiOD1lp5jfckZVnS0o0kI5eKXVLw7UKwIwbNr+NBMBveBVcidSfMizF87T6wb7NBtLSdckQiAnQ== + dependencies: + big-integer "^1.6.48" + mocha "^8.2.1" + wasmcurves "0.0.14" + worker-threads "^1.0.0" + +ffjavascript@0.2.35: + version "0.2.35" + resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.35.tgz#9166d95173b1c0a743b455bb03a72b581922a42e" + integrity sha512-xnC51tWbi0ah4SH+02jEfJyO+P+NiZWnxQrLDLtBYY1Dv3QM5ydxzd+gxnLEfWdT8i1bMM5pIh5P25l6fNCaVQ== + dependencies: + big-integer "^1.6.48" + wasmcurves "0.0.14" + web-worker "^1.0.0" + +ffjavascript@0.2.48, ffjavascript@^0.2.30, ffjavascript@^0.2.35: + version "0.2.48" + resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.48.tgz#0ca408471d7b18bfc096a9631aa3ef3549c8c82b" + integrity sha512-uNrWP+odLofNmmO+iCCPi/Xt/sJh1ku3pVKmKWVWCLFfdCP69hvRrogKUIGnsdiINcWn0lGxcEh5oEjStMFXQQ== + dependencies: + big-integer "^1.6.48" + wasmbuilder "^0.0.12" + wasmcurves "0.1.0" + web-worker "^1.2.0" + +ffwasm@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ffwasm/-/ffwasm-0.0.7.tgz#23bb9a3537ecc87c0f24fcfb3a9ddd0e86855fff" + integrity sha512-17cTLzv7HHAKqZbX8MvHxjSrR0yDdn1sh4TVsTbAvO9e6klhFicnyoVXc/sCuViV/M8g65sCmVrAmoPCZp1YkQ== + dependencies: + big-integer "^1.6.48" + wasmbuilder "0.0.10" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -8652,6 +9239,13 @@ filecoin.js@^0.0.5-alpha: websocket "^1.0.31" ws "^7.3.1" +filelist@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b" + integrity sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ== + dependencies: + minimatch "^3.0.4" + filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" @@ -8764,6 +9358,14 @@ first-chunk-stream@^1.0.0: resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" integrity sha1-Wb+1DNkF9g18OUzT2ayqtOatk04= +fixed-merkle-tree@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/fixed-merkle-tree/-/fixed-merkle-tree-0.3.4.tgz#533888cfacca00f0b4e26c952173be7e456ae63a" + integrity sha512-0nDwPR/WV9nViiItNGr3A8LDCh27JDEqemW2I0i1HK6kkpvPzXfoBSolPXmqg0eo2i/UMwlxF2d6m0F/vyfeMA== + dependencies: + circomlib "git+https://github.com/tornadocash/circomlib.git#5beb6aee94923052faeecea40135d45b6ce6172c" + snarkjs "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5" + fixed-merkle-tree@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/fixed-merkle-tree/-/fixed-merkle-tree-0.5.1.tgz#770bbf64b174e88b1133841721b79ea99a63d0b5" @@ -8804,6 +9406,11 @@ flat@^4.1.0: dependencies: is-buffer "~2.0.3" +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + flatted@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" @@ -8819,6 +9426,11 @@ flow-stoplight@^1.0.0: resolved "https://registry.yarnpkg.com/flow-stoplight/-/flow-stoplight-1.0.0.tgz#4a292c5bcff8b39fa6cc0cb1a853d86f27eeff7b" integrity sha1-SiksW8/4s5+mzAyxqFPYbyfu/3s= +fnv-plus@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/fnv-plus/-/fnv-plus-1.3.1.tgz#c34cb4572565434acb08ba257e4044ce2b006d67" + integrity sha512-Gz1EvfOneuFfk4yG458dJ3TLJ7gV19q3OM/vVvvHf7eT02Hm1DleB4edsia6ahbKgAYxO9gvyQ1ioWZR+a00Yw== + follow-redirects@1.5.10: version "1.5.10" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" @@ -8836,6 +9448,11 @@ follow-redirects@^1.12.1: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== +follow-redirects@^1.14.0: + version "1.14.8" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" + integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== + for-each@^0.3.3, for-each@~0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -9020,7 +9637,7 @@ fsevents@~2.1.1, fsevents@~2.1.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== -fsevents@~2.3.2: +fsevents@~2.3.1, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -9118,7 +9735,7 @@ get-caller-file@^1.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== -get-caller-file@^2.0.1: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -9604,6 +10221,13 @@ hardhat-log-remover@^2.0.2: resolved "https://registry.yarnpkg.com/hardhat-log-remover/-/hardhat-log-remover-2.0.2.tgz#6014fe2c515ced1e0eaa7a4d854e37695aaac61a" integrity sha512-TvEWOisQmZUZ7Mlb7s4XYS/MxgZzjFJSjDI8v3uTcrD6aaXy1QtomW6D6WNsISEWtwwRlSntOGpHQwFjrz2MCw== +hardhat-watcher@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/hardhat-watcher/-/hardhat-watcher-2.1.1.tgz#8b05fec429ed45da11808bbf6054a90f3e34c51a" + integrity sha512-zilmvxAYD34IofBrwOliQn4z92UiDmt2c949DW4Gokf0vS0qk4YTfVCi/LmUBICThGygNANE3WfnRTpjCJGtDA== + dependencies: + chokidar "^3.4.3" + hardhat@^2.4.3: version "2.6.0" resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.6.0.tgz#a00a44d36559a880c170dca6363cc33f7545364b" @@ -9809,7 +10433,7 @@ highlightjs-solidity@^2.0.1: resolved "https://registry.yarnpkg.com/highlightjs-solidity/-/highlightjs-solidity-2.0.1.tgz#ee1beb6f353d4503aa3a011bbb86577976365b59" integrity sha512-9YY+HQpXMTrF8HgRByjeQhd21GXAz2ktMPTcs6oWSj5HJR52fgsNoelMOmgigwcpt9j4tu4IVSaWaJB2n2TbvQ== -hmac-drbg@^1.0.1: +hmac-drbg@^1.0.0, hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= @@ -10362,7 +10986,7 @@ is-buffer@^1.1.0, is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-buffer@~2.0.3: +is-buffer@^2.0.3, is-buffer@~2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== @@ -10617,7 +11241,7 @@ is-plain-obj@^1.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= -is-plain-obj@^2.0.0: +is-plain-obj@^2.0.0, is-plain-obj@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== @@ -10927,6 +11551,16 @@ iterate-value@^1.0.0: es-get-iterator "^1.0.2" iterate-iterator "^1.0.1" +jake@^10.6.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b" + integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A== + dependencies: + async "0.9.x" + chalk "^2.4.2" + filelist "^1.0.1" + minimatch "^3.0.4" + js-sha3@0.5.7, js-sha3@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" @@ -10971,6 +11605,13 @@ js-yaml@3.x, js-yaml@^3.13.0, js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f" + integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q== + dependencies: + argparse "^2.0.1" + jsan@^3.1.13: version "3.1.13" resolved "https://registry.yarnpkg.com/jsan/-/jsan-3.1.13.tgz#4de8c7bf8d1cfcd020c313d438f930cec4b91d86" @@ -11213,6 +11854,11 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jssha@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jssha/-/jssha-3.2.0.tgz#88ec50b866dd1411deaddbe6b3e3692e4c710f16" + integrity sha512-QuruyBENDWdN4tZwJbQq7/eAK85FqrI4oDbXjy5IBhYD+2pTJyBUWZe8ctWaCkrV0gy6AaelgOZZBMeswEa/6Q== + keccak@3.0.1, keccak@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.1.tgz#ae30a0e94dbe43414f741375cff6d64c8bea0bff" @@ -11892,6 +12538,11 @@ loglevel@^1.6.6, loglevel@^1.6.7, loglevel@^1.6.8, loglevel@^1.7.0: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== +logplease@^1.2.15: + version "1.2.15" + resolved "https://registry.yarnpkg.com/logplease/-/logplease-1.2.15.tgz#3da442e93751a5992cc19010a826b08d0293c48a" + integrity sha512-jLlHnlsPSJjpwUfcNyUxXCl33AYg2cHhIf9QhGL2T4iPT0XPB+xP1LRKFPgIg1M/sg9kAJvy94w9CzBNrfnstA== + long@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" @@ -12176,6 +12827,16 @@ merkle-patricia-tree@^4.2.0: rlp "^2.2.4" semaphore-async-await "^1.5.1" +merkletreejs@0.0.22: + version "0.0.22" + resolved "https://registry.yarnpkg.com/merkletreejs/-/merkletreejs-0.0.22.tgz#ccc1008cdfa8f5a01a4f735f91c7a29c34070b6c" + integrity sha512-oZF3PIoRRmbG1ikN/3c0n0i421ZzdyOpNbm6wDNt5LVLIpW2FCany8ERwOyAZq83vM+Nx1zTp7Br7cIpicWzNQ== + dependencies: + buffer-reverse "^1.0.1" + crypto-js "^3.1.9-1" + is-buffer "^2.0.3" + treeify "^1.1.0" + meros@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/meros/-/meros-1.1.4.tgz#c17994d3133db8b23807f62bec7f0cb276cfd948" @@ -12294,7 +12955,7 @@ minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimalistic-crypto-utils@^1.0.1: +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= @@ -12453,6 +13114,37 @@ mocha@^7.1.2: yargs-parser "13.1.2" yargs-unparser "1.6.0" +mocha@^8.2.1: + version "8.4.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.4.0.tgz#677be88bf15980a3cae03a73e10a0fc3997f0cff" + integrity sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.1" + debug "4.3.1" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.1.6" + growl "1.10.5" + he "1.2.0" + js-yaml "4.0.0" + log-symbols "4.0.0" + minimatch "3.0.4" + ms "2.1.3" + nanoid "3.1.20" + serialize-javascript "5.0.1" + strip-json-comments "3.1.1" + supports-color "8.1.1" + which "2.0.2" + wide-align "1.1.3" + workerpool "6.1.0" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + mock-fs@^4.1.0: version "4.14.0" resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" @@ -12507,7 +13199,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: +ms@2.1.3, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -12669,6 +13361,11 @@ nanoassert@^1.0.0: resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-1.1.0.tgz#4f3152e09540fde28c76f44b19bbcd1d5a42478d" integrity sha1-TzFS4JVA/eKMdvRLGbvNHVpCR40= +nanoid@3.1.20: + version "3.1.20" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" + integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw== + nanoid@^2.0.0: version "2.1.11" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" @@ -12921,6 +13618,11 @@ nofilter@^1.0.4: resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-1.0.4.tgz#78d6f4b6a613e7ced8b015cec534625f7667006e" integrity sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA== +nofilter@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-3.1.0.tgz#c757ba68801d41ff930ba2ec55bab52ca184aa66" + integrity sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g== + noop-fn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/noop-fn/-/noop-fn-1.0.0.tgz#5f33d47f13d2150df93e0cb036699e982f78ffbf" @@ -14414,6 +15116,25 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +r1csfile@0.0.16: + version "0.0.16" + resolved "https://registry.yarnpkg.com/r1csfile/-/r1csfile-0.0.16.tgz#53c66a79b50eebc2d15a1048e39d548ce9da7ccd" + integrity sha512-A2jRVWzGgmXeG2lVAc0H4suJmzt50it5UvBnycJgBCpMXM3tH/M6RguP7nvs6suY/yYnkN6jX6iTScSiDUF3FA== + dependencies: + "@iden3/bigarray" "0.0.2" + fastfile "0.0.18" + ffjavascript "0.2.22" + +r1csfile@0.0.32: + version "0.0.32" + resolved "https://registry.yarnpkg.com/r1csfile/-/r1csfile-0.0.32.tgz#64a6c63ff76b737b3ee22bcedb2bb9a033cbeb1a" + integrity sha512-DkRXeOg0iRmfhgIuWICvdkOiLHpyb7+AcUd/WHpqBJEUp27pe7wKXBR4Jr3TPYCT4sTV9a/F3bovyAC4wystnQ== + dependencies: + "@iden3/bigarray" "0.0.2" + "@iden3/binfileutils" "0.0.8" + fastfile "0.0.19" + ffjavascript "0.2.35" + randomatic@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" @@ -14621,6 +15342,13 @@ readdirp@~3.4.0: dependencies: picomatch "^2.2.1" +readdirp@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" + integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== + dependencies: + picomatch "^2.2.1" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -14628,6 +15356,11 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +readline@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/readline/-/readline-1.3.0.tgz#c580d77ef2cfc8752b132498060dc9793a7ac01c" + integrity sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw= + receptacle@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/receptacle/-/receptacle-1.3.2.tgz#a7994c7efafc7a01d0e2041839dab6c4951360d2" @@ -15039,7 +15772,7 @@ rimraf@^2.2.8, rimraf@^2.6.1, rimraf@^2.6.3: dependencies: glob "^7.1.3" -rimraf@^3.0.2: +rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -15298,6 +16031,13 @@ serialize-javascript@4.0.0: dependencies: randombytes "^2.1.0" +serialize-javascript@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" + integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== + dependencies: + randombytes "^2.1.0" + serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" @@ -15542,6 +16282,20 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +snarkjs@^0.3.57: + version "0.3.60" + resolved "https://registry.yarnpkg.com/snarkjs/-/snarkjs-0.3.60.tgz#fe573e347a924af8ed162154e866e02ef8d8230c" + integrity sha512-l3QMKvr+KUetxlJq9TCS0KNxiUquUDYFqHIzn3TxNSPPlcQfIq6V0isZKCjuML+XNGaoJ7s+kfdAZ8qp/2yOYQ== + dependencies: + "@iden3/binfileutils" "0.0.8" + blake2b-wasm "https://github.com/jbaylina/blake2b-wasm.git" + circom_runtime "0.1.13" + fastfile "0.0.19" + ffjavascript "0.2.35" + logplease "^1.2.15" + r1csfile "0.0.32" + readline "^1.3.0" + "snarkjs@git+https://github.com/peppersec/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5": version "0.1.20" uid "869181cfaf7526fe8972073d31655493a04326d5" @@ -15581,6 +16335,20 @@ socketcluster-client@^14.2.1: uuid "3.2.1" ws "^7.5.0" +solc@0.6.8: + version "0.6.8" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.6.8.tgz#accf03634554938e166ba9b9853d17ca5c728131" + integrity sha512-7URBAisWVjO7dwWNpEkQ5dpRSpSF4Wm0aD5EB82D5BQKh+q7jhOxhgkG4K5gax/geM0kPZUAxnaLcgl2ZXBgMQ== + dependencies: + command-exists "^1.2.8" + commander "3.0.2" + fs-extra "^0.30.0" + js-sha3 "0.8.0" + memorystream "^0.3.1" + require-from-string "^2.0.0" + semver "^5.5.0" + tmp "0.0.33" + solc@0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" @@ -15633,6 +16401,11 @@ solidity-ast@^0.4.1: resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.26.tgz#6e644bdb897c245dd07695a63ffa95edfe02c11f" integrity sha512-UR9Ip3QoiEvNON5lOA28JNEzKT+1fLFA4xpIbZSEl4CEnYr/a4Pj0qMJh0652UQ51pKplI/nncZsDOMzdHdCcg== +solidity-ast@^0.4.15: + version "0.4.30" + resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.30.tgz#402d8277311d6680c786f756ba27e1c19f809293" + integrity sha512-3xsQIbZEPx6w7+sQokuOvk1RkMb5GIpuK0GblQDIH6IAkU4+uyJQVJIRNP+8KwhzkViwRKq0hS4zLqQNLKpxOA== + solidity-comments-extractor@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" @@ -16087,7 +16860,7 @@ strip-json-comments@3.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -16139,6 +16912,13 @@ supports-color@7.1.0: dependencies: has-flag "^4.0.0" +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -16439,6 +17219,20 @@ title-case@^2.1.0: no-case "^2.2.0" upper-case "^1.0.3" +tmp-promise@^2.0.2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-2.1.1.tgz#eb97c038995af74efbfe8156f5e07fdd0c935539" + integrity sha512-Z048AOz/w9b6lCbJUpevIJpRpUztENl8zdv1bmAKVHimfqRFl92ROkmT9rp7TVBnrEw2gtMTol/2Cp2S2kJa4Q== + dependencies: + tmp "0.1.0" + +tmp-promise@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-3.0.3.tgz#60a1a1cc98c988674fcbfd23b6e3367bdeac4ce7" + integrity sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ== + dependencies: + tmp "^0.2.0" + tmp@0.0.33, tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -16453,6 +17247,13 @@ tmp@0.1.0: dependencies: rimraf "^2.6.3" +tmp@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + to-absolute-glob@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f" @@ -16544,6 +17345,20 @@ torn-token@^1.0.0, torn-token@^1.0.4: ethereumjs-util "^7.0.3" web3 "^1.2.11" +tornado-anonymity-mining@^2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/tornado-anonymity-mining/-/tornado-anonymity-mining-2.1.5.tgz#7dbc7f099ce9667f2cc91fbb7ce8f78663afc4cc" + integrity sha512-hYXKHyPs7nqpGjPgWpuBJrnDSTZ4FifU8Mv/ujueYXVOzkcL64ZOq30JFDE6ANQ7D09AhD7B7pSx/Odgn+nlgw== + dependencies: + circomlib "git+https://github.com/tornadocash/circomlib.git#3b492f9801573eebcfe1b6c584afe8a3beecf2b4" + decimal.js "^10.2.0" + eth-sig-util "^2.5.3" + fixed-merkle-tree "^0.3.4" + snarkjs "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5" + tornado-trees "^0.0.11" + web3 "^1.2.11" + websnark "git+https://github.com/tornadocash/websnark.git#86a526718cd6f6f5d31bdb1fe26a9ec8819f633e" + tornado-cli@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/tornado-cli/-/tornado-cli-0.0.1.tgz#ee11f6cf781043640c42323bf75ac5a8400876dc" @@ -16593,15 +17408,62 @@ tornado-cli@^0.0.1: web3-utils "^1.3.4" websnark "git+https://github.com/tornadocash/websnark.git#4c0af6a8b65aabea3c09f377f63c44e7a58afa6d" -tornado-governance@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/tornado-governance/-/tornado-governance-1.0.2.tgz#c6f32d3ccdf777937eab0f01ac7bab8e5845a0be" - integrity sha512-Kk+1FuG30FNeJ6Xxym4uDWb2s1stymn9KsYVu/NuQhYCJpn06MimHT8OQgY5kh0pcYikPH+45jVNX+luoDZoFg== +tornado-governance@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tornado-governance/-/tornado-governance-2.0.0.tgz#07f6b52fe86430815ee9603d1b36ec411202cb34" + integrity sha512-JmXzxEBhGGJDxsRDp1M0RkN4ZWmm9MzrIy1agUbMEwQUXtRirY+rK4sYDXEvSRJIj8qDl3Pr8nYwny3O2sNRnA== + dependencies: + "@ethersproject/bignumber" "^5.5.0" + "@gnosis.pm/ido-contracts" "^0.5.0" + "@openzeppelin/contracts" "3.2.0-rc.0" + "@openzeppelin/upgrades-core" "^1.0.1" + torn-token "^1.0.4" + tornado-governance "^1.0.3" + +tornado-governance@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tornado-governance/-/tornado-governance-1.0.3.tgz#2b11ebe698af42cdec35ff77583ac4c5d65847f6" + integrity sha512-T1PYCDCzbabjv0lRKBLIIshmDMKwckrwZQzu8nAXsHygNrRtg052QP5YvGjRx0JpfKEBnf5fKjljC3RZAaA8rQ== dependencies: "@openzeppelin/contracts" "^3.2.0-rc.0" "@openzeppelin/upgrades-core" "^1.0.1" torn-token "^1.0.0" +"tornado-relayer-registry@https://github.com/Rezan-vm/tornado-relayer-registry.git": + version "1.0.0" + resolved "https://github.com/Rezan-vm/tornado-relayer-registry.git#c462d274778e57008414efe9e432dbc03bfbf739" + dependencies: + "@openzeppelin/contracts" "3.2.0" + "@openzeppelin/hardhat-upgrades" "1.10.0" + "@ticket721/e712" "^0.4.1" + "@uniswap/v3-core" "https://github.com/Tisamenus/uniswap-v3-core" + "@uniswap/v3-periphery" "https://github.com/Tisamenus/uniswap-v3-periphery" + eth-ens-namehash "^2.0.8" + ethereum-waffle "^3.4.0" + ethers "^5.5.1" + tornado-anonymity-mining "^2.1.5" + tornado-cli "^0.0.1" + tornado-governance "2.0.0" + tornado-trees "^0.0.11" + +tornado-trees@^0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/tornado-trees/-/tornado-trees-0.0.11.tgz#444b9b65bcb72350c0a535f2f37c4d6d3efd93a7" + integrity sha512-dlVGyA821feaglqyLT40oxzRT2LERz1Sothisbu64DxjrFlLlZA1ATDs76sq6En5yCoTJ9eyoE4D+UsDUpq2Fw== + dependencies: + "@openzeppelin/contracts" "^3.4.0" + "@openzeppelin/upgrades-core" "^1.5.1" + circom "0.5.42" + circom_runtime "^0.1.12" + circomlib "git+https://github.com/tornadocash/circomlib.git#d20d53411d1bef61f38c99a8b36d5d0cc4836aa1" + dotenv "^8.2.0" + ffiasm "^0.1.1" + ffjavascript "^0.2.35" + fixed-merkle-tree "^0.5.0" + jssha "^3.2.0" + snarkjs "^0.3.57" + tmp-promise "^3.0.2" + tough-cookie@^2.2.0, tough-cookie@^2.3.1, tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" @@ -16624,6 +17486,11 @@ tr46@~0.0.1: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= +treeify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8" + integrity sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A== + trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" @@ -17315,6 +18182,52 @@ vuvuzela@1.0.3: resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b" integrity sha1-O+FF5YJxxzylUnndhR8SpoIRSws= +wasmbuilder@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/wasmbuilder/-/wasmbuilder-0.0.10.tgz#b8298b2095ef9979d32f3881d1feef1705ec868a" + integrity sha512-zQSvZ7d74d9OvN+mCN6ucNne4QS5/cBBYTHldX0Oe+u9gStY21orapvuX1ajisA7RVIpuFhYg+ZgdySsPfeh0A== + dependencies: + big-integer "^1.6.48" + +wasmbuilder@^0.0.12: + version "0.0.12" + resolved "https://registry.yarnpkg.com/wasmbuilder/-/wasmbuilder-0.0.12.tgz#a60cb25d6d11f314fe5ab3f4ee041ccb493cb78a" + integrity sha512-dTMpBgrnLOXrN58i2zakn2ScynsBhq9LfyQIsPz4CyxRF9k1GAORniuqn3xmE9NnI1l7g3iiVCkoB2Cl0/oG8w== + dependencies: + big-integer "^1.6.48" + +wasmcurves@0.0.12: + version "0.0.12" + resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.0.12.tgz#1496e2219ac07f9a420f527803ae13b1d7a89246" + integrity sha512-1Jl9mkatyHSNj80ILjf85SZUNuZQBCkTjJlhzqHnZQXUmIimCIWkugaVaYNjozLs1Gun4h/keZe1MBeBN0sRpg== + dependencies: + big-integer "^1.6.42" + blakejs "^1.1.0" + +wasmcurves@0.0.14: + version "0.0.14" + resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.0.14.tgz#cbe0f19650d9554937154afdbed66b305bd2a348" + integrity sha512-G1iMkxlRaQSdqQ1JrwHcU+awLmwyH6kFKfT8g9obd8MWe+u5oSdFXrODB0zmSI5aGGvJPG+4cAmqCGYv9R+7qg== + dependencies: + big-integer "^1.6.42" + blakejs "^1.1.0" + +wasmcurves@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.0.5.tgz#d0b58e803c0b1c09c966b7dc0fad6dd405d18547" + integrity sha512-BmI4GXLjLawGg2YkvHa8zRsnWec+d1uwoxE+Iov8cqOpDL7GA5XO2pk2yuDbXHMzwIug2exnKot3baRZ86R0pA== + dependencies: + big-integer "^1.6.42" + blakejs "^1.1.0" + +wasmcurves@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.1.0.tgz#0bc3f9d465367fcd8243395cb0094a05577e5609" + integrity sha512-kIlcgbVUAv2uQ6lGsepGz/m5V40+Z6rvTBkqCYn3Y2+OcXst+UaP4filJYLh/xDxjJl62FFjZZeAnpeli1Y5/Q== + dependencies: + big-integer "^1.6.42" + blakejs "^1.1.0" + watchpack-chokidar2@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" @@ -17349,6 +18262,11 @@ web-encoding@^1.0.2, web-encoding@^1.0.6: optionalDependencies: "@zxing/text-encoding" "0.9.0" +web-worker@^1.0.0, web-worker@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.2.0.tgz#5d85a04a7fbc1e7db58f66595d7a3ac7c9c180da" + integrity sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA== + web3-bzz@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.11.tgz#41bc19a77444bd5365744596d778b811880f707f" @@ -18611,6 +19529,12 @@ websnark@^0.0.5: dependencies: big-integer "^1.6.42" +"websnark@git+https://github.com/tornadocash/websnark.git#86a526718cd6f6f5d31bdb1fe26a9ec8819f633e": + version "0.0.4" + resolved "git+https://github.com/tornadocash/websnark.git#86a526718cd6f6f5d31bdb1fe26a9ec8819f633e" + dependencies: + big-integer "^1.6.42" + websocket@1.0.32: version "1.0.32" resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.32.tgz#1f16ddab3a21a2d929dec1687ab21cfdc6d3dbb1" @@ -18757,11 +19681,21 @@ wordwrap@~0.0.2: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= +worker-threads@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/worker-threads/-/worker-threads-1.0.0.tgz#2b49ea7c9692ba737d9148f2c9b2be65e14e3470" + integrity sha512-vK6Hhvph8oLxocEJIlc3YfGAZhm210uGzjZsXSu+JYLAQ/s/w4Tqgl60JrdH58hW8NSGP4m3bp8a92qPXgX05w== + workerpool@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.0.0.tgz#85aad67fa1a2c8ef9386a1b43539900f61d03d58" integrity sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA== +workerpool@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.0.tgz#a8e038b4c94569596852de7a8ea4228eefdeb37b" + integrity sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg== + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -18788,6 +19722,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -18920,6 +19863,11 @@ y18n@^3.2.1: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yaeti@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" @@ -18948,6 +19896,11 @@ yargs-parser@13.1.2, yargs-parser@^13.1.0, yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + yargs-parser@^11.1.1: version "11.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" @@ -18980,6 +19933,11 @@ yargs-parser@^2.4.0, yargs-parser@^2.4.1: camelcase "^3.0.0" lodash.assign "^4.0.6" +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + yargs-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" @@ -19007,6 +19965,16 @@ yargs-unparser@1.6.1: is-plain-obj "^1.1.0" yargs "^14.2.3" +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + yargs@13.2.4: version "13.2.4" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" @@ -19040,6 +20008,19 @@ yargs@13.3.2, yargs@^13.3.0: y18n "^4.0.0" yargs-parser "^13.1.2" +yargs@16.2.0, yargs@^16.1.1: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yargs@4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.6.0.tgz#cb4050c0159bfb6bb649c0f4af550526a84619dc"