-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
V4 CLMigrator #51
V4 CLMigrator #51
Conversation
9505919
to
326ebd8
Compare
f5ac980
to
b5cfd04
Compare
uint256 amount0Min; | ||
uint256 amount1Min; | ||
// decide whether to collect fee | ||
bool collectFee; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest we can remove the collectFee flag.
Since we need to collect the liquidity amount , so it is better to collect the fee together.
Because fee number is always smaller than the liquidity amount.
Or we can keep this in the code, but FE use true as default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this works as a checkbox at frontend page. Will double confirm tho.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per internal discussion: will keep it to give flexibility to user
src/pool-cl/CLMigrator.sol
Outdated
|
||
function migrateFromV2( | ||
V2PoolParams calldata v2PoolParams, | ||
INonfungiblePositionManager.MintParams calldata v4MintParams, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we updated the v4MintParams.amount0Desired and amount1Desired based on the real withdraw amount from v2 or v3 ?
Because pool state is constantly changing, so maybe the withdraw amount is different from the number FE calculated.
v4MintParams.amount0Desired = amount0Received + extraAmount0;
v4MintParams.amount1Desired = amount1Received + extraAmount1;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice point. I can update to use the actual amount received. Also, do u think we should have a simple check here to see if the expected amount and actual amount way off
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, we can check .
but if so , we need a rule to define the way off
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per internal discussion: The fields amount0Min and amount1Min in v3#decreaseLiquidity should be sufficient if price’s changed a log. We will add same checking rule for migrateFromV2 case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated, same as the following one.. can take a look
src/pool-cl/CLMigrator.sol
Outdated
v4MintParams.poolKey.currency0, v4MintParams.poolKey.currency1, extraAmount0, extraAmount1 | ||
); | ||
|
||
(,, uint256 amount0Consumed, uint256 amount1Consumed) = _addLiquidityToTargetPool(v4MintParams); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we updated the v4MintParams.amount0Desired and amount1Desired based on the real withdraw amount from v2 or v3 ?
Same as the comment above.
approveMax(params.poolKey.currency0, address(nonfungiblePositionManager)); | ||
} | ||
approveMax(params.poolKey.currency1, address(nonfungiblePositionManager)); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point.
I guess separate call is cheaper 🐶
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, i've initiated call separately
src/base/BaseMigrator.sol
Outdated
} | ||
|
||
// even if user sends native ETH, we still need to unwrap the part from source pool | ||
if (address(token0) == NATIVE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(minor, non blocker) can consider using this currency0.isNative()
applies to other places where we check eg. address(token) == NATIVE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated, thx for reminding
src/pool-cl/CLMigrator.sol
Outdated
// TODO: compare the gas cost of multicall and two separate call | ||
bytes[] memory data = new bytes[](2); | ||
data[0] = abi.encodeWithSelector(nonfungiblePositionManager.mint.selector, params); | ||
data[1] = abi.encodeWithSelector(nonfungiblePositionManager.refundETH.selector); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(optional) -- could it be more gas efficient if we only add refundEth
for nativePair case?
eg.
if (nativePair) {
bytes[] memory data = new bytes[](2);
} else {
bytes[] memory data = new bytes[](1);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will do the gas comparison when start writing test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated to avoid multi call which consumes more gas
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no other feedback in general, structure looks clean and easy to understand for me
if (amount1Received > amount1Consumed) { | ||
v4MintParams.poolKey.currency1.transfer(v4MintParams.recipient, amount1Received - amount1Consumed); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add event for migrateFromV2 and migrateFromV3 ?
Not sure whether FE need events to make statistics about migration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given our v3 doesn't have the event and so far seems fine, i think we can leave it without events for now. (though open if we want to add)
}); | ||
(,, uint256 amount0Consumed, uint256 amount1Consumed) = _addLiquidityToTargetPool(mintParams); | ||
|
||
// refund if necessary, ETH is supported by CurrencyLib |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this use the (amount0Received + extraAmount0) > amount0Consumed ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice finding! fixed
src/base/BaseMigrator.sol
Outdated
|
||
function approveMax(Currency currency, address to) internal { | ||
ERC20 token = ERC20(Currency.unwrap(currency)); | ||
if (token.allowance(address(this), to) == type(uint256).max) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About this check condition , it will only apply for the new ERC20 token.
For old ERC20 tokens which deployed for a long time ago, the approve function did not have the "currentAllowance != type(uint256).max" checker , so it will always reduce the allowance , so for the old tokens will be approved every time when this token allowance was used before.
For example , you can check the Cake Token , no type(uint256).max when spent allowance.
https://bscscan.com/token/0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82#code
so you need to change this condition , just like this :
token.allowance(address(this), to) > 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thx for reminding, can take a look again
/// @dev receive extra tokens from user if necessary and normalize all the WETH to native ETH | ||
function batchAndNormalizeTokens(Currency currency0, Currency currency1, uint256 extraAmount0, uint256 extraAmount1) | ||
internal | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest we can check extraAmount0 and extraAmount1 at the beginning .
if(extraAmount0 == 0 && extraAmount1 == 0) {return;}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unwrapping WETH will still be needed because we might receive WETH from source pool. Or do u think i should move IWETH9(WETH9).withdraw(ERC20(WETH9).balanceOf(address(this)));
to a separate function ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point.
you can skip this suggestion.
Or add extra logic about the WETH withdraw before return.
Separate function is also a good solution.
src/pool-cl/CLMigrator.sol
Outdated
|
||
(tokenId, liquidity, amount0Consumed, amount1Consumed) = | ||
nonfungiblePositionManager.mint{value: nativePair ? params.amount0Desired : 0}(params); | ||
if (nativePair) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
about this , i suggest we can add more condition.
if(nativePair && amount0Consumed < params.amount0Desired)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thx for reminding, updated
} | ||
|
||
// even if user sends native ETH, we still need to unwrap the part from source pool | ||
if (currency0.isNative()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we check the ERC20(WETH9).balanceOf(address(this) > 0 ?
for example , if users try to migrate one v3 position which is out of range , so maybe it will get 0 amount for WETH , in this case , we still will go to call IWETH9(WETH9).withdraw , it will cost extra gas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, updated
src/pool-cl/CLMigrator.sol
Outdated
uint256 extraAmount0, | ||
uint256 extraAmount1 | ||
) external payable override { | ||
IV3NonfungiblePositionManager.DecreaseLiquidityParams memory decreaseLiquidityParams = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Marked
src/base/BaseMigrator.sol
Outdated
@@ -45,6 +41,11 @@ contract BaseMigrator is IBaseMigrator, PeripheryImmutableState, Multicall, Self | |||
IV3NonfungiblePositionManager.DecreaseLiquidityParams memory decreaseLiquidityParams, | |||
bool collectFee | |||
) internal returns (uint256 amount0Received, uint256 amount1Received) { | |||
///@dev make sure the caller is the owner of the token | |||
/// otherwise once the token is approved to migrator, anyone can still money through this function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo : still -> steal
src/base/BaseMigrator.sol
Outdated
} | ||
} | ||
|
||
/// @dev receive extra tokens from user if necessary and normalize all the WETH to native ETH |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(not blocker)
could you add this somewhere? maybe in ICLMigrator
for those core migrateFromV2 and migrateFromV3 method? feel like this might be good to flag out to external dev who are integrating
// @param: extraAmount0: if pool token0 is ETH and msg.value == 0, WETH will be taken from sender. Otherwise if pool token0 is ETH and msg.value !=0, method will assume user have sent extraAmount0 in msg.value```
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will update this right before i merge all 3 PRs ( avoid annoying rebasing 😂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
* feat: impl binPool migrator * refactor: restructure & renaming accordingly * test: add tests cases for binPool migrator * chore: renaming as well to align with clMigrator * fix: add check to prevent token mismatch between source and target pool * feat: added refundETH function and necessary comments * optimization: avoid duplicate external call when query v2/v3 pool info * feat: support selfPermitForERC721 (#62) * feat: support selfPermitForERC721 * docs: added comments suggesting users to use selfPermitERC721IfNecessary * test: added tests to prevent ppl from removing payable keyword from external functions
The new migrator for cl-pool, support the following source pools:
And it will withdraw liquidity from source pool and pipe it to correspond v4 cl-pool.
Features