diff --git a/config.js b/config.js index 07a8148..1d11ea8 100644 --- a/config.js +++ b/config.js @@ -3,11 +3,13 @@ module.exports = { hasher: '0x83584f83f26aF4eDDA9CBe8C730bc87C364b28fe', governance: '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce', instanceRegistry: '0xB20c66C4DE72433F3cE747b58B86830c459CA911', + router: '0xd90e2f925DA726b50C4Ed8D0Fb90Ad053324F31b', merkleTreeHeight: 20, singletonFactory: '0xce0042B868300000d44A59004Da54A005ffdcf9f', salt: '0x0000000000000000000000000000000000000000000000000000000047941987', COMP: '0xc00e94Cb662C3520282E6f5717214004A7f26888', TORN: '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C', tornWhale: '0xF977814e90dA44bFA03b6295A0616a897441aceC', + compWhale: '0xF977814e90dA44bFA03b6295A0616a897441aceC', creationFee: '200000000000000000000', // 200 TORN } diff --git a/test/instance.factory.test.js b/test/factory.test.js similarity index 66% rename from test/instance.factory.test.js rename to test/factory.test.js index 327c7e2..5dd1c04 100644 --- a/test/instance.factory.test.js +++ b/test/factory.test.js @@ -3,8 +3,6 @@ const { ethers, waffle } = hre const { loadFixture } = waffle const { expect } = require('chai') const { BigNumber } = require('@ethersproject/bignumber') -const { rbigint, createDeposit, toHex, generateProof, initialize } = require('tornado-cli') -const MixerContractABI = require('tornado-cli/build/contracts/Mixer.abi.json') const config = require('../config') const { getSignerFromAddress, minewait } = require('./utils') const { PermitSigner } = require('../scripts/permit.js') @@ -39,13 +37,13 @@ describe('Instance Factory Tests', () => { config.COMP, ) - instanceRegistry = await ethers.getContractAt( + const instanceRegistry = await ethers.getContractAt( 'tornado-relayer-registry/contracts/tornado-proxy/InstanceRegistry.sol:InstanceRegistry', config.instanceRegistry, ) // deploy instance factory - InstanceFactory = await ethers.getContractFactory('InstanceFactory') + const InstanceFactory = await ethers.getContractFactory('InstanceFactory') const instanceFactory = await InstanceFactory.connect(deployer).deploy( config.verifier, config.hasher, @@ -137,10 +135,10 @@ describe('Instance Factory Tests', () => { [BigNumber.from(0).sub(config.creationFee), config.creationFee], ) - let logs = await ethers.provider.getLogs(instanceFactory.filters.NewGovernanceProposalCreated()) + let logs = await instanceFactory.queryFilter('NewGovernanceProposalCreated') const proposal = await ethers.getContractAt( 'AddInstanceProposal', - ethers.utils.getAddress('0x' + logs[0].topics[1].slice(26)), + ethers.utils.getAddress('0x' + logs[0].topics[1].slice(-40)), ) expect(await proposal.instanceFactory()).to.be.equal(instanceFactory.address) @@ -183,12 +181,12 @@ describe('Instance Factory Tests', () => { ) expect(await gov.state(id)).to.be.equal(ProposalState.AwaitingExecution) - tx = await gov.execute(id) + let tx = await gov.execute(id) expect(await gov.state(id)).to.be.equal(ProposalState.Executed) // check instance initialization -------------------------------- - receipt = await tx.wait() + let receipt = await tx.wait() const instanceAddr = '0x' + receipt.events[0].topics[1].toString().slice(-40) const instance = await ethers.getContractAt('ERC20TornadoCloneable', instanceAddr) @@ -261,10 +259,10 @@ describe('Instance Factory Tests', () => { [BigNumber.from(0).sub(config.creationFee), config.creationFee], ) - let logs = await ethers.provider.getLogs(instanceFactory.filters.NewGovernanceProposalCreated()) + let logs = await instanceFactory.queryFilter('NewGovernanceProposalCreated') const proposal = await ethers.getContractAt( 'AddInstanceProposal', - ethers.utils.getAddress('0x' + logs[0].topics[1].slice(26)), + ethers.utils.getAddress('0x' + logs[0].topics[1].slice(-40)), ) expect(await proposal.instanceFactory()).to.be.equal(instanceFactory.address) @@ -275,123 +273,4 @@ describe('Instance Factory Tests', () => { expect(await proposal.protocolFeeByIndex(0)).to.be.equal(30) expect(await proposal.denominationByIndex(0)).to.be.equal(ethers.utils.parseEther('100')) }) - - // 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(), - // ) - // } - // }) }) diff --git a/test/instance.tests.js b/test/instance.tests.js new file mode 100644 index 0000000..6b61805 --- /dev/null +++ b/test/instance.tests.js @@ -0,0 +1,165 @@ +const hre = require('hardhat') +const { ethers, waffle } = hre +const { loadFixture } = waffle +const { expect } = require('chai') +const { BigNumber } = require('@ethersproject/bignumber') +const { rbigint, createDeposit, toHex, generateProof, initialize } = require('tornado-cli') +const config = require('../config') +const { getSignerFromAddress, minewait } = require('./utils') + +describe('Instance Factory Tests', () => { + const ProposalState = { + Pending: 0, + Active: 1, + Defeated: 2, + Timelocked: 3, + AwaitingExecution: 4, + Executed: 5, + Expired: 6, + } + + async function fixture() { + const [sender, deployer, multisig] = await ethers.getSigners() + + const tornWhale = await getSignerFromAddress(config.tornWhale) + const compWhale = await getSignerFromAddress(config.compWhale) + + let gov = await ethers.getContractAt('Governance', config.governance) + + 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, + ) + + const router = await ethers.getContractAt( + 'tornado-relayer-registry/contracts/tornado-proxy/TornadoRouter.sol:TornadoRouter', + config.router, + ) + + // deploy instance factory + const InstanceFactory = await ethers.getContractFactory('InstanceFactory') + const instanceFactory = await InstanceFactory.connect(deployer).deploy( + config.verifier, + config.hasher, + config.merkleTreeHeight, + config.governance, + config.instanceRegistry, + config.TORN, + config.creationFee, + ) + await instanceFactory.deployed() + + // deploy proposal + await tornToken.connect(tornWhale).transfer(sender.address, config.creationFee) + await tornToken.approve(instanceFactory.address, config.creationFee) + + await instanceFactory + .connect(sender) + .createProposalApprove(config.COMP, 3000, [ethers.utils.parseEther('100')], [30]) + + let logs = await instanceFactory.queryFilter('NewGovernanceProposalCreated') + const proposal = await ethers.getContractAt( + 'AddInstanceProposal', + ethers.utils.getAddress('0x' + logs[0].topics[1].slice(-40)), + ) + + // propose proposal + 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') + const 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 + 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) + + logs = await instanceFactory.queryFilter('NewInstanceCloneCreated') + const instance = await ethers.getContractAt( + 'ERC20TornadoCloneable', + ethers.utils.getAddress('0x' + logs[0].topics[1].slice(-40)), + ) + + return { + sender, + deployer, + multisig, + tornWhale, + compWhale, + gov, + tornToken, + compToken, + instanceRegistry, + router, + instanceFactory, + instance, + } + } + + it('Should set correct params for factory', async function () { + const { instance } = await loadFixture(fixture) + + 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')) + }) + + it('Should deposit and withdraw into the new instance', async function () { + const { sender, instance, compToken, compWhale, router } = await loadFixture(fixture) + + 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], + ) + }) +})