add uniswap pool check

This commit is contained in:
Drygin 2022-03-15 20:55:01 +03:00
parent 65a01c3ce8
commit 9bfbc01d8e
6 changed files with 68 additions and 5 deletions

View File

@ -29,6 +29,7 @@ Anyone can create governance proposal for the addition of a new ERC20 instance b
1. `max number of new instances in one proposal` - the current version supports the addition of a maximum of 4 instances at once. 1. `max number of new instances in one proposal` - the current version supports the addition of a maximum of 4 instances at once.
2. `proposal creation fee` - this fee is charged from creator of proposal during `createProposalApprove/createProposalPermit` factory method execution. It can be changed by governance. Default value is stored in `config.js`. 2. `proposal creation fee` - this fee is charged from creator of proposal during `createProposalApprove/createProposalPermit` factory method execution. It can be changed by governance. Default value is stored in `config.js`.
3. `TWAPSlotsMin` - minimum number of TWAP slots for Uniswap pool that is chosen during `createProposalApprove/createProposalPermit` factory method call. It can be changed by governance. Default value is stored in `config.js`.
## Warnings ## Warnings
@ -60,8 +61,8 @@ Check config.js for actual values.
With `salt` = `0x0000000000000000000000000000000000000000000000000000000047941987` address must be: With `salt` = `0x0000000000000000000000000000000000000000000000000000000047941987` address must be:
1. `InstanceFactory` - `0x9A04e3F1091A69CB53D163abE7ad9bbc86C23823` 1. `InstanceFactory` - `0x09110e04d5AEF747bcf7A3585D8FFC892Ab9D1Cf`
1. `InstanceFactoryWithRegistry` - `0xee994E045B9Ec5a37f3f85d34f9fD087A0c69236` 2. `InstanceFactoryWithRegistry` - `0xC01D57d83E9Fe35E0Fb900F9D384EFcA679DF4bD`
Check addresses with current config: Check addresses with current config:

View File

@ -15,4 +15,7 @@ module.exports = {
creationFee: '200000000000000000000', // 200 TORN creationFee: '200000000000000000000', // 200 TORN
deployGasLimit: 7000000, deployGasLimit: 7000000,
owner: '0xBAE5aBfa98466Dbe68836763B087f2d189f4D28f', owner: '0xBAE5aBfa98466Dbe68836763B087f2d189f4D28f',
WETH: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
UniswapV3Factory: '0x1F98431c8aD98523631AE4a59f267346ea31F984',
TWAPSlotsMin: 50,
} }

View File

