tornado-pool-factory/test/instance.factory.test.js

310 lines
12 KiB
JavaScript

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 MixerContractABI = require('tornado-cli/build/contracts/Mixer.abi.json')
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,
}
const addressZero = ethers.constants.AddressZero
async function fixture() {
const [sender, deployer, multisig] = await ethers.getSigners()
const tornWhale = await getSignerFromAddress(config.tornWhale)
const gov = await ethers.getContractAt(
'Governance',
config.governance,
)
const tornToken = await ethers.getContractAt(
'@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20',
config.TORN,
)
const compToken = await ethers.getContractAt(
'@openzeppelin/contracts/token/ERC20/IERC20.sol:IERC20',
config.COMP,
)
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 InstanceFactory.connect(deployer).deploy(
config.verifier,
config.hasher,
config.merkleTreeHeight,
config.governance,
config.instanceRegistry
)
await instanceFactory.deployed()
return { sender, deployer, multisig, tornWhale, 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
})
it('Governance should be able to set factory params', async function () {
let { instanceFactory, gov } = await loadFixture(fixture)
await expect(instanceFactory.setVerifier(addressZero)).to.be.reverted
const govSigner = await getSignerFromAddress(gov.address)
instanceFactory = await instanceFactory.connect(govSigner)
await instanceFactory.setVerifier(addressZero)
await instanceFactory.setHasher(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.setVerifier(config.verifier)
await instanceFactory.setHasher(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 deploy/propose/execute proposal - add instance', async function () {
let { instanceFactory, gov, instanceRegistry, tornWhale, tornToken } = await loadFixture(fixture)
// deploy proposal ----------------------------------------------
let tx = await instanceFactory.createNewProposal(
config.COMP,
3000,
[ethers.utils.parseEther('100')],
[30]
)
let receipt = await tx.wait()
const proposal = await ethers.getContractAt(
'AddInstanceProposal',
receipt.events[0].args[0],
)
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)
tx = await gov.execute(id)
expect(await gov.state(id)).to.be.equal(ProposalState.Executed)
// check instance initialization --------------------------------
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 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(),
// )
// }
// })
})