From ea3072e80290b42edbf18fd679421fa1970b7fbb Mon Sep 17 00:00:00 2001 From: pradyuman-verma Date: Fri, 19 Nov 2021 13:59:07 +0530 Subject: [PATCH] fix: minor --- contracts/sample/helpers.sol | 56 ++ contracts/sample/interface.sol | 36 ++ contracts/sample/libraries/IERC20Minimal.sol | 61 ++ contracts/sample/libraries/TransferHelper.sol | 70 ++- contracts/sample/main.sol | 32 + contracts/sample/uniswap-sample.sol | 92 --- hardhat.config.js | 37 +- test/sample/uniswap.js | 80 +++ test/uniswap/uniswap.test.js | 587 ++++++++++-------- 9 files changed, 642 insertions(+), 409 deletions(-) create mode 100644 contracts/sample/helpers.sol create mode 100644 contracts/sample/interface.sol create mode 100644 contracts/sample/libraries/IERC20Minimal.sol create mode 100644 contracts/sample/main.sol delete mode 100644 contracts/sample/uniswap-sample.sol create mode 100644 test/sample/uniswap.js diff --git a/contracts/sample/helpers.sol b/contracts/sample/helpers.sol new file mode 100644 index 00000000..c199f22a --- /dev/null +++ b/contracts/sample/helpers.sol @@ -0,0 +1,56 @@ +pragma solidity ^0.7.6; +pragma abicoder v2; + +import "./interface.sol"; +import {SqrtPriceMath} from "./libraries/SqrtPriceMath.sol"; +import "./libraries/TransferHelper.sol"; + +abstract contract Helpers is ISwapRouter { + ISwapRouter router = + ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); + + UniswapV3Pool state = + UniswapV3Pool(0xCEda10b4d3bdE429DdA3A6daB87b38360313CBdB); + + uint24 public constant poolFee = 3000; + + function getPriceLimit( + ISwapRouter.ExactInputSingleParams memory params, + bool zeroForOne + ) public returns (uint160) { + return ( + SqrtPriceMath.getNextSqrtPriceFromInput( + state.slot0().sqrtPriceX96, + state.liquidity(), + params.amountIn, + zeroForOne + ) + ); + } + + function approveTransfer( + ISwapRouter.ExactInputSingleParams memory params, + address sender, + address recipient + ) public { + TransferHelper.safeTransferFrom( + params.tokenIn, + sender, + recipient, + params.amountIn + ); + + TransferHelper.safeApprove( + params.tokenIn, + address(router), + params.amountIn + ); + } + + function getSingleInput(ISwapRouter.ExactInputSingleParams memory params) + public + returns (uint256) + { + return (uint256(router.exactInputSingle(params))); + } +} diff --git a/contracts/sample/interface.sol b/contracts/sample/interface.sol new file mode 100644 index 00000000..f9c4e4d6 --- /dev/null +++ b/contracts/sample/interface.sol @@ -0,0 +1,36 @@ +pragma solidity ^0.7.6; +pragma abicoder v2; + +interface UniswapV3Pool { + struct Slot0 { + uint160 sqrtPriceX96; + int24 tick; + uint16 observationIndex; + uint16 observationCardinality; + uint16 observationCardinalityNext; + uint8 feeProtocol; + bool unlocked; + } + + function liquidity() external view returns (uint128); + + function slot0() external view returns (Slot0 memory); +} + +interface ISwapRouter { + struct ExactInputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + uint160 sqrtPriceLimitX96; + } + + function exactInputSingle(ExactInputSingleParams calldata params) + external + payable + returns (uint256 amountOut); +} diff --git a/contracts/sample/libraries/IERC20Minimal.sol b/contracts/sample/libraries/IERC20Minimal.sol new file mode 100644 index 00000000..62477df5 --- /dev/null +++ b/contracts/sample/libraries/IERC20Minimal.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity >=0.5.0; + +/// @title Minimal ERC20 interface for Uniswap +/// @notice Contains a subset of the full ERC20 interface that is used in Uniswap V3 +interface IERC20Minimal { + /// @notice Returns the balance of a token + /// @param account The account for which to look up the number of tokens it has, i.e. its balance + /// @return The number of tokens held by the account + function balanceOf(address account) external view returns (uint256); + + /// @notice Transfers the amount of token from the `msg.sender` to the recipient + /// @param recipient The account that will receive the amount transferred + /// @param amount The number of tokens to send from the sender to the recipient + /// @return Returns true for a successful transfer, false for an unsuccessful transfer + function transfer(address recipient, uint256 amount) + external + returns (bool); + + /// @notice Returns the current allowance given to a spender by an owner + /// @param owner The account of the token owner + /// @param spender The account of the token spender + /// @return The current allowance granted by `owner` to `spender` + function allowance(address owner, address spender) + external + view + returns (uint256); + + /// @notice Sets the allowance of a spender from the `msg.sender` to the value `amount` + /// @param spender The account which will be allowed to spend a given amount of the owners tokens + /// @param amount The amount of tokens allowed to be used by `spender` + /// @return Returns true for a successful approval, false for unsuccessful + function approve(address spender, uint256 amount) external returns (bool); + + /// @notice Transfers `amount` tokens from `sender` to `recipient` up to the allowance given to the `msg.sender` + /// @param sender The account from which the transfer will be initiated + /// @param recipient The recipient of the transfer + /// @param amount The amount of the transfer + /// @return Returns true for a successful transfer, false for unsuccessful + function transferFrom( + address sender, + address recipient, + uint256 amount + ) external returns (bool); + + /// @notice Event emitted when tokens are transferred from one address to another, either via `#transfer` or `#transferFrom`. + /// @param from The account from which the tokens were sent, i.e. the balance decreased + /// @param to The account to which the tokens were sent, i.e. the balance increased + /// @param value The amount of tokens that were transferred + event Transfer(address indexed from, address indexed to, uint256 value); + + /// @notice Event emitted when the approval amount for the spender of a given owner's tokens changes. + /// @param owner The account that approved spending of its tokens + /// @param spender The account for which the spending allowance was modified + /// @param value The new allowance from the owner to the spender + event Approval( + address indexed owner, + address indexed spender, + uint256 value + ); +} diff --git a/contracts/sample/libraries/TransferHelper.sol b/contracts/sample/libraries/TransferHelper.sol index 25d63090..b381b6f6 100644 --- a/contracts/sample/libraries/TransferHelper.sol +++ b/contracts/sample/libraries/TransferHelper.sol @@ -1,13 +1,37 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.6.0; -import '../interfaces/IERC20Minimal.sol'; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -/// @title TransferHelper -/// @notice Contains helper methods for interacting with ERC20 tokens that do not consistently return true/false library TransferHelper { + /// @notice Transfers tokens from the targeted address to the given destination + /// @notice Errors with 'STF' if transfer fails + /// @param token The contract address of the token to be transferred + /// @param from The originating address from which the tokens will be transferred + /// @param to The destination address of the transfer + /// @param value The amount to be transferred + function safeTransferFrom( + address token, + address from, + address to, + uint256 value + ) internal { + (bool success, bytes memory data) = token.call( + abi.encodeWithSelector( + IERC20.transferFrom.selector, + from, + to, + value + ) + ); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + "STF" + ); + } + /// @notice Transfers tokens from msg.sender to a recipient - /// @dev Calls transfer on token contract, errors with TF if transfer fails + /// @dev Errors with ST if transfer fails /// @param token The contract address of the token which will be transferred /// @param to The recipient of the transfer /// @param value The value of the transfer @@ -16,8 +40,40 @@ library TransferHelper { address to, uint256 value ) internal { - (bool success, bytes memory data) = - token.call(abi.encodeWithSelector(IERC20Minimal.transfer.selector, to, value)); - require(success && (data.length == 0 || abi.decode(data, (bool))), 'TF'); + (bool success, bytes memory data) = token.call( + abi.encodeWithSelector(IERC20.transfer.selector, to, value) + ); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + "ST" + ); + } + + /// @notice Approves the stipulated contract to spend the given allowance in the given token + /// @dev Errors with 'SA' if transfer fails + /// @param token The contract address of the token to be approved + /// @param to The target of the approval + /// @param value The amount of the given token the target will be allowed to spend + function safeApprove( + address token, + address to, + uint256 value + ) internal { + (bool success, bytes memory data) = token.call( + abi.encodeWithSelector(IERC20.approve.selector, to, value) + ); + require( + success && (data.length == 0 || abi.decode(data, (bool))), + "SA" + ); + } + + /// @notice Transfers ETH to the recipient address + /// @dev Fails with `STE` + /// @param to The destination of the transfer + /// @param value The value to be transferred + function safeTransferETH(address to, uint256 value) internal { + (bool success, ) = to.call{value: value}(new bytes(0)); + require(success, "STE"); } } diff --git a/contracts/sample/main.sol b/contracts/sample/main.sol new file mode 100644 index 00000000..3c5b6fee --- /dev/null +++ b/contracts/sample/main.sol @@ -0,0 +1,32 @@ +pragma solidity ^0.7.6; +pragma abicoder v2; + +import "./helpers.sol"; +import "./interface.sol"; + +abstract contract uniswapSample is Helpers { + function sell( + ISwapRouter.ExactInputSingleParams memory params, + bool zeroForOne + ) public returns (uint256 amountOut) { + approveTransfer(params, msg.sender, address(this)); + + ISwapRouter.ExactInputSingleParams memory params1 = ISwapRouter + .ExactInputSingleParams({ + tokenIn: params.tokenIn, + tokenOut: params.tokenOut, + fee: poolFee, + recipient: address(this), + deadline: block.timestamp + 1, + amountIn: params.amountIn, + amountOutMinimum: 0, + sqrtPriceLimitX96: getPriceLimit(params, true) + }); + + amountOut = getSingleInput(params1); + } +} + +abstract contract UniswapArbitrum is uniswapSample { + string public constant name = "UniswapSample-v1"; +} diff --git a/contracts/sample/uniswap-sample.sol b/contracts/sample/uniswap-sample.sol deleted file mode 100644 index 074dc5ea..00000000 --- a/contracts/sample/uniswap-sample.sol +++ /dev/null @@ -1,92 +0,0 @@ -pragma solidity ^0.7.6; -pragma abicoder v2; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "./libraries/SqrtPriceMath.sol"; - -interface UniswapV3Pool { - struct Slot0 { - uint160 sqrtPriceX96; - int24 tick; - uint16 observationIndex; - uint16 observationCardinality; - uint16 observationCardinalityNext; - uint8 feeProtocol; - bool unlocked; - } - - function liquidity() external view returns (uint128); - - function slot0() external view returns (Slot0); -} - -interface ISwapRouter { - struct ExactInputSingleParams { - address tokenIn; - address tokenOut; - uint24 fee; - address recipient; - uint256 deadline; - uint256 amountIn; - uint256 amountOutMinimum; - uint160 sqrtPriceLimitX96; - } - - function exactInputSingle(ExactInputSingleParams calldata params) - external - payable - returns (uint256 amountOut); -} - -contract uniswapSample { - ISwapRouter router = - ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); - - UniswapV3Pool state = - UniswapV3Pool(0xCEda10b4d3bdE429DdA3A6daB87b38360313CBdB); - uint24 public constant poolFee = 3000; - - function getPriceLimit( - ISwapRouter.ExactInputSingleParams params, - bool zeroForOne - ) public returns (uint160) { - return ( - getNextSqrtPriceFromInput( - state.slot0().sqrtPriceX96, - state.liquidity(), - params.amountIn, - zeroForOne - ) - ); - } - - function sell(ISwapRouter.ExactInputSingleParams params, bool zeroForOne) { - TransferHelper.safeTransferFrom( - params.tokenIn, - msg.sender, - address(this), - params.amountIn - ); - - TransferHelper.safeApprove( - params.tokenIn, - address(swapRouter), - params.amountIn - ); - - ISwapRouter.ExactInputSingleParams memory params1 = ISwapRouter - .ExactInputSingleParams({ - tokenIn: params.tokenIn - tokenOut: params.tokenOut, - fee: poolFee, - recipient: address(this), - deadline: block.timestamp + 1, - amountIn: params.amountIn, - amountOutMinimum: 0, - sqrtPriceLimitX96: getPriceLimit(params, true) - }); - - amountOut = swapRouter.exactInputSingle(params1); - return (amountOut); - } -} diff --git a/hardhat.config.js b/hardhat.config.js index 04300869..ff681edf 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -44,21 +44,6 @@ module.exports = { ], }, networks: { - kovan: { - url: `https://eth-kovan.alchemyapi.io/v2/${ALCHEMY_ID}`, - accounts: [`0x${PRIVATE_KEY}`], - }, - mainnet: { - url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`, - accounts: [`0x${PRIVATE_KEY}`], - timeout: 150000, - gasPrice: parseInt(utils.parseUnits("30", "gwei")), - }, - rinkeby: { - url: `https://eth-rinkeby.alchemyapi.io/v2/${ALCHEMY_ID}`, - accounts: [`0x${PRIVATE_KEY}`], - timeout: 150000, - }, hardhat: { forking: { url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`, @@ -66,26 +51,6 @@ module.exports = { }, blockGasLimit: 12000000, }, - matic: { - url: "https://rpc-mainnet.maticvigil.com/", - accounts: [`0x${PRIVATE_KEY}`], - timeout: 150000, - gasPrice: parseInt(utils.parseUnits("1", "gwei")), - }, - arbitrum: { - chainId: 42161, - url: `https://arb-mainnet.g.alchemy.com/v2/${ALCHEMY_ID}`, - accounts: [`0x${PRIVATE_KEY}`], - timeout: 150000, - gasPrice: parseInt(utils.parseUnits("2", "gwei")), - }, - avax: { - url: 'https://api.avax.network/ext/bc/C/rpc', - chainId: 43114, - accounts: [`0x${PRIVATE_KEY}`], - timeout: 150000, - gasPrice: parseInt(utils.parseUnits("225", "gwei")) - } }, etherscan: { apiKey: ETHERSCAN_API_KEY, @@ -97,4 +62,4 @@ module.exports = { mocha: { timeout: 100 * 1000, }, -}; \ No newline at end of file +}; diff --git a/test/sample/uniswap.js b/test/sample/uniswap.js new file mode 100644 index 00000000..49afb130 --- /dev/null +++ b/test/sample/uniswap.js @@ -0,0 +1,80 @@ +const { expect } = require("chai"); +const hre = require("hardhat"); +const { web3, deployments, waffle, ethers } = hre; +const { provider, deployContract } = waffle; +const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js"); +const buildDSAv2 = require("../../scripts/buildDSAv2"); +const encodeSpells = require("../../scripts/encodeSpells.js"); + +const addresses = require("../../scripts/constant/addresses"); +const abis = require("../../scripts/constant/abis"); + +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"; + +describe("UniswapV3", function() { + const connectorName = "UniswapV3-v1"; + let dsaWallet0; + 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 + ); + connector = await deployAndEnableConnector({ + connectorName, + contractArtifact: connectV2UniswapV3Artifacts, + signer: masterSigner, + connectors: instaConnectorsV2, + }); + console.log("Connector address", connector.address); + }); + + it("Should have contracts deployed.", async function() { + expect(!!instaConnectorsV2.address).to.be.true; + expect(!!connector.address).to.be.true; + expect(!!masterSigner.address).to.be.true; + }); + + describe("DSA wallet setup", function() { + it("Should build DSA v2", async function() { + dsaWallet0 = await buildDSAv2(wallet0.address); + expect(!!dsaWallet0.address).to.be.true; + }); + + it("Perfrom a swap", 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") + ); + }); + }); +}); diff --git a/test/uniswap/uniswap.test.js b/test/uniswap/uniswap.test.js index bd0efdad..185a9d3b 100644 --- a/test/uniswap/uniswap.test.js +++ b/test/uniswap/uniswap.test.js @@ -1,335 +1,374 @@ const { expect } = require("chai"); const hre = require("hardhat"); const { web3, deployments, waffle, ethers } = hre; -const { provider, deployContract } = waffle +const { provider, deployContract } = waffle; -const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js") -const buildDSAv2 = require("../../scripts/buildDSAv2") -const encodeSpells = require("../../scripts/encodeSpells.js") -const encodeFlashcastData = require("../../scripts/encodeFlashcastData.js") -const getMasterSigner = require("../../scripts/getMasterSigner") +const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js"); +const buildDSAv2 = require("../../scripts/buildDSAv2"); +const encodeSpells = require("../../scripts/encodeSpells.js"); +const encodeFlashcastData = require("../../scripts/encodeFlashcastData.js"); +const getMasterSigner = require("../../scripts/getMasterSigner"); const addLiquidity = require("../../scripts/addLiquidity"); 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 { + abi: nftManagerAbi, +} = require("@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json"); const connectV2UniswapV3Artifacts = require("../../artifacts/contracts/mainnet/connectors/uniswap/v3/main.sol/ConnectV2UniswapV3.json"); const { eth } = require("../../scripts/constant/tokens"); const { BigNumber } = require("ethers"); const FeeAmount = { - LOW: 500, - MEDIUM: 3000, - HIGH: 10000, -} + LOW: 500, + MEDIUM: 3000, + HIGH: 10000, +}; const TICK_SPACINGS = { - 500: 10, - 3000: 60, - 10000: 200 -} + 500: 10, + 3000: 60, + 10000: 200, +}; -const USDT_ADDR = "0xdac17f958d2ee523a2206206994597c13d831ec7" -const DAI_ADDR = "0x6b175474e89094c44da98b954eedeac495271d0f" +const USDT_ADDR = "0xdac17f958d2ee523a2206206994597c13d831ec7"; +const DAI_ADDR = "0x6b175474e89094c44da98b954eedeac495271d0f"; -let tokenIds = [] -let liquidities = [] -const abiCoder = ethers.utils.defaultAbiCoder +let tokenIds = []; +let liquidities = []; +const abiCoder = ethers.utils.defaultAbiCoder; -describe("UniswapV3", function () { - const connectorName = "UniswapV3-v1" +describe("UniswapV3", function() { + const connectorName = "UniswapV3-v1"; - let dsaWallet0 - let masterSigner; - let instaConnectorsV2; - let connector; - let nftManager; + let dsaWallet0; + let masterSigner; + let instaConnectorsV2; + let connector; + let nftManager; - const wallets = provider.getWallets() - const [wallet0, wallet1, wallet2, wallet3] = wallets - before(async () => { - await hre.network.provider.request({ - method: "hardhat_reset", - params: [ - { - forking: { - jsonRpcUrl: hre.config.networks.hardhat.forking.url, - blockNumber: 13005785, - }, - }, - ], - }); - 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, - signer: masterSigner, - connectors: instaConnectorsV2 - }) - console.log("Connector address", connector.address) - }) + const wallets = provider.getWallets(); + const [wallet0, wallet1, wallet2, wallet3] = wallets; + before(async () => { + await hre.network.provider.request({ + method: "hardhat_reset", + params: [ + { + forking: { + jsonRpcUrl: hre.config.networks.hardhat.forking.url, + blockNumber: 13005785, + }, + }, + ], + }); + 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, + signer: masterSigner, + connectors: instaConnectorsV2, + }); + console.log("Connector address", connector.address); + }); - it("Should have contracts deployed.", async function () { - expect(!!instaConnectorsV2.address).to.be.true; - expect(!!connector.address).to.be.true; - expect(!!masterSigner.address).to.be.true; + it("Should have contracts deployed.", async function() { + expect(!!instaConnectorsV2.address).to.be.true; + expect(!!connector.address).to.be.true; + expect(!!masterSigner.address).to.be.true; + }); + + describe("DSA wallet setup", function() { + it("Should build DSA v2", async function() { + dsaWallet0 = await buildDSAv2(wallet0.address); + expect(!!dsaWallet0.address).to.be.true; }); - describe("DSA wallet setup", function () { - it("Should build DSA v2", async function () { - dsaWallet0 = await buildDSAv2(wallet0.address) - expect(!!dsaWallet0.address).to.be.true; - }); + it("Deposit ETH & DAI 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") + ); - it("Deposit ETH & DAI 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("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")); - }); + await addLiquidity( + "dai", + dsaWallet0.address, + ethers.utils.parseEther("100000") + ); }); - describe("Main", function () { + 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") + ); - 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" + await addLiquidity( + "usdt", + dsaWallet0.address, + ethers.utils.parseEther("100000") + ); + }); + }); - const getIds = ["0", "0"] - const setId = "0" + describe("Main", 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 spells = [ - { - connector: connectorName, - method: "mint", - args: [ - ethAddress, - DAI_ADDR, - FeeAmount.MEDIUM, - getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - ethAmount, - daiAmount, - "500000000000000000", - getIds, - setId - ], - }, - { - connector: connectorName, - method: "mint", - args: [ - DAI_ADDR, - USDT_ADDR, - FeeAmount.MEDIUM, - getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - daiAmount, - usdtAmount, - "300000000000000000", - getIds, - setId - ], - }, - { - connector: connectorName, - method: "mint", - args: [ - ethAddress, - USDT_ADDR, - FeeAmount.MEDIUM, - getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), - ethAmount, - usdtAmount, - "300000000000000000", - getIds, - setId - ], - } - ] + const getIds = ["0", "0"]; + const setId = "0"; - 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", "int24", "int24"], eventParams[0]); - const params1 = abiCoder.decode(["uint256", "uint256", "uint256", "uint256", "int24", "int24"], eventParams[2]); - tokenIds.push(params[0]); - tokenIds.push(params1[0]); - liquidities.push(params[1]); - event.removeListener(); + const spells = [ + { + connector: connectorName, + method: "mint", + args: [ + ethAddress, + DAI_ADDR, + FeeAmount.MEDIUM, + getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + ethAmount, + daiAmount, + "500000000000000000", + getIds, + setId, + ], + }, + { + connector: connectorName, + method: "mint", + args: [ + DAI_ADDR, + USDT_ADDR, + FeeAmount.MEDIUM, + getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + daiAmount, + usdtAmount, + "300000000000000000", + getIds, + setId, + ], + }, + { + connector: connectorName, + method: "mint", + args: [ + ethAddress, + USDT_ADDR, + FeeAmount.MEDIUM, + getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]), + ethAmount, + usdtAmount, + "300000000000000000", + getIds, + setId, + ], + }, + ]; - resolve({ - eventNames, - }); - }); + 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", "int24", "int24"], + eventParams[0] + ); + const params1 = abiCoder.decode( + ["uint256", "uint256", "uint256", "uint256", "int24", "int24"], + eventParams[2] + ); + tokenIds.push(params[0]); + tokenIds.push(params1[0]); + liquidities.push(params[1]); + event.removeListener(); - setTimeout(() => { - reject(new Error('timeout')); - }, 60000) + resolve({ + eventNames, }); + } + ); - let event = await castEvent + setTimeout(() => { + reject(new Error("timeout")); + }, 60000); + }); - const data = await nftManager.positions(tokenIds[0]) + let event = await castEvent; - expect(data.liquidity).to.be.equals(liquidities[0]); - }).timeout(10000000000); + const data = await nftManager.positions(tokenIds[0]); - it("Should deposit 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" + expect(data.liquidity).to.be.equals(liquidities[0]); + }).timeout(10000000000); - const getIds = ["0", "0"] - const setId = "0" + it("Should deposit 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 spells = [ - { - connector: connectorName, - method: "deposit", - args: [ - tokenIds[0], - daiAmount, - ethAmount, - "500000000000000000", - getIds, - setId - ], - } - ] + const getIds = ["0", "0"]; + const setId = "0"; - const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) - const receipt = await tx.wait() + const spells = [ + { + connector: connectorName, + method: "deposit", + args: [ + tokenIds[0], + daiAmount, + ethAmount, + "500000000000000000", + getIds, + setId, + ], + }, + ]; - 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[1]); - event.removeListener(); + const tx = await dsaWallet0 + .connect(wallet0) + .cast(...encodeSpells(spells), wallet1.address); + const receipt = await tx.wait(); - resolve({ - eventNames, - }); - }); + 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[1]); + event.removeListener(); - setTimeout(() => { - reject(new Error('timeout')); - }, 60000) + resolve({ + eventNames, }); + } + ); - let event = await castEvent + setTimeout(() => { + reject(new Error("timeout")); + }, 60000); + }); - const data = await nftManager.positions(tokenIds[0]) - expect(data.liquidity).to.be.equals(liquidities[0]); - }) + let event = await castEvent; - it("Should withdraw successfully", async function () { + const data = await nftManager.positions(tokenIds[0]); + expect(data.liquidity).to.be.equals(liquidities[0]); + }); - const getId = "0" - const setIds = ["0", "0"] + it("Should withdraw 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 data = await nftManager.positions(tokenIds[0]); + let data1 = await nftManager.positions(tokenIds[1]); - const spells = [ - { - connector: connectorName, - method: "withdraw", - args: [ - tokenIds[0], - data.liquidity, - 0, - 0, - getId, - setIds - ], - }, - { - connector: connectorName, - method: "withdraw", - args: [ - 0, - data1.liquidity, - 0, - 0, - getId, - setIds - ], - }, - ] + const spells = [ + { + connector: connectorName, + method: "withdraw", + args: [tokenIds[0], data.liquidity, 0, 0, getId, setIds], + }, + { + connector: connectorName, + method: "withdraw", + args: [0, data1.liquidity, 0, 0, getId, setIds], + }, + ]; - const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) - const receipt = await tx.wait() + 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); - }) + data1 = await nftManager.positions(tokenIds[1]); + expect(data1.liquidity.toNumber()).to.be.equals(0); + }); - it("Should collect successfully", async function () { + 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 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 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(); + }); - 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: "burn", + args: [tokenIds[0]], + }, + ]; - it("Should burn successfully", async function () { + const tx = await dsaWallet0 + .connect(wallet0) + .cast(...encodeSpells(spells), wallet1.address); + const receipt = await tx.wait(); + }); + }); +}); - const spells = [ - { - connector: connectorName, - method: "burn", - 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 +const getMinTick = (tickSpacing) => + Math.ceil(-887272 / tickSpacing) * tickSpacing; +const getMaxTick = (tickSpacing) => + Math.floor(887272 / tickSpacing) * tickSpacing;