mirror of
https://github.com/tornadocash/tornado-pool-factory
synced 2024-02-02 15:04:08 +01:00
add instance factory tests
This commit is contained in:
parent
35004bc184
commit
41ddd8023d
15
.env.example
15
.env.example
@ -1,14 +1,3 @@
|
|||||||
|
ETHERSCAN_KEY=
|
||||||
ALCHEMY_KEY=
|
ALCHEMY_KEY=
|
||||||
etherscan_api_key=
|
PRIVATE_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
|
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
use_latest_block=false
|
|
||||||
|
|
||||||
PROXY=0x722122dF12D4e14e13Ac3b6895a86e84145b6967
|
|
||||||
DEPLOYER=0xCEe71753C9820f063b38FDbE4cFDAf1d3D928A80
|
|
||||||
HASHER=0x83584f83f26aF4eDDA9CBe8C730bc87C364b28fe
|
|
||||||
VERIFIER=0xce172ce1F20EC0B3728c9965470eaf994A03557A
|
|
||||||
SALT=0x0000000000000000000000000000000000000000000000000000000047941987
|
|
||||||
COMP_ADDRESS=0xc00e94Cb662C3520282E6f5717214004A7f26888
|
|
12
config.js
Normal file
12
config.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
module.exports = {
|
||||||
|
verifier: '0xce172ce1F20EC0B3728c9965470eaf994A03557A',
|
||||||
|
hasher: '0x83584f83f26aF4eDDA9CBe8C730bc87C364b28fe',
|
||||||
|
governance: '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce',
|
||||||
|
instanceRegistry: '0xB20c66C4DE72433F3cE747b58B86830c459CA911',
|
||||||
|
merkleTreeHeight: 20,
|
||||||
|
singletonFactory: '0xce0042B868300000d44A59004Da54A005ffdcf9f',
|
||||||
|
salt: '0x0000000000000000000000000000000000000000000000000000000047941987',
|
||||||
|
COMP: '0xc00e94Cb662C3520282E6f5717214004A7f26888',
|
||||||
|
TORN: '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C',
|
||||||
|
tornWhale: '0xF977814e90dA44bFA03b6295A0616a897441aceC',
|
||||||
|
}
|
@ -12,7 +12,7 @@ contract AddInstanceProposal {
|
|||||||
address public immutable token;
|
address public immutable token;
|
||||||
uint24 public immutable uniswapPoolSwappingFee;
|
uint24 public immutable uniswapPoolSwappingFee;
|
||||||
|
|
||||||
uint256 internal immutable numInstances;
|
uint256 public immutable numInstances;
|
||||||
uint256 internal immutable denomination0;
|
uint256 internal immutable denomination0;
|
||||||
uint256 internal immutable denomination1;
|
uint256 internal immutable denomination1;
|
||||||
uint256 internal immutable denomination2;
|
uint256 internal immutable denomination2;
|
||||||
|
@ -10,11 +10,13 @@ import "./ERC20TornadoCloneable.sol";
|
|||||||
import "./AddInstanceProposal.sol";
|
import "./AddInstanceProposal.sol";
|
||||||
import "./interfaces/IGovernance.sol";
|
import "./interfaces/IGovernance.sol";
|
||||||
|
|
||||||
|
|
||||||
contract InstanceFactory is Ownable {
|
contract InstanceFactory is Ownable {
|
||||||
using Clones for address;
|
using Clones for address;
|
||||||
using Address for address;
|
using Address for address;
|
||||||
|
|
||||||
address immutable governance;
|
address public immutable governance;
|
||||||
|
address public immutable instanceRegistry;
|
||||||
address public implementation;
|
address public implementation;
|
||||||
address public verifier;
|
address public verifier;
|
||||||
address public hasher;
|
address public hasher;
|
||||||
@ -25,19 +27,24 @@ contract InstanceFactory is Ownable {
|
|||||||
event NewTreeHeightSet(uint32 indexed newTreeHeight);
|
event NewTreeHeightSet(uint32 indexed newTreeHeight);
|
||||||
event NewImplementationSet(address indexed newImplemenentation);
|
event NewImplementationSet(address indexed newImplemenentation);
|
||||||
event NewInstanceCloneCreated(address indexed clone);
|
event NewInstanceCloneCreated(address indexed clone);
|
||||||
|
event NewGovernanceProposalCreated(address indexed proposal);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
address _verifier,
|
address _verifier,
|
||||||
address _hasher,
|
address _hasher,
|
||||||
uint32 _merkleTreeHeight,
|
uint32 _merkleTreeHeight,
|
||||||
address _governance
|
address _governance,
|
||||||
|
address _instanceRegistry
|
||||||
) {
|
) {
|
||||||
verifier = _verifier;
|
verifier = _verifier;
|
||||||
hasher = _hasher;
|
hasher = _hasher;
|
||||||
merkleTreeHeight = _merkleTreeHeight;
|
merkleTreeHeight = _merkleTreeHeight;
|
||||||
|
governance = _governance;
|
||||||
|
instanceRegistry = _instanceRegistry;
|
||||||
|
|
||||||
ERC20TornadoCloneable implContract = new ERC20TornadoCloneable(_verifier, _hasher);
|
ERC20TornadoCloneable implContract = new ERC20TornadoCloneable(_verifier, _hasher);
|
||||||
implementation = address(implContract);
|
implementation = address(implContract);
|
||||||
governance = _governance;
|
|
||||||
transferOwnership(_governance);
|
transferOwnership(_governance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,26 +66,25 @@ contract InstanceFactory is Ownable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createNewProposal(
|
function createNewProposal(
|
||||||
string calldata _description,
|
|
||||||
address _instanceRegistry,
|
|
||||||
address _token,
|
address _token,
|
||||||
uint24 _uniswapPoolSwappingFee,
|
uint24 _uniswapPoolSwappingFee,
|
||||||
uint256[] memory _denominations,
|
uint256[] memory _denominations,
|
||||||
uint32[] memory _protocolFees
|
uint32[] memory _protocolFees
|
||||||
) external returns (address) {
|
) external returns (address) {
|
||||||
// TODO test params
|
require(_token.isContract(), "Token is not contract"); // TODO should we check that such instance already exist?
|
||||||
require(_denominations.length == _protocolFees.length);
|
require(_uniswapPoolSwappingFee > 0, "uniswapPoolSwappingFee is zero"); // TODO should we check > 0 ?
|
||||||
|
require(_denominations.length > 0, "Empty denominations");
|
||||||
|
require(_denominations.length == _protocolFees.length, "Incorrect denominations/fees length");
|
||||||
|
|
||||||
address proposal = address(new AddInstanceProposal(
|
address proposal = address(new AddInstanceProposal(
|
||||||
address(this),
|
address(this),
|
||||||
_instanceRegistry,
|
instanceRegistry,
|
||||||
_token,
|
_token,
|
||||||
_uniswapPoolSwappingFee,
|
_uniswapPoolSwappingFee,
|
||||||
_denominations,
|
_denominations,
|
||||||
_protocolFees
|
_protocolFees
|
||||||
));
|
));
|
||||||
|
emit NewGovernanceProposalCreated(proposal);
|
||||||
IGovernance(governance).propose(proposal, _description);
|
|
||||||
|
|
||||||
return proposal;
|
return proposal;
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,6 @@
|
|||||||
pragma solidity 0.6.12 || 0.7.6;
|
pragma solidity 0.6.12 || 0.7.6;
|
||||||
|
|
||||||
import { Governance } from "tornado-governance/contracts/v1/Governance.sol";
|
import { Governance } from "tornado-governance/contracts/v1/Governance.sol";
|
||||||
|
import { InstanceRegistry } from "tornado-relayer-registry/contracts/tornado-proxy/InstanceRegistry.sol";
|
||||||
|
|
||||||
contract CompileDummy {}
|
contract CompileDummy {}
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
require('@nomiclabs/hardhat-ethers')
|
|
||||||
require('@nomiclabs/hardhat-etherscan')
|
|
||||||
require('@nomiclabs/hardhat-waffle')
|
require('@nomiclabs/hardhat-waffle')
|
||||||
|
require('@nomiclabs/hardhat-etherscan')
|
||||||
require('hardhat-log-remover')
|
require('hardhat-log-remover')
|
||||||
require('solidity-coverage')
|
require('solidity-coverage')
|
||||||
|
|
||||||
// require('./tasks/deploy_proposal.js')
|
|
||||||
// require('./tasks/deploy_factory_proposal.js')
|
|
||||||
// require('./tasks/propose_proposal.js')
|
|
||||||
/**
|
/**
|
||||||
* @type import('hardhat/config').HardhatUserConfig
|
* @type import('hardhat/config').HardhatUserConfig
|
||||||
*/
|
*/
|
||||||
@ -38,22 +34,17 @@ module.exports = {
|
|||||||
hardhat: {
|
hardhat: {
|
||||||
forking: {
|
forking: {
|
||||||
url: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`,
|
url: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`,
|
||||||
blockNumber: process.env.use_latest_block == 'true' ? undefined : 13017436,
|
blockNumber: 14220000,
|
||||||
},
|
},
|
||||||
|
chainId: 1,
|
||||||
|
initialBaseFeePerGas: 5,
|
||||||
loggingEnabled: false,
|
loggingEnabled: false,
|
||||||
},
|
allowUnlimitedContractSize: false,
|
||||||
localhost: {
|
blockGasLimit: 50000000,
|
||||||
url: 'http://localhost:8545',
|
|
||||||
timeout: 120000,
|
|
||||||
},
|
},
|
||||||
mainnet: {
|
mainnet: {
|
||||||
url: `https://mainnet.infura.io/v3/${process.env.mainnet_rpc_key}`,
|
url: `https://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`,
|
||||||
accounts: [`${process.env.mainnet_account_pk}`],
|
accounts: [process.env.PRIVATE_KEY],
|
||||||
timeout: 2147483647,
|
|
||||||
},
|
|
||||||
goerli: {
|
|
||||||
url: `https://goerli.infura.io/v3/${process.env.goerli_rpc_key}`,
|
|
||||||
accounts: [`${process.env.goerli_account_pk}`],
|
|
||||||
timeout: 2147483647,
|
timeout: 2147483647,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -63,6 +54,6 @@ module.exports = {
|
|||||||
runOnCompile: true,
|
runOnCompile: true,
|
||||||
},
|
},
|
||||||
etherscan: {
|
etherscan: {
|
||||||
apiKey: `${process.env.etherscan_api_key}`,
|
apiKey: `${process.env.ETHERSCAN_KEY}`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
"torn-token": "^1.0.4",
|
"torn-token": "^1.0.4",
|
||||||
"tornado-cli": "^0.0.1",
|
"tornado-cli": "^0.0.1",
|
||||||
"tornado-core": "https://github.com/tornadocash/tornado-core.git",
|
"tornado-core": "https://github.com/tornadocash/tornado-core.git",
|
||||||
"tornado-governance": "2.0.0"
|
"tornado-governance": "2.0.0",
|
||||||
|
"tornado-relayer-registry": "https://github.com/tornadocash/tornado-relayer-registry.git"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||||
|
@ -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
|
|
@ -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)
|
|
||||||
},
|
|
||||||
)
|
|
@ -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)
|
|
||||||
})
|
|
@ -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)
|
|
||||||
})
|
|
@ -1,348 +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 // TODO take from config
|
|
||||||
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)
|
|
||||||
|
|
||||||
expect(await GovernanceContract.state(id)).to.be.equal(ProposalState.Executed)
|
|
||||||
})
|
|
||||||
|
|
||||||
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://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`,
|
|
||||||
blockNumber: process.env.use_latest_block == 'true' ? undefined : 13017436,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
])
|
|
||||||
})
|
|
||||||
})
|
|
318
test/instance.factory.test.js
Normal file
318
test/instance.factory.test.js
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
|
// execute relayer registry proposal
|
||||||
|
const proposalId = await gov.proposalCount()
|
||||||
|
expect(await gov.state(proposalId)).to.be.equal(ProposalState.Active)
|
||||||
|
await minewait(596400)
|
||||||
|
expect(await gov.state(proposalId)).to.be.equal(ProposalState.AwaitingExecution)
|
||||||
|
|
||||||
|
await gov.execute(proposalId)
|
||||||
|
expect(await gov.state(proposalId)).to.be.equal(ProposalState.Executed)
|
||||||
|
|
||||||
|
// 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(),
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
})
|
@ -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://eth-mainnet.alchemyapi.io/v2/${process.env.ALCHEMY_KEY}`,
|
|
||||||
blockNumber: process.env.use_latest_block == 'true' ? undefined : 13017436,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
])
|
|
||||||
})
|
|
||||||
})
|
|
43
test/utils.js
Normal file
43
test/utils.js
Normal file
@ -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,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user