@ -37,7 +37,7 @@ contract AddInstanceProposal {
token = _token; token = _token;
uniswapPoolSwappingFee = _uniswapPoolSwappingFee; uniswapPoolSwappingFee = _uniswapPoolSwappingFee;
require(_denominations.length == _protocolFees.length, "denominations length != protocolFees length"); require(_denominations.length == _protocolFees.length, "Incorrect denominations/fees length");
uint256 _numInstances = _denominations.length; uint256 _numInstances = _denominations.length;
require(_numInstances > 0 && _numInstances <= 4, "incorrect instances number"); require(_numInstances > 0 && _numInstances <= 4, "incorrect instances number");
numInstances = _numInstances; numInstances = _numInstances;

View File

@ -8,6 +8,8 @@ import "./AddInstanceProposal.sol";
import "./InstanceFactory.sol"; import "./InstanceFactory.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 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 { IUniswapV3PoolState } from "@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol";
contract InstanceFactoryWithRegistry is InstanceFactory { contract InstanceFactoryWithRegistry is InstanceFactory {
using Address for address; using Address for address;
@ -15,9 +17,13 @@ contract InstanceFactoryWithRegistry is InstanceFactory {
address public immutable governance; address public immutable governance;
address public immutable torn; address public immutable torn;
address public immutable instanceRegistry; address public immutable instanceRegistry;
IUniswapV3Factory public immutable UniswapV3Factory;
address public immutable WETH;
uint16 public TWAPSlotsMin;
uint256 public creationFee; uint256 public creationFee;
event NewCreationFeeSet(uint256 indexed newCreationFee); event NewCreationFeeSet(uint256 newCreationFee);
event NewTWAPSlotsMinSet(uint256 newTWAPSlotsMin);
event NewGovernanceProposalCreated(address indexed proposal); event NewGovernanceProposalCreated(address indexed proposal);
/** /**
@ -35,11 +41,17 @@ contract InstanceFactoryWithRegistry is InstanceFactory {
address _governance, address _governance,
address _instanceRegistry, address _instanceRegistry,
address _torn, address _torn,
address _UniswapV3Factory,
address _WETH,
uint16 _TWAPSlotsMin,
uint256 _creationFee uint256 _creationFee
) InstanceFactory(_verifier, _hasher, _merkleTreeHeight, _governance) { ) InstanceFactory(_verifier, _hasher, _merkleTreeHeight, _governance) {
governance = _governance; governance = _governance;
instanceRegistry = _instanceRegistry; instanceRegistry = _instanceRegistry;
torn = _torn; torn = _torn;
UniswapV3Factory = IUniswapV3Factory(_UniswapV3Factory);
WETH = _WETH;
TWAPSlotsMin = _TWAPSlotsMin;
creationFee = _creationFee; creationFee = _creationFee;
} }
@ -103,10 +115,22 @@ contract InstanceFactoryWithRegistry is InstanceFactory {
uint32[] memory _protocolFees uint32[] memory _protocolFees
) internal returns (address) { ) internal returns (address) {
require(_token.isContract(), "Token is not contract"); require(_token.isContract(), "Token is not contract");
require(_uniswapPoolSwappingFee > 0, "uniswapPoolSwappingFee is zero");
require(_denominations.length > 0, "Empty denominations"); require(_denominations.length > 0, "Empty denominations");
require(_denominations.length == _protocolFees.length, "Incorrect denominations/fees length"); require(_denominations.length == _protocolFees.length, "Incorrect denominations/fees length");
// check Uniswap Pool
for (uint8 i = 0; i < _protocolFees.length; i++) {
if (_protocolFees[i] > 0) {
// pool exists
address poolAddr = UniswapV3Factory.getPool(_token, WETH, _uniswapPoolSwappingFee);
require(poolAddr != address(0), "Uniswap pool is not exist");
// TWAP slots
(, , , , uint16 observationCardinalityNext, , ) = IUniswapV3PoolState(poolAddr).slot0();
require(observationCardinalityNext >= TWAPSlotsMin, "Uniswap pool TWAP slots number is low");
break;
}
}
address proposal = address( address proposal = address(
new AddInstanceProposal(address(this), instanceRegistry, _token, _uniswapPoolSwappingFee, _denominations, _protocolFees) new AddInstanceProposal(address(this), instanceRegistry, _token, _uniswapPoolSwappingFee, _denominations, _protocolFees)
); );
@ -119,4 +143,9 @@ contract InstanceFactoryWithRegistry is InstanceFactory {
creationFee = _creationFee; creationFee = _creationFee;
emit NewCreationFeeSet(_creationFee); emit NewCreationFeeSet(_creationFee);
} }
function setTWAPSlotsMin(uint16 _TWAPSlotsMin) external onlyGovernance {
TWAPSlotsMin = _TWAPSlotsMin;
emit NewTWAPSlotsMinSet(_TWAPSlotsMin);
}
} }

View File

@ -26,6 +26,9 @@ async function generate(config = defaultConfig) {
config.governance, config.governance,
config.instanceRegistry, config.instanceRegistry,
config.TORN, config.TORN,
config.UniswapV3Factory,
config.WETH,
config.TWAPSlotsMin,
config.creationFee, config.creationFee,
]) ])
.slice(2) .slice(2)

View File

@ -101,6 +101,9 @@ describe('Instance Factory With Registry Tests', () => {
expect(await instanceFactory.implementation()).to.exist expect(await instanceFactory.implementation()).to.exist
expect(await instanceFactory.creationFee()).to.be.equal(config.creationFee) expect(await instanceFactory.creationFee()).to.be.equal(config.creationFee)
expect(await instanceFactory.torn()).to.be.equal(config.TORN) expect(await instanceFactory.torn()).to.be.equal(config.TORN)
expect(await instanceFactory.TWAPSlotsMin()).to.be.equal(config.TWAPSlotsMin)
expect(await instanceFactory.WETH()).to.be.equal(config.WETH)
expect(await instanceFactory.UniswapV3Factory()).to.be.equal(config.UniswapV3Factory)
}) })
it('Governance should be able to set factory params', async function () { it('Governance should be able to set factory params', async function () {
@ -114,20 +117,24 @@ describe('Instance Factory With Registry Tests', () => {
await instanceFactory.generateNewImplementation(addressZero, addressZero) await instanceFactory.generateNewImplementation(addressZero, addressZero)
await instanceFactory.setMerkleTreeHeight(1) await instanceFactory.setMerkleTreeHeight(1)
await instanceFactory.setCreationFee(0) await instanceFactory.setCreationFee(0)
await instanceFactory.setTWAPSlotsMin(0)
expect(await instanceFactory.verifier()).to.be.equal(addressZero) expect(await instanceFactory.verifier()).to.be.equal(addressZero)
expect(await instanceFactory.hasher()).to.be.equal(addressZero) expect(await instanceFactory.hasher()).to.be.equal(addressZero)
expect(await instanceFactory.merkleTreeHeight()).to.be.equal(1) expect(await instanceFactory.merkleTreeHeight()).to.be.equal(1)
expect(await instanceFactory.creationFee()).to.be.equal(0) expect(await instanceFactory.creationFee()).to.be.equal(0)
expect(await instanceFactory.TWAPSlotsMin()).to.be.equal(0)
await instanceFactory.generateNewImplementation(config.verifier, config.hasher) await instanceFactory.generateNewImplementation(config.verifier, config.hasher)
await instanceFactory.setMerkleTreeHeight(config.merkleTreeHeight) await instanceFactory.setMerkleTreeHeight(config.merkleTreeHeight)
await instanceFactory.setCreationFee(config.creationFee) await instanceFactory.setCreationFee(config.creationFee)
await instanceFactory.setTWAPSlotsMin(config.TWAPSlotsMin)
expect(await instanceFactory.verifier()).to.be.equal(config.verifier) expect(await instanceFactory.verifier()).to.be.equal(config.verifier)
expect(await instanceFactory.hasher()).to.be.equal(config.hasher) expect(await instanceFactory.hasher()).to.be.equal(config.hasher)
expect(await instanceFactory.merkleTreeHeight()).to.be.equal(config.merkleTreeHeight) expect(await instanceFactory.merkleTreeHeight()).to.be.equal(config.merkleTreeHeight)
expect(await instanceFactory.creationFee()).to.be.equal(config.creationFee) expect(await instanceFactory.creationFee()).to.be.equal(config.creationFee)
expect(await instanceFactory.TWAPSlotsMin()).to.be.equal(config.TWAPSlotsMin)
}) })
it('Should successfully deploy/propose/execute proposal - add instance', async function () { it('Should successfully deploy/propose/execute proposal - add instance', async function () {
@ -466,4 +473,24 @@ describe('Instance Factory With Registry Tests', () => {
[BigNumber.from(0).sub(value), value], [BigNumber.from(0).sub(value), value],
) )
}) })
it('Should not deploy proposal with incorrect Uniswap pool', async function () {
let { sender, instanceFactory, tornWhale, tornToken } = await loadFixture(fixture)
// deploy proposal ----------------------------------------------
await tornToken.connect(tornWhale).transfer(sender.address, config.creationFee)
await tornToken.approve(instanceFactory.address, config.creationFee)
await expect(
instanceFactory
.connect(sender)
.createProposalApprove(config.COMP, 4000, [ethers.utils.parseEther('100')], [30]),
).to.be.revertedWith('Uniswap pool is not exist')
await expect(
instanceFactory
.connect(sender)
.createProposalApprove(config.COMP, 10000, [ethers.utils.parseEther('100')], [30]),
).to.be.revertedWith('Uniswap pool TWAP slots number is low')
})
}) })