mirror of
https://github.com/Instadapp/dsa-connectors.git
synced 2024-07-29 22:37:00 +00:00
Merge pull request #68 from Instadapp/feat/uniswap-v3-connector
Uniswap v3 connector
This commit is contained in:
commit
4c2fb6efca
34
contracts/mainnet/connectors/uniswapV3/events.sol
Normal file
34
contracts/mainnet/connectors/uniswapV3/events.sol
Normal file
|
@ -0,0 +1,34 @@
|
|||
pragma solidity ^0.7.0;
|
||||
|
||||
contract Events {
|
||||
event LogMint(
|
||||
uint256 indexed tokenId,
|
||||
uint256 liquidity,
|
||||
uint256 amtA,
|
||||
uint256 amtB,
|
||||
int24 tickLower,
|
||||
int24 tickUpper
|
||||
);
|
||||
|
||||
event LogDeposit(
|
||||
uint256 indexed tokenId,
|
||||
uint256 liquidity,
|
||||
uint256 amountA,
|
||||
uint256 amountB
|
||||
);
|
||||
|
||||
event LogWithdraw(
|
||||
uint256 indexed tokenId,
|
||||
uint256 liquidity,
|
||||
uint256 amountA,
|
||||
uint256 amountB
|
||||
);
|
||||
|
||||
event LogCollect(
|
||||
uint256 tokenId,
|
||||
uint256 amountA,
|
||||
uint256 amountB
|
||||
);
|
||||
|
||||
event LogBurnPosition(uint256 tokenId);
|
||||
}
|
265
contracts/mainnet/connectors/uniswapV3/helpers.sol
Normal file
265
contracts/mainnet/connectors/uniswapV3/helpers.sol
Normal file
|
@ -0,0 +1,265 @@
|
|||
pragma solidity ^0.7.6;
|
||||
pragma abicoder v2;
|
||||
|
||||
import {TokenInterface} from "../../common/interfaces.sol";
|
||||
import {DSMath} from "../../common/math.sol";
|
||||
import {Basic} from "../../common/basic.sol";
|
||||
import "./interface.sol";
|
||||
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
|
||||
import "@uniswap/v3-core/contracts/libraries/TickMath.sol";
|
||||
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
|
||||
import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
|
||||
|
||||
abstract contract Helpers is DSMath, Basic {
|
||||
/**
|
||||
* @dev uniswap v3 NFT Position Manager & Swap Router
|
||||
*/
|
||||
INonfungiblePositionManager constant nftManager =
|
||||
INonfungiblePositionManager(0xC36442b4a4522E871399CD717aBDD847Ab11FE88);
|
||||
ISwapRouter constant swapRouter =
|
||||
ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
|
||||
|
||||
struct MintParams {
|
||||
address tokenA;
|
||||
address tokenB;
|
||||
uint24 fee;
|
||||
int24 tickLower;
|
||||
int24 tickUpper;
|
||||
uint256 amtA;
|
||||
uint256 amtB;
|
||||
uint256 slippage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get Last NFT Index
|
||||
* @param user: User address
|
||||
*/
|
||||
function _getLastNftId(address user)
|
||||
internal
|
||||
view
|
||||
returns (uint256 tokenId)
|
||||
{
|
||||
uint256 len = nftManager.balanceOf(user);
|
||||
tokenId = nftManager.tokenOfOwnerByIndex(user, len - 1);
|
||||
}
|
||||
|
||||
function getMinAmount(
|
||||
TokenInterface token,
|
||||
uint256 amt,
|
||||
uint256 slippage
|
||||
) internal view returns (uint256 minAmt) {
|
||||
uint256 _amt18 = convertTo18(token.decimals(), amt);
|
||||
minAmt = wmul(_amt18, sub(WAD, slippage));
|
||||
minAmt = convert18ToDec(token.decimals(), minAmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Mint function which interact with Uniswap v3
|
||||
*/
|
||||
function _mint(MintParams memory params)
|
||||
internal
|
||||
returns (
|
||||
uint256 tokenId,
|
||||
uint128 liquidity,
|
||||
uint256 amountA,
|
||||
uint256 amountB
|
||||
)
|
||||
{
|
||||
(TokenInterface _token0, TokenInterface _token1) = changeEthAddress(
|
||||
params.tokenA,
|
||||
params.tokenB
|
||||
);
|
||||
|
||||
uint256 _amount0 = params.amtA == uint256(-1)
|
||||
? getTokenBal(TokenInterface(params.tokenA))
|
||||
: params.amtA;
|
||||
uint256 _amount1 = params.amtB == uint256(-1)
|
||||
? getTokenBal(TokenInterface(params.tokenB))
|
||||
: params.amtB;
|
||||
|
||||
convertEthToWeth(address(_token0) == wethAddr, _token0, _amount0);
|
||||
convertEthToWeth(address(_token1) == wethAddr, _token1, _amount1);
|
||||
|
||||
approve(_token0, address(nftManager), _amount0);
|
||||
approve(_token1, address(nftManager), _amount1);
|
||||
|
||||
uint256 _minAmt0 = getMinAmount(_token0, _amount0, params.slippage);
|
||||
uint256 _minAmt1 = getMinAmount(_token1, _amount1, params.slippage);
|
||||
|
||||
INonfungiblePositionManager.MintParams
|
||||
memory params = INonfungiblePositionManager.MintParams(
|
||||
address(_token0),
|
||||
address(_token1),
|
||||
params.fee,
|
||||
params.tickLower,
|
||||
params.tickUpper,
|
||||
_amount0,
|
||||
_amount1,
|
||||
_minAmt0,
|
||||
_minAmt1,
|
||||
address(this),
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
(tokenId, liquidity, amountA, amountB) = nftManager.mint(params);
|
||||
}
|
||||
|
||||
function getNftTokenPairAddresses(uint256 _tokenId)
|
||||
internal
|
||||
view
|
||||
returns (address token0, address token1)
|
||||
{
|
||||
(bool success, bytes memory data) = address(nftManager).staticcall(
|
||||
abi.encodeWithSelector(nftManager.positions.selector, _tokenId)
|
||||
);
|
||||
require(success, "fetching positions failed");
|
||||
{
|
||||
(, , token0, token1, , , , ) = abi.decode(
|
||||
data,
|
||||
(
|
||||
uint96,
|
||||
address,
|
||||
address,
|
||||
address,
|
||||
uint24,
|
||||
int24,
|
||||
int24,
|
||||
uint128
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Check if token address is etherAddr and convert it to weth
|
||||
*/
|
||||
function _checkETH(
|
||||
address _token0,
|
||||
address _token1,
|
||||
uint256 _amount0,
|
||||
uint256 _amount1
|
||||
) internal {
|
||||
|
||||
bool isEth0 = _token0 == wethAddr;
|
||||
bool isEth1 = _token1 == wethAddr;
|
||||
convertEthToWeth(isEth0, TokenInterface(_token0), _amount0);
|
||||
convertEthToWeth(isEth1, TokenInterface(_token1), _amount1);
|
||||
approve(TokenInterface(_token0), address(nftManager), _amount0);
|
||||
approve(TokenInterface(_token1), address(nftManager), _amount1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev addLiquidityWrapper function wrapper of _addLiquidity
|
||||
*/
|
||||
function _addLiquidityWrapper(
|
||||
uint256 tokenId,
|
||||
uint256 amountA,
|
||||
uint256 amountB,
|
||||
uint256 slippage
|
||||
)
|
||||
internal
|
||||
returns (
|
||||
uint256 liquidity,
|
||||
uint256 amtA,
|
||||
uint256 amtB
|
||||
)
|
||||
{
|
||||
(address token0, address token1) = getNftTokenPairAddresses(tokenId);
|
||||
|
||||
(liquidity, amtA, amtB) = _addLiquidity(
|
||||
tokenId,
|
||||
token0,
|
||||
token1,
|
||||
amountA,
|
||||
amountB,
|
||||
slippage
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev addLiquidity function which interact with Uniswap v3
|
||||
*/
|
||||
function _addLiquidity(
|
||||
uint256 _tokenId,
|
||||
address _token0,
|
||||
address _token1,
|
||||
uint256 _amount0,
|
||||
uint256 _amount1,
|
||||
uint256 _slippage
|
||||
)
|
||||
internal
|
||||
returns (
|
||||
uint128 liquidity,
|
||||
uint256 amount0,
|
||||
uint256 amount1
|
||||
)
|
||||
{
|
||||
_checkETH(_token0, _token1, _amount0, _amount1);
|
||||
uint256 _amount0Min = getMinAmount(
|
||||
TokenInterface(_token0),
|
||||
_amount0,
|
||||
_slippage
|
||||
);
|
||||
uint256 _amount1Min = getMinAmount(
|
||||
TokenInterface(_token1),
|
||||
_amount1,
|
||||
_slippage
|
||||
);
|
||||
INonfungiblePositionManager.IncreaseLiquidityParams
|
||||
memory params = INonfungiblePositionManager.IncreaseLiquidityParams(
|
||||
_tokenId,
|
||||
_amount0,
|
||||
_amount1,
|
||||
_amount0Min,
|
||||
_amount1Min,
|
||||
block.timestamp
|
||||
);
|
||||
|
||||
(liquidity, amount0, amount1) = nftManager.increaseLiquidity(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev decreaseLiquidity function which interact with Uniswap v3
|
||||
*/
|
||||
function _decreaseLiquidity(
|
||||
uint256 _tokenId,
|
||||
uint128 _liquidity,
|
||||
uint256 _amount0Min,
|
||||
uint256 _amount1Min
|
||||
) internal returns (uint256 amount0, uint256 amount1) {
|
||||
INonfungiblePositionManager.DecreaseLiquidityParams
|
||||
memory params = INonfungiblePositionManager.DecreaseLiquidityParams(
|
||||
_tokenId,
|
||||
_liquidity,
|
||||
_amount0Min,
|
||||
_amount1Min,
|
||||
block.timestamp
|
||||
);
|
||||
(amount0, amount1) = nftManager.decreaseLiquidity(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev collect function which interact with Uniswap v3
|
||||
*/
|
||||
function _collect(
|
||||
uint256 _tokenId,
|
||||
uint128 _amount0Max,
|
||||
uint128 _amount1Max
|
||||
) internal returns (uint256 amount0, uint256 amount1) {
|
||||
INonfungiblePositionManager.CollectParams
|
||||
memory params = INonfungiblePositionManager.CollectParams(
|
||||
_tokenId,
|
||||
address(this),
|
||||
_amount0Max,
|
||||
_amount1Max
|
||||
);
|
||||
(amount0, amount1) = nftManager.collect(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Burn Function
|
||||
*/
|
||||
function _burn(uint256 _tokenId) internal {
|
||||
nftManager.burn(_tokenId);
|
||||
}
|
||||
}
|
368
contracts/mainnet/connectors/uniswapV3/interface.sol
Normal file
368
contracts/mainnet/connectors/uniswapV3/interface.sol
Normal file
|
@ -0,0 +1,368 @@
|
|||
pragma solidity ^0.7.6;
|
||||
pragma abicoder v2;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
||||
import "@openzeppelin/contracts/token/ERC721/IERC721Metadata.sol";
|
||||
import "@openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol";
|
||||
|
||||
/// @title Callback for IUniswapV3PoolActions#swap
|
||||
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
|
||||
interface IUniswapV3SwapCallback {
|
||||
/// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
|
||||
/// @dev In the implementation you must pay the pool tokens owed for the swap.
|
||||
/// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
|
||||
/// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
|
||||
/// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
|
||||
/// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
|
||||
/// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
|
||||
/// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
|
||||
/// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
|
||||
function uniswapV3SwapCallback(
|
||||
int256 amount0Delta,
|
||||
int256 amount1Delta,
|
||||
bytes calldata data
|
||||
) external;
|
||||
}
|
||||
|
||||
interface ISwapRouter is IUniswapV3SwapCallback {
|
||||
struct ExactInputSingleParams {
|
||||
address tokenIn;
|
||||
address tokenOut;
|
||||
uint24 fee;
|
||||
address recipient;
|
||||
uint256 deadline;
|
||||
uint256 amountIn;
|
||||
uint256 amountOutMinimum;
|
||||
uint160 sqrtPriceLimitX96;
|
||||
}
|
||||
|
||||
/// @notice Swaps `amountIn` of one token for as much as possible of another token
|
||||
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
|
||||
/// @return amountOut The amount of the received token
|
||||
function exactInputSingle(ExactInputSingleParams calldata params)
|
||||
external
|
||||
payable
|
||||
returns (uint256 amountOut);
|
||||
|
||||
struct ExactInputParams {
|
||||
bytes path;
|
||||
address recipient;
|
||||
uint256 deadline;
|
||||
uint256 amountIn;
|
||||
uint256 amountOutMinimum;
|
||||
}
|
||||
|
||||
/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
|
||||
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
|
||||
/// @return amountOut The amount of the received token
|
||||
function exactInput(ExactInputParams calldata params)
|
||||
external
|
||||
payable
|
||||
returns (uint256 amountOut);
|
||||
|
||||
struct ExactOutputSingleParams {
|
||||
address tokenIn;
|
||||
address tokenOut;
|
||||
uint24 fee;
|
||||
address recipient;
|
||||
uint256 deadline;
|
||||
uint256 amountOut;
|
||||
uint256 amountInMaximum;
|
||||
uint160 sqrtPriceLimitX96;
|
||||
}
|
||||
|
||||
/// @notice Swaps as little as possible of one token for `amountOut` of another token
|
||||
/// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
|
||||
/// @return amountIn The amount of the input token
|
||||
function exactOutputSingle(ExactOutputSingleParams calldata params)
|
||||
external
|
||||
payable
|
||||
returns (uint256 amountIn);
|
||||
|
||||
struct ExactOutputParams {
|
||||
bytes path;
|
||||
address recipient;
|
||||
uint256 deadline;
|
||||
uint256 amountOut;
|
||||
uint256 amountInMaximum;
|
||||
}
|
||||
|
||||
/// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
|
||||
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
|
||||
/// @return amountIn The amount of the input token
|
||||
function exactOutput(ExactOutputParams calldata params)
|
||||
external
|
||||
payable
|
||||
returns (uint256 amountIn);
|
||||
}
|
||||
|
||||
/// @title Creates and initializes V3 Pools
|
||||
/// @notice Provides a method for creating and initializing a pool, if necessary, for bundling with other methods that
|
||||
/// require the pool to exist.
|
||||
interface IPoolInitializer {
|
||||
/// @notice Creates a new pool if it does not exist, then initializes if not initialized
|
||||
/// @dev This method can be bundled with others via IMulticall for the first action (e.g. mint) performed against a pool
|
||||
/// @param token0 The contract address of token0 of the pool
|
||||
/// @param token1 The contract address of token1 of the pool
|
||||
/// @param fee The fee amount of the v3 pool for the specified token pair
|
||||
/// @param sqrtPriceX96 The initial square root price of the pool as a Q64.96 value
|
||||
/// @return pool Returns the pool address based on the pair of tokens and fee, will return the newly created pool address if necessary
|
||||
function createAndInitializePoolIfNecessary(
|
||||
address token0,
|
||||
address token1,
|
||||
uint24 fee,
|
||||
uint160 sqrtPriceX96
|
||||
) external payable returns (address pool);
|
||||
}
|
||||
|
||||
/// @title Immutable state
|
||||
/// @notice Functions that return immutable state of the router
|
||||
interface IPeripheryImmutableState {
|
||||
/// @return Returns the address of the Uniswap V3 factory
|
||||
function factory() external view returns (address);
|
||||
|
||||
/// @return Returns the address of WETH9
|
||||
function WETH9() external view returns (address);
|
||||
}
|
||||
|
||||
/// @title Periphery Payments
|
||||
/// @notice Functions to ease deposits and withdrawals of ETH
|
||||
interface IPeripheryPayments {
|
||||
/// @notice Unwraps the contract's WETH9 balance and sends it to recipient as ETH.
|
||||
/// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users.
|
||||
/// @param amountMinimum The minimum amount of WETH9 to unwrap
|
||||
/// @param recipient The address receiving ETH
|
||||
function unwrapWETH9(uint256 amountMinimum, address recipient)
|
||||
external
|
||||
payable;
|
||||
|
||||
/// @notice Refunds any ETH balance held by this contract to the `msg.sender`
|
||||
/// @dev Useful for bundling with mint or increase liquidity that uses ether, or exact output swaps
|
||||
/// that use ether for the input amount
|
||||
function refundETH() external payable;
|
||||
|
||||
/// @notice Transfers the full amount of a token held by this contract to recipient
|
||||
/// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users
|
||||
/// @param token The contract address of the token which will be transferred to `recipient`
|
||||
/// @param amountMinimum The minimum amount of token required for a transfer
|
||||
/// @param recipient The destination address of the token
|
||||
function sweepToken(
|
||||
address token,
|
||||
uint256 amountMinimum,
|
||||
address recipient
|
||||
) external payable;
|
||||
}
|
||||
|
||||
/// @title ERC721 with permit
|
||||
/// @notice Extension to ERC721 that includes a permit function for signature based approvals
|
||||
interface IERC721Permit is IERC721 {
|
||||
/// @notice The permit typehash used in the permit signature
|
||||
/// @return The typehash for the permit
|
||||
function PERMIT_TYPEHASH() external pure returns (bytes32);
|
||||
|
||||
/// @notice The domain separator used in the permit signature
|
||||
/// @return The domain seperator used in encoding of permit signature
|
||||
function DOMAIN_SEPARATOR() external view returns (bytes32);
|
||||
|
||||
/// @notice Approve of a specific token ID for spending by spender via signature
|
||||
/// @param spender The account that is being approved
|
||||
/// @param tokenId The ID of the token that is being approved for spending
|
||||
/// @param deadline The deadline timestamp by which the call must be mined for the approve to work
|
||||
/// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s`
|
||||
/// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s`
|
||||
/// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v`
|
||||
function permit(
|
||||
address spender,
|
||||
uint256 tokenId,
|
||||
uint256 deadline,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s
|
||||
) external payable;
|
||||
}
|
||||
|
||||
/// @title Non-fungible token for positions
|
||||
/// @notice Wraps Uniswap V3 positions in a non-fungible token interface which allows for them to be transferred
|
||||
/// and authorized.
|
||||
interface INonfungiblePositionManager is
|
||||
IPoolInitializer,
|
||||
IPeripheryPayments,
|
||||
IPeripheryImmutableState,
|
||||
IERC721Metadata,
|
||||
IERC721Enumerable,
|
||||
IERC721Permit
|
||||
{
|
||||
/// @notice Emitted when liquidity is increased for a position NFT
|
||||
/// @dev Also emitted when a token is minted
|
||||
/// @param tokenId The ID of the token for which liquidity was increased
|
||||
/// @param liquidity The amount by which liquidity for the NFT position was increased
|
||||
/// @param amount0 The amount of token0 that was paid for the increase in liquidity
|
||||
/// @param amount1 The amount of token1 that was paid for the increase in liquidity
|
||||
event IncreaseLiquidity(
|
||||
uint256 indexed tokenId,
|
||||
uint128 liquidity,
|
||||
uint256 amount0,
|
||||
uint256 amount1
|
||||
);
|
||||
/// @notice Emitted when liquidity is decreased for a position NFT
|
||||
/// @param tokenId The ID of the token for which liquidity was decreased
|
||||
/// @param liquidity The amount by which liquidity for the NFT position was decreased
|
||||
/// @param amount0 The amount of token0 that was accounted for the decrease in liquidity
|
||||
/// @param amount1 The amount of token1 that was accounted for the decrease in liquidity
|
||||
event DecreaseLiquidity(
|
||||
uint256 indexed tokenId,
|
||||
uint128 liquidity,
|
||||
uint256 amount0,
|
||||
uint256 amount1
|
||||
);
|
||||
/// @notice Emitted when tokens are collected for a position NFT
|
||||
/// @dev The amounts reported may not be exactly equivalent to the amounts transferred, due to rounding behavior
|
||||
/// @param tokenId The ID of the token for which underlying tokens were collected
|
||||
/// @param recipient The address of the account that received the collected tokens
|
||||
/// @param amount0 The amount of token0 owed to the position that was collected
|
||||
/// @param amount1 The amount of token1 owed to the position that was collected
|
||||
event Collect(
|
||||
uint256 indexed tokenId,
|
||||
address recipient,
|
||||
uint256 amount0,
|
||||
uint256 amount1
|
||||
);
|
||||
|
||||
/// @notice Returns the position information associated with a given token ID.
|
||||
/// @dev Throws if the token ID is not valid.
|
||||
/// @param tokenId The ID of the token that represents the position
|
||||
/// @return nonce The nonce for permits
|
||||
/// @return operator The address that is approved for spending
|
||||
/// @return token0 The address of the token0 for a specific pool
|
||||
/// @return token1 The address of the token1 for a specific pool
|
||||
/// @return fee The fee associated with the pool
|
||||
/// @return tickLower The lower end of the tick range for the position
|
||||
/// @return tickUpper The higher end of the tick range for the position
|
||||
/// @return liquidity The liquidity of the position
|
||||
/// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position
|
||||
/// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position
|
||||
/// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation
|
||||
/// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation
|
||||
function positions(uint256 tokenId)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
uint96 nonce,
|
||||
address operator,
|
||||
address token0,
|
||||
address token1,
|
||||
uint24 fee,
|
||||
int24 tickLower,
|
||||
int24 tickUpper,
|
||||
uint128 liquidity,
|
||||
uint256 feeGrowthInside0LastX128,
|
||||
uint256 feeGrowthInside1LastX128,
|
||||
uint128 tokensOwed0,
|
||||
uint128 tokensOwed1
|
||||
);
|
||||
|
||||
struct MintParams {
|
||||
address token0;
|
||||
address token1;
|
||||
uint24 fee;
|
||||
int24 tickLower;
|
||||
int24 tickUpper;
|
||||
uint256 amount0Desired;
|
||||
uint256 amount1Desired;
|
||||
uint256 amount0Min;
|
||||
uint256 amount1Min;
|
||||
address recipient;
|
||||
uint256 deadline;
|
||||
}
|
||||
|
||||
/// @notice Creates a new position wrapped in a NFT
|
||||
/// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized
|
||||
/// a method does not exist, i.e. the pool is assumed to be initialized.
|
||||
/// @param params The params necessary to mint a position, encoded as `MintParams` in calldata
|
||||
/// @return tokenId The ID of the token that represents the minted position
|
||||
/// @return liquidity The amount of liquidity for this position
|
||||
/// @return amount0 The amount of token0
|
||||
/// @return amount1 The amount of token1
|
||||
function mint(MintParams calldata params)
|
||||
external
|
||||
payable
|
||||
returns (
|
||||
uint256 tokenId,
|
||||
uint128 liquidity,
|
||||
uint256 amount0,
|
||||
uint256 amount1
|
||||
);
|
||||
|
||||
struct IncreaseLiquidityParams {
|
||||
uint256 tokenId;
|
||||
uint256 amount0Desired;
|
||||
uint256 amount1Desired;
|
||||
uint256 amount0Min;
|
||||
uint256 amount1Min;
|
||||
uint256 deadline;
|
||||
}
|
||||
|
||||
/// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender`
|
||||
/// @param params tokenId The ID of the token for which liquidity is being increased,
|
||||
/// amount0Desired The desired amount of token0 to be spent,
|
||||
/// amount1Desired The desired amount of token1 to be spent,
|
||||
/// amount0Min The minimum amount of token0 to spend, which serves as a slippage check,
|
||||
/// amount1Min The minimum amount of token1 to spend, which serves as a slippage check,
|
||||
/// deadline The time by which the transaction must be included to effect the change
|
||||
/// @return liquidity The new liquidity amount as a result of the increase
|
||||
/// @return amount0 The amount of token0 to acheive resulting liquidity
|
||||
/// @return amount1 The amount of token1 to acheive resulting liquidity
|
||||
function increaseLiquidity(IncreaseLiquidityParams calldata params)
|
||||
external
|
||||
payable
|
||||
returns (
|
||||
uint128 liquidity,
|
||||
uint256 amount0,
|
||||
uint256 amount1
|
||||
);
|
||||
|
||||
struct DecreaseLiquidityParams {
|
||||
uint256 tokenId;
|
||||
uint128 liquidity;
|
||||
uint256 amount0Min;
|
||||
uint256 amount1Min;
|
||||
uint256 deadline;
|
||||
}
|
||||
|
||||
/// @notice Decreases the amount of liquidity in a position and accounts it to the position
|
||||
/// @param params tokenId The ID of the token for which liquidity is being decreased,
|
||||
/// amount The amount by which liquidity will be decreased,
|
||||
/// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity,
|
||||
/// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity,
|
||||
/// deadline The time by which the transaction must be included to effect the change
|
||||
/// @return amount0 The amount of token0 accounted to the position's tokens owed
|
||||
/// @return amount1 The amount of token1 accounted to the position's tokens owed
|
||||
function decreaseLiquidity(DecreaseLiquidityParams calldata params)
|
||||
external
|
||||
payable
|
||||
returns (uint256 amount0, uint256 amount1);
|
||||
|
||||
struct CollectParams {
|
||||
uint256 tokenId;
|
||||
address recipient;
|
||||
uint128 amount0Max;
|
||||
uint128 amount1Max;
|
||||
}
|
||||
|
||||
/// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient
|
||||
/// @param params tokenId The ID of the NFT for which tokens are being collected,
|
||||
/// recipient The account that should receive the tokens,
|
||||
/// amount0Max The maximum amount of token0 to collect,
|
||||
/// amount1Max The maximum amount of token1 to collect
|
||||
/// @return amount0 The amount of fees collected in token0
|
||||
/// @return amount1 The amount of fees collected in token1
|
||||
function collect(CollectParams calldata params)
|
||||
external
|
||||
payable
|
||||
returns (uint256 amount0, uint256 amount1);
|
||||
|
||||
/// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens
|
||||
/// must be collected first.
|
||||
/// @param tokenId The ID of the token that is being burned
|
||||
function burn(uint256 tokenId) external payable;
|
||||
}
|
210
contracts/mainnet/connectors/uniswapV3/main.sol
Normal file
210
contracts/mainnet/connectors/uniswapV3/main.sol
Normal file
|
@ -0,0 +1,210 @@
|
|||
pragma solidity ^0.7.6;
|
||||
pragma abicoder v2;
|
||||
|
||||
/**
|
||||
* @title Uniswap v3.
|
||||
* @dev Decentralized Exchange.
|
||||
*/
|
||||
|
||||
import {TokenInterface} from "../../common/interfaces.sol";
|
||||
import {Helpers} from "./helpers.sol";
|
||||
import {Events} from "./events.sol";
|
||||
|
||||
abstract contract UniswapResolver is Helpers, Events {
|
||||
/**
|
||||
* @dev Mint New Position
|
||||
* @notice Mint New NFT LP Position
|
||||
* @param tokenA tokenA addreess
|
||||
* @param tokenB tokenB addreess
|
||||
* @param fee fee percentage
|
||||
* @param tickLower Lower tick
|
||||
* @param tickUpper Upper tick
|
||||
* @param amtA amount of tokenA
|
||||
* @param amtB amount of tokenB
|
||||
* @param slippage slippage percentage
|
||||
* @param getIds ID to retrieve amtA
|
||||
* @param setId ID stores the amount of LP token
|
||||
*/
|
||||
function mint(
|
||||
address tokenA,
|
||||
address tokenB,
|
||||
uint24 fee,
|
||||
int24 tickLower,
|
||||
int24 tickUpper,
|
||||
uint256 amtA,
|
||||
uint256 amtB,
|
||||
uint256 slippage,
|
||||
uint256[] calldata getIds,
|
||||
uint256 setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
|
||||
MintParams memory params;
|
||||
{
|
||||
params = MintParams(
|
||||
tokenA,
|
||||
tokenB,
|
||||
fee,
|
||||
tickLower,
|
||||
tickUpper,
|
||||
amtA,
|
||||
amtB,
|
||||
slippage
|
||||
);
|
||||
}
|
||||
params.amtA = getUint(getIds[0], params.amtA);
|
||||
params.amtB = getUint(getIds[1], params.amtB);
|
||||
|
||||
(
|
||||
uint256 _tokenId,
|
||||
uint256 liquidity,
|
||||
uint256 amountA,
|
||||
uint256 amountB
|
||||
) = _mint(params);
|
||||
|
||||
setUint(setId, liquidity);
|
||||
|
||||
_eventName = "LogMint(uint256,uint256,uint256,uint256,int24,int24)";
|
||||
_eventParam = abi.encode(
|
||||
_tokenId,
|
||||
liquidity,
|
||||
amountA,
|
||||
amountB,
|
||||
params.tickLower,
|
||||
params.tickUpper
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Increase Liquidity
|
||||
* @notice Increase Liquidity of NFT Position
|
||||
* @param tokenId NFT LP Token ID.
|
||||
* @param amountA tokenA amounts.
|
||||
* @param amountB tokenB amounts.
|
||||
* @param slippage slippage.
|
||||
* @param getIds IDs to retrieve token amounts
|
||||
* @param setId stores the liquidity amount
|
||||
*/
|
||||
function deposit(
|
||||
uint256 tokenId,
|
||||
uint256 amountA,
|
||||
uint256 amountB,
|
||||
uint256 slippage,
|
||||
uint256[] calldata getIds,
|
||||
uint256 setId
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
if (tokenId == 0) tokenId = _getLastNftId(address(this));
|
||||
amountA = getUint(getIds[0], amountA);
|
||||
amountB = getUint(getIds[1], amountB);
|
||||
(
|
||||
uint256 _liquidity,
|
||||
uint256 _amtA,
|
||||
uint256 _amtB
|
||||
) = _addLiquidityWrapper(tokenId, amountA, amountB, slippage);
|
||||
setUint(setId, _liquidity);
|
||||
|
||||
_eventName = "LogDeposit(uint256,uint256,uint256,uint256)";
|
||||
_eventParam = abi.encode(tokenId, _liquidity, _amtA, _amtB);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Decrease Liquidity
|
||||
* @notice Decrease Liquidity of NFT Position
|
||||
* @param tokenId NFT LP Token ID.
|
||||
* @param liquidity LP Token amount.
|
||||
* @param amountAMin Min amount of tokenA.
|
||||
* @param amountBMin Min amount of tokenB.
|
||||
* @param getId ID to retrieve LP token amounts
|
||||
* @param setIds stores the amount of output tokens
|
||||
*/
|
||||
function withdraw(
|
||||
uint256 tokenId,
|
||||
uint256 liquidity,
|
||||
uint256 amountAMin,
|
||||
uint256 amountBMin,
|
||||
uint256 getId,
|
||||
uint256[] calldata setIds
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
if (tokenId == 0) tokenId = _getLastNftId(address(this));
|
||||
uint128 _liquidity = uint128(getUint(getId, liquidity));
|
||||
|
||||
(uint256 _amtA, uint256 _amtB) = _decreaseLiquidity(
|
||||
tokenId,
|
||||
_liquidity,
|
||||
amountAMin,
|
||||
amountBMin
|
||||
);
|
||||
|
||||
setUint(setIds[0], _amtA);
|
||||
setUint(setIds[1], _amtB);
|
||||
|
||||
_eventName = "LogWithdraw(uint256,uint256,uint256,uint256)";
|
||||
_eventParam = abi.encode(tokenId, _liquidity, _amtA, _amtB);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Collect function
|
||||
* @notice Collect from NFT Position
|
||||
* @param tokenId NFT LP Token ID.
|
||||
* @param amount0Max Max amount of token0.
|
||||
* @param amount1Max Max amount of token1.
|
||||
* @param getIds IDs to retrieve amounts
|
||||
* @param setIds stores the amount of output tokens
|
||||
*/
|
||||
function collect(
|
||||
uint256 tokenId,
|
||||
uint256 amount0Max,
|
||||
uint256 amount1Max,
|
||||
uint256[] calldata getIds,
|
||||
uint256[] calldata setIds
|
||||
)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
if (tokenId == 0) tokenId = _getLastNftId(address(this));
|
||||
uint128 _amount0Max = uint128(getUint(getIds[0], amount0Max));
|
||||
uint128 _amount1Max = uint128(getUint(getIds[1], amount1Max));
|
||||
(uint256 amount0, uint256 amount1) = _collect(
|
||||
tokenId,
|
||||
_amount0Max,
|
||||
_amount1Max
|
||||
);
|
||||
|
||||
setUint(setIds[0], amount0);
|
||||
setUint(setIds[1], amount1);
|
||||
_eventName = "LogCollect(uint256,uint256,uint256)";
|
||||
_eventParam = abi.encode(tokenId, amount0, amount1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Burn Function
|
||||
* @notice Burn NFT LP Position
|
||||
* @param tokenId NFT LP Token ID
|
||||
*/
|
||||
function burn(uint256 tokenId)
|
||||
external
|
||||
payable
|
||||
returns (string memory _eventName, bytes memory _eventParam)
|
||||
{
|
||||
if (tokenId == 0) tokenId = _getLastNftId(address(this));
|
||||
_burn(tokenId);
|
||||
_eventName = "LogBurnPosition(uint256)";
|
||||
_eventParam = abi.encode(tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
contract ConnectV2UniswapV3 is UniswapResolver {
|
||||
string public constant name = "UniswapV3-v1";
|
||||
}
|
|
@ -57,9 +57,10 @@ 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"))
|
||||
},
|
||||
matic: {
|
||||
url: "https://rpc-mainnet.maticvigil.com/",
|
||||
|
|
20335
package-lock.json
generated
20335
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
23
package.json
23
package.json
|
@ -7,8 +7,7 @@
|
|||
"test": "hardhat test",
|
||||
"coverage": "./node_modules/.bin/solidity-coverage",
|
||||
"check-husky": "node status-checks/huskyCheck.js",
|
||||
"build-contracts": "sol-merger \"./contracts/connectors/mock.sol\" ./contracts/build",
|
||||
"prepare": "husky install"
|
||||
"build-contracts": "sol-merger \"./contracts/connectors/mock.sol\" ./contracts/build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -22,6 +21,8 @@
|
|||
"homepage": "https://github.com/InstaDApp/dsa-connectors-new#readme",
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^3.4.0-solc-0.7",
|
||||
"@uniswap/v3-core": "^1.0.0",
|
||||
"@uniswap/v3-periphery": "^1.1.1",
|
||||
"chalk": "^4.0.0",
|
||||
"commander": "^7.1.0",
|
||||
"dotenv": "^7.0.0",
|
||||
|
@ -31,21 +32,21 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||
"@nomiclabs/hardhat-etherscan": "^2.1.3",
|
||||
"@nomiclabs/hardhat-etherscan": "^2.1.4",
|
||||
"@nomiclabs/hardhat-waffle": "^2.0.1",
|
||||
"@nomiclabs/hardhat-web3": "^2.0.0",
|
||||
"@openzeppelin/test-helpers": "^0.5.6",
|
||||
"@openzeppelin/test-helpers": "^0.5.12",
|
||||
"@studydefi/money-legos": "^2.3.7",
|
||||
"@tenderly/hardhat-tenderly": "^1.0.6",
|
||||
"@tenderly/hardhat-tenderly": "^1.0.12",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"ethereum-waffle": "^3.3.0",
|
||||
"ethers": "^5.1.4",
|
||||
"hardhat": "^2.3.0",
|
||||
"hardhat-deploy": "^0.7.5",
|
||||
"hardhat-deploy-ethers": "^0.3.0-beta.7",
|
||||
"ethereum-waffle": "^3.4.0",
|
||||
"ethers": "^5.4.4",
|
||||
"hardhat": "^2.6.0",
|
||||
"hardhat-deploy": "^0.8.11",
|
||||
"hardhat-deploy-ethers": "^0.3.0-beta.10",
|
||||
"husky": "^6.0.0",
|
||||
"sol-merger": "^2.0.1",
|
||||
"solidity-coverage": "0.5.11",
|
||||
"web3": "^1.3.0"
|
||||
"web3": "^1.3.6"
|
||||
}
|
||||
}
|
||||
|
|
324
test/uniswap/uniswap.test.js
Normal file
324
test/uniswap/uniswap.test.js
Normal file
|
@ -0,0 +1,324 @@
|
|||
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 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 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"
|
||||
|
||||
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);
|
||||
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;
|
||||
});
|
||||
|
||||
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"));
|
||||
|
||||
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"));
|
||||
});
|
||||
});
|
||||
|
||||
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 getIds = ["0", "0"]
|
||||
const setId = "0"
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "mint",
|
||||
args: [
|
||||
DAI_ADDR,
|
||||
ethAddress,
|
||||
FeeAmount.MEDIUM,
|
||||
getMinTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
getMaxTick(TICK_SPACINGS[FeeAmount.MEDIUM]),
|
||||
daiAmount,
|
||||
ethAmount,
|
||||
"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 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();
|
||||
|
||||
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 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 getIds = ["0", "0"]
|
||||
const setId = "0"
|
||||
|
||||
const spells = [
|
||||
{
|
||||
connector: connectorName,
|
||||
method: "deposit",
|
||||
args: [
|
||||
tokenIds[0],
|
||||
daiAmount,
|
||||
ethAmount,
|
||||
"500000000000000000",
|
||||
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[1]);
|
||||
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 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 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()
|
||||
|
||||
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: "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
|
Loading…
Reference in New Issue
Block a user