8f085566cc
Signed-off-by: T-Hax <>
297 lines
11 KiB
JavaScript
297 lines
11 KiB
JavaScript
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('Sidechain Instance Factory Tests', () => {
|
|
const addressZero = ethers.constants.AddressZero
|
|
|
|
async function fixture() {
|
|
const [sender, deployer] = await ethers.getSigners()
|
|
|
|
const owner = await getSignerFromAddress(config.admin)
|
|
|
|
await sender.sendTransaction({
|
|
to: config.admin,
|
|
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.sidechainFactory.implementation.address)) == '0x') {
|
|
await singletonFactory.deploy(contracts.sidechainFactory.implementation.bytecode, config.salt, {
|
|
gasLimit: config.deployGasLimit,
|
|
})
|
|
}
|
|
if ((await ethers.provider.getCode(contracts.sidechainFactory.proxy.address)) == '0x') {
|
|
await singletonFactory.deploy(contracts.sidechainFactory.proxy.bytecode, config.salt, {
|
|
gasLimit: config.deployGasLimit,
|
|
})
|
|
}
|
|
const instanceFactory = await ethers.getContractAt(
|
|
'SidechainInstanceFactory',
|
|
contracts.sidechainFactory.proxy.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.ERC20Impl()).to.exist
|
|
expect(await instanceFactory.nativeCurImpl()).to.exist
|
|
})
|
|
|
|
it('Admin 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'))
|
|
|
|
// try to deploy the same instance again
|
|
await instanceFactory.connect(sender).createInstanceClone(ethers.utils.parseEther('1000'), config.COMP)
|
|
|
|
// check that instance has not been created - no new NewInstanceCloneCreated event
|
|
let curLogs = await instanceFactory.queryFilter('NewInstanceCloneCreated')
|
|
expect(curLogs.length).to.be.equal(logs.length)
|
|
})
|
|
|
|
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)
|
|
|
|
// 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],
|
|
)
|
|
})
|
|
|
|
it('Should successfully add native currency instance', async function () {
|
|
let { sender, instanceFactory } = await loadFixture(fixture)
|
|
|
|
const denomination = ethers.utils.parseEther('1')
|
|
|
|
// deploy instance
|
|
await instanceFactory.connect(sender).createInstanceClone(denomination, addressZero)
|
|
|
|
// check instance initialization
|
|
let logs = await instanceFactory.queryFilter('NewInstanceCloneCreated')
|
|
const instance = await ethers.getContractAt(
|
|
'ETHTornadoCloneable',
|
|
ethers.utils.getAddress('0x' + logs[logs.length - 1].topics[1].slice(-40)),
|
|
)
|
|
|
|
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(denomination)
|
|
|
|
// try to deploy the same instance again
|
|
await instanceFactory.connect(sender).createInstanceClone(denomination, addressZero)
|
|
|
|
// check that instance has not been created - no new NewInstanceCloneCreated event
|
|
let curLogs = await instanceFactory.queryFilter('NewInstanceCloneCreated')
|
|
expect(curLogs.length).to.be.equal(logs.length)
|
|
})
|
|
|
|
it('Should successfully add native currency 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(addressZero, 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('ETHTornadoCloneable', instanceAddr)
|
|
|
|
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 native currency instance', async function () {
|
|
let { sender, instanceFactory } = await loadFixture(fixture)
|
|
|
|
const denomination = ethers.utils.parseEther('1.5')
|
|
|
|
// deploy instance
|
|
await instanceFactory.connect(sender).createInstanceClone(denomination, addressZero)
|
|
|
|
let logs = await instanceFactory.queryFilter('NewInstanceCloneCreated')
|
|
const instance = await ethers.getContractAt(
|
|
'ETHTornadoCloneable',
|
|
ethers.utils.getAddress('0x' + logs[logs.length - 1].topics[1].slice(-40)),
|
|
)
|
|
|
|
// check instance work ------------------------------------------
|
|
const depo = createDeposit({
|
|
nullifier: rbigint(31),
|
|
secret: rbigint(31),
|
|
})
|
|
|
|
await expect(() =>
|
|
instance.connect(sender).deposit(toHex(depo.commitment), {
|
|
value: denomination,
|
|
}),
|
|
).to.changeEtherBalances([sender, instance], [BigNumber.from(0).sub(denomination), denomination])
|
|
|
|
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.changeEtherBalances(
|
|
[instance, sender],
|
|
[BigNumber.from(0).sub(denomination), denomination],
|
|
)
|
|
})
|
|
})
|