From 05909cf8c9553f43f2a2fcb15a2be373d7636b31 Mon Sep 17 00:00:00 2001 From: IliaAzhel Date: Wed, 18 Sep 2024 16:12:19 +0300 Subject: [PATCH 1/2] [Periphery] returns lists of amountIn/Out in exactInput/Output --- .../contracts/interfaces/IQuoterV2.sol | 16 +-- src/periphery/contracts/lens/QuoterV2.sol | 40 +++--- src/periphery/test/QuoterV2.spec.ts | 129 +++++++++--------- .../test/__snapshots__/QuoterV2.spec.ts.snap | 28 ++-- 4 files changed, 105 insertions(+), 108 deletions(-) diff --git a/src/periphery/contracts/interfaces/IQuoterV2.sol b/src/periphery/contracts/interfaces/IQuoterV2.sol index 4782649a..5c55f38a 100644 --- a/src/periphery/contracts/interfaces/IQuoterV2.sol +++ b/src/periphery/contracts/interfaces/IQuoterV2.sol @@ -13,8 +13,8 @@ interface IQuoterV2 { /// @notice Returns the amount out received for a given exact input swap without executing the swap /// @param path The path of the swap, i.e. each token pair /// @param amountInRequired The desired amount of the first token to swap - /// @return amountOut The amount of the last token that would be received - /// @return amountIn The amount of the last token that should be paid + /// @return amountOutList The amount of the last token that would be received + /// @return amountInList The amount of the last token that should be paid /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path /// @return gasEstimate The estimate of the gas that the swap consumes @@ -25,8 +25,8 @@ interface IQuoterV2 { ) external returns ( - uint256 amountOut, - uint256 amountIn, + uint256[] memory amountOutList, + uint256[] memory amountInList, uint160[] memory sqrtPriceX96AfterList, uint32[] memory initializedTicksCrossedList, uint256 gasEstimate, @@ -69,8 +69,8 @@ interface IQuoterV2 { /// @notice Returns the amount in required for a given exact output swap without executing the swap /// @param path The path of the swap, i.e. each token pair. Path must be provided in reverse order /// @param amountOutRequired The amount of the last token to receive - /// @return amountOut The amount of the last token that would be received - /// @return amountIn The amount of first token required to be paid + /// @return amountOutList The amount of the last token that would be received + /// @return amountInList The amount of first token required to be paid /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path /// @return gasEstimate The estimate of the gas that the swap consumes @@ -81,8 +81,8 @@ interface IQuoterV2 { ) external returns ( - uint256 amountOut, - uint256 amountIn, + uint256[] memory amountOutList, + uint256[] memory amountInList, uint160[] memory sqrtPriceX96AfterList, uint32[] memory initializedTicksCrossedList, uint256 gasEstimate, diff --git a/src/periphery/contracts/lens/QuoterV2.sol b/src/periphery/contracts/lens/QuoterV2.sol index 8edf893a..492c02de 100644 --- a/src/periphery/contracts/lens/QuoterV2.sol +++ b/src/periphery/contracts/lens/QuoterV2.sol @@ -160,14 +160,16 @@ contract QuoterV2 is IQuoterV2, IAlgebraSwapCallback, PeripheryImmutableState { public override returns ( - uint256 amountOut, - uint256 amountIn, + uint256[] memory amountOutList, + uint256[] memory amountInList, uint160[] memory sqrtPriceX96AfterList, uint32[] memory initializedTicksCrossedList, uint256 gasEstimate, uint16[] memory feeList ) { + amountOutList = new uint256[](path.numPools()); + amountInList = new uint256[](path.numPools()); sqrtPriceX96AfterList = new uint160[](path.numPools()); initializedTicksCrossedList = new uint32[](path.numPools()); feeList = new uint16[](path.numPools()); @@ -185,21 +187,17 @@ contract QuoterV2 is IQuoterV2, IAlgebraSwapCallback, PeripheryImmutableState { } // the outputs of prior swaps become the inputs to subsequent ones - uint256 _amountOut; - uint256 _amountIn; uint256 _gasEstimate; ( - _amountOut, - _amountIn, + amountOutList[i], + amountInList[i], sqrtPriceX96AfterList[i], initializedTicksCrossedList[i], _gasEstimate, feeList[i] ) = quoteExactInputSingle(params); - if (i == 0) amountIn = _amountIn; - - amountInRequired = _amountOut; + amountInRequired = amountOutList[i]; gasEstimate += _gasEstimate; i++; @@ -208,8 +206,8 @@ contract QuoterV2 is IQuoterV2, IAlgebraSwapCallback, PeripheryImmutableState { path = path.skipToken(); } else { return ( - amountInRequired, - amountIn, + amountOutList, + amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList, gasEstimate, @@ -264,14 +262,16 @@ contract QuoterV2 is IQuoterV2, IAlgebraSwapCallback, PeripheryImmutableState { public override returns ( - uint256 amountOut, - uint256 amountIn, + uint256[] memory amountOutList, + uint256[] memory amountInList, uint160[] memory sqrtPriceX96AfterList, uint32[] memory initializedTicksCrossedList, uint256 gasEstimate, uint16[] memory feeList ) { + amountOutList = new uint256[](path.numPools()); + amountInList = new uint256[](path.numPools()); sqrtPriceX96AfterList = new uint160[](path.numPools()); initializedTicksCrossedList = new uint32[](path.numPools()); feeList = new uint16[](path.numPools()); @@ -289,21 +289,17 @@ contract QuoterV2 is IQuoterV2, IAlgebraSwapCallback, PeripheryImmutableState { } // the inputs of prior swaps become the outputs of subsequent ones - uint256 _amountOut; - uint256 _amountIn; uint256 _gasEstimate; ( - _amountOut, - _amountIn, + amountOutList[i], + amountInList[i], sqrtPriceX96AfterList[i], initializedTicksCrossedList[i], _gasEstimate, feeList[i] ) = quoteExactOutputSingle(params); - if (i == 0) amountOut = _amountOut; - - amountOutRequired = _amountIn; + amountOutRequired = amountInList[i]; gasEstimate += _gasEstimate; i++; @@ -312,8 +308,8 @@ contract QuoterV2 is IQuoterV2, IAlgebraSwapCallback, PeripheryImmutableState { path = path.skipToken(); } else { return ( - amountOut, - amountOutRequired, + amountOutList, + amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList, gasEstimate, diff --git a/src/periphery/test/QuoterV2.spec.ts b/src/periphery/test/QuoterV2.spec.ts index c478d687..4c963e94 100644 --- a/src/periphery/test/QuoterV2.spec.ts +++ b/src/periphery/test/QuoterV2.spec.ts @@ -85,21 +85,21 @@ describe('QuoterV2', function () { describe('#quoteExactInput', () => { it('0 -> 2 cross 2 tick', async () => { - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactInput.staticCall(encodePath([tokens[0].address, ZERO_ADDRESS, tokens[2].address]), 10000); ////await snapshotGasCost(gasEstimate) expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('78459826284680823468887704103'); expect(initializedTicksCrossedList[0]).to.eq(2); - expect(amountIn).to.eq(10000); - expect(amountOut).to.eq(9897); + expect(amountInList[0]).to.eq(10000); + expect(amountOutList[0]).to.eq(9897); }); it('0 -> 2 cross 2 tick where after is initialized', async () => { // The swap amount is set such that the active tick after the swap is -120. // -120 is an initialized tick for this pool. We check that we don't count it. - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactInput.staticCall(encodePath([tokens[0].address, ZERO_ADDRESS, tokens[2].address]), 6200); ////await snapshotGasCost(gasEstimate) @@ -107,52 +107,52 @@ describe('QuoterV2', function () { expect(sqrtPriceX96AfterList[0]).to.eq('78755992497053066283316544500'); expect(initializedTicksCrossedList.length).to.eq(1); expect(initializedTicksCrossedList[0]).to.eq(1); - expect(amountOut).to.eq(6158); - expect(amountIn).to.eq(6200); + expect(amountOutList[0]).to.eq(6158); + expect(amountInList[0]).to.eq(6200); }); it('0 -> 2 cross 1 tick', async () => { - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactInput.staticCall(encodePath([tokens[0].address, ZERO_ADDRESS, tokens[2].address]), 4000); ////await snapshotGasCost(gasEstimate) expect(initializedTicksCrossedList[0]).to.eq(1); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('78925679077027744088480448931'); - expect(amountOut).to.eq(3981); - expect(amountIn).to.eq(4000); + expect(amountOutList[0]).to.eq(3981); + expect(amountInList[0]).to.eq(4000); }); it('0 -> 2 cross 0 tick, starting tick not initialized', async () => { // Tick before 0, tick after -1. - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactInput.staticCall(encodePath([tokens[0].address, ZERO_ADDRESS, tokens[2].address]), 10); ////await snapshotGasCost(gasEstimate) expect(initializedTicksCrossedList[0]).to.eq(0); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('79227483487511329217250071027'); - expect(amountOut).to.eq(8); - expect(amountIn).to.eq(10); + expect(amountOutList[0]).to.eq(8); + expect(amountInList[0]).to.eq(10); }); it('0 -> 2 cross 0 tick, starting tick initialized', async () => { // Tick before 0, tick after -1. Tick 0 initialized. await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address); - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactInput.staticCall(encodePath([tokens[0].address, ZERO_ADDRESS, tokens[2].address]), 10); ////await snapshotGasCost(gasEstimate) expect(initializedTicksCrossedList[0]).to.eq(1); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('79227817515327498931091950511'); - expect(amountOut).to.eq(8); - expect(amountIn).to.eq(10); + expect(amountOutList[0]).to.eq(8); + expect(amountInList[0]).to.eq(10); }); it('2 -> 0 cross 2', async () => { - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactInput.staticCall(encodePath([tokens[2].address, ZERO_ADDRESS, tokens[0].address]), 10000); ////await snapshotGasCost(gasEstimate) @@ -160,32 +160,31 @@ describe('QuoterV2', function () { expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('80004022856373268738318816658'); expect(initializedTicksCrossedList.length).to.eq(1); - expect(amountOut).to.eq(9897); - expect(amountIn).to.eq(10000); + expect(amountOutList[0]).to.eq(9897); + expect(amountInList[0]).to.eq(10000); }); it('2 -> 0 cross 2 where tick after is initialized', async () => { // The swap amount is set such that the active tick after the swap is 120. // 120 is an initialized tick for this pool. We check we don't count it. - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactInput.staticCall(encodePath([tokens[2].address, ZERO_ADDRESS, tokens[0].address]), 6250); ////await snapshotGasCost(gasEstimate) - console.log(sqrtPriceX96AfterList[0].toString()); expect(initializedTicksCrossedList[0]).to.eq(2); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('79706996475107291736680620388'); expect(initializedTicksCrossedList.length).to.eq(1); - expect(amountOut).to.eq(6206); - expect(amountIn).to.eq(6250); + expect(amountOutList[0]).to.eq(6206); + expect(amountInList[0]).to.eq(6250); }); it('2 -> 0 cross 0 tick, starting tick initialized', async () => { // Tick 0 initialized. Tick after = 1 await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address); - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactInput.staticCall(encodePath([tokens[2].address, ZERO_ADDRESS, tokens[0].address]), 200); ////await snapshotGasCost(gasEstimate) @@ -193,13 +192,13 @@ describe('QuoterV2', function () { expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('79235729830182478001034429156'); expect(initializedTicksCrossedList.length).to.eq(1); - expect(amountOut).to.eq(198); - expect(amountIn).to.eq(200); + expect(amountOutList[0]).to.eq(198); + expect(amountInList[0]).to.eq(200); }); it('2 -> 0 cross 0 tick, starting tick not initialized', async () => { // Tick 0 initialized. Tick after = 1 - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactInput.staticCall(encodePath([tokens[2].address, ZERO_ADDRESS, tokens[0].address]), 103); ////await snapshotGasCost(gasEstimate) @@ -207,12 +206,12 @@ describe('QuoterV2', function () { expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('79235858216754624215638319723'); expect(initializedTicksCrossedList.length).to.eq(1); - expect(amountOut).to.eq(101); - expect(amountIn).to.eq(103); + expect(amountOutList[0]).to.eq(101); + expect(amountInList[0]).to.eq(103); }); it('2 -> 1', async () => { - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactInput.staticCall(encodePath([path[4], path[3], path[2]]), 10000); @@ -220,12 +219,12 @@ describe('QuoterV2', function () { expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('80020047998594409647791422119'); expect(initializedTicksCrossedList[0]).to.eq(0); - expect(amountOut).to.eq(9896); - expect(amountIn).to.eq(10000); + expect(amountOutList[0]).to.eq(9896); + expect(amountInList[0]).to.eq(10000); }); it('0 -> 2 -> 1', async () => { - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactInput.staticCall( encodePath([path[0], ZERO_ADDRESS, path[4], path[3], path[2]]), 10000 @@ -237,8 +236,8 @@ describe('QuoterV2', function () { expect(sqrtPriceX96AfterList[1]).to.eq('80011887497855440421019287092'); expect(initializedTicksCrossedList[0]).to.eq(2); expect(initializedTicksCrossedList[1]).to.eq(0); - expect(amountOut).to.eq(9795); - expect(amountIn).to.eq(10000); + expect(amountOutList[1]).to.eq(9795); + expect(amountInList[0]).to.eq(10000); }); }); @@ -339,13 +338,13 @@ describe('QuoterV2', function () { describe('#quoteExactOutput', () => { it('0 -> 2 cross 2 tick', async () => { - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactOutput.staticCall(encodePath([tokens[2].address, ZERO_ADDRESS, tokens[0].address]), 15000); expect(initializedTicksCrossedList.length).to.eq(1); expect(initializedTicksCrossedList[0]).to.eq(2); - expect(amountIn).to.eq(15234); - expect(amountOut).to.be.eq(15000); + expect(amountInList[0]).to.eq(15234); + expect(amountOutList[0]).to.be.eq(15000); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('78055527257643669242286029831'); @@ -354,25 +353,25 @@ describe('QuoterV2', function () { it('0 -> 2 cross 2 where tick after is initialized', async () => { // The swap amount is set such that the active tick after the swap is -120. // -120 is an initialized tick for this pool. We check that we count it. - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactOutput.staticCall(encodePath([tokens[2].address, ZERO_ADDRESS, tokens[0].address]), 6158); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('78756056567076985409608047254'); expect(initializedTicksCrossedList.length).to.eq(1); expect(initializedTicksCrossedList[0]).to.eq(1); - expect(amountIn).to.eq(6200); - expect(amountOut).to.be.eq(6158); + expect(amountInList[0]).to.eq(6200); + expect(amountOutList[0]).to.be.eq(6158); }); it('0 -> 2 cross 1 tick', async () => { - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactOutput.staticCall(encodePath([tokens[2].address, ZERO_ADDRESS, tokens[0].address]), 4000); expect(initializedTicksCrossedList.length).to.eq(1); expect(initializedTicksCrossedList[0]).to.eq(1); - expect(amountIn).to.eq(4019); - expect(amountOut).to.be.eq(4000); + expect(amountInList[0]).to.eq(4019); + expect(amountOutList[0]).to.be.eq(4000); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('78924219757724709840818372098'); @@ -381,39 +380,39 @@ describe('QuoterV2', function () { it('0 -> 2 cross 0 tick starting tick initialized', async () => { // Tick before 0, tick after 1. Tick 0 initialized. await createPoolWithZeroTickInitialized(nft, wallet, tokens[0].address, tokens[2].address); - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactOutput.staticCall(encodePath([tokens[2].address, ZERO_ADDRESS, tokens[0].address]), 100); expect(initializedTicksCrossedList.length).to.eq(1); expect(initializedTicksCrossedList[0]).to.eq(1); - expect(amountIn).to.eq(102); - expect(amountOut).to.be.eq(100); + expect(amountInList[0]).to.eq(102); + expect(amountOutList[0]).to.be.eq(100); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('79224329176051641448521403903'); }); it('0 -> 2 cross 0 tick starting tick not initialized', async () => { - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactOutput.staticCall(encodePath([tokens[2].address, ZERO_ADDRESS, tokens[0].address]), 10); expect(initializedTicksCrossedList.length).to.eq(1); expect(initializedTicksCrossedList[0]).to.eq(0); - expect(amountIn).to.eq(12); - expect(amountOut).to.be.eq(10); + expect(amountInList[0]).to.eq(12); + expect(amountOutList[0]).to.be.eq(10); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('79227408033628034983534698435'); }); it('2 -> 0 cross 2 ticks', async () => { - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactOutput.staticCall(encodePath([tokens[0].address, ZERO_ADDRESS, tokens[2].address]), 15000); expect(initializedTicksCrossedList.length).to.eq(1); expect(initializedTicksCrossedList[0]).to.eq(2); - expect(amountIn).to.eq(15234); - expect(amountOut).to.be.eq(15000); + expect(amountInList[0]).to.eq(15234); + expect(amountOutList[0]).to.be.eq(15000); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('80418414376567919517220409857'); }); @@ -421,42 +420,42 @@ describe('QuoterV2', function () { it('2 -> 0 cross 2 where tick after is initialized', async () => { // The swap amount is set such that the active tick after the swap is 120. // 120 is an initialized tick for this pool. We check that we don't count it. - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactOutput.staticCall(encodePath([tokens[0].address, ZERO_ADDRESS, tokens[2].address]), 6223); expect(initializedTicksCrossedList[0]).to.eq(2); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('79708304437530892332449657932'); expect(initializedTicksCrossedList.length).to.eq(1); - expect(amountIn).to.eq(6267); - expect(amountOut).to.be.eq(6223); + expect(amountInList[0]).to.eq(6267); + expect(amountOutList[0]).to.be.eq(6223); }); it('2 -> 0 cross 1 tick', async () => { - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactOutput.staticCall(encodePath([tokens[0].address, ZERO_ADDRESS, tokens[2].address]), 6000); expect(initializedTicksCrossedList[0]).to.eq(1); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('79690640184021170956740081887'); expect(initializedTicksCrossedList.length).to.eq(1); - expect(amountIn).to.eq(6040); - expect(amountOut).to.be.eq(6000); + expect(amountInList[0]).to.eq(6040); + expect(amountOutList[0]).to.be.eq(6000); }); it('2 -> 1', async () => { - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactOutput.staticCall(encodePath([path[2], path[3], path[4]]), 9897); expect(sqrtPriceX96AfterList.length).to.eq(1); expect(sqrtPriceX96AfterList[0]).to.eq('80020121658316697953186638498'); expect(initializedTicksCrossedList[0]).to.eq(0); - expect(amountIn).to.eq(10002); - expect(amountOut).to.be.eq(9897); + expect(amountInList[0]).to.eq(10002); + expect(amountOutList[0]).to.be.eq(9897); }); it('0 -> 2 -> 1', async () => { - const { amountOut, amountIn, sqrtPriceX96AfterList, initializedTicksCrossedList } = + const { amountOutList, amountInList, sqrtPriceX96AfterList, initializedTicksCrossedList } = await quoter.quoteExactOutput.staticCall( encodePath([path[0], ZERO_ADDRESS, path[4], path[3], path[2]].reverse()), 9795 @@ -467,8 +466,10 @@ describe('QuoterV2', function () { expect(sqrtPriceX96AfterList[1]).to.eq('78459828570953960157025884610'); expect(initializedTicksCrossedList[0]).to.eq(0); expect(initializedTicksCrossedList[1]).to.eq(2); - expect(amountIn).to.eq(10000); - expect(amountOut).to.be.eq(9795); + expect(amountInList[0]).to.eq(9897); + expect(amountInList[1]).to.eq(10000); + expect(amountOutList[0]).to.be.eq(9795); + expect(amountOutList[1]).to.eq(9897); }); describe('gas [ @skip-on-coverage ]', () => { diff --git a/src/periphery/test/__snapshots__/QuoterV2.spec.ts.snap b/src/periphery/test/__snapshots__/QuoterV2.spec.ts.snap index 77df00a4..84325df3 100644 --- a/src/periphery/test/__snapshots__/QuoterV2.spec.ts.snap +++ b/src/periphery/test/__snapshots__/QuoterV2.spec.ts.snap @@ -1,29 +1,29 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`QuoterV2 quotes #quoteExactInputSingle gas [ @skip-on-coverage ] 0 -> 2 1`] = `156869`; +exports[`QuoterV2 quotes #quoteExactInputSingle gas [ @skip-on-coverage ] 0 -> 2 1`] = `157987`; -exports[`QuoterV2 quotes #quoteExactInputSingle gas [ @skip-on-coverage ] 2 -> 0 1`] = `156805`; +exports[`QuoterV2 quotes #quoteExactInputSingle gas [ @skip-on-coverage ] 2 -> 0 1`] = `157893`; -exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 0 -> 2 -> 1 1`] = `248736`; +exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 0 -> 2 -> 1 1`] = `250721`; -exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 0 -> 2 cross 0 tick starting tick initialized 1`] = `106435`; +exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 0 -> 2 cross 0 tick starting tick initialized 1`] = `107424`; -exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 0 -> 2 cross 0 tick starting tick not initialized 1`] = `91088`; +exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 0 -> 2 cross 0 tick starting tick not initialized 1`] = `91954`; -exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 0 -> 2 cross 1 tick 1`] = `126531`; +exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 0 -> 2 cross 1 tick 1`] = `127520`; -exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 0 -> 2 cross 2 tick 1`] = `156770`; +exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 0 -> 2 cross 2 tick 1`] = `157864`; -exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 0 -> 2 cross 2 where tick after is initialized 1`] = `126540`; +exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 0 -> 2 cross 2 where tick after is initialized 1`] = `127529`; -exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 2 -> 0 cross 1 tick 1`] = `126874`; +exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 2 -> 0 cross 1 tick 1`] = `127884`; -exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 2 -> 0 cross 2 ticks 1`] = `157387`; +exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 2 -> 0 cross 2 ticks 1`] = `158499`; -exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 2 -> 0 cross 2 where tick after is initialized 1`] = `157391`; +exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 2 -> 0 cross 2 where tick after is initialized 1`] = `158503`; -exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 2 -> 1 1`] = `91985`; +exports[`QuoterV2 quotes #quoteExactOutput gas [ @skip-on-coverage ] 2 -> 1 1`] = `92876`; -exports[`QuoterV2 quotes #quoteExactOutputSingle gas [ @skip-on-coverage ] 0 -> 1 1`] = `92069`; +exports[`QuoterV2 quotes #quoteExactOutputSingle gas [ @skip-on-coverage ] 0 -> 1 1`] = `92935`; -exports[`QuoterV2 quotes #quoteExactOutputSingle gas [ @skip-on-coverage ] 1 -> 0 1`] = `92086`; +exports[`QuoterV2 quotes #quoteExactOutputSingle gas [ @skip-on-coverage ] 1 -> 0 1`] = `92952`; From 43f761ee0821e045735e64da0d3645d5c7248259 Mon Sep 17 00:00:00 2001 From: IliaAzhel Date: Wed, 18 Sep 2024 16:30:07 +0300 Subject: [PATCH 2/2] [Periphery] add plugin init data to createAndInitializePoolIfNecessary --- .../contracts/base/PoolInitializer.sol | 5 +- .../contracts/interfaces/IPoolInitializer.sol | 4 +- .../test/NonfungiblePositionManager.spec.ts | 70 +++++++++++-------- .../NonfungiblePositionManager.spec.ts.snap | 32 ++++----- 4 files changed, 64 insertions(+), 47 deletions(-) diff --git a/src/periphery/contracts/base/PoolInitializer.sol b/src/periphery/contracts/base/PoolInitializer.sol index 0c59de7b..6203e061 100644 --- a/src/periphery/contracts/base/PoolInitializer.sol +++ b/src/periphery/contracts/base/PoolInitializer.sol @@ -19,7 +19,8 @@ abstract contract PoolInitializer is IPoolInitializer, PeripheryImmutableState { address token0, address token1, address deployer, - uint160 sqrtPriceX96 + uint160 sqrtPriceX96, + bytes calldata data ) external payable override returns (address pool) { require(token0 < token1, 'Invalid order of tokens'); @@ -32,7 +33,7 @@ abstract contract PoolInitializer is IPoolInitializer, PeripheryImmutableState { if (pool == address(0)) { if (deployer == address(0)) { - pool = _factory.createPool(token0, token1, ''); + pool = _factory.createPool(token0, token1, data); _initializePool(pool, sqrtPriceX96); } diff --git a/src/periphery/contracts/interfaces/IPoolInitializer.sol b/src/periphery/contracts/interfaces/IPoolInitializer.sol index a8f8aac5..8fa9bc33 100644 --- a/src/periphery/contracts/interfaces/IPoolInitializer.sol +++ b/src/periphery/contracts/interfaces/IPoolInitializer.sol @@ -13,11 +13,13 @@ interface IPoolInitializer { /// @param token0 The contract address of token0 of the pool /// @param token1 The contract address of token1 of the pool /// @param sqrtPriceX96 The initial square root price of the pool as a Q64.96 value + /// @param data Data for plugin initialization /// @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, address deployer, - uint160 sqrtPriceX96 + uint160 sqrtPriceX96, + bytes calldata data ) external payable returns (address pool); } diff --git a/src/periphery/test/NonfungiblePositionManager.spec.ts b/src/periphery/test/NonfungiblePositionManager.spec.ts index eb7fe87a..e20768e6 100644 --- a/src/periphery/test/NonfungiblePositionManager.spec.ts +++ b/src/periphery/test/NonfungiblePositionManager.spec.ts @@ -86,13 +86,13 @@ describe('NonfungiblePositionManager', () => { ]); const code = await wallet.provider.getCode(expectedAddress); expect(code).to.eq('0x'); - await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1)); + await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1), '0x'); const codeAfter = await wallet.provider.getCode(expectedAddress); expect(codeAfter).to.not.eq('0x'); }); it('is payable', async () => { - await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1), { value: 1 }); + await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1), '0x', { value: 1 }); }); it('works if pool is created but not initialized', async () => { @@ -105,7 +105,7 @@ describe('NonfungiblePositionManager', () => { await factory.createPool(tokens[0], tokens[1], '0x'); const code = await wallet.provider.getCode(expectedAddress); expect(code).to.not.eq('0x'); - await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(2, 1)); + await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(2, 1), '0x'); }); it('works if pool is created and initialized', async () => { @@ -121,7 +121,7 @@ describe('NonfungiblePositionManager', () => { if (!wallet.provider) throw new Error('No provider'); const code = await wallet.provider.getCode(expectedAddress); expect(code).to.not.eq('0x'); - await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(4, 1)); + await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(4, 1), '0x'); }); it('could theoretically use eth via multicall', async () => { @@ -129,14 +129,14 @@ describe('NonfungiblePositionManager', () => { const createAndInitializePoolIfNecessaryData = nft.interface.encodeFunctionData( 'createAndInitializePoolIfNecessary', - [await token0.getAddress(), await token1.getAddress(), ZERO_ADDRESS, encodePriceSqrt(1, 1)] + [await token0.getAddress(), await token1.getAddress(), ZERO_ADDRESS, encodePriceSqrt(1, 1), '0x'] ); await nft.multicall([createAndInitializePoolIfNecessaryData], { value: expandTo18Decimals(1) }); }); it('gas [ @skip-on-coverage ]', async () => { - await snapshotGasCost(nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1))); + await snapshotGasCost(nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1), '0x')); }); }); @@ -160,7 +160,7 @@ describe('NonfungiblePositionManager', () => { }); it('fails if cannot transfer', async () => { - await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1)); + await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1), '0x'); await tokens[0].approve(nft, 0); await expect( nft.mint({ @@ -180,7 +180,7 @@ describe('NonfungiblePositionManager', () => { }); it('fails if deadline passed', async () => { - await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1)); + await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1), '0x'); await nft.setTime(2); await expect( nft.mint({ @@ -204,7 +204,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await nft.mint({ token0: tokens[0].getAddress(), @@ -253,7 +254,8 @@ describe('NonfungiblePositionManager', () => { await token0.getAddress(), await token1.getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1), + encodePriceSqrt(1, 1), + '0x' ]); const mintData = nft.interface.encodeFunctionData('mint', [ @@ -293,7 +295,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await snapshotGasCost( @@ -315,7 +318,7 @@ describe('NonfungiblePositionManager', () => { it('gas first mint for pool using eth with zero refund [ @skip-on-coverage ]', async () => { const [token0, token1] = await sortedTokens(wnative, tokens[0]); - await nft.createAndInitializePoolIfNecessary(token0, token1, ZERO_ADDRESS, encodePriceSqrt(1, 1)); + await nft.createAndInitializePoolIfNecessary(token0, token1, ZERO_ADDRESS, encodePriceSqrt(1, 1), '0x'); await snapshotGasCost( nft.multicall( @@ -344,7 +347,7 @@ describe('NonfungiblePositionManager', () => { it('gas first mint for pool using eth with non-zero refund [ @skip-on-coverage ]', async () => { const [token0, token1] = await sortedTokens(wnative, tokens[0]); - await nft.createAndInitializePoolIfNecessary(token0, token1, ZERO_ADDRESS, encodePriceSqrt(1, 1)); + await nft.createAndInitializePoolIfNecessary(token0, token1, ZERO_ADDRESS, encodePriceSqrt(1, 1), '0x'); await snapshotGasCost( nft.multicall( @@ -372,7 +375,7 @@ describe('NonfungiblePositionManager', () => { }); it('gas mint on same ticks [ @skip-on-coverage ]', async () => { - await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1)); + await nft.createAndInitializePoolIfNecessary(tokens[0], tokens[1], ZERO_ADDRESS, encodePriceSqrt(1, 1), '0x'); await nft.mint({ token0: await tokens[0].getAddress(), @@ -410,7 +413,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await nft.mint({ @@ -452,7 +456,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await nft.mint({ @@ -523,7 +528,7 @@ describe('NonfungiblePositionManager', () => { const tokenId = 1; - await nft.createAndInitializePoolIfNecessary(token0, token1, ZERO_ADDRESS, encodePriceSqrt(1, 1)); + await nft.createAndInitializePoolIfNecessary(token0, token1, ZERO_ADDRESS, encodePriceSqrt(1, 1), '0x'); const mintData = nft.interface.encodeFunctionData('mint', [ { @@ -577,7 +582,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await nft.mint({ @@ -701,7 +707,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await nft.mint({ @@ -849,7 +856,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await nft.mint({ @@ -930,7 +938,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await nft.mint({ @@ -986,7 +995,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await nft.mint({ @@ -1051,7 +1061,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await nft.mint({ @@ -1111,7 +1122,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await nft.mint({ @@ -1200,7 +1212,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await nft.mint({ @@ -1240,7 +1253,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); // nft 1 earns 25% of fees await nft.mint({ @@ -1297,7 +1311,6 @@ describe('NonfungiblePositionManager', () => { amount0Max: MaxUint128, amount1Max: MaxUint128, }); - console.log(nft1Amount0.toString(), nft1Amount1.toString(), nft2Amount0.toString(), nft2Amount1.toString()); expect(nft1Amount0).to.eq(416); expect(nft1Amount1).to.eq(0); expect(nft2Amount0).to.eq(1250); @@ -1343,7 +1356,8 @@ describe('NonfungiblePositionManager', () => { tokens[0].getAddress(), tokens[1].getAddress(), ZERO_ADDRESS, - encodePriceSqrt(1, 1) + encodePriceSqrt(1, 1), + '0x' ); await nft.mint({ diff --git a/src/periphery/test/__snapshots__/NonfungiblePositionManager.spec.ts.snap b/src/periphery/test/__snapshots__/NonfungiblePositionManager.spec.ts.snap index ff2e5228..447467e0 100644 --- a/src/periphery/test/__snapshots__/NonfungiblePositionManager.spec.ts.snap +++ b/src/periphery/test/__snapshots__/NonfungiblePositionManager.spec.ts.snap @@ -2,38 +2,38 @@ exports[`NonfungiblePositionManager #burn gas [ @skip-on-coverage ] 1`] = `62302`; -exports[`NonfungiblePositionManager #collect gas transfers both [ @skip-on-coverage ] 1`] = `125983`; +exports[`NonfungiblePositionManager #collect gas transfers both [ @skip-on-coverage ] 1`] = `126407`; -exports[`NonfungiblePositionManager #collect gas transfers token0 only [ @skip-on-coverage ] 1`] = `122321`; +exports[`NonfungiblePositionManager #collect gas transfers token0 only [ @skip-on-coverage ] 1`] = `122745`; -exports[`NonfungiblePositionManager #collect gas transfers token1 only [ @skip-on-coverage ] 1`] = `122512`; +exports[`NonfungiblePositionManager #collect gas transfers token1 only [ @skip-on-coverage ] 1`] = `122936`; -exports[`NonfungiblePositionManager #createAndInitializePoolIfNecessary gas [ @skip-on-coverage ] 1`] = `5277310`; +exports[`NonfungiblePositionManager #createAndInitializePoolIfNecessary gas [ @skip-on-coverage ] 1`] = `5231043`; -exports[`NonfungiblePositionManager #decreaseLiquidity gas complete decrease [ @skip-on-coverage ] 1`] = `171239`; +exports[`NonfungiblePositionManager #decreaseLiquidity gas complete decrease [ @skip-on-coverage ] 1`] = `171665`; -exports[`NonfungiblePositionManager #decreaseLiquidity gas partial decrease [ @skip-on-coverage ] 1`] = `176207`; +exports[`NonfungiblePositionManager #decreaseLiquidity gas partial decrease [ @skip-on-coverage ] 1`] = `176589`; -exports[`NonfungiblePositionManager #increaseLiquidity gas [ @skip-on-coverage ] 1`] = `182683`; +exports[`NonfungiblePositionManager #increaseLiquidity gas [ @skip-on-coverage ] 1`] = `184149`; -exports[`NonfungiblePositionManager #mint gas first mint for pool [ @skip-on-coverage ] 1`] = `635168`; +exports[`NonfungiblePositionManager #mint gas first mint for pool [ @skip-on-coverage ] 1`] = `636773`; -exports[`NonfungiblePositionManager #mint gas first mint for pool using eth with non-zero refund [ @skip-on-coverage ] 1`] = `649531`; +exports[`NonfungiblePositionManager #mint gas first mint for pool using eth with non-zero refund [ @skip-on-coverage ] 1`] = `651121`; -exports[`NonfungiblePositionManager #mint gas first mint for pool using eth with zero refund [ @skip-on-coverage ] 1`] = `642364`; +exports[`NonfungiblePositionManager #mint gas first mint for pool using eth with zero refund [ @skip-on-coverage ] 1`] = `643954`; -exports[`NonfungiblePositionManager #mint gas mint for same pool, different ticks [ @skip-on-coverage ] 1`] = `440868`; +exports[`NonfungiblePositionManager #mint gas mint for same pool, different ticks [ @skip-on-coverage ] 1`] = `442385`; -exports[`NonfungiblePositionManager #mint gas mint on same ticks [ @skip-on-coverage ] 1`] = `330678`; +exports[`NonfungiblePositionManager #mint gas mint on same ticks [ @skip-on-coverage ] 1`] = `332156`; -exports[`NonfungiblePositionManager #permit owned by eoa gas [ @skip-on-coverage ] 1`] = `60014`; +exports[`NonfungiblePositionManager #permit owned by eoa gas [ @skip-on-coverage ] 1`] = `60003`; -exports[`NonfungiblePositionManager #permit owned by verifying contract gas [ @skip-on-coverage ] 1`] = `63880`; +exports[`NonfungiblePositionManager #permit owned by verifying contract gas [ @skip-on-coverage ] 1`] = `63869`; exports[`NonfungiblePositionManager #transferFrom gas [ @skip-on-coverage ] 1`] = `86323`; exports[`NonfungiblePositionManager #transferFrom gas comes from approved [ @skip-on-coverage ] 1`] = `87247`; -exports[`NonfungiblePositionManager bytecode size [ @skip-on-coverage ] 1`] = `21901`; +exports[`NonfungiblePositionManager bytecode size [ @skip-on-coverage ] 1`] = `22015`; -exports[`NonfungiblePositionManager multicall exit gas [ @skip-on-coverage ] 1`] = `246963`; +exports[`NonfungiblePositionManager multicall exit gas [ @skip-on-coverage ] 1`] = `247432`;