diff --git a/contracts/optimism/connectors/uniswap/v3/events.sol b/contracts/optimism/connectors/uniswap/v3/events.sol new file mode 100644 index 00000000..6d04f06c --- /dev/null +++ b/contracts/optimism/connectors/uniswap/v3/events.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +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/optimism/connectors/uniswap/v3/helpers.sol b/contracts/optimism/connectors/uniswap/v3/helpers.sol new file mode 100644 index 00000000..85c05a46 --- /dev/null +++ b/contracts/optimism/connectors/uniswap/v3/helpers.sol @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: MIT +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); + } + + function sortTokenAddress(address _token0, address _token1) + internal + view + returns (address token0, address token1) + { + if (_token0 > _token1) { + (token0, token1) = (_token1, _token0); + } else { + (token0, token1) = (_token0, _token1); + } + } + + /** + * @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); + + { + (address token0, ) = sortTokenAddress( + address(_token0), + address(_token1) + ); + + if (token0 != address(_token0)) { + (_token0, _token1) = (_token1, _token0); + (_amount0, _amount1) = (_amount1, _amount0); + } + } + 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/optimism/connectors/uniswap/v3/interface.sol b/contracts/optimism/connectors/uniswap/v3/interface.sol new file mode 100644 index 00000000..ed76b240 --- /dev/null +++ b/contracts/optimism/connectors/uniswap/v3/interface.sol @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: MIT +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/optimism/connectors/uniswap/v3/main.sol b/contracts/optimism/connectors/uniswap/v3/main.sol new file mode 100644 index 00000000..5e079019 --- /dev/null +++ b/contracts/optimism/connectors/uniswap/v3/main.sol @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: MIT +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 ConnectV2UniswapV3Optimism is UniswapResolver { + string public constant name = "UniswapV3-v1"; +}