diff --git a/sdks/v4-sdk/src/PositionManager.test.ts b/sdks/v4-sdk/src/PositionManager.test.ts index d03d21764..edfb82792 100644 --- a/sdks/v4-sdk/src/PositionManager.test.ts +++ b/sdks/v4-sdk/src/PositionManager.test.ts @@ -280,6 +280,44 @@ describe('PositionManager', () => { expect(value).toEqual(toHex(amount0Max)) }) + it('succeeds when migrate is true', () => { + const position: Position = new Position({ + pool: pool_0_1, + tickLower: -TICK_SPACINGS[FeeAmount.MEDIUM], + tickUpper: TICK_SPACINGS[FeeAmount.MEDIUM], + liquidity: 1, + }) + const { calldata, value } = V4PositionManager.addCallParameters(position, { + recipient, + slippageTolerance, + deadline, + migrate: true, + }) + + // Rebuild the data with the planner for the expected mint. MUST sweep since we are using the native currency. + const planner = new V4Planner() + const { amount0: amount0Max, amount1: amount1Max } = position.mintAmountsWithSlippage(slippageTolerance) + // Expect position to be minted correctly + planner.addAction(Actions.MINT_POSITION, [ + pool_0_1.poolKey, + -TICK_SPACINGS[FeeAmount.MEDIUM], + TICK_SPACINGS[FeeAmount.MEDIUM], + 1, + toHex(amount0Max), + toHex(amount1Max), + recipient, + EMPTY_BYTES, + ]) + + planner.addAction(Actions.SETTLE, [toAddress(pool_0_1.currency0), 0, false]) + planner.addAction(Actions.SETTLE, [toAddress(pool_0_1.currency1), 0, false]) + planner.addAction(Actions.SWEEP, [toAddress(pool_0_1.currency0), recipient]) + planner.addAction(Actions.SWEEP, [toAddress(pool_0_1.currency1), recipient]) + expect(calldata).toEqual(V4PositionManager.encodeModifyLiquidities(planner.finalize(), deadline)) + + expect(value).toEqual('0x00') + }) + it('succeeds for batchPermit', () => { const position: Position = new Position({ pool: pool_0_1, diff --git a/sdks/v4-sdk/src/PositionManager.ts b/sdks/v4-sdk/src/PositionManager.ts index cb0c2e1cd..fa32188c5 100644 --- a/sdks/v4-sdk/src/PositionManager.ts +++ b/sdks/v4-sdk/src/PositionManager.ts @@ -59,6 +59,11 @@ export interface MintSpecificOptions { * Initial price to set on the pool if creating */ sqrtPriceX96?: BigintIsh + + /** + * Whether the mint is part of a migration from V3 to V4. + */ + migrate?: boolean } /** @@ -221,8 +226,8 @@ export abstract class V4PositionManager { * Cases: * - if pool does not exist yet, encode initializePool * then, - * - if is mint, encode MINT_POSITION. If it is on a NATIVE pool, encode a SWEEP. Finally encode a SETTLE_PAIR - * - else, encode INCREASE_LIQUIDITY. If it is on a NATIVE pool, encode a SWEEP. Finally encode a SETTLE_PAIR + * - if is mint, encode MINT_POSITION. If migrating, encode a SETTLE and SWEEP for both currencies. Else, encode a SETTLE_PAIR. If on a NATIVE pool, encode a SWEEP. + * - else, encode INCREASE_LIQUIDITY and SETTLE_PAIR. If it is on a NATIVE pool, encode a SWEEP. */ invariant(JSBI.greaterThan(position.liquidity, ZERO), ZERO_LIQUIDITY) @@ -271,8 +276,17 @@ export abstract class V4PositionManager { planner.addIncrease(options.tokenId, position.liquidity, amount0Max, amount1Max, options.hookData) } - // need to settle both currencies when minting / adding liquidity - planner.addSettlePair(position.pool.currency0, position.pool.currency1) + // If migrating, we need to settle and sweep both currencies individually + if (isMint(options) && options.migrate) { + // payer is v4 positiion manager + planner.addSettle(position.pool.currency0, false) + planner.addSettle(position.pool.currency1, false) + planner.addSweep(position.pool.currency0, options.recipient) + planner.addSweep(position.pool.currency1, options.recipient) + } else { + // need to settle both currencies when minting / adding liquidity (user is the payer) + planner.addSettlePair(position.pool.currency0, position.pool.currency1) + } // Any sweeping must happen after the settling. let value: string = toHex(0)