100 lines
3.9 KiB
Solidity
100 lines
3.9 KiB
Solidity
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
pragma solidity =0.7.6;
|
||
|
pragma abicoder v2;
|
||
|
|
||
|
import '@uniswap/v3-core/contracts/libraries/LowGasSafeMath.sol';
|
||
|
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';
|
||
|
|
||
|
import './interfaces/INonfungiblePositionManager.sol';
|
||
|
|
||
|
import './libraries/TransferHelper.sol';
|
||
|
|
||
|
import './interfaces/IV3Migrator.sol';
|
||
|
import './base/PeripheryImmutableState.sol';
|
||
|
import './base/Multicall.sol';
|
||
|
import './base/SelfPermit.sol';
|
||
|
import './interfaces/external/IWETH9.sol';
|
||
|
import './base/PoolInitializer.sol';
|
||
|
|
||
|
/// @title Uniswap V3 Migrator
|
||
|
contract V3Migrator is IV3Migrator, PeripheryImmutableState, PoolInitializer, Multicall, SelfPermit {
|
||
|
using LowGasSafeMath for uint256;
|
||
|
|
||
|
address public immutable nonfungiblePositionManager;
|
||
|
|
||
|
constructor(
|
||
|
address _factory,
|
||
|
address _WETH9,
|
||
|
address _nonfungiblePositionManager
|
||
|
) PeripheryImmutableState(_factory, _WETH9) {
|
||
|
nonfungiblePositionManager = _nonfungiblePositionManager;
|
||
|
}
|
||
|
|
||
|
receive() external payable {
|
||
|
require(msg.sender == WETH9, 'Not WETH9');
|
||
|
}
|
||
|
|
||
|
function migrate(MigrateParams calldata params) external override {
|
||
|
require(params.percentageToMigrate > 0, 'Percentage too small');
|
||
|
require(params.percentageToMigrate <= 100, 'Percentage too large');
|
||
|
|
||
|
// burn v2 liquidity to this address
|
||
|
IUniswapV2Pair(params.pair).transferFrom(msg.sender, params.pair, params.liquidityToMigrate);
|
||
|
(uint256 amount0V2, uint256 amount1V2) = IUniswapV2Pair(params.pair).burn(address(this));
|
||
|
|
||
|
// calculate the amounts to migrate to v3
|
||
|
uint256 amount0V2ToMigrate = amount0V2.mul(params.percentageToMigrate) / 100;
|
||
|
uint256 amount1V2ToMigrate = amount1V2.mul(params.percentageToMigrate) / 100;
|
||
|
|
||
|
// approve the position manager up to the maximum token amounts
|
||
|
TransferHelper.safeApprove(params.token0, nonfungiblePositionManager, amount0V2ToMigrate);
|
||
|
TransferHelper.safeApprove(params.token1, nonfungiblePositionManager, amount1V2ToMigrate);
|
||
|
|
||
|
// mint v3 position
|
||
|
(, , uint256 amount0V3, uint256 amount1V3) =
|
||
|
INonfungiblePositionManager(nonfungiblePositionManager).mint(
|
||
|
INonfungiblePositionManager.MintParams({
|
||
|
token0: params.token0,
|
||
|
token1: params.token1,
|
||
|
fee: params.fee,
|
||
|
tickLower: params.tickLower,
|
||
|
tickUpper: params.tickUpper,
|
||
|
amount0Desired: amount0V2ToMigrate,
|
||
|
amount1Desired: amount1V2ToMigrate,
|
||
|
amount0Min: params.amount0Min,
|
||
|
amount1Min: params.amount1Min,
|
||
|
recipient: params.recipient,
|
||
|
deadline: params.deadline
|
||
|
})
|
||
|
);
|
||
|
|
||
|
// if necessary, clear allowance and refund dust
|
||
|
if (amount0V3 < amount0V2) {
|
||
|
if (amount0V3 < amount0V2ToMigrate) {
|
||
|
TransferHelper.safeApprove(params.token0, nonfungiblePositionManager, 0);
|
||
|
}
|
||
|
|
||
|
uint256 refund0 = amount0V2 - amount0V3;
|
||
|
if (params.refundAsETH && params.token0 == WETH9) {
|
||
|
IWETH9(WETH9).withdraw(refund0);
|
||
|
TransferHelper.safeTransferETH(msg.sender, refund0);
|
||
|
} else {
|
||
|
TransferHelper.safeTransfer(params.token0, msg.sender, refund0);
|
||
|
}
|
||
|
}
|
||
|
if (amount1V3 < amount1V2) {
|
||
|
if (amount1V3 < amount1V2ToMigrate) {
|
||
|
TransferHelper.safeApprove(params.token1, nonfungiblePositionManager, 0);
|
||
|
}
|
||
|
|
||
|
uint256 refund1 = amount1V2 - amount1V3;
|
||
|
if (params.refundAsETH && params.token1 == WETH9) {
|
||
|
IWETH9(WETH9).withdraw(refund1);
|
||
|
TransferHelper.safeTransferETH(msg.sender, refund1);
|
||
|
} else {
|
||
|
TransferHelper.safeTransfer(params.token1, msg.sender, refund1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|