From 9b272ee6b83d94c57e283b000e908fe19d34e9b5 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Tue, 21 Sep 2021 14:45:40 +0530 Subject: [PATCH] Added UniswapV3 Arbitrum connector --- .../arbitrum/connectors/uniswap/v3/events.sol | 34 ++ .../connectors/uniswap/v3/helpers.sol | 263 +++++++++++++ .../connectors/uniswap/v3/interface.sol | 368 ++++++++++++++++++ .../arbitrum/connectors/uniswap/v3/main.sol | 210 ++++++++++ 4 files changed, 875 insertions(+) create mode 100644 contracts/arbitrum/connectors/uniswap/v3/events.sol create mode 100644 contracts/arbitrum/connectors/uniswap/v3/helpers.sol create mode 100644 contracts/arbitrum/connectors/uniswap/v3/interface.sol create mode 100644 contracts/arbitrum/connectors/uniswap/v3/main.sol diff --git a/contracts/arbitrum/connectors/uniswap/v3/events.sol b/contracts/arbitrum/connectors/uniswap/v3/events.sol new file mode 100644 index 00000000..829fadd2 --- /dev/null +++ b/contracts/arbitrum/connectors/uniswap/v3/events.sol @@ -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); +} diff --git a/contracts/arbitrum/connectors/uniswap/v3/helpers.sol b/contracts/arbitrum/connectors/uniswap/v3/helpers.sol new file mode 100644 index 00000000..e16cea83 --- /dev/null +++ b/contracts/arbitrum/connectors/uniswap/v3/helpers.sol @@ -0,0 +1,263 @@ +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); + + 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); + } +} diff --git a/contracts/arbitrum/connectors/uniswap/v3/interface.sol b/contracts/arbitrum/connectors/uniswap/v3/interface.sol new file mode 100644 index 00000000..f8bc6e84 --- /dev/null +++ b/contracts/arbitrum/connectors/uniswap/v3/interface.sol @@ -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; +} diff --git a/contracts/arbitrum/connectors/uniswap/v3/main.sol b/contracts/arbitrum/connectors/uniswap/v3/main.sol new file mode 100644 index 00000000..b585c322 --- /dev/null +++ b/contracts/arbitrum/connectors/uniswap/v3/main.sol @@ -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 ConnectV2UniswapV3Arbitrum is UniswapResolver { + string public constant name = "UniswapV3-v1"; +}