diff --git a/README.md b/README.md index 0f7c102..2463325 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,8 @@ Check config.js for actual values. With `salt` = `0x0000000000000000000000000000000000000000000000000000000047941987` address must be: -1. `InstanceFactory` - `0x09110e04d5AEF747bcf7A3585D8FFC892Ab9D1Cf` -2. `InstanceFactoryWithRegistry` - `0xC01D57d83E9Fe35E0Fb900F9D384EFcA679DF4bD` +1. `MultipleInstanceFactory` - `0xdacb0a030Bcfc7163922d34092a822cC19D12d40` +2. `InstanceFactoryWithRegistry` - `0x6C1F437dFd70501Ad7f152897051446cc51F1eB6` Check addresses with current config: @@ -74,7 +74,7 @@ Check addresses with current config: Deploy InstanceFactory: ```shell - yarn hardhat run scripts/deployInstanceFactory.js --network mainnet + yarn hardhat run scripts/deployMultipleInstanceFactory.js --network mainnet ``` Deploy InstanceFactoryWithRegistry: diff --git a/contracts/InstanceFactoryWithRegistry.sol b/contracts/InstanceFactoryWithRegistry.sol index c9e2b9e..7d157a7 100644 --- a/contracts/InstanceFactoryWithRegistry.sol +++ b/contracts/InstanceFactoryWithRegistry.sol @@ -56,7 +56,7 @@ contract InstanceFactoryWithRegistry is InstanceFactory { } /** - * @dev Throws if called by any account other than the Governance. + * @dev Creates new Tornado instances. 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 */ diff --git a/contracts/MultipleInstanceFactory.sol b/contracts/MultipleInstanceFactory.sol new file mode 100644 index 0000000..645e682 --- /dev/null +++ b/contracts/MultipleInstanceFactory.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.7.6; + +import "./InstanceFactory.sol"; + +contract MultipleInstanceFactory is InstanceFactory { + constructor( + address _verifier, + address _hasher, + uint32 _merkleTreeHeight, + address _owner + ) InstanceFactory(_verifier, _hasher, _merkleTreeHeight, _owner) {} + + /** + * @dev Creates new Tornado instances. + * @param _token address of ERC20 token for a new instance + * @param _denominations list of denominations for each new instance + */ + function createInstanceClones(address _token, uint256[] memory _denominations) external { + for (uint256 i = 0; i < _denominations.length; i++) { + createInstanceClone(_denominations[i], _token); + } + } +} diff --git a/hardhat.config.js b/hardhat.config.js index cec68c9..f03f3e1 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -57,6 +57,12 @@ module.exports = { ? [process.env.PRIVATE_KEY] : { mnemonic: 'test test test test test junk' }, }, + goerli: { + url: `https://goerli.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://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`, accounts: process.env.PRIVATE_KEY diff --git a/scripts/deployInstanceFactory.js b/scripts/deployMultipleInstanceFactory.js similarity index 86% rename from scripts/deployInstanceFactory.js rename to scripts/deployMultipleInstanceFactory.js index 60d639a..1b4dcb7 100644 --- a/scripts/deployInstanceFactory.js +++ b/scripts/deployMultipleInstanceFactory.js @@ -15,7 +15,9 @@ 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`) + console.log( + `MultipleInstanceFactory contract have been deployed on ${contracts.factoryContract.address} address`, + ) } main() diff --git a/src/generateAddresses.js b/src/generateAddresses.js index c6a57c7..17d7ca8 100644 --- a/src/generateAddresses.js +++ b/src/generateAddresses.js @@ -2,7 +2,7 @@ const { ethers } = require('hardhat') const defaultConfig = require('../config') async function generate(config = defaultConfig) { - const FactoryFactory = await ethers.getContractFactory('InstanceFactory') + const FactoryFactory = await ethers.getContractFactory('MultipleInstanceFactory') const deploymentBytecodeFactory = FactoryFactory.bytecode + FactoryFactory.interface @@ -57,7 +57,7 @@ async function generate(config = defaultConfig) { async function generateWithLog() { const contracts = await generate() - console.log('Instance factory contract: ', contracts.factoryContract.address) + console.log('MultipleInstanceFactory contract: ', contracts.factoryContract.address) console.log('Instance factory with registry contract: ', contracts.factoryWithRegistryContract.address) return contracts } diff --git a/test/factory.test.js b/test/multiple.instance.factory.test.js similarity index 80% rename from test/factory.test.js rename to test/multiple.instance.factory.test.js index 0201c63..5e4a406 100644 --- a/test/factory.test.js +++ b/test/multiple.instance.factory.test.js @@ -8,7 +8,7 @@ const { getSignerFromAddress } = require('./utils') const { generate } = require('../src/generateAddresses') const { rbigint, createDeposit, toHex, generateProof, initialize } = require('tornado-cli') -describe('Instance Factory Tests', () => { +describe('Multiple Instance Factory Tests', () => { const addressZero = ethers.constants.AddressZero async function fixture() { @@ -39,7 +39,10 @@ describe('Instance Factory Tests', () => { gasLimit: config.deployGasLimit, }) } - const instanceFactory = await ethers.getContractAt('InstanceFactory', contracts.factoryContract.address) + const instanceFactory = await ethers.getContractAt( + 'MultipleInstanceFactory', + contracts.factoryContract.address, + ) return { sender, @@ -109,6 +112,34 @@ describe('Instance Factory Tests', () => { expect(await instance.denomination()).to.equal(ethers.utils.parseEther('1000')) }) + it('Should successfully add instances', async function () { + let { sender, instanceFactory } = 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 + + // deploy instances + await instanceFactory.connect(sender).createInstanceClones(config.COMP, denominations) + + // check instance initialization + let 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]) + } + }) + it('Should deposit and withdraw into the new instance', async function () { let { sender, instanceFactory, compToken, compWhale } = await loadFixture(fixture)