diff --git a/_test/gs_test.gno b/_test/gs_test.gno index 7dd99713..a1fce6fb 100644 --- a/_test/gs_test.gno +++ b/_test/gs_test.gno @@ -74,16 +74,16 @@ func init() { // println(govAddr, "// gov") } -// 1. [POOL] Init +// 1. [TC - POOL] Init func TestPoolInitManual(t *testing.T) { std.TestSetOrigCaller(pc01) pl.InitManual() - shouldPanicWithMsg(t, func() { pl.InitManual() }, "[POOl] pool_manager.gno__InitManual() || contract must not be initialized") + shouldPanicWithMsg(t, func() { pl.InitManual() }, "[TC - POOl] pool_manager.gno__InitManual() || contract must not be initialized") } -// 2. [POOL] CreatePool +// 2. [TC - POOL] CreatePool func TestPoolCreatePool(t *testing.T) { std.TestSetOrigCaller(pc01) @@ -99,7 +99,7 @@ func TestPoolCreatePool(t *testing.T) { shouldEQ(t, tmpPool.GetTickSpacing(), bigint(10)) } -// 3. [POSITION] Mint LP +// 3. [TC - POSITION] Mint LP func TestPositionMint(t *testing.T) { tmpPool := pl.GetPool(pToken0, pToken1, pFee) @@ -171,7 +171,7 @@ func TestPositionMint(t *testing.T) { } } -// 4. [STAKER] CreateExternalIncentive +// 4. [TC - STAKER] CreateExternalIncentive // Internal incentive will automatcially created via init() func TestStakerCreateExternalIncentive(t *testing.T) { std.TestSetOrigCaller(ci01) @@ -190,11 +190,11 @@ func TestStakerCreateExternalIncentive(t *testing.T) { func() { stk.CreateExternalIncentive("bar_foo_500", "OBL", 10_000_000_000, GetTimestamp(), GetTimestamp()+(TIMESTAMP_30DAYS*2)) }, - "[STAKER] staker.gno__CreateExternalIncentive() || incentive(YmFyX2Zvb181MDBfT0JM) already exists", + "[TC - STAKER] staker.gno__CreateExternalIncentive() || incentive(YmFyX2Zvb181MDBfT0JM) already exists", ) } -// 5. [STAKER] StakeToken +// 5. [TC - STAKER] StakeToken func TestStakerStakeToken(t *testing.T) { // lp01 stakes tokenId '1' std.TestSetPrevAddr(lp01) // r3v4_xxx: only test code, we need to call gnft.Approve directly from user @@ -215,7 +215,7 @@ func TestStakerStakeToken(t *testing.T) { shouldEQ(t, gnft.OwnerOf(bigint(2)), stakerAddr) } -// 6. [POOL] SetFeeProtocol +// 6. [TC - POOL] SetFeeProtocol func TestPoolSetFeeProtocol(t *testing.T) { std.TestSetOrigCaller(pc01) @@ -226,7 +226,7 @@ func TestPoolSetFeeProtocol(t *testing.T) { shouldEQ(t, tmpPool.GetFeeProtocol(), bigint(134)) } -// 7. [POOL] Swap ( token0 -> token1 ) +// 7. [TC - POOL] Swap ( token0 -> token1 ) func TestPoolSwap01(t *testing.T) { tmpPool := pl.GetPool(pToken0, pToken1, pFee) testPrice01 := bigint(MIN_SQRT_RATIO + 1) @@ -283,7 +283,7 @@ func TestPoolSwap01(t *testing.T) { shouldEQ(t, token1Balance(pc01), cAmount1) } -// 8. [POSITION] Collect +// 8. [TC - POSITION] Collect // * collect fee from (swap token0 > token1) func TestPositionCollect01(t *testing.T) { { @@ -337,7 +337,7 @@ func TestPositionCollect01(t *testing.T) { } } -// 9. [POOL] Swap ( token1 -> token0 ) +// 9. [TC - POOL] Swap ( token1 -> token0 ) func TestPoolSwap10(t *testing.T) { tmpPool := pl.GetPool(pToken0, pToken1, pFee) testPrice10 := bigint(MAX_SQRT_RATIO - 1) @@ -393,7 +393,7 @@ func TestPoolSwap10(t *testing.T) { shouldEQ(t, token1Balance(pc01), cAmount1) } -// 10. [POSITION] Collect +// 10. [TC - POSITION] Collect // * collect fee from (swap token1 > token0) func TestPositionCollect10(t *testing.T) { { @@ -447,7 +447,7 @@ func TestPositionCollect10(t *testing.T) { } } -// 11. [STAKER] UnstakeToken +// 11. [TC - STAKER] UnstakeToken func TestStakerUnstakeToken(t *testing.T) { { // lp01 unstakes tokenId '1' @@ -478,7 +478,7 @@ func TestStakerUnstakeToken(t *testing.T) { } } -// 12. [STAKER] EndExternalIncentive +// 12. [TC - STAKER] EndExternalIncentive func TestStakerEndExternalIncentive(t *testing.T) { std.TestSetOrigCaller(ci01) std.TestSkipHeights(1036800) @@ -494,7 +494,7 @@ func TestStakerEndExternalIncentive(t *testing.T) { shouldPanicWithMsg( t, func() { stk.EndExternalIncentive("bar_foo_500", "OBL") }, - "[STAKER] staker.gno__EndIncentive() || cannot end non existent incentive(YmFyX2Zvb181MDBfT0JM)", + "[TC - STAKER] staker.gno__EndIncentive() || cannot end non existent incentive(YmFyX2Zvb181MDBfT0JM)", ) } @@ -513,7 +513,7 @@ func a2u(addr std.Address) users.AddressOrName { func tid(tokenId interface{}) grc721.TokenID { if tokenId == nil { - panic("[POSITION] test_helper.gno__tid() || tokenId is nil") + panic("[TC - POSITION] test_helper.gno__tid() || tokenId is nil") } switch tokenId.(type) { @@ -528,7 +528,7 @@ func tid(tokenId interface{}) grc721.TokenID { case grc721.TokenID: return tokenId.(grc721.TokenID) default: - panic("[STAKER] utils.gno__tid() || unsupported tokenId type") + panic("[TC - STAKER] utils.gno__tid() || unsupported tokenId type") } } diff --git a/_test/phase_v1.mk b/_test/phase_v1.mk index 95b02e6b..e2a9f277 100644 --- a/_test/phase_v1.mk +++ b/_test/phase_v1.mk @@ -116,7 +116,6 @@ approve-lp01: $(info ************ [APPROVE] foo & bar from lp01 to pool ************) @echo "" | gnokey maketx call -pkgpath gno.land/r/foo -func Approve -args $(ADDR_POOL) -args 50000000000 -insecure-password-stdin=true -remote $(GNOLAND_RPC_URL) -broadcast=true -chainid dev -gas-fee 1ugnot -gas-wanted 9000000 -memo "" lp01 > /dev/null @echo "" | gnokey maketx call -pkgpath gno.land/r/bar -func Approve -args $(ADDR_POOL) -args 50000000000 -insecure-password-stdin=true -remote $(GNOLAND_RPC_URL) -broadcast=true -chainid dev -gas-fee 1ugnot -gas-wanted 9000000 -memo "" lp01 > /dev/null - @echo @@ -124,7 +123,6 @@ approve-tr01: $(info ************ [APPROVE] foo & bar from tr01 to pool ************) @echo "" | gnokey maketx call -pkgpath gno.land/r/bar -func Approve -args $(ADDR_POOL) -args 50000000000 -insecure-password-stdin=true -remote $(GNOLAND_RPC_URL) -broadcast=true -chainid dev -gas-fee 1ugnot -gas-wanted 9000000 -memo "" tr01 > /dev/null @echo "" | gnokey maketx call -pkgpath gno.land/r/foo -func Approve -args $(ADDR_POOL) -args 50000000000 -insecure-password-stdin=true -remote $(GNOLAND_RPC_URL) -broadcast=true -chainid dev -gas-fee 1ugnot -gas-wanted 9000000 -memo "" tr01 > /dev/null - @echo diff --git a/pool/pool_multi_lp_fee_api_test.gno b/pool/pool_multi_lp_fee_api_test.gno index e3160475..aa3df056 100644 --- a/pool/pool_multi_lp_fee_api_test.gno +++ b/pool/pool_multi_lp_fee_api_test.gno @@ -107,9 +107,8 @@ func TestSwap(t *testing.T) { Swap(pToken0, pToken1, pFee, tr01, true, bigint(150000), test_price_01) jsonStr = gjson.Parse(ApiGetPool("bar_foo_500")) - jsonStr = gjson.Parse(ApiGetPool("bar_foo_500")) shouldEQ(t, jsonStr.Get("response.data.token0_balance").Int(), 3107550) - shouldEQ(t, jsonStr.Get("response.data.token1_balance").Int(), 8448096) + shouldEQ(t, jsonStr.Get("response.data.token1_balance").Int(), 7635058) shouldEQ(t, jsonStr.Get("response.data.liquidity").Int(), 100000000) shouldEQ(t, len(jsonStr.Get("response.data.positions").Array()), 1) @@ -117,8 +116,8 @@ func TestSwap(t *testing.T) { // Swap(pToken0, pToken1, pFee, tr01, true, bigint(1500000), test_price_01) // two iteration // s0: 1_500_000 // s1: -3_626_984 // currentTick: 7668 std.TestSkipHeights(1) jsonStr = gjson.Parse(ApiGetPool("bar_foo_500")) - shouldEQ(t, jsonStr.Get("response.data.token0_balance").Int(), 4718682) - shouldEQ(t, jsonStr.Get("response.data.token1_balance").Int(), 9049947) + shouldEQ(t, jsonStr.Get("response.data.token0_balance").Int(), 1496418) + shouldEQ(t, jsonStr.Get("response.data.token1_balance").Int(), 8236909) shouldEQ(t, jsonStr.Get("response.data.liquidity").Int(), 100000000) shouldEQ(t, len(jsonStr.Get("response.data.positions").Array()), 1) @@ -132,8 +131,8 @@ func TestSwap(t *testing.T) { Collect(pToken0, pToken1, pFee, lp01, test_tickLower, test_tickUpper, 100000000, 100000000) std.TestSkipHeights(1) jsonStr = gjson.Parse(ApiGetPool("bar_foo_500")) - shouldEQ(t, jsonStr.Get("response.data.token0_balance").Int(), 4718608) - shouldEQ(t, jsonStr.Get("response.data.token1_balance").Int(), 9049647) + shouldEQ(t, jsonStr.Get("response.data.token0_balance").Int(), 1496344) + shouldEQ(t, jsonStr.Get("response.data.token1_balance").Int(), 8236609) shouldEQ(t, jsonStr.Get("response.data.liquidity").Int(), 100000000) shouldEQ(t, len(jsonStr.Get("response.data.positions").Array()), 1) } diff --git a/pool/tick_bitmap.gno b/pool/tick_bitmap.gno index 463a40bd..2530d7d3 100644 --- a/pool/tick_bitmap.gno +++ b/pool/tick_bitmap.gno @@ -15,7 +15,7 @@ func (pool *Pool) tickBitmapFlipTick( tick int32, tickSpacing int32, ) { - require(tick%tickSpacing == 0, ufmt.Sprintf("[POOL] tick_bitmap.gno__tickBitmapFlipTick() || tick MOD tickSpacing(%s) != 0", tick%tickSpacing)) + require(tick%tickSpacing == 0, ufmt.Sprintf("[POOL] tick_bitmap.gno__tickBitmapFlipTick() || tick MOD tickSpacing(%d) != 0", tick%tickSpacing)) wordPos, bitPos := tickBitmapPosition(tick) mask := bigint(1) << uint64(bitPos) requireUnsigned(mask, ufmt.Sprintf("[POOL] tick_bitmap.gno__tickBitmapFlipTick() || mask(%s) > 0", mask)) diff --git a/position/consts.gno b/position/consts.gno index ed0bee79..2e9f85a4 100644 --- a/position/consts.gno +++ b/position/consts.gno @@ -14,4 +14,6 @@ const ( // ETC Q96 bigint = 79228162514264337593543950336 // 2 ** 96 Q128 bigint = 340282366920938463463374607431768211456 // 2 ** 128 + + MAX_UINT160 bigint = 1461501637330902918203684832716283019655932542975 ) diff --git a/position/math_logic.gno b/position/math_logic.gno new file mode 100644 index 00000000..8fc2753a --- /dev/null +++ b/position/math_logic.gno @@ -0,0 +1,54 @@ +package position + +import ( + p "gno.land/r/pool" +) + +func DryMint( + tickCurrent int32, + tickLower int32, + tickUpper int32, + amount0Desired bigint, + amount1Desired bigint, +) (amount0, amount1 bigint) { + sqrtRatioX96 := p.TickMathGetSqrtRatioAtTick(tickCurrent) + sqrtLowerX96 := p.TickMathGetSqrtRatioAtTick(tickLower) + sqrtUpperX96 := p.TickMathGetSqrtRatioAtTick(tickUpper) + + liquidity := liquidityAmountsGetLiquidityForAmounts( + sqrtRatioX96, + sqrtLowerX96, + sqrtUpperX96, + amount0Desired, + amount1Desired, + ) + + if liquidity != 0 { + if tickCurrent < tickLower { + amount0 = sqrtPriceMathGetAmount0Delta( + sqrtLowerX96, + sqrtUpperX96, + liquidity, + ) + } else if tickCurrent < tickUpper { + amount0 = sqrtPriceMathGetAmount0Delta( + sqrtRatioX96, + sqrtUpperX96, + liquidity, + ) + + amount1 = sqrtPriceMathGetAmount1Delta( + sqrtLowerX96, + sqrtRatioX96, + liquidity, + ) + } else { + amount1 = sqrtPriceMathGetAmount1Delta( + sqrtLowerX96, + sqrtUpperX96, + liquidity, + ) + } + } + return +} diff --git a/position/math_logic_test.gno b/position/math_logic_test.gno new file mode 100644 index 00000000..be64d718 --- /dev/null +++ b/position/math_logic_test.gno @@ -0,0 +1,44 @@ +package position + +import ( + "testing" +) + +func TestDryMintInRange(t *testing.T) { + m0, m1 := DryMint( + 10000, // tickCurrent int32 + 7000, // tickLower int32 + 15000, // tickUpper int32 + 10000, // amount0Desired bigint + 16000, // amount1Desired bigint + ) + + shouldEQ(t, m0, bigint(9347)) + shouldEQ(t, m1, bigint(15999)) +} + +func TestDryMintLowerRange(t *testing.T) { + m0, m1 := DryMint( + 7000, // tickCurrent int32 + 5000, // tickLower int32 + 6000, // tickUpper int32 + 10000, // amount0Desired bigint + 16000, // amount1Desired bigint + ) + + shouldEQ(t, m0, bigint(0)) + shouldEQ(t, m1, bigint(15999)) +} + +func TestDryMintUpperRange(t *testing.T) { + m0, m1 := DryMint( + 7000, // tickCurrent int32 + 9000, // tickLower int32 + 11000, // tickUpper int32 + 10000, // amount0Desired bigint + 16000, // amount1Desired bigint + ) + + shouldEQ(t, m0, bigint(9999)) + shouldEQ(t, m1, bigint(0)) +} diff --git a/position/sqrt_price_math.gno b/position/sqrt_price_math.gno new file mode 100644 index 00000000..3d6ed788 --- /dev/null +++ b/position/sqrt_price_math.gno @@ -0,0 +1,192 @@ +package position + +import "gno.land/p/demo/ufmt" + +func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( + sqrtPX96 bigint, + liquidity bigint, + amount bigint, + add bool, +) bigint { + requireUnsigned(sqrtPX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || sqrtPX96(%s) >= 0", sqrtPX96)) + requireUnsigned(liquidity, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || liquidity(%s) >= 0", liquidity)) + requireUnsigned(amount, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || amount(%s) >= 0", amount)) + if amount == 0 { + return sqrtPX96 + } + + numerator1 := liquidity << 96 + requireUnsigned(numerator1, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || numerator1(%s) >= 0", numerator1)) + + product := amount * sqrtPX96 + requireUnsigned(product, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || product(%s) >= 0", product)) + + var denominator bigint + + if add { + if product/amount == sqrtPX96 { + denominator = numerator1 + product + requireUnsigned(denominator, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || denominator(%s) >= 0", denominator)) + + if denominator >= numerator1 { + requireUnsigned(numerator1*sqrtPX96/denominator, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || numerator1 * sqrtPX96 / denominator(%s) >= 0", numerator1*sqrtPX96/denominator)) + return numerator1 * sqrtPX96 / denominator + } + } + + requireUnsigned(numerator1/((numerator1/sqrtPX96)+amount), ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || numerator1 / ( (numerator1 / sqrtPX96) + amount(%s) >= 0", (numerator1/((numerator1/sqrtPX96)+amount)))) + return numerator1 / ((numerator1 / sqrtPX96) + amount) + } + require(product/amount == sqrtPX96 && numerator1 > product, "[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || condition must return true") + + denominator = numerator1 - product + requireUnsigned(denominator, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || denominator(%s) >= 0", denominator)) + + requireUnsigned(numerator1*sqrtPX96/denominator, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || numerator1 * sqrtPX96 / denominator(%s) >= 0", numerator1*sqrtPX96/denominator)) + return numerator1 * sqrtPX96 / denominator +} + +func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown( + sqrtPX96 bigint, + liquidity bigint, + amount bigint, + add bool, +) bigint { + requireUnsigned(sqrtPX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown() || sqrtPX96(%s) >= 0", sqrtPX96)) + requireUnsigned(liquidity, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown() || liquidity(%s) >= 0", liquidity)) + requireUnsigned(amount, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown() || amount(%s) >= 0", amount)) + + var quotient bigint + if add { + if amount <= MAX_UINT160 { + quotient = (amount << 96) / liquidity + } else { + quotient = amount * Q96 / liquidity + } + requireUnsigned(quotient, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown() || quotient(%s) >= 0", quotient)) + return sqrtPX96 + quotient + } else { + if amount <= MAX_UINT160 { + quotient = (amount << 96) / liquidity + } else { + quotient = amount * Q96 / liquidity + } + requireUnsigned(quotient, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown() || quotient(%s) >= 0", quotient)) + + require(sqrtPX96 > quotient, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown() || sqrtPX96(%s) must be greater than quotient(%s)", sqrtPX96, quotient)) + return sqrtPX96 - quotient + } +} + +func sqrtPriceMathGetNextSqrtPriceFromInput( + sqrtPX96 bigint, + liquidity bigint, + amountIn bigint, + zeroForOne bool, +) (sqrtQ bigint) { + requireUnsigned(sqrtPX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromInput() || sqrtPX96(%s) >= 0", sqrtPX96)) + requireUnsigned(liquidity, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromInput() || liquidity(%s) >= 0", liquidity)) + requireUnsigned(amountIn, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromInput() || amountIn(%s) >= 0", amountIn)) + + if zeroForOne { + requireUnsigned(sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true), "[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromInput() || condition must return `v` >= 0__#1") + return sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true) + } + + requireUnsigned(sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true), "[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromInput() || condition must return `v` >= 0__#2") + return sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true) +} + +func sqrtPriceMathGetNextSqrtPriceFromOutput( + sqrtPX96 bigint, + liquidity bigint, + amountOut bigint, + zeroForOne bool, +) (sqrtQ bigint) { + requireUnsigned(sqrtPX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromOutput() || sqrtPX96(%s) >= 0", sqrtPX96)) + requireUnsigned(liquidity, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromOutput() || liquidity(%s) >= 0", liquidity)) + + if zeroForOne { + requireUnsigned(sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false), "[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromOutput() || condition must return `v` >= 0__#1") + return sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) + } + + requireUnsigned(sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false), "[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromOutput() || condition must return `v` >= 0__#2") + return sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false) +} + +func sqrtPriceMathGetAmount0DeltaHelper( + sqrtRatioAX96 bigint, + sqrtRatioBX96 bigint, + liquidity bigint, +) bigint { + requireUnsigned(sqrtRatioAX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount0DeltaHelper() || sqrtRatioAX96(%s) >= 0", sqrtRatioAX96)) + requireUnsigned(sqrtRatioBX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount0DeltaHelper() || sqrtRatioBX96(%s) >= 0", sqrtRatioBX96)) + requireUnsigned(liquidity, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount0DeltaHelper() || liquidity(%s) >= 0", liquidity)) + + if sqrtRatioAX96 > sqrtRatioBX96 { + sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96 + } + requireUnsigned(sqrtRatioAX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount0DeltaHelper() || sqrtRatioAX96(%s) >= 0", sqrtRatioAX96)) + + numerator1 := liquidity << 96 + requireUnsigned(numerator1, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount0DeltaHelper() || numerator1(%s) >= 0", numerator1)) + + numerator2 := sqrtRatioBX96 - sqrtRatioAX96 + requireUnsigned(numerator2, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount0DeltaHelper() || numerator2(%s) >= 0", numerator2)) + + requireUnsigned((numerator1*numerator2/sqrtRatioBX96)/sqrtRatioAX96, "[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount0DeltaHelper() || condition must return `v` >= 0") + return (numerator1 * numerator2 / sqrtRatioBX96) / sqrtRatioAX96 +} + +func sqrtPriceMathGetAmount1DeltaHelper( + sqrtRatioAX96 bigint, + sqrtRatioBX96 bigint, + liquidity bigint, +) bigint { + requireUnsigned(sqrtRatioAX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount1DeltaHelper() || sqrtRatioAX96(%s) >= 0", sqrtRatioAX96)) + requireUnsigned(sqrtRatioBX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount1DeltaHelper() || sqrtRatioBX96(%s) >= 0", sqrtRatioBX96)) + requireUnsigned(liquidity, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount1DeltaHelper() || liquidity(%s) >= 0", liquidity)) + + if sqrtRatioAX96 > sqrtRatioBX96 { + sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96 + } + + return liquidity * (sqrtRatioBX96 - sqrtRatioAX96) / Q96 +} + +func sqrtPriceMathGetAmount0Delta( + sqrtRatioAX96 bigint, + sqrtRatioBX96 bigint, + liquidity bigint, +) bigint { + requireUnsigned(sqrtRatioAX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount0Delta() || sqrtRatioAX96(%s) >= 0", sqrtRatioAX96)) + requireUnsigned(sqrtRatioBX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount0Delta() || sqrtRatioBX96(%s) >= 0", sqrtRatioBX96)) + + if liquidity < 0 { + return -sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, -liquidity) + } + + return sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity) +} + +func sqrtPriceMathGetAmount1Delta( + sqrtRatioAX96 bigint, + sqrtRatioBX96 bigint, + liquidity bigint, +) bigint { + requireUnsigned(sqrtRatioAX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount1Delta() || sqrtRatioAX96(%s) >= 0", sqrtRatioAX96)) + requireUnsigned(sqrtRatioBX96, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount1Delta() || sqrtRatioBX96(%s) >= 0", sqrtRatioBX96)) + + if liquidity < 0 { + return -sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, -liquidity) + } + + return sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity) +} + +func requireUnsigned(x bigint, msg string) { + if x < 0 { + panic(msg) + } +}