From 77bcdb8049b5832bd9489215bed249a9031986e1 Mon Sep 17 00:00:00 2001 From: cryptoDev222 Date: Thu, 12 Aug 2021 10:44:34 -0500 Subject: [PATCH] testcase script file and case tokenID 0 --- .../mainnet/connectors/uniswapV3/events.sol | 4 +- .../mainnet/connectors/uniswapV3/helpers.sol | 2 + .../mainnet/connectors/uniswapV3/main.sol | 38 +-- hardhat.config.js | 2 +- test/uniswap/uniswap.test.js | 234 +++++++++++++++++- 5 files changed, 251 insertions(+), 29 deletions(-) diff --git a/contracts/mainnet/connectors/uniswapV3/events.sol b/contracts/mainnet/connectors/uniswapV3/events.sol index 2be7aac0..82b7526e 100644 --- a/contracts/mainnet/connectors/uniswapV3/events.sol +++ b/contracts/mainnet/connectors/uniswapV3/events.sol @@ -22,12 +22,12 @@ contract Events { uint256 amtB ); - event swap( + event Swap( address indexed tokenIn, address indexed tokenOut, uint256 amtIn, uint256 amtOut ); - event burn(uint256 tokenId); + event BurnPosition(uint256 tokenId); } diff --git a/contracts/mainnet/connectors/uniswapV3/helpers.sol b/contracts/mainnet/connectors/uniswapV3/helpers.sol index 8af8ca67..41671dd5 100644 --- a/contracts/mainnet/connectors/uniswapV3/helpers.sol +++ b/contracts/mainnet/connectors/uniswapV3/helpers.sol @@ -89,6 +89,7 @@ abstract contract Helpers is DSMath, Basic { address(this), block.timestamp ); + (tokenId, liquidity, amount0, amount1) = nftManager.mint(params); } @@ -137,6 +138,7 @@ abstract contract Helpers is DSMath, Basic { _amount1Min, block.timestamp ); + (liquidity, amount0, amount1) = nftManager.increaseLiquidity(params); } diff --git a/contracts/mainnet/connectors/uniswapV3/main.sol b/contracts/mainnet/connectors/uniswapV3/main.sol index 9bcfd78b..25bb046f 100644 --- a/contracts/mainnet/connectors/uniswapV3/main.sol +++ b/contracts/mainnet/connectors/uniswapV3/main.sol @@ -11,33 +11,37 @@ import {Helpers} from "./helpers.sol"; import {Events} from "./events.sol"; abstract contract UniswapResolver is Helpers, Events { + uint256 private _lastMintIndex = 1; /** * @dev Mint New Position * @param params: parameter for mint. - * @param getId: ID to retrieve amtA. + * @param getIds: ID to retrieve amtA. * @param setId: ID stores the amount of LP token. */ function mint( MintParams memory params, - uint256 getId, + uint256[] calldata getIds, uint256 setId ) external payable returns (string memory _eventName, bytes memory _eventParam) { - params.amtA = getUint(getId, params.amtA); + params.amtA = getUint(getIds[0], params.amtA); + params.amtB = getUint(getIds[1], params.amtB); ( - uint256 _tokenID, + uint256 _tokenId, + uint256 liquidity, uint256 _amtA, - uint256 _amtB, - uint256 liquidity + uint256 _amtB ) = _mint(params); setUint(setId, liquidity); - _eventName = "LogMintNewPosition(uint256,uint256,uint256,uint256)"; - _eventParam = abi.encode(_tokenID, _amtA, _amtB, liquidity); + _lastMintIndex = _tokenId; + + _eventName = "LogNewPositionMint(uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode(_tokenId, _amtA, _amtB, liquidity); } /** @@ -63,13 +67,14 @@ abstract contract UniswapResolver is Helpers, Events { payable returns (string memory _eventName, bytes memory _eventParam) { - uint256 amtA = getUint(getIds[0], amountA); - uint256 amtB = getUint(getIds[1], amountB); + if (tokenId == 0) tokenId = _lastMintIndex; + amountA = getUint(getIds[0], amountA); + amountB = getUint(getIds[1], amountB); (uint256 _liquidity, uint256 _amtA, uint256 _amtB) = _addLiquidity( tokenId, - amtA, - amtB, + amountA, + amountB, amountAMin, amountBMin ); @@ -100,6 +105,7 @@ abstract contract UniswapResolver is Helpers, Events { payable returns (string memory _eventName, bytes memory _eventParam) { + if (tokenId == 0) tokenId = _lastMintIndex; uint128 _liquidity = uint128(getUint(getId, liquidity)); (uint256 _amtA, uint256 _amtB) = _decreaseLiquidity( @@ -147,7 +153,7 @@ abstract contract UniswapResolver is Helpers, Events { setUint(setId, amountOut); - _eventName = "swap(address,address,uint256,uint256)"; + _eventName = "Swap(address,address,uint256,uint256)"; _eventParam = abi.encode(tokenIn, tokenOut, _amountIn, amountOut); } @@ -170,6 +176,7 @@ abstract contract UniswapResolver is Helpers, Events { payable returns (string memory _eventName, bytes memory _eventParam) { + if (tokenId == 0) tokenId = _lastMintIndex; uint128 _amount0Max = uint128(getUint(getIds[0], amount0Max)); uint128 _amount1Max = uint128(getUint(getIds[1], amount1Max)); (uint256 amount0, uint256 amount1) = _collect( @@ -180,7 +187,7 @@ abstract contract UniswapResolver is Helpers, Events { setUint(setIds[0], amount0); setUint(setIds[1], amount1); - _eventName = "collect(uint256,uint256,uint256)"; + _eventName = "Collect(uint256,uint256,uint256)"; _eventParam = abi.encode(tokenId, amount0, amount1); } @@ -192,8 +199,9 @@ abstract contract UniswapResolver is Helpers, Events { payable returns (string memory _eventName, bytes memory _eventParam) { + if (tokenId == 0) tokenId = _lastMintIndex; _burn(tokenId); - _eventName = "burnPosition(uint256)"; + _eventName = "BurnPosition(uint256)"; _eventParam = abi.encode(tokenId); } } diff --git a/hardhat.config.js b/hardhat.config.js index c29dd331..55084290 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -57,7 +57,7 @@ module.exports = { hardhat: { forking: { url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`, - blockNumber: 12696000, + blockNumber: 13005785, }, blockGasLimit: 12000000, gasPrice: parseInt(utils.parseUnits("300", "gwei")) diff --git a/test/uniswap/uniswap.test.js b/test/uniswap/uniswap.test.js index 634fa922..94f3e815 100644 --- a/test/uniswap/uniswap.test.js +++ b/test/uniswap/uniswap.test.js @@ -14,8 +14,30 @@ const addresses = require("../../scripts/constant/addresses"); const abis = require("../../scripts/constant/abis"); const constants = require("../../scripts/constant/constant"); const tokens = require("../../scripts/constant/tokens"); +const { abi: nftManagerAbi } = require("@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json") -const connectV2UniswapV3Artifacts = require("../../artifacts/contracts/mainnet/connectors/uniswapV3/main.sol/ConnectV2UniswapV3.json") +const connectV2UniswapV3Artifacts = require("../../artifacts/contracts/mainnet/connectors/uniswapV3/main.sol/ConnectV2UniswapV3.json"); +const { eth } = require("../../scripts/constant/tokens"); +const { BigNumber } = require("ethers"); + +const FeeAmount = { + LOW: 500, + MEDIUM: 3000, + HIGH: 10000, +} + +const TICK_SPACINGS = { + 500: 10, + 3000: 60, + 10000: 200 +} + +const USDT_ADDR = "0xdac17f958d2ee523a2206206994597c13d831ec7" +const DAI_ADDR = "0x6b175474e89094c44da98b954eedeac495271d0f" + +let tokenIds = [] +let liquidities = [] +const abiCoder = ethers.utils.defaultAbiCoder describe("UniswapV3", function () { const connectorName = "UniswapV3-v1" @@ -24,12 +46,14 @@ describe("UniswapV3", function () { let masterSigner; let instaConnectorsV2; let connector; + let nftManager; const wallets = provider.getWallets() const [wallet0, wallet1, wallet2, wallet3] = wallets before(async () => { masterSigner = await getMasterSigner(wallet3) instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2); + nftManager = await ethers.getContractAt(nftManagerAbi, "0xC36442b4a4522E871399CD717aBDD847Ab11FE88"); connector = await deployAndEnableConnector({ connectorName, contractArtifact: connectV2UniswapV3Artifacts, @@ -59,7 +83,16 @@ describe("UniswapV3", function () { expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10")); await addLiquidity("dai", dsaWallet0.address, ethers.utils.parseEther("100000")); + }); + it("Deposit ETH & USDT into DSA wallet", async function () { + await wallet0.sendTransaction({ + to: dsaWallet0.address, + value: ethers.utils.parseEther("10") + }); + expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10")); + + await addLiquidity("usdt", dsaWallet0.address, ethers.utils.parseEther("100000")); }); }); @@ -68,34 +101,213 @@ describe("UniswapV3", function () { it("Should mint successfully", async function () { const ethAmount = ethers.utils.parseEther("0.1") // 1 ETH const daiAmount = ethers.utils.parseEther("400") // 1 ETH + const usdtAmount = ethers.utils.parseEther("400") / Math.pow(10, 12) // 1 ETH const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" - const getId = "0" + const getIds = ["0", "0"] const setId = "0" - const spells2 = [ + const spells = [ { connector: connectorName, method: "mint", args: [ - { + { + tokenA: DAI_ADDR, tokenB: ethAddress, - tokenA: "0x6b175474e89094c44da98b954eedeac495271d0f", - fee: "3000", - tickUpper: "887220", - tickLower: "-887220", + fee: FeeAmount.MEDIUM, + tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), amtA: daiAmount, amtB: ethAmount, - slippage: "0" + slippage: "500000000000000000" }, - getId, + getIds, + setId + ], + }, + { + connector: connectorName, + method: "mint", + args: [ + { + tokenB: USDT_ADDR, + tokenA: DAI_ADDR, + fee: FeeAmount.MEDIUM, + tickUpper: getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + tickLower: getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + amtA: daiAmount, + amtB: usdtAmount, + slippage: "300000000000000000" + }, + getIds, setId ], } ] - const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells2), wallet1.address) + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + let receipt = await tx.wait() + let castEvent = new Promise((resolve, reject) => { + dsaWallet0.on('LogCast', (origin, sender, value, targetNames, targets, eventNames, eventParams, event) => { + const params = abiCoder.decode(["uint256", "uint256", "uint256", "uint256"], eventParams[0]); + const params1 = abiCoder.decode(["uint256", "uint256", "uint256", "uint256"], eventParams[1]); + tokenIds.push(params[0]); + tokenIds.push(params1[0]); + liquidities.push(params[3]); + event.removeListener(); + + resolve({ + eventNames, + }); + }); + + setTimeout(() => { + reject(new Error('timeout')); + }, 60000) + }); + + let event = await castEvent + + const data = await nftManager.positions(tokenIds[0]) + + expect(data.liquidity).to.be.equals(liquidities[0]); + }) + + it("Should increaseLiquidity successfully", async function () { + const daiAmount = ethers.utils.parseEther("400") // 1 ETH + const ethAmount = ethers.utils.parseEther("0.1") // 1 ETH + const usdtAmount = ethers.utils.parseEther("400") / Math.pow(10, 12) // 1 ETH + const ethAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + + const getIds = ["0", "0"] + const setId = "0" + + const spells = [ + { + connector: connectorName, + method: "addLiquidity", + args: [ + tokenIds[0], + daiAmount, + ethAmount, + 0, + 0, + getIds, + setId + ], + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + + let castEvent = new Promise((resolve, reject) => { + dsaWallet0.on('LogCast', (origin, sender, value, targetNames, targets, eventNames, eventParams, event) => { + const params = abiCoder.decode(["uint256", "uint256", "uint256", "uint256"], eventParams[0]); + liquidities[0] = liquidities[0].add(params[3]); + event.removeListener(); + + resolve({ + eventNames, + }); + }); + + setTimeout(() => { + reject(new Error('timeout')); + }, 60000) + }); + + let event = await castEvent + + const data = await nftManager.positions(tokenIds[0]) + expect(data.liquidity).to.be.equals(liquidities[0]); + }) + + it("Should decreaseLiquidity successfully", async function () { + + const getId = "0" + const setIds = ["0", "0"] + + const data = await nftManager.positions(tokenIds[0]) + let data1 = await nftManager.positions(tokenIds[1]) + + const spells = [ + { + connector: connectorName, + method: "decreaseLiquidity", + args: [ + tokenIds[0], + data.liquidity, + 0, + 0, + getId, + setIds + ], + }, + { + connector: connectorName, + method: "decreaseLiquidity", + args: [ + 0, + data1.liquidity, + 0, + 0, + getId, + setIds + ], + }, + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + + data1 = await nftManager.positions(tokenIds[1]) + expect(data1.liquidity.toNumber()).to.be.equals(0); + }) + + it("Should collect successfully", async function () { + + const ethAmount = ethers.utils.parseEther("0.2") // 1 ETH + const daiAmount = ethers.utils.parseEther("800") // 1 ETH + const getIds = ["0", "0"] + const setIds = ["0", "0"] + + const spells = [ + { + connector: connectorName, + method: "collect", + args: [ + tokenIds[0], + daiAmount, + ethAmount, + getIds, + setIds + ], + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + }) + + it("Should burn successfully", async function () { + + const spells = [ + { + connector: connectorName, + method: "burnNFT", + args: [ + tokenIds[0] + ], + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) const receipt = await tx.wait() }) }) }) + +const getMinTick = (tickSpacing) => Math.ceil(-887272 / tickSpacing) * tickSpacing +const getMaxTick = (tickSpacing) => Math.floor(887272 / tickSpacing) * tickSpacing