fork tested
Signed-off-by: T-Hax <>
This commit is contained in:
parent
a8495d76a4
commit
3863e951d8
@ -8,8 +8,11 @@ module.exports = {
|
|||||||
singletonFactory: '0xce0042B868300000d44A59004Da54A005ffdcf9f',
|
singletonFactory: '0xce0042B868300000d44A59004Da54A005ffdcf9f',
|
||||||
singletonFactoryVerboseWrapper: '0xCEe71753C9820f063b38FDbE4cFDAf1d3D928A80',
|
singletonFactoryVerboseWrapper: '0xCEe71753C9820f063b38FDbE4cFDAf1d3D928A80',
|
||||||
salt: '0x0000000000000000000000000000000000000000000000000000000047941987',
|
salt: '0x0000000000000000000000000000000000000000000000000000000047941987',
|
||||||
COMP: '0xc00e94Cb662C3520282E6f5717214004A7f26888',
|
|
||||||
TORN: '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C',
|
TORN: '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C',
|
||||||
|
COMP: '0xc00e94Cb662C3520282E6f5717214004A7f26888',
|
||||||
|
LUSD: '0x5f98805a4e8be255a32880fdec7f6728c6568ba0',
|
||||||
|
RETH: '0xae78736cd615f374d3085123a210448e74fc6393',
|
||||||
|
FRXETH: '0x5E8422345238F34275888049021821E8E08CAa1f',
|
||||||
tornWhale: '0xF977814e90dA44bFA03b6295A0616a897441aceC',
|
tornWhale: '0xF977814e90dA44bFA03b6295A0616a897441aceC',
|
||||||
compWhale: '0xF977814e90dA44bFA03b6295A0616a897441aceC',
|
compWhale: '0xF977814e90dA44bFA03b6295A0616a897441aceC',
|
||||||
creationFee: '200000000000000000000', // 200 TORN
|
creationFee: '200000000000000000000', // 200 TORN
|
||||||
|
@ -8,12 +8,6 @@ import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
|
|||||||
import "./interfaces/IInstanceRegistry.sol";
|
import "./interfaces/IInstanceRegistry.sol";
|
||||||
import "./interfaces/IInstanceFactory.sol";
|
import "./interfaces/IInstanceFactory.sol";
|
||||||
|
|
||||||
contract InstanceAdditionProposal {
|
|
||||||
using SafeMath for uint256;
|
|
||||||
|
|
||||||
IInstanceFactory public immutable instanceFactory;
|
|
||||||
IInstanceRegistry public immutable instanceRegistry;
|
|
||||||
|
|
||||||
struct InstanceAdditionData {
|
struct InstanceAdditionData {
|
||||||
address tokenAddress;
|
address tokenAddress;
|
||||||
uint40 smallDenomination;
|
uint40 smallDenomination;
|
||||||
@ -22,26 +16,43 @@ contract InstanceAdditionProposal {
|
|||||||
uint16 protocolFee;
|
uint16 protocolFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstanceAdditionData[] public toAdd;
|
contract InstanceAdditionDataProvider {
|
||||||
|
InstanceAdditionData[] public toAddData;
|
||||||
|
|
||||||
|
constructor(InstanceAdditionData[] memory _toAdd) {
|
||||||
|
for (uint256 i = 0; i < _toAdd.length; i++) {
|
||||||
|
toAddData.push(_toAdd[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAllDataToAdd() external view returns (InstanceAdditionData[] memory) {
|
||||||
|
return toAddData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract InstanceAdditionProposal {
|
||||||
|
using SafeMath for uint256;
|
||||||
|
|
||||||
|
InstanceAdditionDataProvider public immutable provider;
|
||||||
|
IInstanceFactory public immutable instanceFactory;
|
||||||
|
IInstanceRegistry public immutable instanceRegistry;
|
||||||
|
|
||||||
event AddInstanceForRegistry(address instance, address token, uint256 denomination);
|
event AddInstanceForRegistry(address instance, address token, uint256 denomination);
|
||||||
|
|
||||||
constructor(address _instanceFactory, address _instanceRegistry, InstanceAdditionData[] memory _toAdd) {
|
constructor(address _instanceFactory, address _instanceRegistry, InstanceAdditionData[] memory _toAdd) {
|
||||||
|
provider = new InstanceAdditionDataProvider(_toAdd);
|
||||||
instanceFactory = IInstanceFactory(_instanceFactory);
|
instanceFactory = IInstanceFactory(_instanceFactory);
|
||||||
instanceRegistry = IInstanceRegistry(_instanceRegistry);
|
instanceRegistry = IInstanceRegistry(_instanceRegistry);
|
||||||
|
|
||||||
// Copying structs is not implemented
|
|
||||||
for (uint256 i = 0; i < _toAdd.length; i++) {
|
|
||||||
toAdd.push(_toAdd[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeProposal() external {
|
function executeProposal() external {
|
||||||
uint256 howMany = toAdd.length;
|
InstanceAdditionData[] memory _toAddData = provider.getAllDataToAdd();
|
||||||
|
|
||||||
|
uint256 howMany = _toAddData.length;
|
||||||
|
|
||||||
for (uint256 i = 0; i < howMany; i++) {
|
for (uint256 i = 0; i < howMany; i++) {
|
||||||
// Read out the data for the new instance
|
// Read out the data for the new instance
|
||||||
InstanceAdditionData memory data = toAdd[i];
|
InstanceAdditionData memory data = _toAddData[i];
|
||||||
|
|
||||||
// Safely calculate the denomination
|
// Safely calculate the denomination
|
||||||
uint256 denomination = uint256(data.smallDenomination).mul(10 ** uint256(data.base10Exponent));
|
uint256 denomination = uint256(data.smallDenomination).mul(10 ** uint256(data.base10Exponent));
|
||||||
@ -67,4 +78,13 @@ contract InstanceAdditionProposal {
|
|||||||
emit AddInstanceForRegistry(address(instance), data.tokenAddress, denomination);
|
emit AddInstanceForRegistry(address(instance), data.tokenAddress, denomination);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDataToAddByIndex(uint256 index) external view returns (InstanceAdditionData memory data) {
|
||||||
|
// The compiler is behaving weird here. Something to do with struct type inference.
|
||||||
|
return (provider.getAllDataToAdd())[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAllDataToAdd() external view returns (InstanceAdditionData[] memory) {
|
||||||
|
return provider.getAllDataToAdd();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|||||||
import { IERC20Permit } from "@openzeppelin/contracts/drafts/IERC20Permit.sol";
|
import { IERC20Permit } from "@openzeppelin/contracts/drafts/IERC20Permit.sol";
|
||||||
import { IUniswapV3Factory } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
|
import { IUniswapV3Factory } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
|
||||||
import { IUniswapV3PoolState } from "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol";
|
import { IUniswapV3PoolState } from "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol";
|
||||||
import { InstanceAdditionProposal } from "./InstanceAdditionProposal.sol";
|
import { InstanceAdditionProposal, InstanceAdditionData } from "./InstanceAdditionProposal.sol";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notice Contract which creates instance addition proposals.
|
* @notice Contract which creates instance addition proposals.
|
||||||
@ -87,9 +87,7 @@ contract InstanceProposalFactory {
|
|||||||
uint16[][] calldata _protocolFees,
|
uint16[][] calldata _protocolFees,
|
||||||
uint256 _totalNumberDenominations
|
uint256 _totalNumberDenominations
|
||||||
) external returns (address) {
|
) external returns (address) {
|
||||||
InstanceAdditionProposal.InstanceAdditionData[] memory toAdd = new InstanceAdditionProposal.InstanceAdditionData[](
|
InstanceAdditionData[] memory toAdd = new InstanceAdditionData[](_totalNumberDenominations);
|
||||||
_totalNumberDenominations
|
|
||||||
);
|
|
||||||
|
|
||||||
uint256 toAddSize = 0;
|
uint256 toAddSize = 0;
|
||||||
|
|
||||||
@ -153,7 +151,7 @@ contract InstanceProposalFactory {
|
|||||||
|
|
||||||
// 9️⃣ If all of the above are fine, add the packed struct to the memory array.
|
// 9️⃣ If all of the above are fine, add the packed struct to the memory array.
|
||||||
|
|
||||||
toAdd[toAddSize] = InstanceAdditionProposal.InstanceAdditionData({
|
toAdd[toAddSize] = InstanceAdditionData({
|
||||||
tokenAddress: token,
|
tokenAddress: token,
|
||||||
smallDenomination: smallDenomination,
|
smallDenomination: smallDenomination,
|
||||||
base10Exponent: exponent,
|
base10Exponent: exponent,
|
||||||
|
@ -44,14 +44,14 @@ module.exports = {
|
|||||||
hardhat: {
|
hardhat: {
|
||||||
forking: {
|
forking: {
|
||||||
url: process.env.MAINNET_RPC_URL,
|
url: process.env.MAINNET_RPC_URL,
|
||||||
blockNumber: 14250000,
|
//blockNumber: 14250000,
|
||||||
httpHeaders: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101 Firefox/102.0' },
|
httpHeaders: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:102.0) Gecko/20100101 Firefox/102.0' },
|
||||||
},
|
},
|
||||||
chainId: 1,
|
chainId: 1,
|
||||||
initialBaseFeePerGas: 5,
|
//initialBaseFeePerGas: 5,
|
||||||
loggingEnabled: false,
|
loggingEnabled: false,
|
||||||
allowUnlimitedContractSize: false,
|
allowUnlimitedContractSize: false,
|
||||||
blockGasLimit: 50000000,
|
//blockGasLimit: 50000000,
|
||||||
},
|
},
|
||||||
rinkeby: {
|
rinkeby: {
|
||||||
url: process.env.RINKEBY_RPC_URL,
|
url: process.env.RINKEBY_RPC_URL,
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-plugin-prettier": "^3.4.0",
|
"eslint-plugin-prettier": "^3.4.0",
|
||||||
"ethereum-waffle": "^3.4.0",
|
"ethereum-waffle": "^3.4.0",
|
||||||
"hardhat": "^2.4.3",
|
"hardhat": ">=2.4.3",
|
||||||
"hardhat-contract-sizer": "^2.6.1",
|
"hardhat-contract-sizer": "^2.6.1",
|
||||||
"hardhat-log-remover": "^2.0.2",
|
"hardhat-log-remover": "^2.0.2",
|
||||||
"mocha-lcov-reporter": "^1.3.0",
|
"mocha-lcov-reporter": "^1.3.0",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
|
|
||||||
const { ethers } = require('hardhat')
|
const hre = require('hardhat')
|
||||||
|
const { ethers } = hre
|
||||||
const config = require('../config')
|
const config = require('../config')
|
||||||
const { createInterface } = require('readline')
|
const { createInterface } = require('readline')
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ function idToNetwork(id) {
|
|||||||
case 11155111:
|
case 11155111:
|
||||||
return 'Sepolia'
|
return 'Sepolia'
|
||||||
default:
|
default:
|
||||||
throw Error('\nChain id could not be recognized. What network are you using?\n')
|
throw Error('\nChain Id could not be recognized. What network are you using?\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ function _prompt(prompt, resolve) {
|
|||||||
} else if (answer == 'n') {
|
} else if (answer == 'n') {
|
||||||
userInput.close()
|
userInput.close()
|
||||||
resolve(false)
|
resolve(false)
|
||||||
} else wipeCachePrompt('', resolve)
|
} else _prompt('', resolve)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,44 +41,94 @@ function prompt(prompt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function happyDeployedMessage(name, chainId, address) {
|
function happyDeployedMessage(name, chainId, address) {
|
||||||
return `\n${name} successfully deployed on ${idToNetwork(chainId)} at ${address} 🥳\n`
|
return `\n${name} successfully deployed on ${idToNetwork(chainId)} @ ${address} 🥳\n`
|
||||||
}
|
}
|
||||||
|
|
||||||
function happyVerifiedMessage(name) {
|
function happyVerifiedMessage(name, address) {
|
||||||
return `\n${name} successfully verified on Etherscan!`
|
return `\n${name} @ ${address} successfully verified on Etherscan! 🥳\n`
|
||||||
}
|
}
|
||||||
|
|
||||||
const promptMessageBase = (middle) => `\n${middle}\n\nAre you sure you would like to continue? 🧐 (y/n): `
|
const promptMessageBase = (middle) => `\n${middle}\n\nAre you sure you would like to continue? 🧐 (y/n): `
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const minFacFac = await ethers.getContractFactory('MinimalInstanceFactory')
|
const minimalFactoryContractFactory = await ethers.getContractFactory('MinimalInstanceFactory')
|
||||||
const proposalFacFac = await ethers.getContractFactory('InstanceProposalFactory')
|
const proposalFactoryContractFactory = await ethers.getContractFactory('InstanceProposalFactory')
|
||||||
|
|
||||||
const minFac = await minFacFac.deploy(config.verifier, config.hasher, config.merkleTreeHeight)
|
let minimalFactory, proposalFactory, nativeCloneableImplAddr, erc20CloneableImplAddr
|
||||||
|
|
||||||
console.log(happyDeployedMessage('MinimalInstanceFactory', minFac.address))
|
if (await prompt(promptMessageBase('Continuing to MinimalInstanceFactory deployment.'))) {
|
||||||
|
minimalFactory = await minimalFactoryContractFactory.deploy(
|
||||||
|
config.verifier,
|
||||||
|
config.hasher,
|
||||||
|
config.merkleTreeHeight,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return '\nDecided to stop at InstanceProposalFactory deployment.\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(happyDeployedMessage('MinimalInstanceFactory', minimalFactory.address))
|
||||||
|
|
||||||
|
nativeCloneableImplAddr = await minimalFactory.nativeCurImpl()
|
||||||
|
erc20CloneableImplAddr = await minimalFactory.ERC20Impl()
|
||||||
|
|
||||||
|
console.log(happyDeployedMessage('ETHTornadoCloneable', nativeCloneableImplAddr))
|
||||||
|
console.log(happyDeployedMessage('ERC20TornadoCloneable', erc20CloneableImplAddr))
|
||||||
|
|
||||||
if (await prompt(promptMessageBase('Continuing to InstanceProposalFactory deployment.'))) {
|
if (await prompt(promptMessageBase('Continuing to InstanceProposalFactory deployment.'))) {
|
||||||
const proposalFac = await proposalFacFac.deploy(
|
proposalFactory = await proposalFactoryContractFactory.deploy(
|
||||||
config.governance,
|
config.governance,
|
||||||
minFac.address,
|
minimalFactory.address,
|
||||||
config.instanceRegistry,
|
config.instanceRegistry,
|
||||||
config.UniswapV3Factory,
|
config.UniswapV3Factory,
|
||||||
config.WETH,
|
config.WETH,
|
||||||
config.TWAPSlotsMin,
|
config.TWAPSlotsMin,
|
||||||
)
|
)
|
||||||
|
|
||||||
console.log(happyDeployedMessage('InstanceProposalFactory', proposalFac.address))
|
console.log(happyDeployedMessage('InstanceProposalFactory', proposalFactory.address))
|
||||||
} else {
|
} else {
|
||||||
return '\nDecided to stop at InstanceProposalFactory deployment.\n'
|
return '\nDecided to stop at InstanceProposalFactory deployment.\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await prompt(promptMessageBase('Continuing to contract verification.'))) {
|
if (await prompt(promptMessageBase('Continuing to contract verification.'))) {
|
||||||
|
await hre.run('verify:verify', {
|
||||||
|
address: minimalFactory.address,
|
||||||
|
constructorArguments: [config.verifier, config.hasher, config.merkleTreeHeight],
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(happyVerifiedMessage('MinimalInstanceFactory', minimalFactory.address))
|
||||||
|
|
||||||
|
await hre.run('verify:verify', {
|
||||||
|
address: proposalFactory.address,
|
||||||
|
constructorArguments: [
|
||||||
|
config.governance,
|
||||||
|
minimalFactory.address,
|
||||||
|
config.instanceRegistry,
|
||||||
|
config.UniswapV3Factory,
|
||||||
|
config.WETH,
|
||||||
|
config.TWAPSlotsMin,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(happyVerifiedMessage('InstanceProposalFactory', proposalFactory.address))
|
||||||
|
|
||||||
|
await hre.run('verify:verify', {
|
||||||
|
address: nativeCloneableImplAddr,
|
||||||
|
constructorArguments: [config.verifier, config.hasher],
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(happyVerifiedMessage('ETHTornadoCloneable', nativeCloneableImplAddr))
|
||||||
|
|
||||||
|
await hre.run('verify:verify', {
|
||||||
|
address: erc20CloneableImplAddr,
|
||||||
|
constructorArguments: [config.verifier, config.hasher],
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(happyVerifiedMessage('ERC20TornadoCloneable', erc20CloneableImplAddr))
|
||||||
} else {
|
} else {
|
||||||
return '\nDecided to stop at contract verification.\n'
|
return '\nDecided to stop at contract verification.\n'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main().then((res) => {
|
main().then((res) => {
|
||||||
console.log(res ?? '\nScript succesfully finished.')
|
console.log(res ?? '\nScript succesfully finished.\n')
|
||||||
})
|
})
|
||||||
|
188
test/all.test.js
Normal file
188
test/all.test.js
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
const hre = require('hardhat')
|
||||||
|
const config = require('../config')
|
||||||
|
|
||||||
|
const { ethers, waffle } = hre
|
||||||
|
const { loadFixture } = waffle
|
||||||
|
const { expect } = require('chai')
|
||||||
|
const { minewait } = require('./utils')
|
||||||
|
|
||||||
|
const { BigNumber } = require('@ethersproject/bignumber')
|
||||||
|
|
||||||
|
describe('Tests', () => {
|
||||||
|
let governanceSigner, proposer
|
||||||
|
let minimalFactory, proposalFactory, governance, torn
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
minimalFactory = await (
|
||||||
|
await ethers.getContractFactory('MinimalInstanceFactory')
|
||||||
|
).deploy(config.verifier, config.hasher, config.merkleTreeHeight)
|
||||||
|
|
||||||
|
let gasUsed = await ethers.provider.estimateGas(minimalFactory.deployTransaction.data.toString())
|
||||||
|
|
||||||
|
console.log(`\nManaged to deploy the MinimalInstanceFactory. Gas used: ${gasUsed} 🏭\n`)
|
||||||
|
|
||||||
|
proposalFactory = await (
|
||||||
|
await ethers.getContractFactory('InstanceProposalFactory')
|
||||||
|
).deploy(
|
||||||
|
config.governance,
|
||||||
|
minimalFactory.address,
|
||||||
|
config.instanceRegistry,
|
||||||
|
config.UniswapV3Factory,
|
||||||
|
config.WETH,
|
||||||
|
config.TWAPSlotsMin,
|
||||||
|
)
|
||||||
|
|
||||||
|
gasUsed = await ethers.provider.estimateGas(minimalFactory.deployTransaction.data.toString())
|
||||||
|
|
||||||
|
console.log(`\nManaged to deploy the InstanceProposalFactory. Gas used: ${gasUsed} 🏭\n`)
|
||||||
|
|
||||||
|
await hre.network.provider.request({
|
||||||
|
method: 'hardhat_impersonateAccount',
|
||||||
|
params: [config.governance],
|
||||||
|
})
|
||||||
|
|
||||||
|
await hre.network.provider.request({
|
||||||
|
method: 'hardhat_setBalance',
|
||||||
|
params: [config.governance, ethers.utils.parseUnits('10').toHexString()],
|
||||||
|
})
|
||||||
|
|
||||||
|
governanceSigner = await ethers.getSigner(config.governance)
|
||||||
|
|
||||||
|
governance = await ethers.getContractAt(
|
||||||
|
'tornado-governance/contracts/v1/Governance.sol:Governance',
|
||||||
|
config.governance,
|
||||||
|
governanceSigner,
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log('\nManaged to setup self-signing governance (just like IRL). 🏛️\n')
|
||||||
|
|
||||||
|
torn = await ethers.getContractAt('torn-token/contracts/TORN.sol:TORN', config.TORN, governanceSigner)
|
||||||
|
|
||||||
|
proposer = (await ethers.getSigners())[0]
|
||||||
|
|
||||||
|
const fundAmount = (await torn.balanceOf(governance.address)).div(2)
|
||||||
|
|
||||||
|
await expect(() => torn.transfer(proposer.address, fundAmount)).to.changeTokenBalance(
|
||||||
|
torn,
|
||||||
|
proposer,
|
||||||
|
fundAmount,
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log(`\nFunded proposer with ${fundAmount.div(BigNumber.from(10).pow(18))} TORN 🌪️\n`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Test the entire instance creation process.', async () => {
|
||||||
|
let response = await proposalFactory.createProposalContract(
|
||||||
|
[config.LUSD],
|
||||||
|
// This should work fine
|
||||||
|
[3000, 100000],
|
||||||
|
// This should work fine
|
||||||
|
[18, 3921],
|
||||||
|
[[ethers.utils.parseUnits('10000'), ethers.utils.parseUnits('1000'), ethers.utils.parseUnits('100')]],
|
||||||
|
// This should work fine
|
||||||
|
[[100, 100, 100, 312]],
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log('\nManaged to deploy an LUSD proposal factory. 🏭\n')
|
||||||
|
|
||||||
|
let receipt = await response.wait()
|
||||||
|
|
||||||
|
const proposalContractLUSD = await ethers.getContractAt(
|
||||||
|
'InstanceAdditionProposal',
|
||||||
|
receipt.events[0].args[0],
|
||||||
|
)
|
||||||
|
|
||||||
|
expect((await proposalContractLUSD.getAllDataToAdd()).length).to.equal(3)
|
||||||
|
|
||||||
|
let denominations = [
|
||||||
|
ethers.utils.parseUnits('1000'),
|
||||||
|
ethers.utils.parseUnits('100'),
|
||||||
|
ethers.utils.parseUnits('10'),
|
||||||
|
]
|
||||||
|
|
||||||
|
response = await proposalFactory.createProposalContract(
|
||||||
|
[config.RETH, config.LUSD],
|
||||||
|
// This should work fine
|
||||||
|
[500, 3000, 100000],
|
||||||
|
// This too
|
||||||
|
[18, 18, 3921],
|
||||||
|
[denominations, denominations],
|
||||||
|
// This should work fine
|
||||||
|
[
|
||||||
|
[100, 100, 100, 312],
|
||||||
|
[300, 300, 300, 312],
|
||||||
|
],
|
||||||
|
6,
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log('\nManaged to deploy a RETH + LUSD proposal factory. 🏭\n')
|
||||||
|
|
||||||
|
receipt = await response.wait()
|
||||||
|
|
||||||
|
const proposalContractRETHLUSD = await ethers.getContractAt(
|
||||||
|
'InstanceAdditionProposal',
|
||||||
|
receipt.events[0].args[0],
|
||||||
|
)
|
||||||
|
|
||||||
|
const addedData = await proposalContractRETHLUSD.getAllDataToAdd()
|
||||||
|
|
||||||
|
expect(addedData.length).to.equal(6)
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
proposalFactory.createProposalContract(
|
||||||
|
[config.RETH, config.FRXETH],
|
||||||
|
// Should be reverted because of frxeth
|
||||||
|
[500, 3000],
|
||||||
|
[18, 18, 3921],
|
||||||
|
[denominations, denominations],
|
||||||
|
[
|
||||||
|
[100, 100, 100, 312],
|
||||||
|
[100, 100, 100, 312],
|
||||||
|
],
|
||||||
|
6,
|
||||||
|
),
|
||||||
|
).to.be.reverted
|
||||||
|
|
||||||
|
console.log('\nInsufficient cardinality frxETH reverted. 🦄\n')
|
||||||
|
|
||||||
|
console.log('Starting proposal process on former proposal...\n')
|
||||||
|
|
||||||
|
governance = governance.connect(proposer)
|
||||||
|
torn = torn.connect(proposer)
|
||||||
|
|
||||||
|
const proposerBalance = await torn.balanceOf(proposer.address)
|
||||||
|
|
||||||
|
await torn.approve(governance.address, proposerBalance)
|
||||||
|
|
||||||
|
await expect(() => governance.lockWithApproval(proposerBalance)).to.changeTokenBalance(
|
||||||
|
torn,
|
||||||
|
proposer,
|
||||||
|
proposerBalance.mul('-1'),
|
||||||
|
)
|
||||||
|
|
||||||
|
await expect(governance.propose(proposalContractRETHLUSD.address, 'Add some random tokens.')).to.not.be
|
||||||
|
.reverted
|
||||||
|
|
||||||
|
const proposalId = await governance.latestProposalIds(proposer.address)
|
||||||
|
|
||||||
|
console.log(`\nSuccessfully proposed proposal with id ${proposalId}. 📜\n`)
|
||||||
|
|
||||||
|
const votingDelay = await governance.VOTING_DELAY()
|
||||||
|
|
||||||
|
// Mine the time necessary for the proposal to finish
|
||||||
|
await minewait(votingDelay.toNumber())
|
||||||
|
|
||||||
|
await expect(governance.castVote(proposalId, true)).to.not.be.reverted
|
||||||
|
|
||||||
|
const delay = await governance.EXECUTION_DELAY()
|
||||||
|
const period = await governance.VOTING_PERIOD()
|
||||||
|
|
||||||
|
// Mine the time necessary for the proposal to finish
|
||||||
|
await minewait(delay.add(period.add('43200')).toNumber())
|
||||||
|
|
||||||
|
await expect(governance.execute(proposalId)).to.not.be.reverted
|
||||||
|
|
||||||
|
console.log('\n Successfully executed the proposal! 🥳\n')
|
||||||
|
})
|
||||||
|
})
|
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