From 74d1f55a1f80910a0a6897e4497faa1790247ed6 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Wed, 6 Mar 2024 21:21:51 +0900 Subject: [PATCH 1/4] feat: uint256, int256 instead of bigint --- .../_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno | 10 +- ...EST_scenario_01_full_happy_case_test.gnoa} | 190 +-- ...cenario_02_FAIL_too_small_amount_test.gnoa | 48 +- ...ario_03_FAIL_too_small_liquidity_test.gnoa | 48 +- ...ario_04_router_one_route_one_hop_test.gnoa | 122 +- ...ario_05_router_one_route_two_hop_test.gnoa | 106 +- ...uter_one_route_three_hop_println_test.gnoa | 64 +- ...e_three_hop_large_amount_println_test.gnoa | 64 +- ...sition_one_route_one_hop_println_test.gnoa | 40 +- ...uter_only_upper_position_println_test.gnoa | 54 +- ...scenario_99_router_uniswap_sdk_test.gnoXXX | 244 +++ ...T_scenario_99_router_uniswap_sdk_test.gnoa | 245 ---- common/tick_math.gno | 199 --- consts/consts.gno | 31 +- packages/big/int256/gno.mod | 1 + packages/big/int256/int256.gno | 557 +++++++ packages/big/int256/int256_test.gno | 1 + packages/big/uint256/bits.gno | 599 ++++++++ packages/big/uint256/bits_errors.gno | 17 + packages/big/uint256/bits_table.gno | 79 + packages/big/uint256/gno.mod | 1 + packages/big/uint256/mod.gno | 629 ++++++++ packages/big/uint256/strconv.gno | 203 +++ packages/big/uint256/uint256.gno | 1302 +++++++++++++++++ packages/big/uint256/uint256_test.gno | 18 + packages/big/uint512/uint512.gno | 131 ++ packages/big/uint512/uint512_test.gno | 37 + .../common}/_TEST_tick_math_test.gno | 0 .../common}/liquidity_amounts.gno | 41 +- packages/common/tick_math.gno | 209 +++ pool/TEST_liquidity_math_test.gnoa | 53 - pool/_GET_no_receiver.gno | 131 +- pool/_GET_no_receiver_string.gno | 170 +++ pool/_GET_receiver.gno | 79 +- pool/_RPC_api.gno | 74 +- pool/_RPC_dry.gno | 123 +- .../_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno | 8 +- pool/_TEST_get_test.gno | 232 --- pool/_TEST_pool_dryswap_and_swap_test.gno | 59 +- pool/_TEST_pool_multi_token_test.gno_OK | 327 ----- pool/_TEST_pool_native_swap_test.gn_OK | 27 +- pool/_TEST_pool_single_lp_test.gno | 471 ++++++ pool/_TEST_pool_single_lp_test.gno_OK | 287 ++-- pool/bit_math.gno | 53 +- pool/liquidity_math.gno | 25 +- pool/pool.gno | 603 +++----- pool/pool_manager.gno | 35 +- pool/position.gno | 50 +- pool/position_modify.gno | 25 +- pool/position_update.gno | 13 +- pool/sqrt_price_math.gno | 212 +-- pool/swap_math.gno | 44 +- pool/tick.gno | 126 +- pool/tick_bitmap.gno | 71 +- pool/token_register.gno | 12 + pool/type.gno | 69 +- pool/utils.gno | 23 +- pool/withdrawal_fee.gno | 39 +- position/_GET_no_receiver.gno.gno | 14 +- position/_GET_no_receiver_string.gno | 26 + position/_RPC_api.gno | 71 +- position/_RPC_dry.gno | 43 +- position/_TEST_0_INIT_TOKEN_REGISTER_test.gno | 16 +- .../_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno | 8 +- ..._test.gno => _TEST_position_api_test.gnoa} | 22 +- ..._TEST_position_increase_decrease_test.gnoa | 96 +- ...tion_test.gnoa => _TEST_position_test.gno} | 69 +- ...st_two_position_used_single_swap_test.gnoa | 55 +- position/liquidity_management.gno | 47 +- position/position.gno | 269 +++- position/sqrt_price_math.gno | 237 ++- position/test_helper.gno | 2 - position/type.gno | 56 +- position/{util.gno => utils.gno} | 13 +- router/_RPC_api.gno | 49 +- .../_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno | 8 +- ...swap_route_1route_1hop_out_range_test.gnoa | 36 +- ...EST_router_swap_route_1route_1hop_test.gno | 178 +++ ...ST_router_swap_route_1route_1hop_test.gnoa | 172 --- ..._route_1route_2hop_native_in_out_test.gnoa | 40 +- ..._route_1route_3hop_native_middle_test.gnoa | 28 +- ...T_router_swap_route_2route_2hop_test.gnoa} | 102 +- router/_TEST_routes_find_swap_path_test.gnoa | 42 +- router/comptue_routes.gno | 7 +- router/router.gno | 66 +- router/router_dry.gno | 60 +- router/swap_inner.gno | 96 +- router/swap_multi.gno | 43 +- router/swap_single.gno | 14 +- router/type.gno | 16 +- router/{util.gno => utils.gno} | 45 +- staker/_GET_no_receiver.gno | 39 +- staker/_RPC_api_stake.gno | 17 +- .../_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno | 8 +- ... => _TEST_staker_collect_reward_test.gnoa} | 66 +- staker/_TEST_staker_get_test.gnoa | 54 +- ...> _TEST_staker_internal_external_test.gno} | 97 +- ..._TEST_staker_one_external_native_test.gnoa | 62 +- staker/_TEST_staker_one_external_test.gnoa | 62 +- ...EST_staker_one_increase_external_test.gnoa | 64 +- staker/_TEST_staker_rpc_get_test.gnoa | 67 +- staker/reward_fee.gno | 21 +- staker/reward_math.gno | 127 +- staker/staker.gno | 116 +- staker/type.gno | 4 +- staker/utils.gno | 2 - 106 files changed, 7741 insertions(+), 3842 deletions(-) rename _test/{_TEST_scenario_01_full_happy_case_test.gno => _TEST_scenario_01_full_happy_case_test.gnoa} (79%) create mode 100644 _test/_TEST_scenario_99_router_uniswap_sdk_test.gnoXXX delete mode 100644 _test/_TEST_scenario_99_router_uniswap_sdk_test.gnoa delete mode 100644 common/tick_math.gno create mode 100644 packages/big/int256/gno.mod create mode 100644 packages/big/int256/int256.gno create mode 100644 packages/big/int256/int256_test.gno create mode 100644 packages/big/uint256/bits.gno create mode 100644 packages/big/uint256/bits_errors.gno create mode 100644 packages/big/uint256/bits_table.gno create mode 100644 packages/big/uint256/gno.mod create mode 100644 packages/big/uint256/mod.gno create mode 100644 packages/big/uint256/strconv.gno create mode 100644 packages/big/uint256/uint256.gno create mode 100644 packages/big/uint256/uint256_test.gno create mode 100644 packages/big/uint512/uint512.gno create mode 100644 packages/big/uint512/uint512_test.gno rename {common => packages/common}/_TEST_tick_math_test.gno (100%) rename {common => packages/common}/liquidity_amounts.gno (82%) create mode 100644 packages/common/tick_math.gno delete mode 100644 pool/TEST_liquidity_math_test.gnoa create mode 100644 pool/_GET_no_receiver_string.gno delete mode 100644 pool/_TEST_get_test.gno create mode 100644 pool/_TEST_pool_single_lp_test.gno create mode 100644 position/_GET_no_receiver_string.gno rename position/{_TEST_position_api_test.gno => _TEST_position_api_test.gnoa} (63%) rename position/{_TEST_position_test.gnoa => _TEST_position_test.gno} (72%) rename position/{util.gno => utils.gno} (51%) create mode 100644 router/_TEST_router_swap_route_1route_1hop_test.gno delete mode 100644 router/_TEST_router_swap_route_1route_1hop_test.gnoa rename router/{_TEST_router_swap_route_2route_2hop_test.gno => _TEST_router_swap_route_2route_2hop_test.gnoa} (64%) rename router/{util.gno => utils.gno} (57%) rename staker/{_TEST_staker_collect_reward_test.gno => _TEST_staker_collect_reward_test.gnoa} (73%) rename staker/{_TEST_staker_internal_external_test.gnoa => _TEST_staker_internal_external_test.gno} (73%) diff --git a/_test/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno b/_test/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno index 5916cb0d..5ab54c57 100644 --- a/_test/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno +++ b/_test/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno @@ -25,11 +25,11 @@ var ( // wugnotPath string = "gno.land/r/demo/wugnot" // from consts // gnsPath string = "gno.land/r/demo/gns" // from consts - fee100 uint16 = 100 - fee500 uint16 = 500 - fee3000 uint16 = 3000 + fee100 uint32 = 100 + fee500 uint32 = 500 + fee3000 uint32 = 3000 - max_timeout bigint = 9999999999 + max_timeout int64 = 9999999999 ) /* UTIL */ @@ -54,8 +54,6 @@ func tid(tokenId interface{}) grc721.TokenID { } switch tokenId.(type) { - case bigint: - return grc721.TokenID(string(tokenId.(bigint))) case string: return grc721.TokenID(tokenId.(string)) case int: diff --git a/_test/_TEST_scenario_01_full_happy_case_test.gno b/_test/_TEST_scenario_01_full_happy_case_test.gnoa similarity index 79% rename from _test/_TEST_scenario_01_full_happy_case_test.gno rename to _test/_TEST_scenario_01_full_happy_case_test.gnoa index 41411864..869a5eef 100644 --- a/_test/_TEST_scenario_01_full_happy_case_test.gno +++ b/_test/_TEST_scenario_01_full_happy_case_test.gnoa @@ -43,16 +43,16 @@ func TestPoolCreatePools(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*4) // bar-baz - pl.CreatePool(barPath, bazPath, 100, common.TickMathGetSqrtRatioAtTick(29960)) // 1:20 + pl.CreatePool(barPath, bazPath, 100, common.TickMathGetSqrtRatioAtTick(29960).ToString()) // 1:20 // baz-foo - pl.CreatePool(bazPath, fooPath, 100, common.TickMathGetSqrtRatioAtTick(-23030)) // 1:0.1 + pl.CreatePool(bazPath, fooPath, 100, common.TickMathGetSqrtRatioAtTick(-23030).ToString()) // 1:0.1 // foo-wugnot - pl.CreatePool(fooPath, consts.WRAPPED_WUGNOT, 100, common.TickMathGetSqrtRatioAtTick(-29960)) // 1:0.05 + pl.CreatePool(fooPath, consts.WRAPPED_WUGNOT, 100, common.TickMathGetSqrtRatioAtTick(-29960).ToString()) // 1:0.05 // gns-wugnot - pl.CreatePool(consts.GNS_PATH, consts.WRAPPED_WUGNOT, 500, common.TickMathGetSqrtRatioAtTick(0)) // 1:1 + pl.CreatePool(consts.GNS_PATH, consts.WRAPPED_WUGNOT, 500, common.TickMathGetSqrtRatioAtTick(0).ToString()) // 1:1 std.TestSkipHeights(5) } @@ -94,17 +94,17 @@ func TestPositionMintBarBazInRange(t *testing.T) { 100, // fee 29950, // tickLower 29970, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(1)) - shouldEQ(t, liquidity, bigint(4473213900)) - shouldEQ(t, amount0, bigint(499941)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 1) + shouldEQ(t, liquidity, "4473213900") + shouldEQ(t, amount0, "499941") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) } @@ -123,17 +123,17 @@ func TestPositionMintBarBazLowerRange(t *testing.T) { 100, // fee 29900, // tickLower 29910, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(2)) - shouldEQ(t, liquidity, bigint(4484410364)) - shouldEQ(t, amount0, bigint(0)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 2) + shouldEQ(t, liquidity, "4484410364") + shouldEQ(t, amount0, "0") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) } @@ -152,17 +152,17 @@ func TestPositionMintBarBazUpperRange(t *testing.T) { 100, // fee 30000, // tickLower 32000, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(3)) - shouldEQ(t, liquidity, bigint(470937834)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(0)) + shouldEQ(t, tokenId, 3) + shouldEQ(t, liquidity, "470937834") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "0") std.TestSkipHeights(3) } @@ -180,17 +180,17 @@ func TestPositionMintBazFooInRange(t *testing.T) { 100, // fee -23050, // tickLower -23010, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(4)) - shouldEQ(t, liquidity, bigint(3163542978)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(999700)) + shouldEQ(t, tokenId, 4) + shouldEQ(t, liquidity, "3163542978") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "999700") std.TestSkipHeights(3) } @@ -217,17 +217,17 @@ func TestPositionMintFooGnotInRange(t *testing.T) { 100, // fee -30960, // tickLower -28960, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(5)) - shouldEQ(t, liquidity, bigint(45848241)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(499941)) + shouldEQ(t, tokenId, 5) + shouldEQ(t, liquidity, "45848241") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "499941") std.TestSkipHeights(4) } @@ -255,17 +255,17 @@ func TestPositionMintGnsGnotInRange(t *testing.T) { 500, // fee -1000, // tickLower 1000, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(6)) - shouldEQ(t, liquidity, bigint(205051662)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 6) + shouldEQ(t, liquidity, "205051662") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(4) } @@ -280,7 +280,7 @@ func TestStakerCreateExternalIncentive(t *testing.T) { sr.CreateExternalIncentive( "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // targetPoolPath oblPath, // rewardTokenPath - 100_000_000, // rewardAmount + "100000000", // rewardAmount 1234568045, // startTimestamp 1234568045+7776000, // endTimestamp ( 90 days ) ) @@ -312,7 +312,7 @@ func TestStakerStakeTokenForExternalReward(t *testing.T) { func TestApproveGNS(t *testing.T) { std.TestSetOrigCaller(consts.INTERNAL_REWARD_ACCOUNT) - gns.Approve(a2u(consts.STAKER_ADDR), uint64(consts.MAX_UINT64)) // internal reward distribution + gns.Approve(a2u(consts.STAKER_ADDR), consts.UINT64_MAX) // internal reward distribution std.TestSkipHeights(1) } @@ -324,7 +324,7 @@ func TestStakerCollectInternalReward(t *testing.T) { sr.CollectReward(6) - shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90003268) + shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90163351) shouldEQ(t, obl.BalanceOf(a2u(lp01)), 0) std.TestSkipHeights(1) @@ -333,12 +333,12 @@ func TestStakerCollectInternalReward(t *testing.T) { func TestStakerCollectExternalReward(t *testing.T) { std.TestSetOrigCaller(lp01) - shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90003268) + shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90163351) shouldEQ(t, obl.BalanceOf(a2u(lp01)), 0) sr.CollectReward(1) - shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90003268) + shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90163351) shouldEQ(t, obl.BalanceOf(a2u(lp01)), 21) std.TestSkipHeights(1) @@ -371,12 +371,12 @@ func TestRouterDrySwapRouteBarBazExactIn(t *testing.T) { dryResult := rr.DrySwapRoute( barPath, // inputToken bazPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, bigint(1999835)) + shouldEQ(t, dryResult, "1999835") std.TestSkipHeights(1) } @@ -394,13 +394,13 @@ func TestRouterSwapRouteBarBazExactIn(t *testing.T) { swapResult := rr.SwapRoute( barPath, // inputToken bazPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr "100", // quoteArr - 1, // tokenAmountLimit + "1", // tokenAmountLimit ) - shouldEQ(t, swapResult, bigint(1996836)) + shouldEQ(t, swapResult, "1996836") shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99900000) shouldEQ(t, baz.BalanceOf(a2u(tr01)), 101996836) @@ -413,7 +413,7 @@ func TestRouterSwapRouteBarBazExactOut(t *testing.T) { // approve bar to pool bar.Approve(a2u(consts.POOL_ADDR), 100000) - baz.Approve(a2u(consts.ROUTER_ADDR), uint64(consts.MAX_UINT64)) + baz.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99900000) shouldEQ(t, baz.BalanceOf(a2u(tr01)), 101996836) @@ -421,13 +421,13 @@ func TestRouterSwapRouteBarBazExactOut(t *testing.T) { swapResult := rr.SwapRoute( barPath, // inputToken bazPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr - "100", // quoteArr - 100000, // tokenAmountLimit + "100", // quoteArr + "100000", // tokenAmountLimit ) - shouldEQ(t, swapResult, bigint(5000)) + shouldEQ(t, swapResult, "5000") shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99895000) shouldEQ(t, baz.BalanceOf(a2u(tr01)), 102096686) @@ -440,7 +440,7 @@ func TestRouterSwapRouteBarBazFooWgnotExactIn(t *testing.T) { // approve bar to pool bar.Approve(a2u(consts.POOL_ADDR), 100000) - wugnot.Approve(a2u(consts.ROUTER_ADDR), uint64(consts.MAX_UINT64)) + wugnot.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99895000) shouldEQ(t, wugnot.BalanceOf(a2u(tr01)), 0) @@ -448,13 +448,13 @@ func TestRouterSwapRouteBarBazFooWgnotExactIn(t *testing.T) { swapResult := rr.SwapRoute( barPath, // inputToken consts.WRAPPED_WUGNOT, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100*POOL*gno.land/r/demo/foo:gno.land/r/demo/wugnot:100", // strRouteArr "100", // quoteArr - 1, // tokenAmountLimit + "1", // tokenAmountLimit ) - shouldEQ(t, swapResult, bigint(9965)) + shouldEQ(t, swapResult, "9965") shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99795000) shouldEQ(t, wugnot.BalanceOf(a2u(tr01)), 9965) @@ -476,7 +476,7 @@ func TestRouterSwapRouteWgnotFooBazBarExactIn(t *testing.T) { // approve wugnot to pool wugnot.Approve(a2u(consts.POOL_ADDR), 100000) - bar.Approve(a2u(consts.ROUTER_ADDR), uint64(consts.MAX_UINT64)) + bar.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) shouldEQ(t, wugnot.BalanceOf(a2u(tr01)), 109965) shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99795000) @@ -484,13 +484,13 @@ func TestRouterSwapRouteWgnotFooBazBarExactIn(t *testing.T) { swapResult := rr.SwapRoute( consts.WRAPPED_WUGNOT, // inputToken barPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_OUT", // swapType "gno.land/r/demo/wugnot:gno.land/r/demo/foo:100*POOL*gno.land/r/demo/foo:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:100", // strRouteArr - "100", // quoteArr - 300000, // tokenAmountLimit + "100", // quoteArr + "300000", // tokenAmountLimit ) - shouldEQ(t, swapResult, bigint(9958)) + shouldEQ(t, swapResult, "9958") shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99894789) shouldEQ(t, wugnot.BalanceOf(a2u(tr01)), 100007) @@ -501,10 +501,12 @@ func TestRouterSwapRouteWgnotFooBazBarExactIn(t *testing.T) { func TestPositionCollectFeeLpTokenId_1(t *testing.T) { std.TestSetOrigCaller(lp01) + baz.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) // to collect protocol fee + tokenId, amount0, amount1, poolPath := pn.CollectFee(1) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, amount0, bigint(19)) - shouldEQ(t, amount1, bigint(198)) + shouldEQ(t, amount0, "19") + shouldEQ(t, amount1, "198") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/baz:100") std.TestSkipHeights(1) @@ -515,10 +517,12 @@ func TestPositionCollectFeeLpTokenId_1(t *testing.T) { func TestPositionCollectFeeLpTokenId_4(t *testing.T) { std.TestSetOrigCaller(lp01) + foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) // to collect protocol fee + tokenId, amount0, amount1, poolPath := pn.CollectFee(4) shouldEQ(t, tokenId, uint64(4)) - shouldEQ(t, amount0, bigint(198)) - shouldEQ(t, amount1, bigint(20)) + shouldEQ(t, amount0, "198") + shouldEQ(t, amount1, "20") shouldEQ(t, poolPath, "gno.land/r/demo/baz:gno.land/r/demo/foo:100") std.TestSkipHeights(1) @@ -529,8 +533,8 @@ func TestPositionCollectFeeLpTokenId_5(t *testing.T) { tokenId, amount0, amount1, poolPath := pn.CollectFee(5) shouldEQ(t, tokenId, uint64(5)) - shouldEQ(t, amount0, bigint(19)) - shouldEQ(t, amount1, bigint(0)) + shouldEQ(t, amount0, "19") + shouldEQ(t, amount1, "0") shouldEQ(t, poolPath, "gno.land/r/demo/foo:gno.land/r/demo/wugnot:100") std.TestSkipHeights(1) @@ -540,10 +544,10 @@ func TestPositionDecreaseLiquidityStakedPosition(t *testing.T) { std.TestSetOrigCaller(lp01) shouldPanic(t, func() { pn.DecreaseLiquidity( - 1, - consts.MAX_UINT256, - 0, - 0, + 1, // tokenId + consts.MAX_UINT256, // liquidity + "0", // amount0Min + "0", // amount1Min max_timeout, ) }) @@ -558,8 +562,8 @@ func TestStakerUnstake(t *testing.T) { // it will return unstaked position's poolPath, amount0, amount1 ( not reward ) poolPath, amount0, amount1 := sr.UnstakeToken(1) shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/baz:100") - shouldEQ(t, amount0, bigint(604982)) - shouldEQ(t, amount1, bigint(7899135)) + shouldEQ(t, amount0, "604982") + shouldEQ(t, amount1, "7899135") std.TestSkipHeights(1) } @@ -568,14 +572,14 @@ func TestPositionDecreaseLiquidityUnstakedPosition(t *testing.T) { tokenId, liquidity, amount0, amount1, poolPath := pn.DecreaseLiquidity( 1, consts.MAX_UINT256, - 0, - 0, + "0", + "0", max_timeout, ) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, liquidity, bigint(4473213900)) - shouldEQ(t, amount0, bigint(604982)) - shouldEQ(t, amount1, bigint(7899135)) + shouldEQ(t, liquidity, "4473213900") + shouldEQ(t, amount0, "604982") + shouldEQ(t, amount1, "7899135") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/baz:100") std.TestSkipHeights(1) diff --git a/_test/_TEST_scenario_02_FAIL_too_small_amount_test.gnoa b/_test/_TEST_scenario_02_FAIL_too_small_amount_test.gnoa index 471ad089..44f11732 100644 --- a/_test/_TEST_scenario_02_FAIL_too_small_amount_test.gnoa +++ b/_test/_TEST_scenario_02_FAIL_too_small_amount_test.gnoa @@ -39,10 +39,10 @@ func TestPoolCreatePools(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*2) // bar-baz - pl.CreatePool(barPath, bazPath, 100, 354340008410679467268648495215) // tick 29960 ≈ 1:20 + pl.CreatePool(barPath, bazPath, 100, "354340008410679467268648495215") // tick 29960 ≈ 1:20 // baz-foo - pl.CreatePool(bazPath, fooPath, 100, 79228162514264337593543950337) // tick 0 ≈ 1:1 + pl.CreatePool(bazPath, fooPath, 100, "79228162514264337593543950337") // tick 0 ≈ 1:1 std.TestSkipHeights(2) } @@ -78,17 +78,17 @@ func TestPositionMintBarBazInRange(t *testing.T) { 100, // fee 29950, // tickLower 29970, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(1)) - shouldEQ(t, liquidity, bigint(4473213900)) - shouldEQ(t, amount0, bigint(499941)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 1) + shouldEQ(t, liquidity, "4473213900") + shouldEQ(t, amount0, "499941") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) } @@ -106,17 +106,17 @@ func TestPositionMintBazFooInRange(t *testing.T) { 100, // fee -1000, // tickLower 1000, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(2)) - shouldEQ(t, liquidity, bigint(205051662)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 2) + shouldEQ(t, liquidity, "205051662") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) } @@ -140,28 +140,26 @@ func TestRouterDrySwapBarBazExactIn(t *testing.T) { dryResult := rr.DrySwapRoute( barPath, // inputToken bazPath, // outputToken - 10, // amountSpecified + "10", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100,gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr "95,5", // quoteArr ) - shouldEQ(t, dryResult, bigint(-1)) // -1 means fail + shouldEQ(t, dryResult, "-1") // -1 means fail } func TestRouterSwapBarBazExactIn(t *testing.T) { bar.Approve(a2u(consts.POOL_ADDR), 100000) - shouldPanicWithMsg(t, func() { + shouldPanic(t, func() { rr.SwapRoute( barPath, // inputToken bazPath, // outputToken - 10, // amountSpecified + "10", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100,gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr "95,5", // quoteArr "1", // tokenAmountLimit ) - }, - "[POOL] pool.gno__Swap() || amountSpecified(0) != 0", - ) + }) } diff --git a/_test/_TEST_scenario_03_FAIL_too_small_liquidity_test.gnoa b/_test/_TEST_scenario_03_FAIL_too_small_liquidity_test.gnoa index d2074742..3fa9808b 100644 --- a/_test/_TEST_scenario_03_FAIL_too_small_liquidity_test.gnoa +++ b/_test/_TEST_scenario_03_FAIL_too_small_liquidity_test.gnoa @@ -38,10 +38,10 @@ func TestPoolCreatePools(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*2) // bar-baz - pl.CreatePool(barPath, bazPath, 100, 354340008410679467268648495215) // tick 29960 ≈ 1:20 + pl.CreatePool(barPath, bazPath, 100, "354340008410679467268648495215") // tick 29960 ≈ 1:20 // baz-foo - pl.CreatePool(bazPath, fooPath, 100, 79228162514264337593543950337) // tick 0 ≈ 1:1 + pl.CreatePool(bazPath, fooPath, 100, "79228162514264337593543950337") // tick 0 ≈ 1:1 std.TestSkipHeights(2) } @@ -77,17 +77,17 @@ func TestPositionMintBarBazInRange(t *testing.T) { 100, // fee 29950, // tickLower 29970, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(1)) - shouldEQ(t, liquidity, bigint(4473213900)) - shouldEQ(t, amount0, bigint(499941)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 1) + shouldEQ(t, liquidity, "4473213900") + shouldEQ(t, amount0, "499941") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) } @@ -105,17 +105,17 @@ func TestPositionMintBazFooInRange(t *testing.T) { 100, // fee -1000, // tickLower 1000, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(2)) - shouldEQ(t, liquidity, bigint(205051662)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 2) + shouldEQ(t, liquidity, "205051662") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) } @@ -139,28 +139,26 @@ func TestRouterDrySwapBarBazExactIn(t *testing.T) { dryResult := rr.DrySwapRoute( barPath, // inputToken bazPath, // outputToken - 10, // amountSpecified + "10", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100,gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr "95,5", // quoteArr ) - shouldEQ(t, dryResult, bigint(-1)) + shouldEQ(t, dryResult, "-1") } func TestRouterSwapBarBazExactIn(t *testing.T) { bar.Approve(a2u(consts.POOL_ADDR), 100000) - shouldPanicWithMsg(t, func() { + shouldPanic(t, func() { rr.SwapRoute( barPath, // inputToken bazPath, // outputToken - 10, // amountSpecified + "10", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100,gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr "95,5", // quoteArr "1", // tokenAmountLimit ) - }, - "[POOL] pool.gno__Swap() || amountSpecified(0) != 0", - ) + }) } diff --git a/_test/_TEST_scenario_04_router_one_route_one_hop_test.gnoa b/_test/_TEST_scenario_04_router_one_route_one_hop_test.gnoa index 752134ec..cc8b1b99 100644 --- a/_test/_TEST_scenario_04_router_one_route_one_hop_test.gnoa +++ b/_test/_TEST_scenario_04_router_one_route_one_hop_test.gnoa @@ -1,4 +1,4 @@ -// SwapRoute & DrySwapRoute [ 1 rrte 1 hop ] +// SwapRoute & DrySwapRoute [ 1 route 1 hop ] package swap_scenario import ( @@ -44,13 +44,13 @@ func TestPoolCreatePools(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*3) // bar-baz - pl.CreatePool(barPath, bazPath, 100, 354340008410679467268648495215) // tick 29960 ≈ 1:20 + pl.CreatePool(barPath, bazPath, 100, "354340008410679467268648495215") // tick 29960 ≈ 1:20 // baz-foo - pl.CreatePool(bazPath, fooPath, 100, 25050389945027294416741547334) // tick -23030 ≈ 1:0.1 + pl.CreatePool(bazPath, fooPath, 100, "25050389945027294416741547334") // tick -23030 ≈ 1:0.1 // foo-wugnot - pl.CreatePool(fooPath, consts.WRAPPED_WUGNOT, 100, 17714911063927984461157312042) // tick -29960 ≈ 1:0.05 + pl.CreatePool(fooPath, consts.WRAPPED_WUGNOT, 100, "17714911063927984461157312042") // tick -29960 ≈ 1:0.05 std.TestSkipHeights(3) } @@ -89,17 +89,17 @@ func TestpnitionMintBarBazInRange(t *testing.T) { 100, // fee 29950, // tickLower 29970, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(1)) - shouldEQ(t, liquidity, bigint(4473213900)) - shouldEQ(t, amount0, bigint(499941)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 1) + shouldEQ(t, liquidity, "4473213900") + shouldEQ(t, amount0, "499941") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) } @@ -118,17 +118,17 @@ func TestpnitionMintBarBazLowerRange(t *testing.T) { 100, // fee 29900, // tickLower 29910, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(2)) - shouldEQ(t, liquidity, bigint(4484410364)) - shouldEQ(t, amount0, bigint(0)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 2) + shouldEQ(t, liquidity, "4484410364") + shouldEQ(t, amount0, "0") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) } @@ -147,17 +147,17 @@ func TestpnitionMintBarBazUpperRange(t *testing.T) { 100, // fee 30000, // tickLower 32000, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(3)) - shouldEQ(t, liquidity, bigint(470937834)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(0)) + shouldEQ(t, tokenId, 3) + shouldEQ(t, liquidity, "470937834") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "0") std.TestSkipHeights(3) } @@ -175,17 +175,17 @@ func TestpnitionMintBazFooInRange(t *testing.T) { 100, // fee -23050, // tickLower -23010, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(4)) - shouldEQ(t, liquidity, bigint(3163542978)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(999700)) + shouldEQ(t, tokenId, 4) + shouldEQ(t, liquidity, "3163542978") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "999700") std.TestSkipHeights(3) } @@ -212,17 +212,17 @@ func TestpnitionMintFooGnotInRange(t *testing.T) { 100, // fee -30960, // tickLower -28960, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(5)) - shouldEQ(t, liquidity, bigint(45848241)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(499941)) + shouldEQ(t, tokenId, 5) + shouldEQ(t, liquidity, "45848241") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "499941") std.TestSkipHeights(4) } @@ -243,7 +243,7 @@ func TestStakerCreateExternalIncentive(t *testing.T) { sr.CreateExternalIncentive( "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // targetPoolPath oblPath, // rewardTokenPath - 100000000, // rewardAmount + "100000000", // rewardAmount 1234568045, // startTimestamp 1234568045+7776000, // endTimestamp ( 90 days ) ) @@ -311,12 +311,12 @@ func TestRouterDrySwapRouteBarBazExactIn(t *testing.T) { dryResult := rr.DrySwapRoute( barPath, // inputToken bazPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_IN", // swapType - "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strrrteArr + "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, bigint(1999835)) + shouldEQ(t, dryResult, "1999835") std.TestSkipHeights(2) } @@ -333,13 +333,13 @@ func TestRouterSwapRouteBarBazExactIn(t *testing.T) { swapResult := rr.SwapRoute( barPath, // inputToken bazPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_IN", // swapType - "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strrrteArr + "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr "100", // quoteArr - 1, // tokenAmountLimit (minRecv) + "1", // tokenAmountLimit (minRecv) ) - shouldEQ(t, swapResult, bigint(1996836)) + shouldEQ(t, swapResult, "1996836") shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99900000) shouldEQ(t, baz.BalanceOf(a2u(tr01)), 101996836) @@ -353,12 +353,12 @@ func TestRouterDrySwapRouteBarBazExactOutAfterSwap(t *testing.T) { dryResult := rr.DrySwapRoute( barPath, // inputToken bazPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_OUT", // swapType - "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strrrteArr + "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, bigint(5000)) + shouldEQ(t, dryResult, "5000") std.TestSkipHeights(2) } @@ -367,7 +367,7 @@ func TestRouterSwapRouteBarBazExactOutAfterSwap(t *testing.T) { // approve bar to pool bar.Approve(a2u(consts.POOL_ADDR), 100000) - baz.Approve(a2u(consts.ROUTER_ADDR), uint64(consts.MAX_UINT64)) + baz.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99900000) shouldEQ(t, baz.BalanceOf(a2u(tr01)), 101996836) @@ -375,13 +375,13 @@ func TestRouterSwapRouteBarBazExactOutAfterSwap(t *testing.T) { swapResult := rr.SwapRoute( barPath, // inputToken bazPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_OUT", // swapType - "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strrrteArr - "100", // quoteArr - 5001, // tokenAmountLimit (maxSpent) + "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr + "100", // quoteArr + "5001", // tokenAmountLimit (maxSpent) ) - shouldEQ(t, swapResult, bigint(5000)) + shouldEQ(t, swapResult, "5000") shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99895000) shouldEQ(t, baz.BalanceOf(a2u(tr01)), 102096686) diff --git a/_test/_TEST_scenario_05_router_one_route_two_hop_test.gnoa b/_test/_TEST_scenario_05_router_one_route_two_hop_test.gnoa index 3ed64caf..46b5de0b 100644 --- a/_test/_TEST_scenario_05_router_one_route_two_hop_test.gnoa +++ b/_test/_TEST_scenario_05_router_one_route_two_hop_test.gnoa @@ -44,13 +44,13 @@ func TestPoolCreatePools(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*3) // bar-baz - pl.CreatePool(barPath, bazPath, 100, 354340008410679467268648495215) // tick 29960 ≈ 1:20 + pl.CreatePool(barPath, bazPath, 100, "354340008410679467268648495215") // tick 29960 ≈ 1:20 // baz-foo - pl.CreatePool(bazPath, fooPath, 100, 25050389945027294416741547334) // tick -23030 ≈ 1:0.1 + pl.CreatePool(bazPath, fooPath, 100, "25050389945027294416741547334") // tick -23030 ≈ 1:0.1 // foo-wugnot - pl.CreatePool(fooPath, consts.WRAPPED_WUGNOT, 100, 17714911063927984461157312042) // tick -29960 ≈ 1:0.05 + pl.CreatePool(fooPath, consts.WRAPPED_WUGNOT, 100, "17714911063927984461157312042") // tick -29960 ≈ 1:0.05 std.TestSkipHeights(4) } @@ -89,17 +89,17 @@ func TestPositionMintBarBazInRange(t *testing.T) { 100, // fee 29950, // tickLower 29970, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(1)) - shouldEQ(t, liquidity, bigint(4473213900)) - shouldEQ(t, amount0, bigint(499941)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 1) + shouldEQ(t, liquidity, "4473213900") + shouldEQ(t, amount0, "499941") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) } @@ -118,17 +118,17 @@ func TestPositionMintBarBazLowerRange(t *testing.T) { 100, // fee 29900, // tickLower 29910, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(2)) - shouldEQ(t, liquidity, bigint(4484410364)) - shouldEQ(t, amount0, bigint(0)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 2) + shouldEQ(t, liquidity, "4484410364") + shouldEQ(t, amount0, "0") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) } @@ -147,17 +147,17 @@ func TestPositionMintBarBazUpperRange(t *testing.T) { 100, // fee 30000, // tickLower 32000, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(3)) - shouldEQ(t, liquidity, bigint(470937834)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(0)) + shouldEQ(t, tokenId, 3) + shouldEQ(t, liquidity, "470937834") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "0") std.TestSkipHeights(3) } @@ -175,17 +175,17 @@ func TestPositionMintBazFooInRange(t *testing.T) { 100, // fee -23050, // tickLower -23010, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(4)) - shouldEQ(t, liquidity, bigint(3163542978)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(999700)) + shouldEQ(t, tokenId, 4) + shouldEQ(t, liquidity, "3163542978") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "999700") std.TestSkipHeights(3) } @@ -212,17 +212,17 @@ func TestPositionMintFooGnotInRange(t *testing.T) { 100, // fee -30960, // tickLower -28960, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(5)) - shouldEQ(t, liquidity, bigint(45848241)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(499941)) + shouldEQ(t, tokenId, 5) + shouldEQ(t, liquidity, "45848241") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "499941") std.TestSkipHeights(4) } @@ -243,7 +243,7 @@ func TestStakerCreateExternalIncentive(t *testing.T) { sr.CreateExternalIncentive( "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // targetPoolPath oblPath, // rewardTokenPath - 100000000, // rewardAmount + "100000000", // rewardAmount 1234568045, // startTimestamp 1234568045+7776000, // endTimestamp ( 90 days ) ) @@ -301,12 +301,12 @@ func TestRouterDrySwapRouteBarFooExactIn(t *testing.T) { dryResult := rr.DrySwapRoute( barPath, // inputToken fooPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, bigint(199863)) + shouldEQ(t, dryResult, "199863") std.TestSkipHeights(2) } @@ -323,13 +323,13 @@ func TestRouterSwapRouteBarFooExactIn(t *testing.T) { swapResult := rr.SwapRoute( barPath, // inputToken fooPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr "100", // quoteArr "1", // tokenAmountLimit (minRecv) ) - shouldEQ(t, swapResult, bigint(199564)) + shouldEQ(t, swapResult, "199564") shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99900000) shouldEQ(t, foo.BalanceOf(a2u(tr01)), 100199564) @@ -343,12 +343,12 @@ func TestRouterDrySwapRouteBarFooExactOutAfterSwap(t *testing.T) { dryResult := rr.DrySwapRoute( barPath, // inputToken fooPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, bigint(50056)) + shouldEQ(t, dryResult, "50056") std.TestSkipHeights(2) } @@ -357,7 +357,7 @@ func TestRouterSwapRouteBarFooExactOutAfterSwap(t *testing.T) { // approve bar to pool bar.Approve(a2u(consts.POOL_ADDR), 100000) - foo.Approve(a2u(consts.ROUTER_ADDR), uint64(consts.MAX_UINT64)) + foo.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99900000) shouldEQ(t, foo.BalanceOf(a2u(tr01)), 100199564) @@ -365,13 +365,13 @@ func TestRouterSwapRouteBarFooExactOutAfterSwap(t *testing.T) { swapResult := rr.SwapRoute( barPath, // inputToken fooPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr "100", // quoteArr "50056", // maxSpent ) - shouldEQ(t, swapResult, bigint(50056)) + shouldEQ(t, swapResult, "50056") shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99849944) shouldEQ(t, foo.BalanceOf(a2u(tr01)), 100299414) diff --git a/_test/_TEST_scenario_06_router_one_route_three_hop_println_test.gnoa b/_test/_TEST_scenario_06_router_one_route_three_hop_println_test.gnoa index d7645453..bf6c5958 100644 --- a/_test/_TEST_scenario_06_router_one_route_three_hop_println_test.gnoa +++ b/_test/_TEST_scenario_06_router_one_route_three_hop_println_test.gnoa @@ -38,13 +38,13 @@ func TestPoolCreatePools(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*3) // bar-baz - pl.CreatePool(barPath, bazPath, 100, 354340008410679467268648495215) // tick 29960 ≈ 1:20 + pl.CreatePool(barPath, bazPath, 100, "354340008410679467268648495215") // tick 29960 ≈ 1:20 // baz-foo - pl.CreatePool(bazPath, fooPath, 100, 25050389945027294416741547334) // tick -23030 ≈ 1:0.1 + pl.CreatePool(bazPath, fooPath, 100, "25050389945027294416741547334") // tick -23030 ≈ 1:0.1 // foo-qux - pl.CreatePool(fooPath, quxPath, 100, 17714911063927984461157312042) // tick -29960 ≈ 1:0.05 + pl.CreatePool(fooPath, quxPath, 100, "17714911063927984461157312042") // tick -29960 ≈ 1:0.05 std.TestSkipHeights(3) } @@ -83,17 +83,17 @@ func TestPositionMintBarBazInRange(t *testing.T) { 100, // fee 29950, // tickLower 29970, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(1)) - shouldEQ(t, liquidity, bigint(4473213900)) - shouldEQ(t, amount0, bigint(499941)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 1) + shouldEQ(t, liquidity, "4473213900") + shouldEQ(t, amount0, "499941") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) } @@ -111,17 +111,17 @@ func TestPositionMintBazFooInRange(t *testing.T) { 100, // fee -23050, // tickLower -23010, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(2)) - shouldEQ(t, liquidity, bigint(3163542978)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(999700)) + shouldEQ(t, tokenId, 2) + shouldEQ(t, liquidity, "3163542978") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "999700") std.TestSkipHeights(3) } @@ -139,17 +139,17 @@ func TestPositionMintFooQuxInRange(t *testing.T) { 100, // fee -29980, // tickLower -29940, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(3)) - shouldEQ(t, liquidity, bigint(2237166073)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(499941)) + shouldEQ(t, tokenId, 3) + shouldEQ(t, liquidity, "2237166073") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "499941") std.TestSkipHeights(3) } @@ -181,7 +181,7 @@ func TestRouterDrySwapRouteBarQuxExactIn(t *testing.T) { dryResult := rr.DrySwapRoute( barPath, // inputToken quxPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100*POOL*gno.land/r/demo/foo:gno.land/r/demo/qux:100", // strRouteArr "100", // quoteArr @@ -203,7 +203,7 @@ func TestRouterSwapRouteBarQuxExactIn(t *testing.T) { swapResult := rr.SwapRoute( barPath, // inputToken quxPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100*POOL*gno.land/r/demo/foo:gno.land/r/demo/qux:100", // strRouteArr "100", // quoteArr @@ -226,7 +226,7 @@ func TestRouterDrySwapRouteBarQuxExactOutAfterSwap(t *testing.T) { dryResult := rr.DrySwapRoute( barPath, // inputToken quxPath, // outputToken - 10000, // amountSpecified + "10000", // amountSpecified "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100*POOL*gno.land/r/demo/foo:gno.land/r/demo/qux:100", // strRouteArr "100", // quoteArr @@ -240,7 +240,7 @@ func TestRouterSwapRouteBarQuxExactOutAfterSwap(t *testing.T) { // approve bar to pool bar.Approve(a2u(consts.POOL_ADDR), 500000) - qux.Approve(a2u(consts.ROUTER_ADDR), uint64(consts.MAX_UINT64)) + qux.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) oldBar := bar.BalanceOf(a2u(tr01)) oldQux := qux.BalanceOf(a2u(tr01)) @@ -248,7 +248,7 @@ func TestRouterSwapRouteBarQuxExactOutAfterSwap(t *testing.T) { swapResult := rr.SwapRoute( barPath, // inputToken quxPath, // outputToken - 10000, // amountSpecified + "10000", // amountSpecified "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100*POOL*gno.land/r/demo/foo:gno.land/r/demo/qux:100", // strRouteArr "100", // quoteArr diff --git a/_test/_TEST_scenario_07_FAIL_router_one_route_three_hop_large_amount_println_test.gnoa b/_test/_TEST_scenario_07_FAIL_router_one_route_three_hop_large_amount_println_test.gnoa index fe857d25..0de0b4a4 100644 --- a/_test/_TEST_scenario_07_FAIL_router_one_route_three_hop_large_amount_println_test.gnoa +++ b/_test/_TEST_scenario_07_FAIL_router_one_route_three_hop_large_amount_println_test.gnoa @@ -39,13 +39,13 @@ func TestPoolCreatePools(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*3) // bar-baz - pl.CreatePool(barPath, bazPath, 100, 354340008410679467268648495215) // tick 29960 ≈ 1:20 + pl.CreatePool(barPath, bazPath, 100, "354340008410679467268648495215") // tick 29960 ≈ 1:20 // baz-foo - pl.CreatePool(bazPath, fooPath, 100, 25050389945027294416741547334) // tick -23030 ≈ 1:0.1 + pl.CreatePool(bazPath, fooPath, 100, "25050389945027294416741547334") // tick -23030 ≈ 1:0.1 // foo-qux - pl.CreatePool(fooPath, quxPath, 100, 17714911063927984461157312042) // tick -29960 ≈ 1:0.05 + pl.CreatePool(fooPath, quxPath, 100, "17714911063927984461157312042") // tick -29960 ≈ 1:0.05 std.TestSkipHeights(3) } @@ -84,17 +84,17 @@ func TestPositionMintBarBazInRange(t *testing.T) { 100, // fee 29950, // tickLower 29970, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(1)) - shouldEQ(t, liquidity, bigint(4473213900)) - shouldEQ(t, amount0, bigint(499941)) - shouldEQ(t, amoutn1, bigint(9999999)) + shouldEQ(t, tokenId, 1) + shouldEQ(t, liquidity, "4473213900") + shouldEQ(t, amount0, "499941") + shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) } @@ -112,17 +112,17 @@ func TestPositionMintBazFooInRange(t *testing.T) { 100, // fee -23050, // tickLower -23010, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(2)) - shouldEQ(t, liquidity, bigint(3163542978)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(999700)) + shouldEQ(t, tokenId, 2) + shouldEQ(t, liquidity, "3163542978") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "999700") std.TestSkipHeights(3) } @@ -140,17 +140,17 @@ func TestPositionMintFooQuxInRange(t *testing.T) { 100, // fee -29980, // tickLower -29940, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(3)) - shouldEQ(t, liquidity, bigint(2237166073)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(499941)) + shouldEQ(t, tokenId, 3) + shouldEQ(t, liquidity, "2237166073") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "499941") std.TestSkipHeights(3) } @@ -182,7 +182,7 @@ func TestRouterDrySwapRouteBarQuxExactIn(t *testing.T) { dryResult := rr.DrySwapRoute( barPath, // inputToken quxPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100*POOL*gno.land/r/demo/foo:gno.land/r/demo/qux:100", // strRouteArr "100", // quoteArr @@ -204,7 +204,7 @@ func TestRouterSwapRouteBarQuxExactIn(t *testing.T) { swapResult := rr.SwapRoute( barPath, // inputToken quxPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100*POOL*gno.land/r/demo/foo:gno.land/r/demo/qux:100", // strRouteArr "100", // quoteArr @@ -227,7 +227,7 @@ func TestRouterDrySwapRouteBarQuxExactOutAfterSwap(t *testing.T) { dryResult := rr.DrySwapRoute( barPath, // inputToken quxPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100*POOL*gno.land/r/demo/foo:gno.land/r/demo/qux:100", // strRouteArr "100", // quoteArr @@ -249,13 +249,13 @@ func TestRouterSwapRouteBarQuxExactOutAfterSwap(t *testing.T) { rr.SwapRoute( barPath, // inputToken quxPath, // outputToken - 100000, // amountSpecified + "100000", // amountSpecified "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100*POOL*gno.land/r/demo/foo:gno.land/r/demo/qux:100", // strRouteArr "100", // quoteArr "123456789", // tokenAmountLimit (maxSpent) ) }, - "[POOL] pool.gno__Swap() || amountSpecified(0) != 0", + "[POOL] pool.gno__Swap() || _amountSpecified == 0", ) } diff --git a/_test/_TEST_scenario_08_router_two_position_one_route_one_hop_println_test.gnoa b/_test/_TEST_scenario_08_router_two_position_one_route_one_hop_println_test.gnoa index e2c9dfb8..5b1b2a8c 100644 --- a/_test/_TEST_scenario_08_router_two_position_one_route_one_hop_println_test.gnoa +++ b/_test/_TEST_scenario_08_router_two_position_one_route_one_hop_println_test.gnoa @@ -36,7 +36,7 @@ func TestPoolCreatePools(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) // bar-baz - pl.CreatePool(barPath, bazPath, 100, 354340008410679467268648495215) // tick 29960 ≈ 1:20 + pl.CreatePool(barPath, bazPath, 100, "354340008410679467268648495215") // tick 29960 ≈ 1:20 std.TestSkipHeights(4) } @@ -69,16 +69,16 @@ func TestPositionMintBarBazInRange(t *testing.T) { 100, // fee 29950, // tickLower 29970, // tickUpper - 1000, // amount0Desired - 1000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "1000", // amount0Desired + "1000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(1)) - shouldEQ(t, liquidity, bigint(447321)) - shouldEQ(t, amount0, bigint(49)) - shouldEQ(t, amoutn1, bigint(999)) + shouldEQ(t, tokenId, 1) + shouldEQ(t, liquidity, "447321") + shouldEQ(t, amount0, "49") + shouldEQ(t, amoutn1, "999") std.TestSkipHeights(3) } @@ -96,16 +96,16 @@ func TestPositionMintBarBazInRangeMore(t *testing.T) { 100, // fee 29950, // tickLower 29970, // tickUpper - 1000, // amount0Desired - 1000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "1000", // amount0Desired + "1000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, tokenId, bigint(2)) - shouldEQ(t, liquidity, bigint(447321)) - shouldEQ(t, amount0, bigint(49)) - shouldEQ(t, amoutn1, bigint(999)) + shouldEQ(t, tokenId, 2) + shouldEQ(t, liquidity, "447321") + shouldEQ(t, amount0, "49") + shouldEQ(t, amoutn1, "999") std.TestSkipHeights(3) @@ -135,7 +135,7 @@ func TestRouterDrySwapRouteBarBazExactOut(t *testing.T) { dryResult := rr.DrySwapRoute( barPath, // inputToken bazPath, // outputToken - 1800, // amountSpecified + "1800", // amountSpecified "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr "100", // quoteArr @@ -149,7 +149,7 @@ func TestRouterSwapRouteBarBazExactOut(t *testing.T) { // approve bar to pool bar.Approve(a2u(consts.POOL_ADDR), 100000) - baz.Approve(a2u(consts.ROUTER_ADDR), uint64(consts.MAX_UINT64)) + baz.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) oldBar := bar.BalanceOf(a2u(tr01)) oldBaz := baz.BalanceOf(a2u(tr01)) @@ -157,7 +157,7 @@ func TestRouterSwapRouteBarBazExactOut(t *testing.T) { swapResult := rr.SwapRoute( barPath, // inputToken bazPath, // outputToken - 1800, // amountSpecified + "1800", // amountSpecified "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr "100", // quoteArr diff --git a/_test/_TEST_scenario_98_router_only_upper_position_println_test.gnoa b/_test/_TEST_scenario_98_router_only_upper_position_println_test.gnoa index 2fa14ac5..881d9d27 100644 --- a/_test/_TEST_scenario_98_router_only_upper_position_println_test.gnoa +++ b/_test/_TEST_scenario_98_router_only_upper_position_println_test.gnoa @@ -36,7 +36,7 @@ func TestPoolCreatePools(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) // bar-baz - pl.CreatePool(barPath, bazPath, 100, 354340008410679467268648495215) // tick 29960 ≈ 1:20 + pl.CreatePool(barPath, bazPath, 100, "354340008410679467268648495215") // tick 29960 ≈ 1:20 std.TestSkipHeights(4) } @@ -69,16 +69,16 @@ func TestFaucetLP01(t *testing.T) { // 100, // fee // 29940, // tickLower // 29980, // tickUpper -// 1000, // amount0Desired -// 1000, // amount1Desired -// 0, // amount0Min -// 0, // amount1Min +// "1000", // amount0Desired +// "1000", // amount1Desired +// "0", // amount0Min +// "0", // amount1Min // max_timeout, // deadline // ) -// // shouldEQ(t, tokenId, bigint(1)) -// shouldEQ(t, liquidity, bigint(223717)) -// shouldEQ(t, amount0, bigint(49)) -// shouldEQ(t, amoutn1, bigint(1000)) +// // shouldEQ(t, tokenId, 1) +// shouldEQ(t, liquidity, "223717")) +// shouldEQ(t, amount0, "49")) +// shouldEQ(t, amoutn1, "1000")) // poolBar := bar.BalanceOf(a2u(consts.POOL_ADDR)) // poolBaz := baz.BalanceOf(a2u(consts.POOL_ADDR)) @@ -101,16 +101,16 @@ func TestPositionMintBarBazUpperRange(t *testing.T) { 100, // fee 30000, // tickLower 34000, // tickUpper - 1000, // amount0Desired - 1000, // amount1Desired - 0, // amount0Min - 0, // amount1Min + "1000", // amount0Desired + "1000", // amount1Desired + "0", // amount0Min + "0", // amount1Min max_timeout, // deadline ) - // shouldEQ(t, tokenId, bigint(2)) - shouldEQ(t, liquidity, bigint(24723)) - shouldEQ(t, amount0, bigint(999)) - shouldEQ(t, amoutn1, bigint(0)) + // shouldEQ(t, tokenId, "2")) + shouldEQ(t, liquidity, "24723") + shouldEQ(t, amount0, "999") + shouldEQ(t, amoutn1, "0") poolBar := bar.BalanceOf(a2u(consts.POOL_ADDR)) poolBaz := baz.BalanceOf(a2u(consts.POOL_ADDR)) @@ -138,7 +138,7 @@ func TestRouterDrySwapRouteBazBarExactIn(t *testing.T) { dryResult := rr.DrySwapRoute( bazPath, // inputToken barPath, // outputToken - 1000, // amountSpecified + "1000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/baz:gno.land/r/demo/bar:100", // strRouteArr "100", // quoteArr @@ -161,7 +161,7 @@ func TestRouterSwapRouteBazBarExactIn(t *testing.T) { swapResult := rr.SwapRoute( bazPath, // inputToken barPath, // outputToken - 1000, // amountSpecified + "1000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/baz:gno.land/r/demo/bar:100", // strRouteArr "100", // quoteArr @@ -182,10 +182,10 @@ func TestRouterDrySwapRouteBazBarExactInTooMuch(t *testing.T) { std.TestSetOrigCaller(tr01) dryResult := rr.DrySwapRoute( - bazPath, // inputToken - barPath, // outputToken - 100000000, // amountSpecified - "EXACT_IN", // swapType + bazPath, // inputToken + barPath, // outputToken + "100000000", // amountSpecified + "EXACT_IN", // swapType "gno.land/r/demo/baz:gno.land/r/demo/bar:100", // strRouteArr "100", // quoteArr ) @@ -205,10 +205,10 @@ func TestRouterSwapRouteBazBarExactInTooMuch(t *testing.T) { shouldPanicWithMsg(t, func() { rr.SwapRoute( - bazPath, // inputToken - barPath, // outputToken - 100000000, // amountSpecified - "EXACT_IN", // swapType + bazPath, // inputToken + barPath, // outputToken + "100000000", // amountSpecified + "EXACT_IN", // swapType "gno.land/r/demo/baz:gno.land/r/demo/bar:100", // strRouteArr "100", // quoteArr "10000000", // tokenAmountLimit (minReceived) diff --git a/_test/_TEST_scenario_99_router_uniswap_sdk_test.gnoXXX b/_test/_TEST_scenario_99_router_uniswap_sdk_test.gnoXXX new file mode 100644 index 00000000..8d9b5718 --- /dev/null +++ b/_test/_TEST_scenario_99_router_uniswap_sdk_test.gnoXXX @@ -0,0 +1,244 @@ +/* +UNISWAP TEST REF + - https://github.com/Uniswap/v3-core/blob/main/test/shared/fixtures.ts + - https://github.com/Uniswap/v3-core/blob/main/test/UniswapV3Router.spec.ts + - https://github.com/Uniswap/router-sdk/blob/main/src/swapRouter.test.ts +*/ +package swap_scenario + +import ( + "std" + "testing" + + "gno.land/p/demo/testutils" + + "gno.land/r/demo/consts" + + pl "gno.land/r/demo/pool" + pn "gno.land/r/demo/position" + + "gno.land/r/demo/bar" + "gno.land/r/demo/baz" + "gno.land/r/demo/foo" + + "gno.land/r/demo/gns" +) + +var ( + lp01 = testutils.TestAddress("lp01") + tr01 = testutils.TestAddress("tr01") + + // vars from Uniswap TEST + feeAmount uint32 = 3000 + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L24 + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/shared/utilities.ts#L23 + + tickSpacing = 60 + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L25 + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/shared/utilities.ts#L29 + + minTick int32 = -887272 + maxTick int32 = 887272 + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/shared/utilities.ts#L10-L11 +) + +func TestPoolInitByAdmin(t *testing.T) { + std.TestSetOrigCaller(gsa) + pl.InitManual() + + std.TestSkipHeights(1) +} + +func TestPoolCreatePools(t *testing.T) { + std.TestSetPrevAddr(test1) + gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*2) + + // bar-baz + pl.CreatePool(barPath, bazPath, 100, "79228162514264337593543950337") // tick 0 ≈ 1:1 + + // baz-foo + // pl.CreatePool(bazPath, fooPath, 100, "79228162514264337593543950337") // tick 0 ≈ 1:1 + + std.TestSkipHeights(4) +} + +func TestFaucetLP01(t *testing.T) { + std.TestSetOrigCaller(lp01) + + shouldEQ(t, bar.BalanceOf(a2u(lp01)), 0) + shouldEQ(t, baz.BalanceOf(a2u(lp01)), 0) + shouldEQ(t, foo.BalanceOf(a2u(lp01)), 0) + + bar.Faucet(lp01) + baz.Faucet(lp01) + foo.Faucet(lp01) + + shouldEQ(t, bar.BalanceOf(a2u(lp01)), 100000000) + shouldEQ(t, baz.BalanceOf(a2u(lp01)), 100000000) + shouldEQ(t, foo.BalanceOf(a2u(lp01)), 100000000) + std.TestSkipHeights(5) +} + +// https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L83C16-L83C16 +func TestPositionMintBarBazInRange(t *testing.T) { + std.TestSetOrigCaller(lp01) + + // approve bar, baz to pool ( position.Mint() calls pool.Mint() ≈ so approve to pool ) + bar.Approve(a2u(consts.POOL_ADDR), 10000000) + baz.Approve(a2u(consts.POOL_ADDR), 10000000) + + tokenId, liquidity, amount0, amoutn1 := pn.Mint( + barPath, // token0 + bazPath, // token1 + 100, // fee + minTick, // tickLower + maxTick, // tickUpper + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min + max_timeout, // deadline + ) + + shouldEQ(t, tokenId, 1) + shouldEQ(t, liquidity, "10000000") + shouldEQ(t, amount0, "9999999") + shouldEQ(t, amoutn1, "9999999") + + std.TestSkipHeights(3) +} + +// // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L84 +// func TestPositionMintBazFooInRange(t *testing.T) { +// std.TestSetOrigCaller(lp01) + +// // approve bar, baz to pool ( position.Mint() calls pool.Mint() ≈ so approve to pool ) +// baz.Approve(a2u(consts.POOL_ADDR), 10000000) +// foo.Approve(a2u(consts.POOL_ADDR), 10000000) + +// tokenId, liquidity, amount0, amoutn1 := pn.Mint( +// bazPath, // token0 +// fooPath, // token1 +// 100, // fee +// minTick, // tickLower +// maxTick, // tickUpper +// "10000000", // amount0Desired +// "10000000", // amount1Desired +// "0", // amount0Min +// "0", // amount1Min +// max_timeout, // deadline +// ) + +// shouldEQ(t, tokenId, 2) +// shouldEQ(t, liquidity, "10000000") +// shouldEQ(t, amount0, "9999999") +// shouldEQ(t, amoutn1, "9999999") + +// std.TestSkipHeights(3) +// } + +// func TestFaucetTR01(t *testing.T) { +// std.TestSetOrigCaller(tr01) + +// shouldEQ(t, bar.BalanceOf(a2u(tr01)), 0) + +// bar.Faucet(tr01) + +// shouldEQ(t, bar.BalanceOf(a2u(tr01)), 100000000) + +// std.TestSkipHeights(5) +// } + +// func TestRouterDrySwapRouteBarFooExactIn(t *testing.T) { +// std.TestSetOrigCaller(tr01) + +// dryResult := rr.DrySwapRoute( +// barPath, // inputToken +// fooPath, // outputToken +// "100000", // amountSpecified +// "EXACT_IN", // swapType +// "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr +// "100", // quoteArr +// ) +// shouldEQ(t, dryResult, "98019") +// std.TestSkipHeights(2) +// } + +// func TestRouterSwapRouteBarFooExactIn(t *testing.T) { +// std.TestSetOrigCaller(tr01) + +// // approve bar to pool +// bar.Approve(a2u(consts.POOL_ADDR), 100000) +// foo.Approve(a2u(consts.ROUTER_ADDR), 148) // 0.15% of 98019 + +// barOld := bar.BalanceOf(a2u(tr01)) +// fooOld := foo.BalanceOf(a2u(tr01)) +// shouldEQ(t, barOld, 100000000) +// shouldEQ(t, fooOld, 0) + +// swapResult := rr.SwapRoute( +// barPath, // inputToken +// fooPath, // outputToken +// "100000", // amountSpecified +// "EXACT_IN", // swapType +// "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr +// "100", // quoteArr +// "1", // tokenAmountLimit (minRecv) +// ) +// shouldEQ(t, swapResult, "97872") + +// barNew := bar.BalanceOf(a2u(tr01)) +// fooNew := foo.BalanceOf(a2u(tr01)) + +// shouldEQ(t, barOld-barNew, 100000) +// shouldEQ(t, fooNew-fooOld, 97872) + +// std.TestSkipHeights(2) +// } + +// func TestRouterDrySwapRouteBarFooExactOutAfterSwap(t *testing.T) { +// std.TestSetOrigCaller(tr01) + +// dryResult := rr.DrySwapRoute( +// barPath, // inputToken +// fooPath, // outputToken +// "100000", // amountSpecified +// "EXACT_OUT", // swapType +// "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr +// "100", // quoteArr +// ) +// shouldEQ(t, dryResult, "106226") +// std.TestSkipHeights(2) +// } + +// func TestRouterSwapRouteBarFooExactOutAfterSwap(t *testing.T) { +// std.TestSetOrigCaller(tr01) + +// // approve bar to pool +// bar.Approve(a2u(consts.POOL_ADDR), 106226) +// foo.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) + +// barOld := bar.BalanceOf(a2u(tr01)) +// fooOld := foo.BalanceOf(a2u(tr01)) +// shouldEQ(t, barOld, 99900000) +// shouldEQ(t, fooOld, 97872) + +// swapResult := rr.SwapRoute( +// barPath, // inputToken +// fooPath, // outputToken +// "100000", // amountSpecified +// "EXACT_OUT", // swapType +// "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr +// "100", // quoteArr +// "123456", // tokenAmountLimit (maxSpent) +// ) +// shouldEQ(t, swapResult, "106226") + +// barNew := bar.BalanceOf(a2u(tr01)) +// fooNew := foo.BalanceOf(a2u(tr01)) + +// shouldEQ(t, barOld-barNew, 106226) +// shouldEQ(t, fooNew-fooOld, 99849) + +// std.TestSkipHeights(2) +// } diff --git a/_test/_TEST_scenario_99_router_uniswap_sdk_test.gnoa b/_test/_TEST_scenario_99_router_uniswap_sdk_test.gnoa deleted file mode 100644 index c296740e..00000000 --- a/_test/_TEST_scenario_99_router_uniswap_sdk_test.gnoa +++ /dev/null @@ -1,245 +0,0 @@ -/* -UNISWAP TEST REF - - https://github.com/Uniswap/v3-core/blob/main/test/shared/fixtures.ts - - https://github.com/Uniswap/v3-core/blob/main/test/UniswapV3Router.spec.ts - - https://github.com/Uniswap/router-sdk/blob/main/src/swapRouter.test.ts -*/ -package swap_scenario - -import ( - "std" - "testing" - - "gno.land/p/demo/testutils" - - "gno.land/r/demo/consts" - - pl "gno.land/r/demo/pool" - pn "gno.land/r/demo/position" - rr "gno.land/r/demo/router" - - "gno.land/r/demo/bar" - "gno.land/r/demo/baz" - "gno.land/r/demo/foo" - - "gno.land/r/demo/gns" -) - -var ( - lp01 = testutils.TestAddress("lp01") - tr01 = testutils.TestAddress("tr01") - - // vars from Uniswap TEST - feeAmount = 3000 - // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L24 - // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/shared/utilities.ts#L23 - - tickSpacing = 60 - // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L25 - // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/shared/utilities.ts#L29 - - minTick int32 = -887272 - maxTick int32 = 887272 - // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/shared/utilities.ts#L10-L11 -) - -func TestPoolInitByAdmin(t *testing.T) { - std.TestSetOrigCaller(gsa) - pl.InitManual() - - std.TestSkipHeights(1) -} - -func TestPoolCreatePools(t *testing.T) { - std.TestSetPrevAddr(test1) - gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*2) - - // bar-baz - pl.CreatePool(barPath, bazPath, 100, 79228162514264337593543950337) // tick 0 ≈ 1:1 - - // baz-foo - pl.CreatePool(bazPath, fooPath, 100, 79228162514264337593543950337) // tick 0 ≈ 1:1 - - std.TestSkipHeights(4) -} - -func TestFaucetLP01(t *testing.T) { - std.TestSetOrigCaller(lp01) - - shouldEQ(t, bar.BalanceOf(a2u(lp01)), 0) - shouldEQ(t, baz.BalanceOf(a2u(lp01)), 0) - shouldEQ(t, foo.BalanceOf(a2u(lp01)), 0) - - bar.Faucet(lp01) - baz.Faucet(lp01) - foo.Faucet(lp01) - - shouldEQ(t, bar.BalanceOf(a2u(lp01)), 100000000) - shouldEQ(t, baz.BalanceOf(a2u(lp01)), 100000000) - shouldEQ(t, foo.BalanceOf(a2u(lp01)), 100000000) - std.TestSkipHeights(5) -} - -// https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L83C16-L83C16 -func TestPositionMintBarBazInRange(t *testing.T) { - std.TestSetOrigCaller(lp01) - - // approve bar, baz to pool ( position.Mint() calls pool.Mint() ≈ so approve to pool ) - bar.Approve(a2u(consts.POOL_ADDR), 10000000) - baz.Approve(a2u(consts.POOL_ADDR), 10000000) - - tokenId, liquidity, amount0, amoutn1 := pn.Mint( - barPath, // token0 - bazPath, // token1 - 100, // fee - minTick, // tickLower - maxTick, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min - max_timeout, // deadline - ) - - shouldEQ(t, tokenId, bigint(1)) - shouldEQ(t, liquidity, bigint(10000000)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(9999999)) - - std.TestSkipHeights(3) -} - -// https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L84 -func TestPositionMintBazFooInRange(t *testing.T) { - std.TestSetOrigCaller(lp01) - - // approve bar, baz to pool ( position.Mint() calls pool.Mint() ≈ so approve to pool ) - baz.Approve(a2u(consts.POOL_ADDR), 10000000) - foo.Approve(a2u(consts.POOL_ADDR), 10000000) - - tokenId, liquidity, amount0, amoutn1 := pn.Mint( - bazPath, // token0 - fooPath, // token1 - 100, // fee - minTick, // tickLower - maxTick, // tickUpper - 10000000, // amount0Desired - 10000000, // amount1Desired - 0, // amount0Min - 0, // amount1Min - max_timeout, // deadline - ) - - shouldEQ(t, tokenId, bigint(2)) - shouldEQ(t, liquidity, bigint(10000000)) - shouldEQ(t, amount0, bigint(9999999)) - shouldEQ(t, amoutn1, bigint(9999999)) - - std.TestSkipHeights(3) -} - -func TestFaucetTR01(t *testing.T) { - std.TestSetOrigCaller(tr01) - - shouldEQ(t, bar.BalanceOf(a2u(tr01)), 0) - - bar.Faucet(tr01) - - shouldEQ(t, bar.BalanceOf(a2u(tr01)), 100000000) - - std.TestSkipHeights(5) -} - -func TestRouterDrySwapRouteBarFooExactIn(t *testing.T) { - std.TestSetOrigCaller(tr01) - - dryResult := rr.DrySwapRoute( - barPath, // inputToken - fooPath, // outputToken - 100000, // amountSpecified - "EXACT_IN", // swapType - "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr - "100", // quoteArr - ) - shouldEQ(t, dryResult, bigint(98019)) - std.TestSkipHeights(2) -} - -func TestRouterSwapRouteBarFooExactIn(t *testing.T) { - std.TestSetOrigCaller(tr01) - - // approve bar to pool - bar.Approve(a2u(consts.POOL_ADDR), 100000) - foo.Approve(a2u(consts.ROUTER_ADDR), 148) // 0.15% of 98019 - - barOld := bar.BalanceOf(a2u(tr01)) - fooOld := foo.BalanceOf(a2u(tr01)) - shouldEQ(t, barOld, 100000000) - shouldEQ(t, fooOld, 0) - - swapResult := rr.SwapRoute( - barPath, // inputToken - fooPath, // outputToken - 100000, // amountSpecified - "EXACT_IN", // swapType - "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr - "100", // quoteArr - "1", // tokenAmountLimit (minRecv) - ) - shouldEQ(t, swapResult, bigint(97872)) - - barNew := bar.BalanceOf(a2u(tr01)) - fooNew := foo.BalanceOf(a2u(tr01)) - - shouldEQ(t, barOld-barNew, 100000) - shouldEQ(t, fooNew-fooOld, 97872) - - std.TestSkipHeights(2) -} - -func TestRouterDrySwapRouteBarFooExactOutAfterSwap(t *testing.T) { - std.TestSetOrigCaller(tr01) - - dryResult := rr.DrySwapRoute( - barPath, // inputToken - fooPath, // outputToken - 100000, // amountSpecified - "EXACT_OUT", // swapType - "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr - "100", // quoteArr - ) - shouldEQ(t, dryResult, bigint(106226)) - std.TestSkipHeights(2) -} - -func TestRouterSwapRouteBarFooExactOutAfterSwap(t *testing.T) { - std.TestSetOrigCaller(tr01) - - // approve bar to pool - bar.Approve(a2u(consts.POOL_ADDR), 106226) - foo.Approve(a2u(consts.ROUTER_ADDR), uint64(consts.MAX_UINT64)) - - barOld := bar.BalanceOf(a2u(tr01)) - fooOld := foo.BalanceOf(a2u(tr01)) - shouldEQ(t, barOld, 99900000) - shouldEQ(t, fooOld, 97872) - - swapResult := rr.SwapRoute( - barPath, // inputToken - fooPath, // outputToken - 100000, // amountSpecified - "EXACT_OUT", // swapType - "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr - "100", // quoteArr - "123456", // tokenAmountLimit (maxSpent) - ) - shouldEQ(t, swapResult, bigint(106226)) - - barNew := bar.BalanceOf(a2u(tr01)) - fooNew := foo.BalanceOf(a2u(tr01)) - - shouldEQ(t, barOld-barNew, 106226) - shouldEQ(t, fooNew-fooOld, 99849) - - std.TestSkipHeights(2) -} diff --git a/common/tick_math.gno b/common/tick_math.gno deleted file mode 100644 index f3e55fc5..00000000 --- a/common/tick_math.gno +++ /dev/null @@ -1,199 +0,0 @@ -package common - -import ( - "gno.land/p/demo/u256" - "gno.land/p/demo/ufmt" - "gno.land/r/demo/consts" -) - -var tickRatioMap = map[uint64]*u256.Uint{ - 0x1: u256.FromBigint(0xfffcb933bd6fad37aa2d162d1a594001), - 0x2: u256.FromBigint(0xfff97272373d413259a46990580e213a), - 0x4: u256.FromBigint(0xfff2e50f5f656932ef12357cf3c7fdcc), - 0x8: u256.FromBigint(0xffe5caca7e10e4e61c3624eaa0941cd0), - 0x10: u256.FromBigint(0xffcb9843d60f6159c9db58835c926644), - 0x20: u256.FromBigint(0xff973b41fa98c081472e6896dfb254c0), - 0x40: u256.FromBigint(0xff2ea16466c96a3843ec78b326b52861), - 0x80: u256.FromBigint(0xfe5dee046a99a2a811c461f1969c3053), - 0x100: u256.FromBigint(0xfcbe86c7900a88aedcffc83b479aa3a4), - 0x200: u256.FromBigint(0xf987a7253ac413176f2b074cf7815e54), - 0x400: u256.FromBigint(0xf3392b0822b70005940c7a398e4b70f3), - 0x800: u256.FromBigint(0xe7159475a2c29b7443b29c7fa6e889d9), - 0x1000: u256.FromBigint(0xd097f3bdfd2022b8845ad8f792aa5825), - 0x2000: u256.FromBigint(0xa9f746462d870fdf8a65dc1f90e061e5), - 0x4000: u256.FromBigint(0x70d869a156d2a1b890bb3df62baf32f7), - 0x8000: u256.FromBigint(0x31be135f97d08fd981231505542fcfa6), - 0x10000: u256.FromBigint(0x9aa508b5b7a84e1c677de54f3e99bc9), - 0x20000: u256.FromBigint(0x5d6af8dedb81196699c329225ee604), - 0x40000: u256.FromBigint(0x2216e584f5fa1ea926041bedfe98), - 0x80000: u256.FromBigint(0x48a170391f7dc42444e8fa2), -} - -var binaryLogConsts = [8]*u256.Uint{ - u256.FromBigint(0x0), - u256.FromBigint(0x3), - u256.FromBigint(0xF), - u256.FromBigint(0xFF), - u256.FromBigint(0xFFFF), - u256.FromBigint(0xFFFFFFFF), - u256.FromBigint(0xFFFFFFFFFFFFFFFF), - u256.FromBigint(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF), -} - -func TickMathGetSqrtRatioAtTick(tick int32) *u256.Uint { - absTick := absTick(tick) - require( - absTick <= uint64(consts.MAX_TICK), - ufmt.Sprintf( - "[POOL] tick_math.gno__TickMathGetSqrtRatioAtTick() || absTick(%d) <= consts.MAX_TICK(%d)", - absTick, consts.MAX_TICK, - ), - ) - - ratio := u256.FromBigint(consts.Q128) - for mask, value := range tickRatioMap { - if absTick&mask != 0 { - ratio.Mul(ratio, value) - ratio.Rsh(ratio, 128) - } - } - - if tick > 0 { - ratio.Div(u256.FromBigint(consts.Q96), ratio) - } - - shifted := new(u256.Uint).Rsh(ratio, 32) - remainder := new(u256.Uint).Mod(ratio, u256.NewUint(1<<32)) - - if new(u256.Uint).Add(shifted, remainder).IsZero() { - return shifted - } - - return shifted.Add(shifted, u256.One()) -} - -func TickMathGetTickAtSqrtRatio(sqrtPriceX96 *u256.Uint) int32 { - require( - sqrtPriceX96.Gte(u256.FromBigint(consts.MIN_SQRT_RATIO)) && sqrtPriceX96.Lt(u256.FromBigint(consts.MAX_SQRT_RATIO)), - ufmt.Sprintf("[POOL] sqrtPriceX96(%d) is out of range [%d, %d)", sqrtPriceX96.Dec(), consts.MIN_SQRT_RATIO, consts.MAX_SQRT_RATIO)) - ratio := new(u256.Uint).Lsh(sqrtPriceX96, 32) - - msb, adjustedRatio := findMSB(ratio) - adjustedRatio = adjustRatio(ratio, msb) - - log2 := calculateLog2(msb, adjustedRatio) - tick := getTickValue(log2, sqrtPriceX96) - - return tick -} - -// findMSB computes the MSB (most significant bit) of the given ratio. -func findMSB(ratio *u256.Uint) (uint64, *u256.Uint) { - msb := uint64(0) - - for i := 7; i >= 1; i-- { - f := gt(ratio, binaryLogConsts[i]) << i - msb = msb | f - ratio.Rsh(ratio, uint(f)) - } - - // handle the remaining bits - { - f := gt(ratio, u256.One()) - msb = msb | f - } - - return msb, ratio -} - -// adjustRatio adjusts the given ratio based on the MSB found. -// -// This adjustment ensures that the ratio falls within the specific range. -func adjustRatio(ratio *u256.Uint, msb uint64) *u256.Uint { - if msb >= 128 { - return new(u256.Uint).Rsh(ratio, uint(msb-127)) - } - - return new(u256.Uint).Lsh(ratio, uint(127-msb)) -} - -// calculateLog2 calculates the binary logarith, of the adjusted ratio using a fixed-point arithmetic. -// -// This function iteratively squares the ratio and adjusts the result to compute the log base 2, which will determine the tick value. -func calculateLog2(msb uint64, ratio *u256.Uint) *u256.Int { - log_2 := u256.NewInt(int64(msb - 128)) - log_2.Lsh(log_2, 64) - - for i := 63; i >= 51; i-- { - ratio.Mul(ratio, ratio) - ratio.Rsh(ratio, 127) - f := new(u256.Uint).Rsh(ratio, 128) - log_2.Or(log_2, new(u256.Uint).Lsh(f, uint(i)).Int()) - ratio.Rsh(ratio, uint(f.Uint64())) // XXXXXXXXX possibly overflow - } - - // handle the remaining bits - { - ratio.Mul(ratio, ratio) - ratio.Rsh(ratio, 127) - f := new(u256.Uint).Rsh(ratio, 128) - log_2.Or(log_2, new(u256.Uint).Lsh(f, uint(50)).Int()) - } - - return log_2 -} - -// getTickValue determines the tick value corresponding to a given sqrtPriveX96. -// -// It calculates the upper and lower bounds for each tick, and selects the appropriate tock value -// based on the given sqrtPriceX96. -func getTickValue(log2 *u256.Int, sqrtPriceX96 *u256.Uint) int32 { - // ref: https://github.com/Uniswap/v3-core/issues/500 - // 2^64 / log2 (√1.0001) = 255738958999603826347141 - log_sqrt10001 := new(u256.Int).Mul(log2, u256.FromBigint(255738958999603826347141).Int()) - - // ref: https://ethereum.stackexchange.com/questions/113844/how-does-uniswap-v3s-logarithm-library-tickmath-sol-work/113912#113912 - // 0.010000497 x 2^128 = 3402992956809132418596140100660247210 - tickLow256 := new(u256.Int).Sub(log_sqrt10001, u256.FromBigint(3402992956809132418596140100660247210).Int()) - tickLow256.Rsh(tickLow256, 128) - tickLow := int32(tickLow256.Int64()) // XXXXX: needs to be checked if bound - - // ref: https://ethereum.stackexchange.com/questions/113844/how-does-uniswap-v3s-logarithm-library-tickmath-sol-work/113912#113912 - // 0.856 x 2^128 = 291339464771989622907027621153398088495 - tickHi256 := new(u256.Int).Add(log_sqrt10001, u256.FromBigint(291339464771989622907027621153398088495).Int()) - tickHi256.Rsh(tickHi256, 128) - tickHi := int32(tickHi256.Int64()) // XXXXX: needs to be checked if bound - - var tick int32 - if tickLow == tickHi { - tick = tickLow - } else if TickMathGetSqrtRatioAtTick(tickHi).Lte(sqrtPriceX96) { - tick = tickHi - } else { - tick = tickLow - } - - return tick -} - -func gt(x, y *u256.Uint) uint64 { - if x.Gt(y) { - return 1 - } else { - return 0 - } -} - -func require(condition bool, message string) { - if !condition { - panic(message) - } -} - -func absTick(n int32) uint64 { - if n < 0 { - return uint64(-n) - } - - return uint64(n) -} diff --git a/consts/consts.gno b/consts/consts.gno index 3ab59fdb..3b1eb7fa 100644 --- a/consts/consts.gno +++ b/consts/consts.gno @@ -52,33 +52,38 @@ const ( // NUMBER const ( // calculated by https://mathiasbynens.be/demo/integer-range - MAX_UINT8 bigint = 255 + MAX_UINT8 string = "255" + UINT8_MAX uint8 = 255 - MAX_UINT16 bigint = 65535 + MAX_UINT16 string = "65535" + UINT16_MAX uint16 = 65535 - MAX_UINT32 bigint = 4294967295 + MAX_UINT32 string = "4294967295" + UINT32_MAX uint32 = 4294967295 - MAX_UINT64 bigint = 18446744073709551615 + MAX_UINT64 string = "18446744073709551615" + UINT64_MAX uint64 = 18446744073709551615 - MAX_UINT128 bigint = 340282366920938463463374607431768211455 + MAX_UINT128 string = "340282366920938463463374607431768211455" - MAX_UINT160 bigint = 1461501637330902918203684832716283019655932542975 + MAX_UINT160 string = "1461501637330902918203684832716283019655932542975" - MAX_UINT256 bigint = 115792089237316195423570985008687907853269984665640564039457584007913129639935 + MAX_UINT256 string = "115792089237316195423570985008687907853269984665640564039457584007913129639935" // Tick Related MIN_TICK int32 = -887272 MAX_TICK int32 = 887272 - MIN_SQRT_RATIO bigint = 4295128739 // same as TickMathGetSqrtRatioAtTick(MIN_TICK) - MAX_SQRT_RATIO bigint = 1461446703485210103287273052203988822378723970342 // same as TickMathGetSqrtRatioAtTick(MAX_TICK) + MIN_SQRT_RATIO string = "4295128739" // same as TickMathGetSqrtRatioAtTick(MIN_TICK) + MAX_SQRT_RATIO string = "1461446703485210103287273052203988822378723970342" // same as TickMathGetSqrtRatioAtTick(MAX_TICK) - MIN_PRICE bigint = 4295128740 // MIN_SQRT_RATIO + 1 - MAX_PRICE bigint = 1461446703485210103287273052203988822378723970341 // MAX_SQRT_RATIO - 1 + MIN_PRICE string = "4295128740" // MIN_SQRT_RATIO + 1 + MAX_PRICE string = "1461446703485210103287273052203988822378723970341" // MAX_SQRT_RATIO - 1 // ETC - Q96 bigint = 79228162514264337593543950336 // 2 ** 96 - Q128 bigint = 340282366920938463463374607431768211456 // 2 ** 128 + Q64 string = "18446744073709551616" // 2 ** 64 + Q96 string = "79228162514264337593543950336" // 2 ** 96 + Q128 string = "340282366920938463463374607431768211456" // 2 ** 128 ) diff --git a/packages/big/int256/gno.mod b/packages/big/int256/gno.mod new file mode 100644 index 00000000..727a5b2f --- /dev/null +++ b/packages/big/int256/gno.mod @@ -0,0 +1 @@ +module gno.land/p/big/int256 \ No newline at end of file diff --git a/packages/big/int256/int256.gno b/packages/big/int256/int256.gno new file mode 100644 index 00000000..5ee9ac72 --- /dev/null +++ b/packages/big/int256/int256.gno @@ -0,0 +1,557 @@ +// github.com/mempooler/int256 + +package int256 + +import ( + "gno.land/p/big/uint256" +) + +var one = uint256.NewUint(1) + +type Int struct { + abs *uint256.Uint + neg bool +} + +func Zero() *Int { + return NewInt(0) +} + +func One() *Int { + return NewInt(1) +} + +// Sign returns: +// +// -1 if x < 0 +// 0 if x == 0 +// +1 if x > 0 +func (z *Int) Sign() int { + if len(z.abs) == 0 { + return 0 + } + if z.neg { + return -1 + } + return 1 +} + +func New() *Int { + return &Int{ + abs: new(uint256.Uint), + } +} + +// SetInt64 sets z to x and returns z. +func (z *Int) SetInt64(x int64) *Int { + neg := false + if x < 0 { + neg = true + x = -x + } + if z.abs == nil { + panic("abs is nil") + } + z.abs = z.abs.SetUint64(uint64(x)) + z.neg = neg + return z +} + +// SetUint64 sets z to x and returns z. +func (z *Int) SetUint64(x uint64) *Int { + if z.abs == nil { + panic("abs is nil") + } + z.abs = z.abs.SetUint64(x) + z.neg = false + return z +} + +// NewInt allocates and returns a new Int set to x. +func NewInt(x int64) *Int { + return New().SetInt64(x) +} + +func FromDecimal(s string) (*Int, error) { + return new(Int).SetString(s) +} + +func UnsafeFromDecimal(s string) *Int { + z, err := FromDecimal(s) + if err != nil { + panic(err) + } + return z +} + +// SetString sets s to the value of z and returns z and a boolean indicating success. +func (z *Int) SetString(s string) (*Int, error) { + origin := s + neg := false + // Remove max one leading + + if len(s) > 0 && s[0] == '+' { + neg = false + s = s[1:] + } + + if len(s) > 0 && s[0] == '-' { + neg = true + s = s[1:] + } + var ( + abs *uint256.Uint + err error + ) + abs, err = uint256.FromDecimal(s) + if err != nil { + return nil, err + } + + return &Int{ + abs, + neg, + }, nil +} + +// // setFromScanner implements SetString given an io.ByteScanner. +// // For documentation see comments of SetString. +// func (z *Int) setFromScanner(r io.ByteScanner, base int) (*Int, bool) { +// if _, _, err := z.scan(r, base); err != nil { +// return nil, false +// } +// // entire content must have been consumed +// if _, err := r.ReadByte(); err != io.EOF { +// return nil, false +// } +// return z, true // err == io.EOF => scan consumed all content of r +// } + +func (z *Int) Add(x, y *Int) *Int { + neg := x.neg + + if x.neg == y.neg { + // x + y == x + y + // (-x) + (-y) == -(x + y) + z.abs = z.abs.Add(x.abs, y.abs) + } else { + // x + (-y) == x - y == -(y - x) + // (-x) + y == y - x == -(x - y) + if x.abs.Cmp(y.abs) >= 0 { + z.abs = z.abs.Sub(x.abs, y.abs) + } else { + neg = !neg + z.abs = z.abs.Sub(y.abs, x.abs) + } + } + z.neg = neg // 0 has no sign + return z +} + +// Sub sets z to the difference x-y and returns z. +func (z *Int) Sub(x, y *Int) *Int { + neg := x.neg + if x.neg != y.neg { + // x - (-y) == x + y + // (-x) - y == -(x + y) + z.abs = z.abs.Add(x.abs, y.abs) + } else { + // x - y == x - y == -(y - x) + // (-x) - (-y) == y - x == -(x - y) + if x.abs.Cmp(y.abs) >= 0 { + z.abs = z.abs.Sub(x.abs, y.abs) + } else { + neg = !neg + z.abs = z.abs.Sub(y.abs, x.abs) + } + } + z.neg = neg // 0 has no sign + return z +} + +// Mul sets z to the product x*y and returns z. +func (z *Int) Mul(x, y *Int) *Int { + z.abs = z.abs.Mul(x.abs, y.abs) + z.neg = x.neg != y.neg // 0 has no sign + return z +} + +// Rsh sets z = x >> n and returns z. +func (z *Int) Rsh(x *Int, n uint) *Int { + if !x.neg { + z.abs.Rsh(x.abs, n) + z.neg = x.neg + return z + } + + // REF: https://cs.opensource.google/go/go/+/refs/tags/go1.22.1:src/math/big/int.go;l=1118-1126;drc=d57303e65f00b84b528ee682747dbe1fd3316d30 + t := NewInt(0).Sub(FromUint256(x.abs), NewInt(0)) + t = t.Rsh(t, n) + + _tmp := t.Add(t, NewInt(1)) + z.abs = _tmp.Abs() + z.neg = true + + return z +} + +// Quo sets z to the quotient x/y for y != 0 and returns z. +// If y == 0, a division-by-zero run-time panic occurs. +// Quo implements truncated division (like Go); see QuoRem for more details. +func (z *Int) Quo(x, y *Int) *Int { + z.abs = z.abs.Div(x.abs, y.abs) + z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign + return z +} + +// Rem sets z to the remainder x%y for y != 0 and returns z. +// If y == 0, a division-by-zero run-time panic occurs. +// Rem implements truncated modulus (like Go); see QuoRem for more details. +func (z *Int) Rem(x, y *Int) *Int { + z.abs.Mod(x.abs, y.abs) + z.neg = len(z.abs) > 0 && x.neg // 0 has no sign + return z +} + +// Cmp compares x and y and returns: +// +// -1 if x < y +// 0 if x == y +// +1 if x > y +func (z *Int) Cmp(x *Int) (r int) { + // x cmp y == x cmp y + // x cmp (-y) == x + // (-x) cmp y == y + // (-x) cmp (-y) == -(x cmp y) + switch { + case z == x: + // nothing to do + case z.neg == x.neg: + r = z.abs.Cmp(x.abs) + if z.neg { + r = -r + } + case z.neg: + r = -1 + default: + r = 1 + } + return +} + +func (z *Int) Div(x, y *Int) *Int { + z.abs.Div(x.abs, y.abs) + if x.neg == y.neg { + z.neg = false + } else { + z.neg = true + } + return z +} + +// Lsh sets z = x << n and returns z. +func (z *Int) Lsh(x *Int, n uint) *Int { + z.abs.Lsh(x.abs, n) + z.neg = x.neg + return z +} + +// And sets z = x & y and returns z. +func (z *Int) And(x, y *Int) *Int { + if x.neg == y.neg { + if x.neg { + // (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1) + x1 := new(uint256.Uint).Sub(x.abs, one) + y1 := new(uint256.Uint).Sub(y.abs, one) + z.abs = z.abs.Add(z.abs.Or(x1, y1), one) + z.neg = true // z cannot be zero if x and y are negative + return z + } + + // x & y == x & y + z.abs = z.abs.And(x.abs, y.abs) + z.neg = false + return z + } + + // x.neg != y.neg + // REF: https://cs.opensource.google/go/go/+/refs/tags/go1.22.1:src/math/big/int.go;l=1192-1202;drc=d57303e65f00b84b528ee682747dbe1fd3316d30 + if x.neg { + x, y = y, x // & is symmetric + } + + // x & (-y) == x & ^(y-1) == x &^ (y-1) + y1 := new(uint256.Uint).Sub(y.abs, uint256.One()) + z.abs = z.abs.AndNot(x.abs, y1) + z.neg = false + return z +} + +// Or sets z = x | y and returns z. +func (z *Int) Or(x, y *Int) *Int { + if x.neg == y.neg { + if x.neg { + // (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1) + x1 := new(uint256.Uint).Sub(x.abs, one) + y1 := new(uint256.Uint).Sub(y.abs, one) + z.abs = z.abs.Add(z.abs.And(x1, y1), one) + z.neg = true // z cannot be zero if x and y are negative + return z + } + + // x | y == x | y + z.abs = z.abs.Or(x.abs, y.abs) + z.neg = false + return z + } + + // x.neg != y.neg + if x.neg { + x, y = y, x // | is symmetric + } + + // x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1) + y1 := new(uint256.Uint).Sub(y.abs, one) + z.abs = z.abs.Add(z.abs.AndNot(y1, x.abs), one) + z.neg = true // z cannot be zero if one of x or y is negative + + // // TODO: implement + // big := new(big.Int).Or(x.ToBig(), y.ToBig()) + // z = MustFromBig(big) + return z +} + +// FromUint256 is a convenience-constructor from uint256.Uint. +// Returns a new Int and whether overflow occurred. +// OBS: If u is `nil`, this method returns `nil, false` +func FromUint256(x *uint256.Uint) *Int { + if x == nil { + return nil + } + z := New() + // z := &Int{} + z.SetUint256(x) + return z +} + +// Abs returns |z| +func (z *Int) Abs() *uint256.Uint { + return z.abs.Clone() +} + +// AbsGt returns true if |z| > x, where x is a uint256 +func (z *Int) AbsGt(x *uint256.Uint) bool { + return z.abs.Gt(x) +} + +// AbsLt returns true if |z| < x, where x is a uint256 +func (z *Int) AbsLt(x *uint256.Uint) bool { + return z.abs.Lt(x) +} + +// AddUint256 set z to the sum x + y, where y is a uint256, and returns z +func (z *Int) AddUint256(x *Int, y *uint256.Uint) *Int { + if x.neg { + if x.abs.Gt(y) { + z.abs.Sub(x.abs, y) + z.neg = true + } else { + z.abs.Sub(y, x.abs) + z.neg = false + } + } else { + z.abs.Add(x.abs, y) + z.neg = false + } + return z +} + +// Clone creates a new Int identical to z +func (z *Int) Clone() *Int { + return &Int{z.abs.Clone(), z.neg} +} + +// DivUint256 sets z to the quotient x/y, where y is a uint256, and returns z +// If y == 0, z is set to 0 +func (z *Int) DivUint256(x *Int, y *uint256.Uint) *Int { + z.abs.Div(x.abs, y) + if z.abs.IsZero() { + z.neg = false + } else { + z.neg = x.neg + } + return z +} + +// Eq returns true if z == x +func (z *Int) Eq(x *Int) bool { + return (z.neg == x.neg) && z.abs.Eq(x.abs) +} + +// IsZero returns true if z == 0 +func (z *Int) IsZero() bool { + return z.abs.IsZero() +} + +// IsNeg returns true if z < 0 +func (z *Int) IsNeg() bool { + return z.neg +} + +// Lt returns true if z < x +func (z *Int) Lt(x *Int) bool { + if z.neg { + if x.neg { + return z.abs.Gt(x.abs) + } else { + return true + } + } else { + if x.neg { + return false + } else { + return z.abs.Lt(x.abs) + } + } +} + +// Gt returns true if z > x +func (z *Int) Gt(x *Int) bool { + if z.neg { + if x.neg { + return z.abs.Lt(x.abs) + } else { + return false + } + } else { + if x.neg { + return true + } else { + return z.abs.Gt(x.abs) + } + } +} + +// Mod sets z to the modulus x%y for y != 0 and returns z. +// If y == 0, z is set to 0 (OBS: differs from the big.Int) +func (z *Int) Mod(x, y *Int) *Int { + if x.neg { + z.abs.Div(x.abs, y.abs) + z.abs.Add(z.abs, one) + z.abs.Mul(z.abs, y.abs) + z.abs.Sub(z.abs, x.abs) + z.abs.Mod(z.abs, y.abs) + } else { + z.abs.Mod(x.abs, y.abs) + } + z.neg = false + return z +} + +// MulUint256 sets z to the product x*y, where y is a uint256, and returns z +func (z *Int) MulUint256(x *Int, y *uint256.Uint) *Int { + z.abs.Mul(x.abs, y) + if z.abs.IsZero() { + z.neg = false + } else { + z.neg = x.neg + } + return z +} + +// Neg sets z to -x and returns z.) +func (z *Int) Neg(x *Int) *Int { + z.abs.Set(x.abs) + if z.abs.IsZero() { + z.neg = false + } else { + z.neg = !x.neg + } + return z +} + +// Set sets z to x and returns z. +func (z *Int) Set(x *Int) *Int { + z.abs.Set(x.abs) + z.neg = x.neg + return z +} + +// SetFromUint256 converts a uint256.Uint to Int and sets the value to z. +func (z *Int) SetUint256(x *uint256.Uint) *Int { + z.abs.Set(x) + z.neg = false + return z +} + +// SubUint256 set z to the difference x - y, where y is a uint256, and returns z +func (z *Int) SubUint256(x *Int, y *uint256.Uint) *Int { + if x.neg { + z.abs.Add(x.abs, y) + z.neg = true + } else { + if x.abs.Lt(y) { + z.abs.Sub(y, x.abs) + z.neg = true + } else { + z.abs.Sub(x.abs, y) + z.neg = false + } + } + return z +} + +// Uint64 returns the lower 64-bits of z +func (z *Int) Uint64() uint64 { + return z.abs.Uint64() +} + +// Int64 returns the lower 64-bits of z +func (z *Int) Int64() int64 { + + _abs := z.abs.Clone() + + if z.neg { + return -int64(_abs.Uint64()) + } + return int64(_abs.Uint64()) +} + +// Sets z to the sum x + y, where z and x are uint256s and y is an int256. +func AddDelta(z, x *uint256.Uint, y *Int) { + if y.neg { + z.Sub(x, y.abs) + } else { + z.Add(x, y.abs) + } +} + +// Sets z to the sum x + y, where z and x are uint256s and y is an int256. +func AddDeltaOverflow(z, x *uint256.Uint, y *Int) bool { + var overflow bool + if y.neg { + _, overflow = z.SubOverflow(x, y.abs) + } else { + _, overflow = z.AddOverflow(x, y.abs) + } + return overflow +} + +// NIL TO ZERO +func (z *Int) NilToZero() *Int { + if z == nil { + return NewInt(0) + } + return z +} + +func (z *Int) ToString() string { + if z == nil { + panic("int256: nil pointer") + } + + t := z.abs.Dec() + if z.neg { + return "-" + t + } + return t +} diff --git a/packages/big/int256/int256_test.gno b/packages/big/int256/int256_test.gno new file mode 100644 index 00000000..e5b80598 --- /dev/null +++ b/packages/big/int256/int256_test.gno @@ -0,0 +1 @@ +package int256 diff --git a/packages/big/uint256/bits.gno b/packages/big/uint256/bits.gno new file mode 100644 index 00000000..581ce48a --- /dev/null +++ b/packages/big/uint256/bits.gno @@ -0,0 +1,599 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run make_tables.go + +// Package bits implements bit counting and manipulation +// functions for the predeclared unsigned integer types. +// +// Functions in this package may be implemented directly by +// the compiler, for better performance. For those functions +// the code in this package will not be used. Which +// functions are implemented by the compiler depends on the +// architecture and the Go release. +package uint256 + +const uintSize = 32 << (^uint(0) >> 63) // 32 or 64 + +// UintSize is the size of a uint in bits. +const UintSize = uintSize + +// --- LeadingZeros --- + +// LeadingZeros returns the number of leading zero bits in x; the result is [UintSize] for x == 0. +func LeadingZeros(x uint) int { return UintSize - Len(x) } + +// LeadingZeros8 returns the number of leading zero bits in x; the result is 8 for x == 0. +func LeadingZeros8(x uint8) int { return 8 - Len8(x) } + +// LeadingZeros16 returns the number of leading zero bits in x; the result is 16 for x == 0. +func LeadingZeros16(x uint16) int { return 16 - Len16(x) } + +// LeadingZeros32 returns the number of leading zero bits in x; the result is 32 for x == 0. +func LeadingZeros32(x uint32) int { return 32 - Len32(x) } + +// LeadingZeros64 returns the number of leading zero bits in x; the result is 64 for x == 0. +func LeadingZeros64(x uint64) int { return 64 - Len64(x) } + +// --- TrailingZeros --- + +// See http://supertech.csail.mit.edu/papers/debruijn.pdf +const deBruijn32 = 0x077CB531 + +var deBruijn32tab = [32]byte{ + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9, +} + +const deBruijn64 = 0x03f79d71b4ca8b09 + +var deBruijn64tab = [64]byte{ + 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4, + 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5, + 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11, + 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6, +} + +// TrailingZeros returns the number of trailing zero bits in x; the result is [UintSize] for x == 0. +func TrailingZeros(x uint) int { + if UintSize == 32 { + return TrailingZeros32(uint32(x)) + } + return TrailingZeros64(uint64(x)) +} + +// TrailingZeros8 returns the number of trailing zero bits in x; the result is 8 for x == 0. +func TrailingZeros8(x uint8) int { + return int(ntz8tab[x]) +} + +// TrailingZeros16 returns the number of trailing zero bits in x; the result is 16 for x == 0. +func TrailingZeros16(x uint16) int { + if x == 0 { + return 16 + } + // see comment in TrailingZeros64 + return int(deBruijn32tab[uint32(x&-x)*deBruijn32>>(32-5)]) +} + +// TrailingZeros32 returns the number of trailing zero bits in x; the result is 32 for x == 0. +func TrailingZeros32(x uint32) int { + if x == 0 { + return 32 + } + // see comment in TrailingZeros64 + return int(deBruijn32tab[(x&-x)*deBruijn32>>(32-5)]) +} + +// TrailingZeros64 returns the number of trailing zero bits in x; the result is 64 for x == 0. +func TrailingZeros64(x uint64) int { + if x == 0 { + return 64 + } + // If popcount is fast, replace code below with return popcount(^x & (x - 1)). + // + // x & -x leaves only the right-most bit set in the word. Let k be the + // index of that bit. Since only a single bit is set, the value is two + // to the power of k. Multiplying by a power of two is equivalent to + // left shifting, in this case by k bits. The de Bruijn (64 bit) constant + // is such that all six bit, consecutive substrings are distinct. + // Therefore, if we have a left shifted version of this constant we can + // find by how many bits it was shifted by looking at which six bit + // substring ended up at the top of the word. + // (Knuth, volume 4, section 7.3.1) + return int(deBruijn64tab[(x&-x)*deBruijn64>>(64-6)]) +} + +// --- OnesCount --- + +const m0 = 0x5555555555555555 // 01010101 ... +const m1 = 0x3333333333333333 // 00110011 ... +const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ... +const m3 = 0x00ff00ff00ff00ff // etc. +const m4 = 0x0000ffff0000ffff + +// OnesCount returns the number of one bits ("population count") in x. +func OnesCount(x uint) int { + if UintSize == 32 { + return OnesCount32(uint32(x)) + } + return OnesCount64(uint64(x)) +} + +// OnesCount8 returns the number of one bits ("population count") in x. +func OnesCount8(x uint8) int { + return int(pop8tab[x]) +} + +// OnesCount16 returns the number of one bits ("population count") in x. +func OnesCount16(x uint16) int { + return int(pop8tab[x>>8] + pop8tab[x&0xff]) +} + +// OnesCount32 returns the number of one bits ("population count") in x. +func OnesCount32(x uint32) int { + return int(pop8tab[x>>24] + pop8tab[x>>16&0xff] + pop8tab[x>>8&0xff] + pop8tab[x&0xff]) +} + +// OnesCount64 returns the number of one bits ("population count") in x. +func OnesCount64(x uint64) int { + // Implementation: Parallel summing of adjacent bits. + // See "Hacker's Delight", Chap. 5: Counting Bits. + // The following pattern shows the general approach: + // + // x = x>>1&(m0&m) + x&(m0&m) + // x = x>>2&(m1&m) + x&(m1&m) + // x = x>>4&(m2&m) + x&(m2&m) + // x = x>>8&(m3&m) + x&(m3&m) + // x = x>>16&(m4&m) + x&(m4&m) + // x = x>>32&(m5&m) + x&(m5&m) + // return int(x) + // + // Masking (& operations) can be left away when there's no + // danger that a field's sum will carry over into the next + // field: Since the result cannot be > 64, 8 bits is enough + // and we can ignore the masks for the shifts by 8 and up. + // Per "Hacker's Delight", the first line can be simplified + // more, but it saves at best one instruction, so we leave + // it alone for clarity. + const m = 1<<64 - 1 + x = x>>1&(m0&m) + x&(m0&m) + x = x>>2&(m1&m) + x&(m1&m) + x = (x>>4 + x) & (m2 & m) + x += x >> 8 + x += x >> 16 + x += x >> 32 + return int(x) & (1<<7 - 1) +} + +// --- RotateLeft --- + +// RotateLeft returns the value of x rotated left by (k mod [UintSize]) bits. +// To rotate x right by k bits, call RotateLeft(x, -k). +// +// This function's execution time does not depend on the inputs. +func RotateLeft(x uint, k int) uint { + if UintSize == 32 { + return uint(RotateLeft32(uint32(x), k)) + } + return uint(RotateLeft64(uint64(x), k)) +} + +// RotateLeft8 returns the value of x rotated left by (k mod 8) bits. +// To rotate x right by k bits, call RotateLeft8(x, -k). +// +// This function's execution time does not depend on the inputs. +func RotateLeft8(x uint8, k int) uint8 { + const n = 8 + s := uint(k) & (n - 1) + return x<>(n-s) +} + +// RotateLeft16 returns the value of x rotated left by (k mod 16) bits. +// To rotate x right by k bits, call RotateLeft16(x, -k). +// +// This function's execution time does not depend on the inputs. +func RotateLeft16(x uint16, k int) uint16 { + const n = 16 + s := uint(k) & (n - 1) + return x<>(n-s) +} + +// RotateLeft32 returns the value of x rotated left by (k mod 32) bits. +// To rotate x right by k bits, call RotateLeft32(x, -k). +// +// This function's execution time does not depend on the inputs. +func RotateLeft32(x uint32, k int) uint32 { + const n = 32 + s := uint(k) & (n - 1) + return x<>(n-s) +} + +// RotateLeft64 returns the value of x rotated left by (k mod 64) bits. +// To rotate x right by k bits, call RotateLeft64(x, -k). +// +// This function's execution time does not depend on the inputs. +func RotateLeft64(x uint64, k int) uint64 { + const n = 64 + s := uint(k) & (n - 1) + return x<>(n-s) +} + +// --- Reverse --- + +// Reverse returns the value of x with its bits in reversed order. +func Reverse(x uint) uint { + if UintSize == 32 { + return uint(Reverse32(uint32(x))) + } + return uint(Reverse64(uint64(x))) +} + +// Reverse8 returns the value of x with its bits in reversed order. +func Reverse8(x uint8) uint8 { + return rev8tab[x] +} + +// Reverse16 returns the value of x with its bits in reversed order. +func Reverse16(x uint16) uint16 { + return uint16(rev8tab[x>>8]) | uint16(rev8tab[x&0xff])<<8 +} + +// Reverse32 returns the value of x with its bits in reversed order. +func Reverse32(x uint32) uint32 { + const m = 1<<32 - 1 + x = x>>1&(m0&m) | x&(m0&m)<<1 + x = x>>2&(m1&m) | x&(m1&m)<<2 + x = x>>4&(m2&m) | x&(m2&m)<<4 + return ReverseBytes32(x) +} + +// Reverse64 returns the value of x with its bits in reversed order. +func Reverse64(x uint64) uint64 { + const m = 1<<64 - 1 + x = x>>1&(m0&m) | x&(m0&m)<<1 + x = x>>2&(m1&m) | x&(m1&m)<<2 + x = x>>4&(m2&m) | x&(m2&m)<<4 + return ReverseBytes64(x) +} + +// --- ReverseBytes --- + +// ReverseBytes returns the value of x with its bytes in reversed order. +// +// This function's execution time does not depend on the inputs. +func ReverseBytes(x uint) uint { + if UintSize == 32 { + return uint(ReverseBytes32(uint32(x))) + } + return uint(ReverseBytes64(uint64(x))) +} + +// ReverseBytes16 returns the value of x with its bytes in reversed order. +// +// This function's execution time does not depend on the inputs. +func ReverseBytes16(x uint16) uint16 { + return x>>8 | x<<8 +} + +// ReverseBytes32 returns the value of x with its bytes in reversed order. +// +// This function's execution time does not depend on the inputs. +func ReverseBytes32(x uint32) uint32 { + const m = 1<<32 - 1 + x = x>>8&(m3&m) | x&(m3&m)<<8 + return x>>16 | x<<16 +} + +// ReverseBytes64 returns the value of x with its bytes in reversed order. +// +// This function's execution time does not depend on the inputs. +func ReverseBytes64(x uint64) uint64 { + const m = 1<<64 - 1 + x = x>>8&(m3&m) | x&(m3&m)<<8 + x = x>>16&(m4&m) | x&(m4&m)<<16 + return x>>32 | x<<32 +} + +// --- Len --- + +// Len returns the minimum number of bits required to represent x; the result is 0 for x == 0. +func Len(x uint) int { + if UintSize == 32 { + return Len32(uint32(x)) + } + return Len64(uint64(x)) +} + +// Len8 returns the minimum number of bits required to represent x; the result is 0 for x == 0. +func Len8(x uint8) int { + return int(len8tab[x]) +} + +// Len16 returns the minimum number of bits required to represent x; the result is 0 for x == 0. +func Len16(x uint16) (n int) { + if x >= 1<<8 { + x >>= 8 + n = 8 + } + return n + int(len8tab[x]) +} + +// Len32 returns the minimum number of bits required to represent x; the result is 0 for x == 0. +func Len32(x uint32) (n int) { + if x >= 1<<16 { + x >>= 16 + n = 16 + } + if x >= 1<<8 { + x >>= 8 + n += 8 + } + return n + int(len8tab[x]) +} + +// Len64 returns the minimum number of bits required to represent x; the result is 0 for x == 0. +func Len64(x uint64) (n int) { + if x >= 1<<32 { + x >>= 32 + n = 32 + } + if x >= 1<<16 { + x >>= 16 + n += 16 + } + if x >= 1<<8 { + x >>= 8 + n += 8 + } + return n + int(len8tab[x]) +} + +// --- Add with carry --- + +// Add returns the sum with carry of x, y and carry: sum = x + y + carry. +// The carry input must be 0 or 1; otherwise the behavior is undefined. +// The carryOut output is guaranteed to be 0 or 1. +// +// This function's execution time does not depend on the inputs. +func Add(x, y, carry uint) (sum, carryOut uint) { + if UintSize == 32 { + s32, c32 := Add32(uint32(x), uint32(y), uint32(carry)) + return uint(s32), uint(c32) + } + s64, c64 := Add64(uint64(x), uint64(y), uint64(carry)) + return uint(s64), uint(c64) +} + +// Add32 returns the sum with carry of x, y and carry: sum = x + y + carry. +// The carry input must be 0 or 1; otherwise the behavior is undefined. +// The carryOut output is guaranteed to be 0 or 1. +// +// This function's execution time does not depend on the inputs. +func Add32(x, y, carry uint32) (sum, carryOut uint32) { + sum64 := uint64(x) + uint64(y) + uint64(carry) + sum = uint32(sum64) + carryOut = uint32(sum64 >> 32) + return +} + +// Add64 returns the sum with carry of x, y and carry: sum = x + y + carry. +// The carry input must be 0 or 1; otherwise the behavior is undefined. +// The carryOut output is guaranteed to be 0 or 1. +// +// This function's execution time does not depend on the inputs. +func Add64(x, y, carry uint64) (sum, carryOut uint64) { + sum = x + y + carry + // The sum will overflow if both top bits are set (x & y) or if one of them + // is (x | y), and a carry from the lower place happened. If such a carry + // happens, the top bit will be 1 + 0 + 1 = 0 (&^ sum). + carryOut = ((x & y) | ((x | y) &^ sum)) >> 63 + return +} + +// --- Subtract with borrow --- + +// Sub returns the difference of x, y and borrow: diff = x - y - borrow. +// The borrow input must be 0 or 1; otherwise the behavior is undefined. +// The borrowOut output is guaranteed to be 0 or 1. +// +// This function's execution time does not depend on the inputs. +func Sub(x, y, borrow uint) (diff, borrowOut uint) { + if UintSize == 32 { + d32, b32 := Sub32(uint32(x), uint32(y), uint32(borrow)) + return uint(d32), uint(b32) + } + d64, b64 := Sub64(uint64(x), uint64(y), uint64(borrow)) + return uint(d64), uint(b64) +} + +// Sub32 returns the difference of x, y and borrow, diff = x - y - borrow. +// The borrow input must be 0 or 1; otherwise the behavior is undefined. +// The borrowOut output is guaranteed to be 0 or 1. +// +// This function's execution time does not depend on the inputs. +func Sub32(x, y, borrow uint32) (diff, borrowOut uint32) { + diff = x - y - borrow + // The difference will underflow if the top bit of x is not set and the top + // bit of y is set (^x & y) or if they are the same (^(x ^ y)) and a borrow + // from the lower place happens. If that borrow happens, the result will be + // 1 - 1 - 1 = 0 - 0 - 1 = 1 (& diff). + borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 31 + return +} + +// Sub64 returns the difference of x, y and borrow: diff = x - y - borrow. +// The borrow input must be 0 or 1; otherwise the behavior is undefined. +// The borrowOut output is guaranteed to be 0 or 1. +// +// This function's execution time does not depend on the inputs. +func Sub64(x, y, borrow uint64) (diff, borrowOut uint64) { + diff = x - y - borrow + // See Sub32 for the bit logic. + borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63 + return +} + +// --- Full-width multiply --- + +// Mul returns the full-width product of x and y: (hi, lo) = x * y +// with the product bits' upper half returned in hi and the lower +// half returned in lo. +// +// This function's execution time does not depend on the inputs. +func Mul(x, y uint) (hi, lo uint) { + if UintSize == 32 { + h, l := Mul32(uint32(x), uint32(y)) + return uint(h), uint(l) + } + h, l := Mul64(uint64(x), uint64(y)) + return uint(h), uint(l) +} + +// Mul32 returns the 64-bit product of x and y: (hi, lo) = x * y +// with the product bits' upper half returned in hi and the lower +// half returned in lo. +// +// This function's execution time does not depend on the inputs. +func Mul32(x, y uint32) (hi, lo uint32) { + tmp := uint64(x) * uint64(y) + hi, lo = uint32(tmp>>32), uint32(tmp) + return +} + +// Mul64 returns the 128-bit product of x and y: (hi, lo) = x * y +// with the product bits' upper half returned in hi and the lower +// half returned in lo. +// +// This function's execution time does not depend on the inputs. +func Mul64(x, y uint64) (hi, lo uint64) { + const mask32 = 1<<32 - 1 + x0 := x & mask32 + x1 := x >> 32 + y0 := y & mask32 + y1 := y >> 32 + w0 := x0 * y0 + t := x1*y0 + w0>>32 + w1 := t & mask32 + w2 := t >> 32 + w1 += x0 * y1 + hi = x1*y1 + w2 + w1>>32 + lo = x * y + return +} + +// --- Full-width divide --- + +// Div returns the quotient and remainder of (hi, lo) divided by y: +// quo = (hi, lo)/y, rem = (hi, lo)%y with the dividend bits' upper +// half in parameter hi and the lower half in parameter lo. +// Div panics for y == 0 (division by zero) or y <= hi (quotient overflow). +func Div(hi, lo, y uint) (quo, rem uint) { + if UintSize == 32 { + q, r := Div32(uint32(hi), uint32(lo), uint32(y)) + return uint(q), uint(r) + } + q, r := Div64(uint64(hi), uint64(lo), uint64(y)) + return uint(q), uint(r) +} + +// Div32 returns the quotient and remainder of (hi, lo) divided by y: +// quo = (hi, lo)/y, rem = (hi, lo)%y with the dividend bits' upper +// half in parameter hi and the lower half in parameter lo. +// Div32 panics for y == 0 (division by zero) or y <= hi (quotient overflow). +func Div32(hi, lo, y uint32) (quo, rem uint32) { + if y != 0 && y <= hi { + panic(overflowError) + } + z := uint64(hi)<<32 | uint64(lo) + quo, rem = uint32(z/uint64(y)), uint32(z%uint64(y)) + return +} + +// Div64 returns the quotient and remainder of (hi, lo) divided by y: +// quo = (hi, lo)/y, rem = (hi, lo)%y with the dividend bits' upper +// half in parameter hi and the lower half in parameter lo. +// Div64 panics for y == 0 (division by zero) or y <= hi (quotient overflow). +func Div64(hi, lo, y uint64) (quo, rem uint64) { + if y == 0 { + panic(divideError) + } + if y <= hi { + panic(overflowError) + } + + // If high part is zero, we can directly return the results. + if hi == 0 { + return lo / y, lo % y + } + + s := uint(LeadingZeros64(y)) + y <<= s + + const ( + two32 = 1 << 32 + mask32 = two32 - 1 + ) + yn1 := y >> 32 + yn0 := y & mask32 + un32 := hi<>(64-s) + un10 := lo << s + un1 := un10 >> 32 + un0 := un10 & mask32 + q1 := un32 / yn1 + rhat := un32 - q1*yn1 + + for q1 >= two32 || q1*yn0 > two32*rhat+un1 { + q1-- + rhat += yn1 + if rhat >= two32 { + break + } + } + + un21 := un32*two32 + un1 - q1*y + q0 := un21 / yn1 + rhat = un21 - q0*yn1 + + for q0 >= two32 || q0*yn0 > two32*rhat+un0 { + q0-- + rhat += yn1 + if rhat >= two32 { + break + } + } + + return q1*two32 + q0, (un21*two32 + un0 - q0*y) >> s +} + +// Rem returns the remainder of (hi, lo) divided by y. Rem panics for +// y == 0 (division by zero) but, unlike Div, it doesn't panic on a +// quotient overflow. +func Rem(hi, lo, y uint) uint { + if UintSize == 32 { + return uint(Rem32(uint32(hi), uint32(lo), uint32(y))) + } + return uint(Rem64(uint64(hi), uint64(lo), uint64(y))) +} + +// Rem32 returns the remainder of (hi, lo) divided by y. Rem32 panics +// for y == 0 (division by zero) but, unlike [Div32], it doesn't panic +// on a quotient overflow. +func Rem32(hi, lo, y uint32) uint32 { + return uint32((uint64(hi)<<32 | uint64(lo)) % uint64(y)) +} + +// Rem64 returns the remainder of (hi, lo) divided by y. Rem64 panics +// for y == 0 (division by zero) but, unlike [Div64], it doesn't panic +// on a quotient overflow. +func Rem64(hi, lo, y uint64) uint64 { + // We scale down hi so that hi < y, then use Div64 to compute the + // rem with the guarantee that it won't panic on quotient overflow. + // Given that + // hi ≡ hi%y (mod y) + // we have + // hi<<64 + lo ≡ (hi%y)<<64 + lo (mod y) + _, rem := Div64(hi%y, lo, y) + return rem +} diff --git a/packages/big/uint256/bits_errors.gno b/packages/big/uint256/bits_errors.gno new file mode 100644 index 00000000..17b57b69 --- /dev/null +++ b/packages/big/uint256/bits_errors.gno @@ -0,0 +1,17 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !compiler_bootstrap + +package uint256 + +import ( + "errors" +) + +//go:linkname overflowError runtime.overflowError +var overflowError error = errors.New("u256: integer overflow") + +//go:linkname divideError runtime.divideError +var divideError error = errors.New("u256: integer divide by zero") diff --git a/packages/big/uint256/bits_table.gno b/packages/big/uint256/bits_table.gno new file mode 100644 index 00000000..7cb2081f --- /dev/null +++ b/packages/big/uint256/bits_table.gno @@ -0,0 +1,79 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated by go run make_tables.go. DO NOT EDIT. + +package uint256 + +const ntz8tab = "" + + "\x08\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x06\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x07\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x06\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + + "\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" + +const pop8tab = "" + + "\x00\x01\x01\x02\x01\x02\x02\x03\x01\x02\x02\x03\x02\x03\x03\x04" + + "\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" + + "\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" + + "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + + "\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" + + "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + + "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + + "\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" + + "\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" + + "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + + "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + + "\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" + + "\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" + + "\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" + + "\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" + + "\x04\x05\x05\x06\x05\x06\x06\x07\x05\x06\x06\x07\x06\x07\x07\x08" + +const rev8tab = "" + + "\x00\x80\x40\xc0\x20\xa0\x60\xe0\x10\x90\x50\xd0\x30\xb0\x70\xf0" + + "\x08\x88\x48\xc8\x28\xa8\x68\xe8\x18\x98\x58\xd8\x38\xb8\x78\xf8" + + "\x04\x84\x44\xc4\x24\xa4\x64\xe4\x14\x94\x54\xd4\x34\xb4\x74\xf4" + + "\x0c\x8c\x4c\xcc\x2c\xac\x6c\xec\x1c\x9c\x5c\xdc\x3c\xbc\x7c\xfc" + + "\x02\x82\x42\xc2\x22\xa2\x62\xe2\x12\x92\x52\xd2\x32\xb2\x72\xf2" + + "\x0a\x8a\x4a\xca\x2a\xaa\x6a\xea\x1a\x9a\x5a\xda\x3a\xba\x7a\xfa" + + "\x06\x86\x46\xc6\x26\xa6\x66\xe6\x16\x96\x56\xd6\x36\xb6\x76\xf6" + + "\x0e\x8e\x4e\xce\x2e\xae\x6e\xee\x1e\x9e\x5e\xde\x3e\xbe\x7e\xfe" + + "\x01\x81\x41\xc1\x21\xa1\x61\xe1\x11\x91\x51\xd1\x31\xb1\x71\xf1" + + "\x09\x89\x49\xc9\x29\xa9\x69\xe9\x19\x99\x59\xd9\x39\xb9\x79\xf9" + + "\x05\x85\x45\xc5\x25\xa5\x65\xe5\x15\x95\x55\xd5\x35\xb5\x75\xf5" + + "\x0d\x8d\x4d\xcd\x2d\xad\x6d\xed\x1d\x9d\x5d\xdd\x3d\xbd\x7d\xfd" + + "\x03\x83\x43\xc3\x23\xa3\x63\xe3\x13\x93\x53\xd3\x33\xb3\x73\xf3" + + "\x0b\x8b\x4b\xcb\x2b\xab\x6b\xeb\x1b\x9b\x5b\xdb\x3b\xbb\x7b\xfb" + + "\x07\x87\x47\xc7\x27\xa7\x67\xe7\x17\x97\x57\xd7\x37\xb7\x77\xf7" + + "\x0f\x8f\x4f\xcf\x2f\xaf\x6f\xef\x1f\x9f\x5f\xdf\x3f\xbf\x7f\xff" + +const len8tab = "" + + "\x00\x01\x02\x02\x03\x03\x03\x03\x04\x04\x04\x04\x04\x04\x04\x04" + + "\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05" + + "\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06" + + "\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06" + + "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + "\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" + + "\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08" \ No newline at end of file diff --git a/packages/big/uint256/gno.mod b/packages/big/uint256/gno.mod new file mode 100644 index 00000000..39a64d3f --- /dev/null +++ b/packages/big/uint256/gno.mod @@ -0,0 +1 @@ +module gno.land/p/big/uint256 \ No newline at end of file diff --git a/packages/big/uint256/mod.gno b/packages/big/uint256/mod.gno new file mode 100644 index 00000000..16f312ea --- /dev/null +++ b/packages/big/uint256/mod.gno @@ -0,0 +1,629 @@ +// uint256: Fixed size 256-bit math library +// Copyright 2021 uint256 Authors +// SPDX-License-Identifier: BSD-3-Clause + +package uint256 + +import ( + "math/bits" +) + +// Some utility functions + +func leadingZeros(x *Uint) (z int) { + var t int + z = bits.LeadingZeros64(x.arr[3]) + t = bits.LeadingZeros64(x.arr[2]) + if z == 64 { + z = t + 64 + } + t = bits.LeadingZeros64(x.arr[1]) + if z == 128 { + z = t + 128 + } + t = bits.LeadingZeros64(x.arr[0]) + if z == 192 { + z = t + 192 + } + return z +} + +// Reciprocal computes a 320-bit value representing 1/m +// +// Notes: +// - specialized for m.arr[3] != 0, hence limited to 2^192 <= m < 2^256 +// - returns zero if m.arr[3] == 0 +// - starts with a 32-bit division, refines with newton-raphson iterations +func Reciprocal(m *Uint) (mu [5]uint64) { + + if m.arr[3] == 0 { + return mu + } + + s := bits.LeadingZeros64(m.arr[3]) // Replace with leadingZeros(m) for general case + p := 255 - s // floor(log_2(m)), m>0 + + // 0 or a power of 2? + + // Check if at least one bit is set in m.arr[2], m.arr[1] or m.arr[0], + // or at least two bits in m.arr[3] + + if m.arr[0]|m.arr[1]|m.arr[2]|(m.arr[3]&(m.arr[3]-1)) == 0 { + + mu[4] = ^uint64(0) >> uint(p&63) + mu[3] = ^uint64(0) + mu[2] = ^uint64(0) + mu[1] = ^uint64(0) + mu[0] = ^uint64(0) + + return mu + } + + // Maximise division precision by left-aligning divisor + + var ( + y Uint // left-aligned copy of m + r0 uint32 // estimate of 2^31/y + ) + + y.Lsh(m, uint(s)) // 1/2 < y < 1 + + // Extract most significant 32 bits + + yh := uint32(y.arr[3] >> 32) + + if yh == 0x80000000 { // Avoid overflow in division + r0 = 0xffffffff + } else { + r0, _ = bits.Div32(0x80000000, 0, yh) + } + + // First iteration: 32 -> 64 + + t1 := uint64(r0) // 2^31/y + t1 *= t1 // 2^62/y^2 + t1, _ = bits.Mul64(t1, y.arr[3]) // 2^62/y^2 * 2^64/y / 2^64 = 2^62/y + + r1 := uint64(r0) << 32 // 2^63/y + r1 -= t1 // 2^63/y - 2^62/y = 2^62/y + r1 *= 2 // 2^63/y + + if (r1 | (y.arr[3] << 1)) == 0 { + r1 = ^uint64(0) + } + + // Second iteration: 64 -> 128 + + // square: 2^126/y^2 + a2h, a2l := bits.Mul64(r1, r1) + + // multiply by y: e2h:e2l:b2h = 2^126/y^2 * 2^128/y / 2^128 = 2^126/y + b2h, _ := bits.Mul64(a2l, y.arr[2]) + c2h, c2l := bits.Mul64(a2l, y.arr[3]) + d2h, d2l := bits.Mul64(a2h, y.arr[2]) + e2h, e2l := bits.Mul64(a2h, y.arr[3]) + + b2h, c := bits.Add64(b2h, c2l, 0) + e2l, c = bits.Add64(e2l, c2h, c) + e2h, _ = bits.Add64(e2h, 0, c) + + _, c = bits.Add64(b2h, d2l, 0) + e2l, c = bits.Add64(e2l, d2h, c) + e2h, _ = bits.Add64(e2h, 0, c) + + // subtract: t2h:t2l = 2^127/y - 2^126/y = 2^126/y + t2l, b := bits.Sub64(0, e2l, 0) + t2h, _ := bits.Sub64(r1, e2h, b) + + // double: r2h:r2l = 2^127/y + r2l, c := bits.Add64(t2l, t2l, 0) + r2h, _ := bits.Add64(t2h, t2h, c) + + if (r2h | r2l | (y.arr[3] << 1)) == 0 { + r2h = ^uint64(0) + r2l = ^uint64(0) + } + + // Third iteration: 128 -> 192 + + // square r2 (keep 256 bits): 2^190/y^2 + a3h, a3l := bits.Mul64(r2l, r2l) + b3h, b3l := bits.Mul64(r2l, r2h) + c3h, c3l := bits.Mul64(r2h, r2h) + + a3h, c = bits.Add64(a3h, b3l, 0) + c3l, c = bits.Add64(c3l, b3h, c) + c3h, _ = bits.Add64(c3h, 0, c) + + a3h, c = bits.Add64(a3h, b3l, 0) + c3l, c = bits.Add64(c3l, b3h, c) + c3h, _ = bits.Add64(c3h, 0, c) + + // multiply by y: q = 2^190/y^2 * 2^192/y / 2^192 = 2^190/y + + x0 := a3l + x1 := a3h + x2 := c3l + x3 := c3h + + var q0, q1, q2, q3, q4, t0 uint64 + + q0, _ = bits.Mul64(x2, y.arr[0]) + q1, t0 = bits.Mul64(x3, y.arr[0]) + q0, c = bits.Add64(q0, t0, 0) + q1, _ = bits.Add64(q1, 0, c) + + t1, _ = bits.Mul64(x1, y.arr[1]) + q0, c = bits.Add64(q0, t1, 0) + q2, t0 = bits.Mul64(x3, y.arr[1]) + q1, c = bits.Add64(q1, t0, c) + q2, _ = bits.Add64(q2, 0, c) + + t1, t0 = bits.Mul64(x2, y.arr[1]) + q0, c = bits.Add64(q0, t0, 0) + q1, c = bits.Add64(q1, t1, c) + q2, _ = bits.Add64(q2, 0, c) + + t1, t0 = bits.Mul64(x1, y.arr[2]) + q0, c = bits.Add64(q0, t0, 0) + q1, c = bits.Add64(q1, t1, c) + q3, t0 = bits.Mul64(x3, y.arr[2]) + q2, c = bits.Add64(q2, t0, c) + q3, _ = bits.Add64(q3, 0, c) + + t1, _ = bits.Mul64(x0, y.arr[2]) + q0, c = bits.Add64(q0, t1, 0) + t1, t0 = bits.Mul64(x2, y.arr[2]) + q1, c = bits.Add64(q1, t0, c) + q2, c = bits.Add64(q2, t1, c) + q3, _ = bits.Add64(q3, 0, c) + + t1, t0 = bits.Mul64(x1, y.arr[3]) + q1, c = bits.Add64(q1, t0, 0) + q2, c = bits.Add64(q2, t1, c) + q4, t0 = bits.Mul64(x3, y.arr[3]) + q3, c = bits.Add64(q3, t0, c) + q4, _ = bits.Add64(q4, 0, c) + + t1, t0 = bits.Mul64(x0, y.arr[3]) + q0, c = bits.Add64(q0, t0, 0) + q1, c = bits.Add64(q1, t1, c) + t1, t0 = bits.Mul64(x2, y.arr[3]) + q2, c = bits.Add64(q2, t0, c) + q3, c = bits.Add64(q3, t1, c) + q4, _ = bits.Add64(q4, 0, c) + + // subtract: t3 = 2^191/y - 2^190/y = 2^190/y + _, b = bits.Sub64(0, q0, 0) + _, b = bits.Sub64(0, q1, b) + t3l, b := bits.Sub64(0, q2, b) + t3m, b := bits.Sub64(r2l, q3, b) + t3h, _ := bits.Sub64(r2h, q4, b) + + // double: r3 = 2^191/y + r3l, c := bits.Add64(t3l, t3l, 0) + r3m, c := bits.Add64(t3m, t3m, c) + r3h, _ := bits.Add64(t3h, t3h, c) + + // Fourth iteration: 192 -> 320 + + // square r3 + + a4h, a4l := bits.Mul64(r3l, r3l) + b4h, b4l := bits.Mul64(r3l, r3m) + c4h, c4l := bits.Mul64(r3l, r3h) + d4h, d4l := bits.Mul64(r3m, r3m) + e4h, e4l := bits.Mul64(r3m, r3h) + f4h, f4l := bits.Mul64(r3h, r3h) + + b4h, c = bits.Add64(b4h, c4l, 0) + e4l, c = bits.Add64(e4l, c4h, c) + e4h, _ = bits.Add64(e4h, 0, c) + + a4h, c = bits.Add64(a4h, b4l, 0) + d4l, c = bits.Add64(d4l, b4h, c) + d4h, c = bits.Add64(d4h, e4l, c) + f4l, c = bits.Add64(f4l, e4h, c) + f4h, _ = bits.Add64(f4h, 0, c) + + a4h, c = bits.Add64(a4h, b4l, 0) + d4l, c = bits.Add64(d4l, b4h, c) + d4h, c = bits.Add64(d4h, e4l, c) + f4l, c = bits.Add64(f4l, e4h, c) + f4h, _ = bits.Add64(f4h, 0, c) + + // multiply by y + + x1, x0 = bits.Mul64(d4h, y.arr[0]) + x3, x2 = bits.Mul64(f4h, y.arr[0]) + t1, t0 = bits.Mul64(f4l, y.arr[0]) + x1, c = bits.Add64(x1, t0, 0) + x2, c = bits.Add64(x2, t1, c) + x3, _ = bits.Add64(x3, 0, c) + + t1, t0 = bits.Mul64(d4h, y.arr[1]) + x1, c = bits.Add64(x1, t0, 0) + x2, c = bits.Add64(x2, t1, c) + x4, t0 := bits.Mul64(f4h, y.arr[1]) + x3, c = bits.Add64(x3, t0, c) + x4, _ = bits.Add64(x4, 0, c) + t1, t0 = bits.Mul64(d4l, y.arr[1]) + x0, c = bits.Add64(x0, t0, 0) + x1, c = bits.Add64(x1, t1, c) + t1, t0 = bits.Mul64(f4l, y.arr[1]) + x2, c = bits.Add64(x2, t0, c) + x3, c = bits.Add64(x3, t1, c) + x4, _ = bits.Add64(x4, 0, c) + + t1, t0 = bits.Mul64(a4h, y.arr[2]) + x0, c = bits.Add64(x0, t0, 0) + x1, c = bits.Add64(x1, t1, c) + t1, t0 = bits.Mul64(d4h, y.arr[2]) + x2, c = bits.Add64(x2, t0, c) + x3, c = bits.Add64(x3, t1, c) + x5, t0 := bits.Mul64(f4h, y.arr[2]) + x4, c = bits.Add64(x4, t0, c) + x5, _ = bits.Add64(x5, 0, c) + t1, t0 = bits.Mul64(d4l, y.arr[2]) + x1, c = bits.Add64(x1, t0, 0) + x2, c = bits.Add64(x2, t1, c) + t1, t0 = bits.Mul64(f4l, y.arr[2]) + x3, c = bits.Add64(x3, t0, c) + x4, c = bits.Add64(x4, t1, c) + x5, _ = bits.Add64(x5, 0, c) + + t1, t0 = bits.Mul64(a4h, y.arr[3]) + x1, c = bits.Add64(x1, t0, 0) + x2, c = bits.Add64(x2, t1, c) + t1, t0 = bits.Mul64(d4h, y.arr[3]) + x3, c = bits.Add64(x3, t0, c) + x4, c = bits.Add64(x4, t1, c) + x6, t0 := bits.Mul64(f4h, y.arr[3]) + x5, c = bits.Add64(x5, t0, c) + x6, _ = bits.Add64(x6, 0, c) + t1, t0 = bits.Mul64(a4l, y.arr[3]) + x0, c = bits.Add64(x0, t0, 0) + x1, c = bits.Add64(x1, t1, c) + t1, t0 = bits.Mul64(d4l, y.arr[3]) + x2, c = bits.Add64(x2, t0, c) + x3, c = bits.Add64(x3, t1, c) + t1, t0 = bits.Mul64(f4l, y.arr[3]) + x4, c = bits.Add64(x4, t0, c) + x5, c = bits.Add64(x5, t1, c) + x6, _ = bits.Add64(x6, 0, c) + + // subtract + _, b = bits.Sub64(0, x0, 0) + _, b = bits.Sub64(0, x1, b) + r4l, b := bits.Sub64(0, x2, b) + r4k, b := bits.Sub64(0, x3, b) + r4j, b := bits.Sub64(r3l, x4, b) + r4i, b := bits.Sub64(r3m, x5, b) + r4h, _ := bits.Sub64(r3h, x6, b) + + // Multiply candidate for 1/4y by y, with full precision + + x0 = r4l + x1 = r4k + x2 = r4j + x3 = r4i + x4 = r4h + + q1, q0 = bits.Mul64(x0, y.arr[0]) + q3, q2 = bits.Mul64(x2, y.arr[0]) + q5, q4 := bits.Mul64(x4, y.arr[0]) + + t1, t0 = bits.Mul64(x1, y.arr[0]) + q1, c = bits.Add64(q1, t0, 0) + q2, c = bits.Add64(q2, t1, c) + t1, t0 = bits.Mul64(x3, y.arr[0]) + q3, c = bits.Add64(q3, t0, c) + q4, c = bits.Add64(q4, t1, c) + q5, _ = bits.Add64(q5, 0, c) + + t1, t0 = bits.Mul64(x0, y.arr[1]) + q1, c = bits.Add64(q1, t0, 0) + q2, c = bits.Add64(q2, t1, c) + t1, t0 = bits.Mul64(x2, y.arr[1]) + q3, c = bits.Add64(q3, t0, c) + q4, c = bits.Add64(q4, t1, c) + q6, t0 := bits.Mul64(x4, y.arr[1]) + q5, c = bits.Add64(q5, t0, c) + q6, _ = bits.Add64(q6, 0, c) + + t1, t0 = bits.Mul64(x1, y.arr[1]) + q2, c = bits.Add64(q2, t0, 0) + q3, c = bits.Add64(q3, t1, c) + t1, t0 = bits.Mul64(x3, y.arr[1]) + q4, c = bits.Add64(q4, t0, c) + q5, c = bits.Add64(q5, t1, c) + q6, _ = bits.Add64(q6, 0, c) + + t1, t0 = bits.Mul64(x0, y.arr[2]) + q2, c = bits.Add64(q2, t0, 0) + q3, c = bits.Add64(q3, t1, c) + t1, t0 = bits.Mul64(x2, y.arr[2]) + q4, c = bits.Add64(q4, t0, c) + q5, c = bits.Add64(q5, t1, c) + q7, t0 := bits.Mul64(x4, y.arr[2]) + q6, c = bits.Add64(q6, t0, c) + q7, _ = bits.Add64(q7, 0, c) + + t1, t0 = bits.Mul64(x1, y.arr[2]) + q3, c = bits.Add64(q3, t0, 0) + q4, c = bits.Add64(q4, t1, c) + t1, t0 = bits.Mul64(x3, y.arr[2]) + q5, c = bits.Add64(q5, t0, c) + q6, c = bits.Add64(q6, t1, c) + q7, _ = bits.Add64(q7, 0, c) + + t1, t0 = bits.Mul64(x0, y.arr[3]) + q3, c = bits.Add64(q3, t0, 0) + q4, c = bits.Add64(q4, t1, c) + t1, t0 = bits.Mul64(x2, y.arr[3]) + q5, c = bits.Add64(q5, t0, c) + q6, c = bits.Add64(q6, t1, c) + q8, t0 := bits.Mul64(x4, y.arr[3]) + q7, c = bits.Add64(q7, t0, c) + q8, _ = bits.Add64(q8, 0, c) + + t1, t0 = bits.Mul64(x1, y.arr[3]) + q4, c = bits.Add64(q4, t0, 0) + q5, c = bits.Add64(q5, t1, c) + t1, t0 = bits.Mul64(x3, y.arr[3]) + q6, c = bits.Add64(q6, t0, c) + q7, c = bits.Add64(q7, t1, c) + q8, _ = bits.Add64(q8, 0, c) + + // Final adjustment + + // subtract q from 1/4 + _, b = bits.Sub64(0, q0, 0) + _, b = bits.Sub64(0, q1, b) + _, b = bits.Sub64(0, q2, b) + _, b = bits.Sub64(0, q3, b) + _, b = bits.Sub64(0, q4, b) + _, b = bits.Sub64(0, q5, b) + _, b = bits.Sub64(0, q6, b) + _, b = bits.Sub64(0, q7, b) + _, b = bits.Sub64(uint64(1)<<62, q8, b) + + // decrement the result + x0, t := bits.Sub64(r4l, 1, 0) + x1, t = bits.Sub64(r4k, 0, t) + x2, t = bits.Sub64(r4j, 0, t) + x3, t = bits.Sub64(r4i, 0, t) + x4, _ = bits.Sub64(r4h, 0, t) + + // commit the decrement if the subtraction underflowed (reciprocal was too large) + if b != 0 { + r4h, r4i, r4j, r4k, r4l = x4, x3, x2, x1, x0 + } + + // Shift to correct bit alignment, truncating excess bits + + p = (p & 63) - 1 + + x0, c = bits.Add64(r4l, r4l, 0) + x1, c = bits.Add64(r4k, r4k, c) + x2, c = bits.Add64(r4j, r4j, c) + x3, c = bits.Add64(r4i, r4i, c) + x4, _ = bits.Add64(r4h, r4h, c) + + if p < 0 { + r4h, r4i, r4j, r4k, r4l = x4, x3, x2, x1, x0 + p = 0 // avoid negative shift below + } + + { + r := uint(p) // right shift + l := uint(64 - r) // left shift + + x0 = (r4l >> r) | (r4k << l) + x1 = (r4k >> r) | (r4j << l) + x2 = (r4j >> r) | (r4i << l) + x3 = (r4i >> r) | (r4h << l) + x4 = (r4h >> r) + } + + if p > 0 { + r4h, r4i, r4j, r4k, r4l = x4, x3, x2, x1, x0 + } + + mu[0] = r4l + mu[1] = r4k + mu[2] = r4j + mu[3] = r4i + mu[4] = r4h + + return mu +} + +// reduce4 computes the least non-negative residue of x modulo m +// +// requires a four-word modulus (m.arr[3] > 1) and its inverse (mu) +func reduce4(x [8]uint64, m *Uint, mu [5]uint64) (z Uint) { + + // NB: Most variable names in the comments match the pseudocode for + // Barrett reduction in the Handbook of Applied Cryptography. + + // q1 = x/2^192 + + x0 := x[3] + x1 := x[4] + x2 := x[5] + x3 := x[6] + x4 := x[7] + + // q2 = q1 * mu; q3 = q2 / 2^320 + + var q0, q1, q2, q3, q4, q5, t0, t1, c uint64 + + q0, _ = bits.Mul64(x3, mu[0]) + q1, t0 = bits.Mul64(x4, mu[0]) + q0, c = bits.Add64(q0, t0, 0) + q1, _ = bits.Add64(q1, 0, c) + + t1, _ = bits.Mul64(x2, mu[1]) + q0, c = bits.Add64(q0, t1, 0) + q2, t0 = bits.Mul64(x4, mu[1]) + q1, c = bits.Add64(q1, t0, c) + q2, _ = bits.Add64(q2, 0, c) + + t1, t0 = bits.Mul64(x3, mu[1]) + q0, c = bits.Add64(q0, t0, 0) + q1, c = bits.Add64(q1, t1, c) + q2, _ = bits.Add64(q2, 0, c) + + t1, t0 = bits.Mul64(x2, mu[2]) + q0, c = bits.Add64(q0, t0, 0) + q1, c = bits.Add64(q1, t1, c) + q3, t0 = bits.Mul64(x4, mu[2]) + q2, c = bits.Add64(q2, t0, c) + q3, _ = bits.Add64(q3, 0, c) + + t1, _ = bits.Mul64(x1, mu[2]) + q0, c = bits.Add64(q0, t1, 0) + t1, t0 = bits.Mul64(x3, mu[2]) + q1, c = bits.Add64(q1, t0, c) + q2, c = bits.Add64(q2, t1, c) + q3, _ = bits.Add64(q3, 0, c) + + t1, _ = bits.Mul64(x0, mu[3]) + q0, c = bits.Add64(q0, t1, 0) + t1, t0 = bits.Mul64(x2, mu[3]) + q1, c = bits.Add64(q1, t0, c) + q2, c = bits.Add64(q2, t1, c) + q4, t0 = bits.Mul64(x4, mu[3]) + q3, c = bits.Add64(q3, t0, c) + q4, _ = bits.Add64(q4, 0, c) + + t1, t0 = bits.Mul64(x1, mu[3]) + q0, c = bits.Add64(q0, t0, 0) + q1, c = bits.Add64(q1, t1, c) + t1, t0 = bits.Mul64(x3, mu[3]) + q2, c = bits.Add64(q2, t0, c) + q3, c = bits.Add64(q3, t1, c) + q4, _ = bits.Add64(q4, 0, c) + + t1, t0 = bits.Mul64(x0, mu[4]) + _, c = bits.Add64(q0, t0, 0) + q1, c = bits.Add64(q1, t1, c) + t1, t0 = bits.Mul64(x2, mu[4]) + q2, c = bits.Add64(q2, t0, c) + q3, c = bits.Add64(q3, t1, c) + q5, t0 = bits.Mul64(x4, mu[4]) + q4, c = bits.Add64(q4, t0, c) + q5, _ = bits.Add64(q5, 0, c) + + t1, t0 = bits.Mul64(x1, mu[4]) + q1, c = bits.Add64(q1, t0, 0) + q2, c = bits.Add64(q2, t1, c) + t1, t0 = bits.Mul64(x3, mu[4]) + q3, c = bits.Add64(q3, t0, c) + q4, c = bits.Add64(q4, t1, c) + q5, _ = bits.Add64(q5, 0, c) + + // Drop the fractional part of q3 + + q0 = q1 + q1 = q2 + q2 = q3 + q3 = q4 + q4 = q5 + + // r1 = x mod 2^320 + + x0 = x[0] + x1 = x[1] + x2 = x[2] + x3 = x[3] + x4 = x[4] + + // r2 = q3 * m mod 2^320 + + var r0, r1, r2, r3, r4 uint64 + + r4, r3 = bits.Mul64(q0, m.arr[3]) + _, t0 = bits.Mul64(q1, m.arr[3]) + r4, _ = bits.Add64(r4, t0, 0) + + t1, r2 = bits.Mul64(q0, m.arr[2]) + r3, c = bits.Add64(r3, t1, 0) + _, t0 = bits.Mul64(q2, m.arr[2]) + r4, _ = bits.Add64(r4, t0, c) + + t1, t0 = bits.Mul64(q1, m.arr[2]) + r3, c = bits.Add64(r3, t0, 0) + r4, _ = bits.Add64(r4, t1, c) + + t1, r1 = bits.Mul64(q0, m.arr[1]) + r2, c = bits.Add64(r2, t1, 0) + t1, t0 = bits.Mul64(q2, m.arr[1]) + r3, c = bits.Add64(r3, t0, c) + r4, _ = bits.Add64(r4, t1, c) + + t1, t0 = bits.Mul64(q1, m.arr[1]) + r2, c = bits.Add64(r2, t0, 0) + r3, c = bits.Add64(r3, t1, c) + _, t0 = bits.Mul64(q3, m.arr[1]) + r4, _ = bits.Add64(r4, t0, c) + + t1, r0 = bits.Mul64(q0, m.arr[0]) + r1, c = bits.Add64(r1, t1, 0) + t1, t0 = bits.Mul64(q2, m.arr[0]) + r2, c = bits.Add64(r2, t0, c) + r3, c = bits.Add64(r3, t1, c) + _, t0 = bits.Mul64(q4, m.arr[0]) + r4, _ = bits.Add64(r4, t0, c) + + t1, t0 = bits.Mul64(q1, m.arr[0]) + r1, c = bits.Add64(r1, t0, 0) + r2, c = bits.Add64(r2, t1, c) + t1, t0 = bits.Mul64(q3, m.arr[0]) + r3, c = bits.Add64(r3, t0, c) + r4, _ = bits.Add64(r4, t1, c) + + // r = r1 - r2 + + var b uint64 + + r0, b = bits.Sub64(x0, r0, 0) + r1, b = bits.Sub64(x1, r1, b) + r2, b = bits.Sub64(x2, r2, b) + r3, b = bits.Sub64(x3, r3, b) + r4, b = bits.Sub64(x4, r4, b) + + // if r<0 then r+=m + + if b != 0 { + r0, c = bits.Add64(r0, m.arr[0], 0) + r1, c = bits.Add64(r1, m.arr[1], c) + r2, c = bits.Add64(r2, m.arr[2], c) + r3, c = bits.Add64(r3, m.arr[3], c) + r4, _ = bits.Add64(r4, 0, c) + } + + // while (r>=m) r-=m + + for { + // q = r - m + q0, b = bits.Sub64(r0, m.arr[0], 0) + q1, b = bits.Sub64(r1, m.arr[1], b) + q2, b = bits.Sub64(r2, m.arr[2], b) + q3, b = bits.Sub64(r3, m.arr[3], b) + q4, b = bits.Sub64(r4, 0, b) + + // if borrow break + if b != 0 { + break + } + + // r = q + r4, r3, r2, r1, r0 = q4, q3, q2, q1, q0 + } + + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = r3, r2, r1, r0 + + return z +} diff --git a/packages/big/uint256/strconv.gno b/packages/big/uint256/strconv.gno new file mode 100644 index 00000000..c1496135 --- /dev/null +++ b/packages/big/uint256/strconv.gno @@ -0,0 +1,203 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uint256 + +const fastSmalls = true // enable fast path for small integers + +// FormatUint returns the string representation of i in the given base, +// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z' +// for digit values >= 10. +func FormatUint(i uint64, base int) string { + if fastSmalls && i < nSmalls && base == 10 { + return small(int(i)) + } + _, s := formatBits(nil, i, base, false, false) + return s +} + +// FormatInt returns the string representation of i in the given base, +// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z' +// for digit values >= 10. +func FormatInt(i int64, base int) string { + if fastSmalls && 0 <= i && i < nSmalls && base == 10 { + return small(int(i)) + } + _, s := formatBits(nil, uint64(i), base, i < 0, false) + return s +} + +// Itoa is equivalent to FormatInt(int64(i), 10). +func Itoa(i int) string { + return FormatInt(int64(i), 10) +} + +// AppendInt appends the string form of the integer i, +// as generated by FormatInt, to dst and returns the extended buffer. +func AppendInt(dst []byte, i int64, base int) []byte { + if fastSmalls && 0 <= i && i < nSmalls && base == 10 { + return append(dst, small(int(i))...) + } + dst, _ = formatBits(dst, uint64(i), base, i < 0, true) + return dst +} + +// AppendUint appends the string form of the unsigned integer i, +// as generated by FormatUint, to dst and returns the extended buffer. +func AppendUint(dst []byte, i uint64, base int) []byte { + if fastSmalls && i < nSmalls && base == 10 { + return append(dst, small(int(i))...) + } + dst, _ = formatBits(dst, i, base, false, true) + return dst +} + +// small returns the string for an i with 0 <= i < nSmalls. +func small(i int) string { + if i < 10 { + return digits[i : i+1] + } + return smallsString[i*2 : i*2+2] +} + +const nSmalls = 100 + +const smallsString = "00010203040506070809" + + "10111213141516171819" + + "20212223242526272829" + + "30313233343536373839" + + "40414243444546474849" + + "50515253545556575859" + + "60616263646566676869" + + "70717273747576777879" + + "80818283848586878889" + + "90919293949596979899" + +const host32bit = ^uint(0)>>32 == 0 + +const digits = "0123456789abcdefghijklmnopqrstuvwxyz" + +// formatBits computes the string representation of u in the given base. +// If neg is set, u is treated as negative int64 value. If append_ is +// set, the string is appended to dst and the resulting byte slice is +// returned as the first result value; otherwise the string is returned +// as the second result value. +func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s string) { + if base < 2 || base > len(digits) { + panic("strconv: illegal AppendInt/FormatInt base") + } + // 2 <= base && base <= len(digits) + + var a [64 + 1]byte // +1 for sign of 64bit value in base 2 + i := len(a) + + if neg { + u = -u + } + + // convert bits + // We use uint values where we can because those will + // fit into a single register even on a 32bit machine. + if base == 10 { + // common case: use constants for / because + // the compiler can optimize it into a multiply+shift + + if host32bit { + // convert the lower digits using 32bit operations + for u >= 1e9 { + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / 1e9 + us := uint(u - q*1e9) // u % 1e9 fits into a uint + for j := 4; j > 0; j-- { + is := us % 100 * 2 + us /= 100 + i -= 2 + a[i+1] = smallsString[is+1] + a[i+0] = smallsString[is+0] + } + + // us < 10, since it contains the last digit + // from the initial 9-digit us. + i-- + a[i] = smallsString[us*2+1] + + u = q + } + // u < 1e9 + } + + // u guaranteed to fit into a uint + us := uint(u) + for us >= 100 { + is := us % 100 * 2 + us /= 100 + i -= 2 + a[i+1] = smallsString[is+1] + a[i+0] = smallsString[is+0] + } + + // us < 100 + is := us * 2 + i-- + a[i] = smallsString[is+1] + if us >= 10 { + i-- + a[i] = smallsString[is] + } + + } else if isPowerOfTwo(base) { + // Use shifts and masks instead of / and %. + // Base is a power of 2 and 2 <= base <= len(digits) where len(digits) is 36. + // The largest power of 2 below or equal to 36 is 32, which is 1 << 5; + // i.e., the largest possible shift count is 5. By &-ind that value with + // the constant 7 we tell the compiler that the shift count is always + // less than 8 which is smaller than any register width. This allows + // the compiler to generate better code for the shift operation. + shift := uint(TrailingZeros(uint(base))) & 7 + b := uint64(base) + m := uint(base) - 1 // == 1<= b { + i-- + a[i] = digits[uint(u)&m] + u >>= shift + } + // u < base + i-- + a[i] = digits[uint(u)] + } else { + // general case + b := uint64(base) + for u >= b { + i-- + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / b + a[i] = digits[uint(u-q*b)] + u = q + } + // u < base + i-- + a[i] = digits[uint(u)] + } + + // add sign, if any + if neg { + i-- + a[i] = '-' + } + + if append_ { + d = append(dst, a[i:]...) + return + } + s = string(a[i:]) + return +} + +func isPowerOfTwo(x int) bool { + return x&(x-1) == 0 +} diff --git a/packages/big/uint256/uint256.gno b/packages/big/uint256/uint256.gno new file mode 100644 index 00000000..08daf9f3 --- /dev/null +++ b/packages/big/uint256/uint256.gno @@ -0,0 +1,1302 @@ +// Ported from https://github.com/holiman/uint256 +package uint256 + +import ( + "errors" +) + +const MaxUint64 = 1<<64 - 1 + +func Zero() *Uint { + return NewUint(0) +} + +func One() *Uint { + return NewUint(1) +} + +func (x *Uint) Min(y *Uint) *Uint { + if x.Lt(y) { + return x + } + return y +} + +// Uint is represented as an array of 4 uint64, in little-endian order, +// so that Uint[3] is the most significant, and Uint[0] is the least significant +type Uint struct { + arr [4]uint64 +} + +// func (x *Uint) Int() *Int { +// // panic if x > MaxInt64 +// if x.arr[3] > 0x7fffffffffffffff { +// panic("U256 Int overflow") +// } + +// return &Int{v: *x} +// } + +// NewUint returns a new initialized Uint. +func NewUint(val uint64) *Uint { + z := &Uint{arr: [4]uint64{val, 0, 0, 0}} + return z +} + +// Uint64 returns the lower 64-bits of z +func (z *Uint) Uint64() uint64 { + return z.arr[0] +} + +func (z *Uint) Int32() int32 { + x := z.arr[0] + if x > 0x7fffffff { + panic("U256 Int32 overflow") + } + return int32(x) +} + +// SetUint64 sets z to the value x +func (z *Uint) SetUint64(x uint64) *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = 0, 0, 0, x + return z +} + +// IsUint64 reports whether z can be represented as a uint64. +func (z *Uint) IsUint64() bool { + return (z.arr[1] | z.arr[2] | z.arr[3]) == 0 +} + +// IsZero returns true if z == 0 +func (z *Uint) IsZero() bool { + return (z.arr[0] | z.arr[1] | z.arr[2] | z.arr[3]) == 0 +} + +// Clear sets z to 0 +func (z *Uint) Clear() *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = 0, 0, 0, 0 + return z +} + +// SetAllOne sets all the bits of z to 1 +func (z *Uint) SetAllOne() *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = MaxUint64, MaxUint64, MaxUint64, MaxUint64 + return z +} + +// Not sets z = ^x and returns z. +func (z *Uint) Not(x *Uint) *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = ^x.arr[3], ^x.arr[2], ^x.arr[1], ^x.arr[0] + return z +} + +// Lt returns true if z < x +func (z *Uint) Lt(x *Uint) bool { + // z < x <=> z - x < 0 i.e. when subtraction overflows. + _, carry := Sub64(z.arr[0], x.arr[0], 0) + _, carry = Sub64(z.arr[1], x.arr[1], carry) + _, carry = Sub64(z.arr[2], x.arr[2], carry) + _, carry = Sub64(z.arr[3], x.arr[3], carry) + + return carry != 0 +} + +// Gt returns true if z > x +func (z *Uint) Gt(x *Uint) bool { + return x.Lt(z) +} + +// Lte returns true if z <= x +func (z *Uint) Lte(x *Uint) bool { + cond1 := z.Lt(x) + cond2 := z.Eq(x) + + if cond1 || cond2 { + return true + } + return false +} + +// Gte returns true if z >= x +func (z *Uint) Gte(x *Uint) bool { + cond1 := z.Gt(x) + cond2 := z.Eq(x) + + if cond1 || cond2 { + return true + } + return false +} + +// Eq returns true if z == x +func (z *Uint) Eq(x *Uint) bool { + return (z.arr[0] == x.arr[0]) && (z.arr[1] == x.arr[1]) && (z.arr[2] == x.arr[2]) && (z.arr[3] == x.arr[3]) +} + +// Cmp compares z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +func (z *Uint) Cmp(x *Uint) (r int) { + // z < x <=> z - x < 0 i.e. when subtraction overflows. + d0, carry := Sub64(z.arr[0], x.arr[0], 0) + d1, carry := Sub64(z.arr[1], x.arr[1], carry) + d2, carry := Sub64(z.arr[2], x.arr[2], carry) + d3, carry := Sub64(z.arr[3], x.arr[3], carry) + if carry == 1 { + return -1 + } + if d0|d1|d2|d3 == 0 { + return 0 + } + return 1 +} + +// Set sets z to x and returns z. +func (z *Uint) Set(x *Uint) *Uint { + *z = *x + + return z +} + +// SetOne sets z to 1 +func (z *Uint) SetOne() *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = 0, 0, 0, 1 + return z +} + +// func (z *Uint) AddInt(x *Uint, y *Int) *Uint { +// if y.IsNeg() { +// return z.Sub(x, y.Abs()) +// } +// return z.Add(x, y.Uint()) +// } + +// Add sets z to the sum x+y +func (z *Uint) Add(x, y *Uint) *Uint { + var carry uint64 + z.arr[0], carry = Add64(x.arr[0], y.arr[0], 0) + z.arr[1], carry = Add64(x.arr[1], y.arr[1], carry) + z.arr[2], carry = Add64(x.arr[2], y.arr[2], carry) + z.arr[3], _ = Add64(x.arr[3], y.arr[3], carry) + // Different from the original implementation! + // We panic on overflow + if carry != 0 { + panic("U256 Add overflow") + } + return z +} + +func (z *Uint) UnsafeAdd(x, y *Uint) *Uint { + var carry uint64 + z.arr[0], carry = Add64(x.arr[0], y.arr[0], 0) + z.arr[1], carry = Add64(x.arr[1], y.arr[1], carry) + z.arr[2], carry = Add64(x.arr[2], y.arr[2], carry) + z.arr[3], _ = Add64(x.arr[3], y.arr[3], carry) + // Different from the original implementation! + // // We panic on overflow + // if carry != 0 { + // panic("U256 Add overflow") + // } + return z +} + +// AddOverflow sets z to the sum x+y, and returns z and whether overflow occurred +func (z *Uint) AddOverflow(x, y *Uint) (*Uint, bool) { + var carry uint64 + z.arr[0], carry = Add64(x.arr[0], y.arr[0], 0) + z.arr[1], carry = Add64(x.arr[1], y.arr[1], carry) + z.arr[2], carry = Add64(x.arr[2], y.arr[2], carry) + z.arr[3], carry = Add64(x.arr[3], y.arr[3], carry) + return z, carry != 0 +} + +// SubOverflow sets z to the difference x-y and returns z and true if the operation underflowed +func (z *Uint) SubOverflow(x, y *Uint) (*Uint, bool) { + var carry uint64 + z.arr[0], carry = Sub64(x.arr[0], y.arr[0], 0) + z.arr[1], carry = Sub64(x.arr[1], y.arr[1], carry) + z.arr[2], carry = Sub64(x.arr[2], y.arr[2], carry) + z.arr[3], carry = Sub64(x.arr[3], y.arr[3], carry) + return z, carry != 0 +} + +// Sub sets z to the difference x-y +func (z *Uint) Sub(x, y *Uint) *Uint { + var carry uint64 + z.arr[0], carry = Sub64(x.arr[0], y.arr[0], 0) + z.arr[1], carry = Sub64(x.arr[1], y.arr[1], carry) + z.arr[2], carry = Sub64(x.arr[2], y.arr[2], carry) + z.arr[3], _ = Sub64(x.arr[3], y.arr[3], carry) + + // Different from the original implementation! + // We panic on underflow + // r3v4 -> mconcat : why do we panic? + if carry != 0 { + panic("U256 Sub underflow") + } + return z +} + +// Sub sets z to the difference x-y +func (z *Uint) UnsafeSub(x, y *Uint) *Uint { + var carry uint64 + z.arr[0], carry = Sub64(x.arr[0], y.arr[0], 0) + z.arr[1], carry = Sub64(x.arr[1], y.arr[1], carry) + z.arr[2], carry = Sub64(x.arr[2], y.arr[2], carry) + z.arr[3], _ = Sub64(x.arr[3], y.arr[3], carry) + + return z +} + +// commented out for possible overflow +// Mul sets z to the product x*y +func (z *Uint) Mul(x, y *Uint) *Uint { + var ( + res Uint + carry uint64 + res1, res2, res3 uint64 + ) + + carry, res.arr[0] = Mul64(x.arr[0], y.arr[0]) + carry, res1 = umulHop(carry, x.arr[1], y.arr[0]) + carry, res2 = umulHop(carry, x.arr[2], y.arr[0]) + res3 = x.arr[3]*y.arr[0] + carry + + carry, res.arr[1] = umulHop(res1, x.arr[0], y.arr[1]) + carry, res2 = umulStep(res2, x.arr[1], y.arr[1], carry) + res3 = res3 + x.arr[2]*y.arr[1] + carry + + carry, res.arr[2] = umulHop(res2, x.arr[0], y.arr[2]) + res3 = res3 + x.arr[1]*y.arr[2] + carry + + res.arr[3] = res3 + x.arr[0]*y.arr[3] + + + return z.Set(&res) +} + +// MulOverflow sets z to the product x*y, and returns z and whether overflow occurred +func (z *Uint) MulOverflow(x, y *Uint) (*Uint, bool) { + p := umul(x, y) + copy(z.arr[:], p[:4]) + return z, (p[4] | p[5] | p[6] | p[7]) != 0 +} + +// MulMod calculates the modulo-m multiplication of x and y and +// returns z. +// If m == 0, z is set to 0 (OBS: differs from the big.Int) +func (z *Uint) MulMod(x, y, m *Uint) *Uint { + if x.IsZero() || y.IsZero() || m.IsZero() { + return z.Clear() + } + p := umul(x, y) + + if m.arr[3] != 0 { + mu := Reciprocal(m) + r := reduce4(p, m, mu) + return z.Set(&r) + } + + var ( + pl Uint + ph Uint + ) + // copy(pl[:], p[:4]) + // copy(ph[:], p[4:]) + + pl = Uint{arr: [4]uint64{p[0], p[1], p[2], p[3]}} + + // If the multiplication is within 256 bits use Mod(). + if ph.IsZero() { + return z.Mod(&pl, m) + } + + var quot [8]uint64 + rem := udivrem(quot[:], p[:], m) + return z.Set(&rem) +} + +// umulStep computes (hi * 2^64 + lo) = z + (x * y) + carry. +func umulStep(z, x, y, carry uint64) (hi, lo uint64) { + hi, lo = Mul64(x, y) + lo, carry = Add64(lo, carry, 0) + hi, _ = Add64(hi, 0, carry) + lo, carry = Add64(lo, z, 0) + hi, _ = Add64(hi, 0, carry) + return hi, lo +} + +// umulHop computes (hi * 2^64 + lo) = z + (x * y) +func umulHop(z, x, y uint64) (hi, lo uint64) { + hi, lo = Mul64(x, y) + lo, carry := Add64(lo, z, 0) + hi, _ = Add64(hi, 0, carry) + return hi, lo +} + +// umul computes full 256 x 256 -> 512 multiplication. +func umul(x, y *Uint) [8]uint64 { + var ( + res [8]uint64 + carry, carry4, carry5, carry6 uint64 + res1, res2, res3, res4, res5 uint64 + ) + + carry, res[0] = Mul64(x.arr[0], y.arr[0]) + carry, res1 = umulHop(carry, x.arr[1], y.arr[0]) + carry, res2 = umulHop(carry, x.arr[2], y.arr[0]) + carry4, res3 = umulHop(carry, x.arr[3], y.arr[0]) + + carry, res[1] = umulHop(res1, x.arr[0], y.arr[1]) + carry, res2 = umulStep(res2, x.arr[1], y.arr[1], carry) + carry, res3 = umulStep(res3, x.arr[2], y.arr[1], carry) + carry5, res4 = umulStep(carry4, x.arr[3], y.arr[1], carry) + + carry, res[2] = umulHop(res2, x.arr[0], y.arr[2]) + carry, res3 = umulStep(res3, x.arr[1], y.arr[2], carry) + carry, res4 = umulStep(res4, x.arr[2], y.arr[2], carry) + carry6, res5 = umulStep(carry5, x.arr[3], y.arr[2], carry) + + carry, res[3] = umulHop(res3, x.arr[0], y.arr[3]) + carry, res[4] = umulStep(res4, x.arr[1], y.arr[3], carry) + carry, res[5] = umulStep(res5, x.arr[2], y.arr[3], carry) + res[7], res[6] = umulStep(carry6, x.arr[3], y.arr[3], carry) + + return res +} + +// commented out for possible overflow +// Div sets z to the quotient x/y for returns z. +// If y == 0, z is set to 0 +func (z *Uint) Div(x, y *Uint) *Uint { + if y.IsZero() || y.Gt(x) { + return z.Clear() + } + if x.Eq(y) { + return z.SetOne() + } + // Shortcut some cases + if x.IsUint64() { + return z.SetUint64(x.Uint64() / y.Uint64()) + } + + // At this point, we know + // x/y ; x > y > 0 + + var quot Uint + udivrem(quot.arr[:], x.arr[:], y) + return z.Set(") +} + +// udivrem divides u by d and produces both quotient and remainder. +// The quotient is stored in provided quot - len(u)-len(d)+1 words. +// It loosely follows the Knuth's division algorithm (sometimes referenced as "schoolbook" division) using 64-bit words. +// See Knuth, Volume 2, section 4.3.1, Algorithm D. +func udivrem(quot, u []uint64, d *Uint) (rem Uint) { + var dLen int + for i := len(d.arr) - 1; i >= 0; i-- { + if d.arr[i] != 0 { + dLen = i + 1 + break + } + } + + shift := uint(LeadingZeros64(d.arr[dLen-1])) + + var dnStorage Uint + dn := dnStorage.arr[:dLen] + for i := dLen - 1; i > 0; i-- { + dn[i] = (d.arr[i] << shift) | (d.arr[i-1] >> (64 - shift)) + } + dn[0] = d.arr[0] << shift + + var uLen int + for i := len(u) - 1; i >= 0; i-- { + if u[i] != 0 { + uLen = i + 1 + break + } + } + + if uLen < dLen { + copy(rem.arr[:], u) + return rem + } + + var unStorage [9]uint64 + un := unStorage[:uLen+1] + un[uLen] = u[uLen-1] >> (64 - shift) + for i := uLen - 1; i > 0; i-- { + un[i] = (u[i] << shift) | (u[i-1] >> (64 - shift)) + } + un[0] = u[0] << shift + + // TODO: Skip the highest word of numerator if not significant. + + if dLen == 1 { + r := udivremBy1(quot, un, dn[0]) + rem.SetUint64(r >> shift) + return rem + } + + udivremKnuth(quot, un, dn) + + for i := 0; i < dLen-1; i++ { + rem.arr[i] = (un[i] >> shift) | (un[i+1] << (64 - shift)) + } + rem.arr[dLen-1] = un[dLen-1] >> shift + + return rem +} + +// udivremBy1 divides u by single normalized word d and produces both quotient and remainder. +// The quotient is stored in provided quot. +func udivremBy1(quot, u []uint64, d uint64) (rem uint64) { + reciprocal := reciprocal2by1(d) + rem = u[len(u)-1] // Set the top word as remainder. + for j := len(u) - 2; j >= 0; j-- { + quot[j], rem = udivrem2by1(rem, u[j], d, reciprocal) + } + return rem +} + +// udivremKnuth implements the division of u by normalized multiple word d from the Knuth's division algorithm. +// The quotient is stored in provided quot - len(u)-len(d) words. +// Updates u to contain the remainder - len(d) words. +func udivremKnuth(quot, u, d []uint64) { + dh := d[len(d)-1] + dl := d[len(d)-2] + reciprocal := reciprocal2by1(dh) + + for j := len(u) - len(d) - 1; j >= 0; j-- { + u2 := u[j+len(d)] + u1 := u[j+len(d)-1] + u0 := u[j+len(d)-2] + + var qhat, rhat uint64 + if u2 >= dh { // Division overflows. + qhat = ^uint64(0) + // TODO: Add "qhat one to big" adjustment (not needed for correctness, but helps avoiding "add back" case). + } else { + qhat, rhat = udivrem2by1(u2, u1, dh, reciprocal) + ph, pl := Mul64(qhat, dl) + if ph > rhat || (ph == rhat && pl > u0) { + qhat-- + // TODO: Add "qhat one to big" adjustment (not needed for correctness, but helps avoiding "add back" case). + } + } + + // Multiply and subtract. + borrow := subMulTo(u[j:], d, qhat) + u[j+len(d)] = u2 - borrow + if u2 < borrow { // Too much subtracted, add back. + qhat-- + u[j+len(d)] += addTo(u[j:], d) + } + + quot[j] = qhat // Store quotient digit. + } +} + +// isBitSet returns true if bit n-th is set, where n = 0 is LSB. +// The n must be <= 255. +func (z *Uint) isBitSet(n uint) bool { + return (z.arr[n/64] & (1 << (n % 64))) != 0 +} + +// addTo computes x += y. +// Requires len(x) >= len(y). +func addTo(x, y []uint64) uint64 { + var carry uint64 + for i := 0; i < len(y); i++ { + x[i], carry = Add64(x[i], y[i], carry) + } + return carry +} + +// subMulTo computes x -= y * multiplier. +// Requires len(x) >= len(y). +func subMulTo(x, y []uint64, multiplier uint64) uint64 { + var borrow uint64 + for i := 0; i < len(y); i++ { + s, carry1 := Sub64(x[i], borrow, 0) + ph, pl := Mul64(y[i], multiplier) + t, carry2 := Sub64(s, pl, 0) + x[i] = t + borrow = ph + carry1 + carry2 + } + return borrow +} + +// reciprocal2by1 computes <^d, ^0> / d. +func reciprocal2by1(d uint64) uint64 { + reciprocal, _ := Div64(^d, ^uint64(0), d) + return reciprocal +} + +// udivrem2by1 divides / d and produces both quotient and remainder. +// It uses the provided d's reciprocal. +// Implementation ported from https://github.com/chfast/intx and is based on +// "Improved division by invariant integers", Algorithm 4. +func udivrem2by1(uh, ul, d, reciprocal uint64) (quot, rem uint64) { + qh, ql := Mul64(reciprocal, uh) + ql, carry := Add64(ql, ul, 0) + qh, _ = Add64(qh, uh, carry) + qh++ + + r := ul - qh*d + + if r > ql { + qh-- + r += d + } + + if r >= d { + qh++ + r -= d + } + + return qh, r +} + +// Lsh sets z = x << n and returns z. +func (z *Uint) Lsh(x *Uint, n uint) *Uint { + // n % 64 == 0 + if n&0x3f == 0 { + switch n { + case 0: + return z.Set(x) + case 64: + return z.lsh64(x) + case 128: + return z.lsh128(x) + case 192: + return z.lsh192(x) + default: + return z.Clear() + } + } + var ( + a, b uint64 + ) + // Big swaps first + switch { + case n > 192: + if n > 256 { + return z.Clear() + } + z.lsh192(x) + n -= 192 + goto sh192 + case n > 128: + z.lsh128(x) + n -= 128 + goto sh128 + case n > 64: + z.lsh64(x) + n -= 64 + goto sh64 + default: + z.Set(x) + } + + // remaining shifts + a = z.arr[0] >> (64 - n) + z.arr[0] = z.arr[0] << n + +sh64: + b = z.arr[1] >> (64 - n) + z.arr[1] = (z.arr[1] << n) | a + +sh128: + a = z.arr[2] >> (64 - n) + z.arr[2] = (z.arr[2] << n) | b + +sh192: + z.arr[3] = (z.arr[3] << n) | a + + return z +} + +// Rsh sets z = x >> n and returns z. +func (z *Uint) Rsh(x *Uint, n uint) *Uint { + // n % 64 == 0 + if n&0x3f == 0 { + switch n { + case 0: + return z.Set(x) + case 64: + return z.rsh64(x) + case 128: + return z.rsh128(x) + case 192: + return z.rsh192(x) + default: + return z.Clear() + } + } + var ( + a, b uint64 + ) + // Big swaps first + switch { + case n > 192: + if n > 256 { + return z.Clear() + } + z.rsh192(x) + n -= 192 + goto sh192 + case n > 128: + z.rsh128(x) + n -= 128 + goto sh128 + case n > 64: + z.rsh64(x) + n -= 64 + goto sh64 + default: + z.Set(x) + } + + // remaining shifts + a = z.arr[3] << (64 - n) + z.arr[3] = z.arr[3] >> n + +sh64: + b = z.arr[2] << (64 - n) + z.arr[2] = (z.arr[2] >> n) | a + +sh128: + a = z.arr[1] << (64 - n) + z.arr[1] = (z.arr[1] >> n) | b + +sh192: + z.arr[0] = (z.arr[0] >> n) | a + + return z +} + +// SRsh (Signed/Arithmetic right shift) +// considers z to be a signed integer, during right-shift +// and sets z = x >> n and returns z. +func (z *Uint) SRsh(x *Uint, n uint) *Uint { + // If the MSB is 0, SRsh is same as Rsh. + if !x.isBitSet(255) { + return z.Rsh(x, n) + } + if n%64 == 0 { + switch n { + case 0: + return z.Set(x) + case 64: + return z.srsh64(x) + case 128: + return z.srsh128(x) + case 192: + return z.srsh192(x) + default: + return z.SetAllOne() + } + } + var ( + a uint64 = MaxUint64 << (64 - n%64) + ) + // Big swaps first + switch { + case n > 192: + if n > 256 { + return z.SetAllOne() + } + z.srsh192(x) + n -= 192 + goto sh192 + case n > 128: + z.srsh128(x) + n -= 128 + goto sh128 + case n > 64: + z.srsh64(x) + n -= 64 + goto sh64 + default: + z.Set(x) + } + + // remaining shifts + z.arr[3], a = (z.arr[3]>>n)|a, z.arr[3]<<(64-n) + +sh64: + z.arr[2], a = (z.arr[2]>>n)|a, z.arr[2]<<(64-n) + +sh128: + z.arr[1], a = (z.arr[1]>>n)|a, z.arr[1]<<(64-n) + +sh192: + z.arr[0] = (z.arr[0] >> n) | a + + return z +} + +func (z *Uint) lsh64(x *Uint) *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = x.arr[2], x.arr[1], x.arr[0], 0 + return z +} +func (z *Uint) lsh128(x *Uint) *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = x.arr[1], x.arr[0], 0, 0 + return z +} +func (z *Uint) lsh192(x *Uint) *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = x.arr[0], 0, 0, 0 + return z +} +func (z *Uint) rsh64(x *Uint) *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = 0, x.arr[3], x.arr[2], x.arr[1] + return z +} +func (z *Uint) rsh128(x *Uint) *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = 0, 0, x.arr[3], x.arr[2] + return z +} +func (z *Uint) rsh192(x *Uint) *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = 0, 0, 0, x.arr[3] + return z +} +func (z *Uint) srsh64(x *Uint) *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = MaxUint64, x.arr[3], x.arr[2], x.arr[1] + return z +} +func (z *Uint) srsh128(x *Uint) *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = MaxUint64, MaxUint64, x.arr[3], x.arr[2] + return z +} +func (z *Uint) srsh192(x *Uint) *Uint { + z.arr[3], z.arr[2], z.arr[1], z.arr[0] = MaxUint64, MaxUint64, MaxUint64, x.arr[3] + return z +} + +// Or sets z = x | y and returns z. +func (z *Uint) Or(x, y *Uint) *Uint { + z.arr[0] = x.arr[0] | y.arr[0] + z.arr[1] = x.arr[1] | y.arr[1] + z.arr[2] = x.arr[2] | y.arr[2] + z.arr[3] = x.arr[3] | y.arr[3] + return z +} + +// And sets z = x & y and returns z. +func (z *Uint) And(x, y *Uint) *Uint { + z.arr[0] = x.arr[0] & y.arr[0] + z.arr[1] = x.arr[1] & y.arr[1] + z.arr[2] = x.arr[2] & y.arr[2] + z.arr[3] = x.arr[3] & y.arr[3] + return z +} + +// Xor sets z = x ^ y and returns z. +func (z *Uint) Xor(x, y *Uint) *Uint { + z.arr[0] = x.arr[0] ^ y.arr[0] + z.arr[1] = x.arr[1] ^ y.arr[1] + z.arr[2] = x.arr[2] ^ y.arr[2] + z.arr[3] = x.arr[3] ^ y.arr[3] + return z +} + +// MarshalJSON implements json.Marshaler. +// MarshalJSON marshals using the 'decimal string' representation. This is _not_ compatible +// with big.Uint: big.Uint marshals into JSON 'native' numeric format. +// +// The JSON native format is, on some platforms, (e.g. javascript), limited to 53-bit large +// integer space. Thus, U256 uses string-format, which is not compatible with +// big.int (big.Uint refuses to unmarshal a string representation). +func (z *Uint) MarshalJSON() ([]byte, error) { + return []byte(`"` + z.Dec() + `"`), nil +} + +// UnmarshalJSON implements json.Unmarshaler. UnmarshalJSON accepts either +// - Quoted string: either hexadecimal OR decimal +// - Not quoted string: only decimal +func (z *Uint) UnmarshalJSON(input []byte) error { + if len(input) < 2 || input[0] != '"' || input[len(input)-1] != '"' { + // if not quoted, it must be decimal + return z.fromDecimal(string(input)) + } + return z.UnmarshalText(input[1 : len(input)-1]) +} + +// MarshalText implements encoding.TextMarshaler +// MarshalText marshals using the decimal representation (compatible with big.Uint) +func (z *Uint) MarshalText() ([]byte, error) { + return []byte(z.Dec()), nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. This method +// can unmarshal either hexadecimal or decimal. +// - For hexadecimal, the input _must_ be prefixed with 0x or 0X +func (z *Uint) UnmarshalText(input []byte) error { + if len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X') { + return z.fromHex(string(input)) + } + return z.fromDecimal(string(input)) +} + +const ( + hextable = "0123456789abcdef" + bintable = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x01\x02\x03\x04\x05\x06\a\b\t\xff\xff\xff\xff\xff\xff\xff\n\v\f\r\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\n\v\f\r\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + badNibble = 0xff +) + +// fromHex is the internal implementation of parsing a hex-string. +func (z *Uint) fromHex(hex string) error { + if err := checkNumberS(hex); err != nil { + return err + } + if len(hex) > 66 { + return ErrBig256Range + } + z.Clear() + end := len(hex) + for i := 0; i < 4; i++ { + start := end - 16 + if start < 2 { + start = 2 + } + for ri := start; ri < end; ri++ { + nib := bintable[hex[ri]] + if nib == badNibble { + return ErrSyntax + } + z.arr[i] = z.arr[i] << 4 + z.arr[i] += uint64(nib) + } + end = start + } + return nil +} + +// FromDecimal is a convenience-constructor to create an Uint from a +// decimal (base 10) string. Numbers larger than 256 bits are not accepted. +func FromDecimal(decimal string) (*Uint, error) { + var z Uint + if err := z.SetFromDecimal(decimal); err != nil { + return nil, err + } + return &z, nil +} + +// UnsafeFromDecimal is a convenience-constructor to create an Uint from a +// decimal (base 10) string. Numbers larger than 256 bits are not accepted. +// panic if the input is invalid +func UnsafeFromDecimal(decimal string) *Uint { + var z Uint + if err := z.SetFromDecimal(decimal); err != nil { + panic("UNSAFE FROM DECIMAL") + } + return &z +} + +const twoPow256Sub1 = "115792089237316195423570985008687907853269984665640564039457584007913129639935" + +// SetFromDecimal sets z from the given string, interpreted as a decimal number. +// OBS! This method is _not_ strictly identical to the (*big.Uint).SetString(..., 10) method. +// Notable differences: +// - This method does not accept underscore input, e.g. "100_000", +// - This method does not accept negative zero as valid, e.g "-0", +// - (this method does not accept any negative input as valid)) +func (z *Uint) SetFromDecimal(s string) (err error) { + // Remove max one leading + + if len(s) > 0 && s[0] == '+' { + s = s[1:] + } + // Remove any number of leading zeroes + if len(s) > 0 && s[0] == '0' { + var i int + var c rune + for i, c = range s { + if c != '0' { + break + } + } + s = s[i:] + } + if len(s) < len(twoPow256Sub1) { + return z.fromDecimal(s) + } + if len(s) == len(twoPow256Sub1) { + if s > twoPow256Sub1 { + return ErrBig256Range + } + return z.fromDecimal(s) + } + return ErrBig256Range +} + +var ( + ErrEmptyString = errors.New("empty hex string") + ErrSyntax = errors.New("invalid hex string") + ErrMissingPrefix = errors.New("hex string without 0x prefix") + ErrEmptyNumber = errors.New("hex string \"0x\"") + ErrLeadingZero = errors.New("hex number with leading zero digits") + ErrBig256Range = errors.New("hex number > 256 bits") + ErrBadBufferLength = errors.New("bad ssz buffer length") + ErrBadEncodedLength = errors.New("bad ssz encoded length") +) + +func checkNumberS(input string) error { + l := len(input) + if l == 0 { + return ErrEmptyString + } + if l < 2 || input[0] != '0' || + (input[1] != 'x' && input[1] != 'X') { + return ErrMissingPrefix + } + if l == 2 { + return ErrEmptyNumber + } + if len(input) > 3 && input[2] == '0' { + return ErrLeadingZero + } + return nil +} + +// multipliers holds the values that are needed for fromDecimal +var multipliers = [5]*Uint{ + nil, // represents first round, no multiplication needed + &Uint{[4]uint64{10000000000000000000, 0, 0, 0}}, // 10 ^ 19 + &Uint{[4]uint64{687399551400673280, 5421010862427522170, 0, 0}}, // 10 ^ 38 + &Uint{[4]uint64{5332261958806667264, 17004971331911604867, 2938735877055718769, 0}}, // 10 ^ 57 + &Uint{[4]uint64{0, 8607968719199866880, 532749306367912313, 1593091911132452277}}, // 10 ^ 76 +} + +// fromDecimal is a helper function to only ever be called via SetFromDecimal +// this function takes a string and chunks it up, calling ParseUint on it up to 5 times +// these chunks are then multiplied by the proper power of 10, then added together. +func (z *Uint) fromDecimal(bs string) error { + // first clear the input + z.Clear() + // the maximum value of uint64 is 18446744073709551615, which is 20 characters + // one less means that a string of 19 9's is always within the uint64 limit + var ( + num uint64 + err error + remaining = len(bs) + ) + if remaining == 0 { + return errors.New("EOF") + } + // We proceed in steps of 19 characters (nibbles), from least significant to most significant. + // This means that the first (up to) 19 characters do not need to be multiplied. + // In the second iteration, our slice of 19 characters needs to be multipleied + // by a factor of 10^19. Et cetera. + for i, mult := range multipliers { + if remaining <= 0 { + return nil // Done + } else if remaining > 19 { + num, err = parseUint(bs[remaining-19:remaining], 10, 64) + } else { + // Final round + num, err = parseUint(bs, 10, 64) + } + if err != nil { + return err + } + // add that number to our running total + if i == 0 { + z.SetUint64(num) + } else { + base := NewUint(num) + z.Add(z, base.Mul(base, mult)) + } + // Chop off another 19 characters + if remaining > 19 { + bs = bs[0 : remaining-19] + } + remaining -= 19 + } + return nil +} + +// lower(c) is a lower-case letter if and only if +// c is either that lower-case letter or the equivalent upper-case letter. +// Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'. +// Note that lower of non-letters can produce other non-letters. +func lower(c byte) byte { + return c | ('x' - 'X') +} + +// ParseUint is like ParseUint but for unsigned numbers. +// +// A sign prefix is not permitted. +func parseUint(s string, base int, bitSize int) (uint64, error) { + const fnParseUint = "ParseUint" + + if s == "" { + return 0, errors.New("syntax error: ParseUint empty string") + } + + base0 := base == 0 + + s0 := s + switch { + case 2 <= base && base <= 36: + // valid base; nothing to do + + case base == 0: + // Look for octal, hex prefix. + base = 10 + if s[0] == '0' { + switch { + case len(s) >= 3 && lower(s[1]) == 'b': + base = 2 + s = s[2:] + case len(s) >= 3 && lower(s[1]) == 'o': + base = 8 + s = s[2:] + case len(s) >= 3 && lower(s[1]) == 'x': + base = 16 + s = s[2:] + default: + base = 8 + s = s[1:] + } + } + + default: + return 0, errors.New("invalid base") + } + + if bitSize == 0 { + bitSize = UintSize + } else if bitSize < 0 || bitSize > 64 { + return 0, errors.New("invalid bit size") + } + + // Cutoff is the smallest number such that cutoff*base > maxUint64. + // Use compile-time constants for common cases. + var cutoff uint64 + switch base { + case 10: + cutoff = MaxUint64/10 + 1 + case 16: + cutoff = MaxUint64/16 + 1 + default: + cutoff = MaxUint64/uint64(base) + 1 + } + + maxVal := uint64(1)<= byte(base) { + return 0, errors.New("syntax error") + } + + if n >= cutoff { + // n*base overflows + return maxVal, errors.New("range error") + } + n *= uint64(base) + + n1 := n + uint64(d) + if n1 < n || n1 > maxVal { + // n+d overflows + return maxVal, errors.New("range error") + } + n = n1 + } + + if underscores && !underscoreOK(s0) { + return 0, errors.New("syntax error") + } + + return n, nil +} + +// underscoreOK reports whether the underscores in s are allowed. +// Checking them in this one function lets all the parsers skip over them simply. +// Underscore must appear only between digits or between a base prefix and a digit. +func underscoreOK(s string) bool { + // saw tracks the last character (class) we saw: + // ^ for beginning of number, + // 0 for a digit or base prefix, + // _ for an underscore, + // ! for none of the above. + saw := '^' + i := 0 + + // Optional sign. + if len(s) >= 1 && (s[0] == '-' || s[0] == '+') { + s = s[1:] + } + + // Optional base prefix. + hex := false + if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') { + i = 2 + saw = '0' // base prefix counts as a digit for "underscore as digit separator" + hex = lower(s[1]) == 'x' + } + + // Number proper. + for ; i < len(s); i++ { + // Digits are always okay. + if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lower(s[i]) && lower(s[i]) <= 'f' { + saw = '0' + continue + } + // Underscore must follow digit. + if s[i] == '_' { + if saw != '0' { + return false + } + saw = '_' + continue + } + // Underscore must also be followed by digit. + if saw == '_' { + return false + } + // Saw non-digit, non-underscore. + saw = '!' + } + return saw != '_' +} + +// Dec returns the decimal representation of z. +func (z *Uint) Dec() string { + if z.IsZero() { + return "0" + } + if z.IsUint64() { + return FormatUint(z.Uint64(), 10) + } + + // The max uint64 value being 18446744073709551615, the largest + // power-of-ten below that is 10000000000000000000. + // When we do a DivMod using that number, the remainder that we + // get back is the lower part of the output. + // + // The ascii-output of remainder will never exceed 19 bytes (since it will be + // below 10000000000000000000). + // + // Algorithm example using 100 as divisor + // + // 12345 % 100 = 45 (rem) + // 12345 / 100 = 123 (quo) + // -> output '45', continue iterate on 123 + var ( + // out is 98 bytes long: 78 (max size of a string without leading zeroes, + // plus slack so we can copy 19 bytes every iteration). + // We init it with zeroes, because when strconv appends the ascii representations, + // it will omit leading zeroes. + out = []byte("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") + divisor = NewUint(10000000000000000000) // 20 digits + y = new(Uint).Set(z) // copy to avoid modifying z + pos = len(out) // position to write to + buf = make([]byte, 0, 19) // buffer to write uint64:s to + ) + for { + // Obtain Q and R for divisor + var quot Uint + rem := udivrem(quot.arr[:], y.arr[:], divisor) + y.Set(") // Set Q for next loop + // Convert the R to ascii representation + buf = AppendUint(buf[:0], rem.Uint64(), 10) + // Copy in the ascii digits + copy(out[pos-len(buf):], buf) + if y.IsZero() { + break + } + // Move 19 digits left + pos -= 19 + } + // skip leading zeroes by only using the 'used size' of buf + return string(out[pos-len(buf):]) +} + +func (z *Uint) ToString() string { + if z == nil { + panic("U256 ToString() nil") + } + + return z.Dec() +} + +// Mod sets z to the modulus x%y for y != 0 and returns z. +// If y == 0, z is set to 0 (OBS: differs from the big.Uint) +func (z *Uint) Mod(x, y *Uint) *Uint { + if x.IsZero() || y.IsZero() { + return z.Clear() + } + switch x.Cmp(y) { + case -1: + // x < y + copy(z.arr[:], x.arr[:]) + return z + case 0: + // x == y + return z.Clear() // They are equal + } + + // At this point: + // x != 0 + // y != 0 + // x > y + + // Shortcut trivial case + if x.IsUint64() { + return z.SetUint64(x.Uint64() % y.Uint64()) + } + + var quot Uint + *z = udivrem(quot.arr[:], x.arr[:], y) + return z +} + +// Clone creates a new Int identical to z +func (z *Uint) Clone() *Uint { + var x Uint + x.arr[0] = z.arr[0] + x.arr[1] = z.arr[1] + x.arr[2] = z.arr[2] + x.arr[3] = z.arr[3] + + return &x +} + +func (z *Uint) IsNil() bool { + return z == nil +} + +func (z *Uint) NilToZero() *Uint { + if z == nil { + z = NewUint(0) + } + + return z +} + +func (z *Uint) AndNot(x, y *Uint) *Uint { + z.arr[0] = x.arr[0] &^ y.arr[0] + z.arr[1] = x.arr[1] &^ y.arr[1] + z.arr[2] = x.arr[2] &^ y.arr[2] + z.arr[3] = x.arr[3] &^ y.arr[3] + return z +} diff --git a/packages/big/uint256/uint256_test.gno b/packages/big/uint256/uint256_test.gno new file mode 100644 index 00000000..5c56abd5 --- /dev/null +++ b/packages/big/uint256/uint256_test.gno @@ -0,0 +1,18 @@ +package uint256 + +import ( + "testing" +) + +func TestFuncs(t *testing.T) { + x := NewUint(0) + y := NewUint(1) + + // println(x.Dec()) + + var m256 bigint = 115792089237316195423570985008687907853269984665640564039457584007913129639935 + + z := FromBigint(m256) + + println(z.Dec()) +} diff --git a/packages/big/uint512/uint512.gno b/packages/big/uint512/uint512.gno new file mode 100644 index 00000000..38ce69c9 --- /dev/null +++ b/packages/big/uint512/uint512.gno @@ -0,0 +1,131 @@ +// REF: https://github.com/Uniswap/solidity-lib/blob/master/contracts/libraries/FullMath.sol +package uint512 + +import ( + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" +) + +func fullMul( + x *u256.Uint, + y *u256.Uint, +) (*u256.Uint, *u256.Uint) { // l, h + mm := new(u256.Uint).MulMod(x, y, u256.UnsafeFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935")) + + l := new(u256.Uint).Mul(x, y) + h := new(u256.Uint).Sub(mm, l) + + if mm.Lt(l) { + h = new(u256.Uint).Sub(h, u256.One()) + } + + return l, h +} + +func fullDiv( + l *u256.Uint, + h *u256.Uint, + d *u256.Uint, +) *u256.Uint { + // uint256 pow2 = d & -d; + posD := i256.FromUint256(d) + negD := i256.Zero().Neg(posD) + + intPow2 := i256.Zero().And(posD, negD) + + d = new(u256.Uint).Div(d, intPow2.Abs()) + l = new(u256.Uint).Div(l, intPow2.Abs()) + + // l += h * ((-pow2) / pow2 + 1); + _negPow2 := new(u256.Uint).Sub(u256.UnsafeFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935"), intPow2.Abs()) + _negPow2 = new(u256.Uint).Add(_negPow2, u256.One()) + + value1 := new(u256.Uint).Div(_negPow2, intPow2.Abs()) // (-pow2) / pow2 + // println("value1:", value1.ToString()) + + value2 := new(u256.Uint).UnsafeAdd(value1, u256.One()) // (-pow2) / pow2 + 1) + // println("value2:", value2.ToString()) + + // _intH := i256.FromUint256(h) + value3 := new(u256.Uint).Mul(h, value2) // h * ((-pow2) / pow2 + 1); + l = new(u256.Uint).UnsafeAdd(l, value3) + + r := u256.One() + + // r *= 2 - d * r; [ x8 ] + // value11 := new(u256.Uint).UnsafeSub(u256.NewUint(2), d) // 2 - d + // value12 := new(u256.Uint).Mul(value11, r) // 2 - d * r + // r = new(u256.Uint).Mul(r, value12) // r *= 2 - d * r; + + // d * r + // 2 - ( d * r ) + + for i := 0; i < 8; i++ { + value1 := new(u256.Uint).Mul(d, r) // d * r + value2 := new(u256.Uint).UnsafeSub(u256.NewUint(2), value1) // 2 - ( d * r ) + r = new(u256.Uint).Mul(r, value2) // r *= 2 - d * r; + + } + + println("l:", l.ToString()) + println("r:", r.ToString()) + + res := new(u256.Uint).Mul(l, r) + println("res:", res.ToString()) + return res + // return new(u256.Uint).Mul(l, r) + +} + +func MulDiv( + x *u256.Uint, + y *u256.Uint, + d *u256.Uint, +) *u256.Uint { + l, h := fullMul(x, y) + mm := new(u256.Uint).MulMod(x, y, d) + + if mm.Gt(l) { + h = new(u256.Uint).Sub(h, u256.One()) + } + l = new(u256.Uint).Sub(l, mm) + + if h.IsZero() { + return new(u256.Uint).Div(l, d) + } + + if !(h.Lt(d)) { + panic("FULLDIV_OVERFLOW") + } + + return fullDiv(l, h, d) +} + +func DivRoundingUp( + x *u256.Uint, + y *u256.Uint, +) *u256.Uint { + div := new(u256.Uint).Div(x, y) + + mod := new(u256.Uint).Mod(x, y) + gt := u256.Zero() + if mod.Gt(u256.Zero()) { + gt = mod + } else { + gt = u256.Zero() + } + + return new(u256.Uint).Add(div, gt) +} + +// HELPERs +func mulmod( + x *u256.Uint, + y *u256.Uint, + z *u256.Uint, +) *u256.Uint { + mul := new(u256.Uint).Mul(x, y) + mod := new(u256.Uint).Mod(mul, z) + + return mod +} diff --git a/packages/big/uint512/uint512_test.gno b/packages/big/uint512/uint512_test.gno new file mode 100644 index 00000000..b261c048 --- /dev/null +++ b/packages/big/uint512/uint512_test.gno @@ -0,0 +1,37 @@ +package uint512 + +import ( + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" + + "testing" +) + +func init() { + var _1 = i256.Zero() + var _2 = u256.Zero() +} + +// func TestFunc(*testing.T) { +// x := u256.UnsafeFromDecimal("792281625142643375935439503360000000") +// y := u256.UnsafeFromDecimal("1461446703485210103208044889689724484785180020005") +// d := u256.One() + +// z := MulDiv(x, y, d) +// println(z.ToString()) +// } + +func TestFunc2(t *testing.T) { + x := u256.UnsafeFromDecimal("792281625142643375935439503360000000") // num1 + y := u256.UnsafeFromDecimal("1461446703485210103208044889689724484785180020005") // num2 + // d := u256.One() + + sqrtB := u256.UnsafeFromDecimal("1461446703485210103287273052203988822378723970342") + sqrtA := u256.UnsafeFromDecimal("79228162514264337593543950337") + + z := MulDiv(x, y, sqrtB) + println("num1 * num2 / sqrtB:", z.ToString()) + + r := DivRoundingUp(z, sqrtA) + println("num1 * num2 / sqrtB / sqrtA:", r.ToString()) +} diff --git a/common/_TEST_tick_math_test.gno b/packages/common/_TEST_tick_math_test.gno similarity index 100% rename from common/_TEST_tick_math_test.gno rename to packages/common/_TEST_tick_math_test.gno diff --git a/common/liquidity_amounts.gno b/packages/common/liquidity_amounts.gno similarity index 82% rename from common/liquidity_amounts.gno rename to packages/common/liquidity_amounts.gno index 448b7989..d0be00d3 100644 --- a/common/liquidity_amounts.gno +++ b/packages/common/liquidity_amounts.gno @@ -1,8 +1,9 @@ package common import ( - "gno.land/p/demo/u256" "gno.land/r/demo/consts" + + u256 "gno.land/p/big/uint256" ) // toAscendingOrder checkes if the first value is greater than @@ -18,10 +19,10 @@ func toAscendingOrder(a, b *u256.Uint) (*u256.Uint, *u256.Uint) { // calcIntermediateValue computes the intermediate value // used in liquidity calculations. func calcIntermediateValue(sqrtRatioAX96, sqrtRatioBX96 *u256.Uint) *u256.Uint { - result := new(u256.Uint).Mul(sqrtRatioAX96, sqrtRatioBX96) - result.Div(result, u256.FromBigint(consts.Q96)) - return result + res := new(u256.Uint).Mul(sqrtRatioAX96, sqrtRatioBX96) + res = res.Div(res, u256.UnsafeFromDecimal(consts.Q96)) + return res } // computeLiquidityForAmount0 calculates liquidity for a given amount of token 0. @@ -31,9 +32,9 @@ func computeLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0 *u256.Uint diff := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) // we don't need to care about division by zero here. - result := new(u256.Uint).Mul(amount0, intermediate) - result.Div(result, diff) - return result + res := new(u256.Uint).Mul(amount0, intermediate) + res = res.Div(res, diff) + return res } // computeLiquidityForAmount1 calculates liquidity for a given amount of token 1. @@ -41,9 +42,9 @@ func computeLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1 *u256.Uint sqrtRatioAX96, sqrtRatioBX96 = toAscendingOrder(sqrtRatioAX96, sqrtRatioBX96) diff := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - result := new(u256.Uint).Mul(amount1, u256.FromBigint(consts.Q96)) - result.Div(result, diff) - return result + res := new(u256.Uint).Mul(amount1, u256.UnsafeFromDecimal(consts.Q96)) + res = res.Div(res, diff) + return res } // GetLiquidityForAmounts calculates the liquidity for given amounts od token 0 and token 1. @@ -53,7 +54,7 @@ func GetLiquidityForAmounts(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, amount0, if sqrtRatioX96.Lte(sqrtRatioAX96) { liquidity = computeLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0) - } else if sqrtRatioX96 < sqrtRatioBX96 { + } else if sqrtRatioX96.Lt(sqrtRatioBX96) { liquidity0 := computeLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0) liquidity1 := computeLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1) @@ -75,12 +76,13 @@ func computeAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity *u256.Ui sqrtRatioAX96, sqrtRatioBX96 = toAscendingOrder(sqrtRatioAX96, sqrtRatioBX96) diff := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - numerator := new(u256.Uint).Lsh(liquidity, 96) - numerator.Mul(numerator, diff) + res := new(u256.Uint).Lsh(liquidity, 96) + res = res.Mul(res, diff) - denominator := new(u256.Uint).Mul(sqrtRatioBX96, sqrtRatioAX96) + _tmp := new(u256.Uint).Mul(sqrtRatioBX96, sqrtRatioAX96) + res = res.Div(res, _tmp) - return numerator.Div(numerator, denominator) + return res } // computeAmount1ForLiquidity calculates the amount of token 1 for a given liquidity. @@ -88,9 +90,10 @@ func computeAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity *u256.Ui sqrtRatioAX96, sqrtRatioBX96 = toAscendingOrder(sqrtRatioAX96, sqrtRatioBX96) diff := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - result := new(u256.Uint).Mul(liquidity, diff) - result.Div(result, u256.FromBigint(consts.Q96)) - return result + res := new(u256.Uint).Mul(liquidity, diff) + res = res.Div(res, u256.UnsafeFromDecimal(consts.Q96)) + + return res } // GetAmountsForLiquidity calculates the amounts of token 0 and token 1 for a given liquidity. @@ -110,5 +113,5 @@ func GetAmountsForLiquidity(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, liquidit amount1 = computeAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity) } - return amount0, amount1 + return amount0.NilToZero(), amount1.NilToZero() } diff --git a/packages/common/tick_math.gno b/packages/common/tick_math.gno new file mode 100644 index 00000000..b6cb0e8c --- /dev/null +++ b/packages/common/tick_math.gno @@ -0,0 +1,209 @@ +package common + +import ( + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" +) + +var tickRatioMap = map[int32]*u256.Uint{ + 0x1: u256.UnsafeFromDecimal("340265354078544963557816517032075149313"), // 0xfffcb933bd6fad37aa2d162d1a594001, + 0x2: u256.UnsafeFromDecimal("340248342086729790484326174814286782778"), // 0xfff97272373d413259a46990580e213a, + 0x4: u256.UnsafeFromDecimal("340214320654664324051920982716015181260"), // 0xfff2e50f5f656932ef12357cf3c7fdcc, + 0x8: u256.UnsafeFromDecimal("340146287995602323631171512101879684304"), // 0xffe5caca7e10e4e61c3624eaa0941cd0, + 0x10: u256.UnsafeFromDecimal("340010263488231146823593991679159461444"), // 0xffcb9843d60f6159c9db58835c926644, + 0x20: u256.UnsafeFromDecimal("339738377640345403697157401104375502016"), // 0xff973b41fa98c081472e6896dfb254c0, + 0x40: u256.UnsafeFromDecimal("339195258003219555707034227454543997025"), // 0xff2ea16466c96a3843ec78b326b52861, + 0x80: u256.UnsafeFromDecimal("338111622100601834656805679988414885971"), // 0xfe5dee046a99a2a811c461f1969c3053, + 0x100: u256.UnsafeFromDecimal("335954724994790223023589805789778977700"), // 0xfcbe86c7900a88aedcffc83b479aa3a4, + 0x200: u256.UnsafeFromDecimal("331682121138379247127172139078559817300"), // 0xf987a7253ac413176f2b074cf7815e54, + 0x400: u256.UnsafeFromDecimal("323299236684853023288211250268160618739"), // 0xf3392b0822b70005940c7a398e4b70f3, + 0x800: u256.UnsafeFromDecimal("307163716377032989948697243942600083929"), // 0xe7159475a2c29b7443b29c7fa6e889d9, + 0x1000: u256.UnsafeFromDecimal("277268403626896220162999269216087595045"), // 0xd097f3bdfd2022b8845ad8f792aa5825, + 0x2000: u256.UnsafeFromDecimal("225923453940442621947126027127485391333"), // 0xa9f746462d870fdf8a65dc1f90e061e5, + 0x4000: u256.UnsafeFromDecimal("149997214084966997727330242082538205943"), // 0x70d869a156d2a1b890bb3df62baf32f7, + 0x8000: u256.UnsafeFromDecimal("66119101136024775622716233608466517926"), // 0x31be135f97d08fd981231505542fcfa6, + 0x10000: u256.UnsafeFromDecimal("12847376061809297530290974190478138313"), // 0x9aa508b5b7a84e1c677de54f3e99bc9, + 0x20000: u256.UnsafeFromDecimal("485053260817066172746253684029974020"), // 0x5d6af8dedb81196699c329225ee604, + 0x40000: u256.UnsafeFromDecimal("691415978906521570653435304214168"), // 0x2216e584f5fa1ea926041bedfe98, + 0x80000: u256.UnsafeFromDecimal("1404880482679654955896180642"), // 0x48a170391f7dc42444e8fa2, +} + +var binaryLogConsts = [8]*u256.Uint{ + u256.UnsafeFromDecimal("0"), // 0x0, + u256.UnsafeFromDecimal("3"), // 0x3, + u256.UnsafeFromDecimal("15"), // 0xF, + u256.UnsafeFromDecimal("255"), // 0xFF, + u256.UnsafeFromDecimal("65535"), // 0xFFFF, + u256.UnsafeFromDecimal("4294967295"), // 0xFFFFFFFF, + u256.UnsafeFromDecimal("18446744073709551615"), // 0xFFFFFFFFFFFFFFFF, + u256.UnsafeFromDecimal("340282366920938463463374607431768211455"), // 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, +} + +var ( + shift1By32Left = u256.UnsafeFromDecimal("4294967296") // (1 << 32) +) + +func TickMathGetSqrtRatioAtTick(tick int32) *u256.Uint { // uint160 sqrtPriceX96 + absTick := abs(tick) + ratio := u256.UnsafeFromDecimal("340282366920938463463374607431768211456") // consts.Q128 + + for mask, value := range tickRatioMap { + if absTick&mask != 0 { + // ratio = (ratio * value) >> 128 + ratio = ratio.Mul(ratio, value) + ratio = ratio.Rsh(ratio, 128) + } + } + + if tick > 0 { + _maxUint256 := u256.UnsafeFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935") // consts.MAX_UINT256 + _tmp := new(u256.Uint).Div(_maxUint256, ratio) + ratio = _tmp.Clone() + } + + shifted := ratio.Rsh(ratio, 32).Clone() + + remainder := ratio.Mod(ratio, shift1By32Left) + + if new(u256.Uint).Add(shifted.Clone(), remainder.Clone()).IsZero() { + return shifted + } + + return new(u256.Uint).Add(shifted, u256.One()) +} + +func TickMathGetTickAtSqrtRatio(sqrtPriceX96 *u256.Uint) int32 { + + ratio := new(u256.Uint).Lsh(sqrtPriceX96, 32) + + msb, adjustedRatio := findMSB(ratio) + adjustedRatio = adjustRatio(ratio, msb) + + log2 := calculateLog2(msb, adjustedRatio) + tick := getTickValue(log2, sqrtPriceX96) + + return tick +} + +// findMSB computes the MSB (most significant bit) of the given ratio. +func findMSB(ratio *u256.Uint) (*u256.Uint, *u256.Uint) { + msb := u256.Zero() + + for i := 7; i >= 1; i-- { + f := new(u256.Uint).Lsh(gt(ratio, binaryLogConsts[i]), uint(i)) + msb = new(u256.Uint).Or(msb, f) + ratio = new(u256.Uint).Rsh(ratio, uint(f.Uint64())) + } + + // handle the remaining bits + { + f := gt(ratio, u256.One()) // 0x1 + // msb = msb | f + msb = new(u256.Uint).Or(msb, f) + } + + return msb, ratio +} + +// adjustRatio adjusts the given ratio based on the MSB found. +// +// This adjustment ensures that the ratio falls within the specific range. +func adjustRatio(ratio, msb *u256.Uint) *u256.Uint { + if msb.Gte(u256.NewUint(128)) { + return new(u256.Uint).Rsh(ratio, uint(msb.Uint64()-127)) + } + + return new(u256.Uint).Lsh(ratio, uint(127-msb.Uint64())) +} + +// calculateLog2 calculates the binary logarith, of the adjusted ratio using a fixed-point arithmetic. +// +// This function iteratively squares the ratio and adjusts the result to compute the log base 2, which will determine the tick value. +func calculateLog2(msb, ratio *u256.Uint) *i256.Int { + _msb := i256.FromUint256(msb) + _128 := i256.NewInt(128) + + log_2 := i256.Zero().Sub(_msb, _128) + log_2 = log_2.Lsh(log_2, 64) + + for i := 63; i >= 51; i-- { + ratio = new(u256.Uint).Mul(ratio, ratio) + ratio = ratio.Rsh(ratio, 127) + + f := i256.FromUint256(new(u256.Uint).Rsh(ratio, 128)) + + // log_2 = log_2 | (f << i) + log_2 = i256.Zero().Or(log_2, i256.Zero().Lsh(f, uint(i))) + + // ratio = ratio >> uint64(f) + ratio = ratio.Rsh(ratio, uint(f.Uint64())) + } + + // handle the remaining bits + { + // ratio = ratio * ratio >> 127 + ratio = new(u256.Uint).Mul(ratio, ratio) + ratio = new(u256.Uint).Rsh(ratio, 127) + + f := i256.FromUint256(new(u256.Uint).Rsh(ratio, 128)) + + log_2 = i256.Zero().Or(log_2, i256.Zero().Lsh(f, 50)) + } + + return log_2 +} + +// getTickValue determines the tick value corresponding to a given sqrtPriveX96. +// +// It calculates the upper and lower bounds for each tick, and selects the appropriate tock value +// based on the given sqrtPriceX96. +func getTickValue(log2 *i256.Int, sqrtPriceX96 *u256.Uint) int32 { + // ref: https://github.com/Uniswap/v3-core/issues/500 + // 2^64 / log2 (√1.0001) = 255738958999603826347141 + log_sqrt10001 := i256.Zero().Mul(log2, i256.UnsafeFromDecimal("255738958999603826347141")) + + // ref: https://ethereum.stackexchange.com/questions/113844/how-does-uniswap-v3s-logarithm-library-tickmath-sol-work/113912#113912 + // 0.010000497 x 2^128 = 3402992956809132418596140100660247210 + tickLow256 := i256.Zero().Sub(log_sqrt10001, i256.UnsafeFromDecimal("3402992956809132418596140100660247210")) + tickLow256 = tickLow256.Rsh(tickLow256, 128) + tickLow := int32(tickLow256.Int64()) + + // ref: https://ethereum.stackexchange.com/questions/113844/how-does-uniswap-v3s-logarithm-library-tickmath-sol-work/113912#113912 + // 0.856 x 2^128 = 291339464771989622907027621153398088495 + tickHi256 := i256.Zero().Add(log_sqrt10001, i256.UnsafeFromDecimal("291339464771989622907027621153398088495")) + tickHi256 = tickHi256.Rsh(tickHi256, 128) + tickHi := int32(tickHi256.Int64()) + + var tick int32 + if tickLow == tickHi { + tick = tickLow + } else if TickMathGetSqrtRatioAtTick(tickHi).Lte(sqrtPriceX96) { + tick = tickHi + } else { + tick = tickLow + } + + return tick +} + +func gt(x, y *u256.Uint) *u256.Uint { + if x.Gt(y) { + return u256.One() + } + + return u256.Zero() +} + +func require(condition bool, message string) { + if !condition { + panic(message) + } +} + +func abs(x int32) int32 { + if x < 0 { + return -x + } + + return x +} diff --git a/pool/TEST_liquidity_math_test.gnoa b/pool/TEST_liquidity_math_test.gnoa deleted file mode 100644 index 00c00e29..00000000 --- a/pool/TEST_liquidity_math_test.gnoa +++ /dev/null @@ -1,53 +0,0 @@ -package pool - -// import ( -// "testing" -// "gno.land/p/demo/ufmt" -// ) - -// func TestLiquidityMathAddDelta(t *testing.T) { -// testCases := []struct { -// x bigint -// y bigint -// expected bigint -// isErr bool -// }{ -// {-1000, -500, -1500, true}, -// {-1000, 500, -500, true}, -// {-200, -100, -300, true}, -// {-200, 100, -100, true}, -// {-100, -50, -150, true}, -// {-100, 50, -50, true}, -// {0, -100, -100, true}, -// {0, 0, 0, false}, -// {10, -5, 5, false}, -// {10, 5, 15, false}, -// {100, -50, 50, false}, -// {100, 50, 150, false}, -// {200, -100, 100, false}, -// {200, 100, 300, false}, -// {1000, -500, 500, false}, -// {1000, 500, 1500, false}, -// } - -// for i, tc := range testCases { -// func() { -// defer func() { -// if r := recover(); r != nil { -// if !tc.isErr { -// t.Errorf("Test case %d failed: x=%d, y=%d, expected=%d, got panic but didn't expect one", i+1, tc.x, tc.y, tc.expected) -// } -// } else { -// if tc.isErr { -// t.Errorf("Test case %d failed: x=%d, y=%d, expected panic but didn't get one", i+1, tc.x, tc.y) -// } -// } -// }() - -// result := liquidityMathAddDelta(tc.x, tc.y) -// if result != tc.expected && !tc.isErr { -// t.Errorf("Test case %d failed: x=%d, y=%d, expected=%d, got=%d", i+1, tc.x, tc.y, tc.expected, result) -// } -// }() -// } -// } diff --git a/pool/_GET_no_receiver.gno b/pool/_GET_no_receiver.gno index 57389a14..b346232d 100644 --- a/pool/_GET_no_receiver.gno +++ b/pool/_GET_no_receiver.gno @@ -2,199 +2,202 @@ package pool import ( "gno.land/p/demo/ufmt" + + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) // Slot0 -func PoolGetSlot0SqrtPriceX96(poolPath string) bigint { +func PoolGetSlot0SqrtPriceX96(poolPath string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetSlot0SqrtPriceX96() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetSlot0SqrtPriceX96() || pool(%s) does not exist", poolPath)) return pool.slot0.sqrtPriceX96 } func PoolGetSlot0Tick(poolPath string) int32 { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetSlot0Tick() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetSlot0Tick() || pool(%s) does not exist", poolPath)) return pool.slot0.tick } func PoolGetSlot0FeeProtocol(poolPath string) uint8 { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetSlot0FeeProtocol() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetSlot0FeeProtocol() || pool(%s) does not exist", poolPath)) return pool.slot0.feeProtocol } // Balances -func PoolGetToken0Balance(poolPath string) bigint { +func PoolGetToken0Balance(poolPath string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetToken0Balance() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetToken0Balance() || pool(%s) does not exist", poolPath)) return pool.balances.token0 } -func PoolGetToken1Balance(poolPath string) bigint { +func PoolGetToken1Balance(poolPath string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetToken1Balance() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetToken1Balance() || pool(%s) does not exist", poolPath)) return pool.balances.token1 } // ProtocolFees -func PoolGetToken0ProtocolFee(poolPath string) bigint { +func PoolGetToken0ProtocolFee(poolPath string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetToken0ProtocolFee() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetToken0ProtocolFee() || pool(%s) does not exist", poolPath)) return pool.protocolFees.token0 } -func PoolGetToken1ProtocolFee(poolPath string) bigint { +func PoolGetToken1ProtocolFee(poolPath string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetToken1ProtocolFee() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetToken1ProtocolFee() || pool(%s) does not exist", poolPath)) return pool.protocolFees.token1 } // PositionInfo -func PoolGetPositionLiquidity(poolPath, key string) bigint { +func PoolGetPositionLiquidity(poolPath, key string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionLiquidity() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetPositionLiquidity() || pool(%s) does not exist", poolPath)) position, exist := pool.positions[key] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionLiquidity() || position(%s) does not exist", key)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetPositionLiquidity() || position(%s) does not exist", key)) return position.liquidity } -func PoolGetPositionFeeGrowthInside0LastX128(poolPath, key string) bigint { +func PoolGetPositionFeeGrowthInside0LastX128(poolPath, key string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionFeeGrowthInside0LastX128() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetPositionFeeGrowthInside0LastX128() || pool(%s) does not exist", poolPath)) position, exist := pool.positions[key] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionFeeGrowthInside0LastX128) || position(%s) does not exist", key)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetPositionFeeGrowthInside0LastX128) || position(%s) does not exist", key)) return position.feeGrowthInside0LastX128 } -func PoolGetPositionFeeGrowthInside1LastX128(poolPath, key string) bigint { +func PoolGetPositionFeeGrowthInside1LastX128(poolPath, key string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionFeeGrowthInside1LastX128() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetPositionFeeGrowthInside1LastX128() || pool(%s) does not exist", poolPath)) position, exist := pool.positions[key] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionFeeGrowthInside1LastX128() || position(%s) does not exist", key)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetPositionFeeGrowthInside1LastX128() || position(%s) does not exist", key)) return position.feeGrowthInside1LastX128 } -func PoolGetPositionTokensOwed0(poolPath, key string) bigint { +func PoolGetPositionTokensOwed0(poolPath, key string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionTokensOwed0() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetPositionTokensOwed0() || pool(%s) does not exist", poolPath)) position, exist := pool.positions[key] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionTokensOwed0() || position(%s) does not exist", key)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetPositionTokensOwed0() || position(%s) does not exist", key)) return position.tokensOwed0 } -func PoolGetPositionTokensOwed1(poolPath, key string) bigint { +func PoolGetPositionTokensOwed1(poolPath, key string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionTokensOwed1() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetPositionTokensOwed1() || pool(%s) does not exist", poolPath)) position, exist := pool.positions[key] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionTokensOwed1() || position(%s) does not exist", key)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetPositionTokensOwed1() || position(%s) does not exist", key)) return position.tokensOwed1 } // TickInfo -func PoolGetTickLiquidityGross(poolPath string, x int32) bigint { +func PoolGetTickLiquidityGross(poolPath string, x int32) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickLiquidityGross() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickLiquidityGross() || pool(%s) does not exist", poolPath)) tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickLiquidityGross() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickLiquidityGross() || tick(%d) does not exist", x)) return tick.liquidityGross } -func PoolGetTickLiquidityNet(poolPath string, x int32) bigint { +func PoolGetTickLiquidityNet(poolPath string, x int32) *i256.Int { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickLiquidityNet() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickLiquidityNet() || pool(%s) does not exist", poolPath)) tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickLiquidityNet() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickLiquidityNet() || tick(%d) does not exist", x)) return tick.liquidityNet } -func PoolGetTickFeeGrowthOutside0X128(poolPath string, x int32) bigint { +func PoolGetTickFeeGrowthOutside0X128(poolPath string, x int32) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickFeeGrowthOutside0X128() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickFeeGrowthOutside0X128() || pool(%s) does not exist", poolPath)) tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickFeeGrowthOutside0X128() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickFeeGrowthOutside0X128() || tick(%d) does not exist", x)) return tick.feeGrowthOutside0X128 } -func PoolGetTickFeeGrowthOutside1X128(poolPath string, x int32) bigint { +func PoolGetTickFeeGrowthOutside1X128(poolPath string, x int32) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickFeeGrowthOutside1X128() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickFeeGrowthOutside1X128() || pool(%s) does not exist", poolPath)) tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickFeeGrowthOutside1X128() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickFeeGrowthOutside1X128() || tick(%d) does not exist", x)) return tick.feeGrowthOutside1X128 } -func PoolGetTickTickCumulativeOutside(poolPath string, x int32) bigint { +func PoolGetTickTickCumulativeOutside(poolPath string, x int32) int64 { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickTickCumulativeOutside() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickTickCumulativeOutside() || pool(%s) does not exist", poolPath)) tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickTickCumulativeOutside() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickTickCumulativeOutside() || tick(%d) does not exist", x)) return tick.tickCumulativeOutside } -func PoolGetTickSecondsPerLiquidityOutsideX128(poolPath string, x int32) bigint { +func PoolGetTickSecondsPerLiquidityOutsideX128(poolPath string, x int32) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickSecondsPerLiquidityOutsideX128() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickSecondsPerLiquidityOutsideX128() || pool(%s) does not exist", poolPath)) tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickSecondsPerLiquidityOutsideX128() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickSecondsPerLiquidityOutsideX128() || tick(%d) does not exist", x)) return tick.secondsPerLiquidityOutsideX128 } -func PoolGetTickSecondsOutside(poolPath string, x int32) bigint { +func PoolGetTickSecondsOutside(poolPath string, x int32) uint32 { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickSecondsOutside() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickSecondsOutside() || pool(%s) does not exist", poolPath)) tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickSecondsOutside() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickSecondsOutside() || tick(%d) does not exist", x)) return tick.secondsOutside } func PoolGetTickInitialized(poolPath string, x int32) bool { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickInitialized() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickInitialized() || pool(%s) does not exist", poolPath)) tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickInitialized() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickInitialized() || tick(%d) does not exist", x)) return tick.initialized } // TickBitmaps -func PoolGetTickBitmap(poolPath string, x int16) bigint { +func PoolGetTickBitmap(poolPath string, x int16) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickBitmap() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickBitmap() || pool(%s) does not exist", poolPath)) tickBitmap, exist := pool.tickBitmaps[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickBitmap() || tickBitmap(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickBitmap() || tickBitmap(%d) does not exist", x)) return tickBitmap } @@ -202,49 +205,49 @@ func PoolGetTickBitmap(poolPath string, x int16) bigint { // Pool func PoolGetToken0Path(poolPath string) string { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetToken0Path() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetToken0Path() || pool(%s) does not exist", poolPath)) return pool.token0Path } func PoolGetToken1Path(poolPath string) string { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetToken1Path() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetToken1Path() || pool(%s) does not exist", poolPath)) return pool.token1Path } -func PoolGetFee(poolPath string) uint16 { +func PoolGetFee(poolPath string) uint32 { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetFee() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetFee() || pool(%s) does not exist", poolPath)) return pool.fee } func PoolGetTickSpacing(poolPath string) int32 { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickSpacing() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetTickSpacing() || pool(%s) does not exist", poolPath)) return pool.tickSpacing } -func PoolGetFeeGrowthGlobal0X128(poolPath string) bigint { +func PoolGetFeeGrowthGlobal0X128(poolPath string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetFeeGrowthGlobal0X128() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetFeeGrowthGlobal0X128() || pool(%s) does not exist", poolPath)) return pool.feeGrowthGlobal0X128 } -func PoolGetFeeGrowthGlobal1X128(poolPath string) bigint { +func PoolGetFeeGrowthGlobal1X128(poolPath string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetFeeGrowthGlobal1X128() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetFeeGrowthGlobal1X128() || pool(%s) does not exist", poolPath)) return pool.feeGrowthGlobal1X128 } -func PoolGetLiquidity(poolPath string) bigint { +func PoolGetLiquidity(poolPath string) *u256.Uint { pool, exist := pools[poolPath] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetLiquidity() || pool(%s) does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_no_receiver.gno__PoolGetLiquidity() || pool(%s) does not exist", poolPath)) return pool.liquidity } diff --git a/pool/_GET_no_receiver_string.gno b/pool/_GET_no_receiver_string.gno new file mode 100644 index 00000000..54439309 --- /dev/null +++ b/pool/_GET_no_receiver_string.gno @@ -0,0 +1,170 @@ +package pool + +import ( + "gno.land/p/demo/ufmt" +) + +// Balances +func PoolGetToken0BalanceStr(poolPath string) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetToken0BalanceStr() || pool(%s) does not exist", poolPath)) + + return pool.balances.token0.ToString() +} + +func PoolGetToken1BalanceStr(poolPath string) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetToken1BalanceStr() || pool(%s) does not exist", poolPath)) + + return pool.balances.token1.ToString() +} + +// ProtocolFees +func PoolGetToken0ProtocolFeeStr(poolPath string) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetToken0ProtocolFeeStr() || pool(%s) does not exist", poolPath)) + + return pool.protocolFees.token0.ToString() +} + +func PoolGetToken1ProtocolFeeStr(poolPath string) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetToken1ProtocolFeeStr() || pool(%s) does not exist", poolPath)) + + return pool.protocolFees.token1.ToString() +} + +// PositionInfo +func PoolGetPositionLiquidityStr(poolPath, key string) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetPositionLiquidityStr() || pool(%s) does not exist", poolPath)) + + position, exist := pool.positions[key] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetPositionLiquidityStr() || position(%s) does not exist", key)) + + return position.liquidity.ToString() +} + +func PoolGetPositionFeeGrowthInside0LastX128Str(poolPath, key string) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetPositionFeeGrowthInside0LastX128Str() || pool(%s) does not exist", poolPath)) + + position, exist := pool.positions[key] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetPositionFeeGrowthInside0LastX128Str) || position(%s) does not exist", key)) + + return position.feeGrowthInside0LastX128.ToString() +} + +func PoolGetPositionFeeGrowthInside1LastX128Str(poolPath, key string) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetPositionFeeGrowthInside1LastX128Str() || pool(%s) does not exist", poolPath)) + + position, exist := pool.positions[key] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetPositionFeeGrowthInside1LastX128Str() || position(%s) does not exist", key)) + + return position.feeGrowthInside1LastX128.ToString() +} + +func PoolGetPositionTokensOwed0Str(poolPath, key string) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetPositionTokensOwed0Str() || pool(%s) does not exist", poolPath)) + + position, exist := pool.positions[key] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetPositionTokensOwed0Str() || position(%s) does not exist", key)) + + return position.tokensOwed0.ToString() +} + +func PoolGetPositionTokensOwed1Str(poolPath, key string) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetPositionTokensOwed1Str() || pool(%s) does not exist", poolPath)) + + position, exist := pool.positions[key] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetPositionTokensOwed1Str() || position(%s) does not exist", key)) + + return position.tokensOwed1.ToString() +} + +// TickInfo +func PoolGetTickLiquidityGrossStr(poolPath string, x int32) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetTickLiquidityGrossStr() || pool(%s) does not exist", poolPath)) + + tick, exist := pool.ticks[x] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetTickLiquidityGrossStr() || tick(%d) does not exist", x)) + + return tick.liquidityGross.ToString() +} + +func PoolGetTickLiquidityNetStr(poolPath string, x int32) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetTickLiquidityNetStr() || pool(%s) does not exist", poolPath)) + + tick, exist := pool.ticks[x] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetTickLiquidityNetStr() || tick(%d) does not exist", x)) + + return tick.liquidityNet.ToString() +} + +func PoolGetTickFeeGrowthOutside0X128Str(poolPath string, x int32) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetTickFeeGrowthOutside0X128Str() || pool(%s) does not exist", poolPath)) + + tick, exist := pool.ticks[x] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetTickFeeGrowthOutside0X128Str() || tick(%d) does not exist", x)) + + return tick.feeGrowthOutside0X128.ToString() +} + +func PoolGetTickFeeGrowthOutside1X128Str(poolPath string, x int32) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetTickFeeGrowthOutside1X128Str() || pool(%s) does not exist", poolPath)) + + tick, exist := pool.ticks[x] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetTickFeeGrowthOutside1X128Str() || tick(%d) does not exist", x)) + + return tick.feeGrowthOutside1X128.ToString() +} + +func PoolGetTickSecondsPerLiquidityOutsideX128Str(poolPath string, x int32) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetTickSecondsPerLiquidityOutsideX128Str() || pool(%s) does not exist", poolPath)) + + tick, exist := pool.ticks[x] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetTickSecondsPerLiquidityOutsideX128Str() || tick(%d) does not exist", x)) + + return tick.secondsPerLiquidityOutsideX128.ToString() +} + +// TickBitmaps +func PoolGetTickBitmapStr(poolPath string, x int16) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetTickBitmapStr() || pool(%s) does not exist", poolPath)) + + tickBitmap, exist := pool.tickBitmaps[x] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetTickBitmapStr() || tickBitmap(%d) does not exist", x)) + + return tickBitmap.ToString() +} + +// Pool +func PoolGetFeeGrowthGlobal0X128Str(poolPath string) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetFeeGrowthGlobal0X128Str() || pool(%s) does not exist", poolPath)) + + return pool.feeGrowthGlobal0X128.ToString() +} + +func PoolGetFeeGrowthGlobal1X128Str(poolPath string) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetFeeGrowthGlobal1X128Str() || pool(%s) does not exist", poolPath)) + + return pool.feeGrowthGlobal1X128.ToString() +} + +func PoolGetLiquidityStr(poolPath string) string { + pool, exist := pools[poolPath] + requireExist(exist, ufmt.Sprintf("[POOL]_GET_no_receiver_string.gno__PoolGetLiquidityStr() || pool(%s) does not exist", poolPath)) + + return pool.liquidity.ToString() +} diff --git a/pool/_GET_receiver.gno b/pool/_GET_receiver.gno index e4c25a5c..d0ae7820 100644 --- a/pool/_GET_receiver.gno +++ b/pool/_GET_receiver.gno @@ -2,6 +2,9 @@ package pool import ( "gno.land/p/demo/ufmt" + + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) func PoolGetPoolList() []string { @@ -18,7 +21,7 @@ func (pool *Pool) PoolGetSlot0() Slot0 { return pool.slot0 } -func (pool *Pool) PoolGetSlot0SqrtPriceX96() bigint { +func (pool *Pool) PoolGetSlot0SqrtPriceX96() *u256.Uint { return pool.slot0.sqrtPriceX96 } @@ -31,20 +34,20 @@ func (pool *Pool) PoolGetSlot0FeeProtocol() uint8 { } // Balances -func (pool *Pool) PoolGetToken0Balance() bigint { +func (pool *Pool) PoolGetToken0Balance() *u256.Uint { return pool.balances.token0 } -func (pool *Pool) PoolGetToken1Balance() bigint { +func (pool *Pool) PoolGetToken1Balance() *u256.Uint { return pool.balances.token1 } // ProtocolFees -func (pool *Pool) PoolGetToken0ProtocolFee() bigint { +func (pool *Pool) PoolGetToken0ProtocolFee() *u256.Uint { return pool.protocolFees.token0 } -func (pool *Pool) PoolGetToken1ProtocolFee() bigint { +func (pool *Pool) PoolGetToken1ProtocolFee() *u256.Uint { return pool.protocolFees.token1 } @@ -55,42 +58,42 @@ func (pool *Pool) PoolGetPositions() Positions { func (pool *Pool) PoolGetPosition(key string) PositionInfo { position, exist := pool.positions[key] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPosition() || position(%s) does not exist", key)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetPosition() || position(%s) does not exist", key)) return position } -func (pool *Pool) PoolGetPositionLiquidity(key string) bigint { +func (pool *Pool) PoolGetPositionLiquidity(key string) *u256.Uint { position, exist := pool.positions[key] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionLiquidity() || position(%s) does not exist", key)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetPositionLiquidity() || position(%s) does not exist", key)) return position.liquidity } -func (pool *Pool) PoolGetPositionFeeGrowthInside0LastX128(key string) bigint { +func (pool *Pool) PoolGetPositionFeeGrowthInside0LastX128(key string) *u256.Uint { position, exist := pool.positions[key] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionFeeGrowthInside0LastX128) || position(%s) does not exist", key)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetPositionFeeGrowthInside0LastX128) || position(%s) does not exist", key)) return position.feeGrowthInside0LastX128 } -func (pool *Pool) PoolGetPositionFeeGrowthInside1LastX128(key string) bigint { +func (pool *Pool) PoolGetPositionFeeGrowthInside1LastX128(key string) *u256.Uint { position, exist := pool.positions[key] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionFeeGrowthInside1LastX128() || position(%s) does not exist", key)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetPositionFeeGrowthInside1LastX128() || position(%s) does not exist", key)) return position.feeGrowthInside1LastX128 } -func (pool *Pool) PoolGetPositionTokensOwed0(key string) bigint { +func (pool *Pool) PoolGetPositionTokensOwed0(key string) *u256.Uint { position, exist := pool.positions[key] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionTokensOwed0() || position(%s) does not exist", key)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetPositionTokensOwed0() || position(%s) does not exist", key)) return position.tokensOwed0 } -func (pool *Pool) PoolGetPositionTokensOwed1(key string) bigint { +func (pool *Pool) PoolGetPositionTokensOwed1(key string) *u256.Uint { position, exist := pool.positions[key] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetPositionTokensOwed1() || position(%s) does not exist", key)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetPositionTokensOwed1() || position(%s) does not exist", key)) return position.tokensOwed1 } @@ -98,71 +101,71 @@ func (pool *Pool) PoolGetPositionTokensOwed1(key string) bigint { // TickInfo func (pool *Pool) PoolGetTick(x int32) TickInfo { tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTick() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetTick() || tick(%d) does not exist", x)) return tick } -func (pool *Pool) PoolGetTickLiquidityGross(x int32) bigint { +func (pool *Pool) PoolGetTickLiquidityGross(x int32) *u256.Uint { tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickLiquidityGross() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetTickLiquidityGross() || tick(%d) does not exist", x)) return tick.liquidityGross } -func (pool *Pool) PoolGetTickLiquidityNet(x int32) bigint { +func (pool *Pool) PoolGetTickLiquidityNet(x int32) *i256.Int { tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickLiquidityNet() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetTickLiquidityNet() || tick(%d) does not exist", x)) return tick.liquidityNet } -func (pool *Pool) PoolGetTickFeeGrowthOutside0X128(x int32) bigint { +func (pool *Pool) PoolGetTickFeeGrowthOutside0X128(x int32) *u256.Uint { tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickFeeGrowthOutside0X128() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetTickFeeGrowthOutside0X128() || tick(%d) does not exist", x)) return tick.feeGrowthOutside0X128 } -func (pool *Pool) PoolGetTickFeeGrowthOutside1X128(x int32) bigint { +func (pool *Pool) PoolGetTickFeeGrowthOutside1X128(x int32) *u256.Uint { tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickFeeGrowthOutside1X128() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetTickFeeGrowthOutside1X128() || tick(%d) does not exist", x)) return tick.feeGrowthOutside1X128 } -func (pool *Pool) PoolGetTickTickCumulativeOutside(x int32) bigint { +func (pool *Pool) PoolGetTickTickCumulativeOutside(x int32) int64 { tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickTickCumulativeOutside() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetTickTickCumulativeOutside() || tick(%d) does not exist", x)) return tick.tickCumulativeOutside } -func (pool *Pool) PoolGetTickSecondsPerLiquidityOutsideX128(x int32) bigint { +func (pool *Pool) PoolGetTickSecondsPerLiquidityOutsideX128(x int32) *u256.Uint { tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickSecondsPerLiquidityOutsideX128() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetTickSecondsPerLiquidityOutsideX128() || tick(%d) does not exist", x)) return tick.secondsPerLiquidityOutsideX128 } -func (pool *Pool) PoolGetTickSecondsOutside(x int32) bigint { +func (pool *Pool) PoolGetTickSecondsOutside(x int32) uint32 { tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickSecondsOutside() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetTickSecondsOutside() || tick(%d) does not exist", x)) return tick.secondsOutside } func (pool *Pool) PoolGetTickInitialized(x int32) bool { tick, exist := pool.ticks[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickInitialized() || tick(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetTickInitialized() || tick(%d) does not exist", x)) return tick.initialized } // TickBitmaps -func (pool *Pool) PoolGetTickBitmap(x int16) bigint { +func (pool *Pool) PoolGetTickBitmap(x int16) *u256.Uint { tickBitmap, exist := pool.tickBitmaps[x] - requireExist(exist, ufmt.Sprintf("[POOL] _GET_pool.gno__PoolGetTickBitmap() || tickBitmap(%d) does not exist", x)) + requireExist(exist, ufmt.Sprintf("[POOL] _GET_receiver.gno__PoolGetTickBitmap() || tickBitmap(%d) does not exist", x)) return tickBitmap } @@ -176,7 +179,7 @@ func (pool *Pool) PoolGetToken1Path() string { return pool.token1Path } -func (pool *Pool) PoolGetFee() uint16 { +func (pool *Pool) PoolGetFee() uint32 { return pool.fee } @@ -184,14 +187,14 @@ func (pool *Pool) PoolGetTickSpacing() int32 { return pool.tickSpacing } -func (pool *Pool) PoolGetFeeGrowthGlobal0X128() bigint { +func (pool *Pool) PoolGetFeeGrowthGlobal0X128() *u256.Uint { return pool.feeGrowthGlobal0X128 } -func (pool *Pool) PoolGetFeeGrowthGlobal1X128() bigint { +func (pool *Pool) PoolGetFeeGrowthGlobal1X128() *u256.Uint { return pool.feeGrowthGlobal1X128 } -func (pool *Pool) PoolGetLiquidity() bigint { +func (pool *Pool) PoolGetLiquidity() *u256.Uint { return pool.liquidity } diff --git a/pool/_RPC_api.gno b/pool/_RPC_api.gno index 0a428f87..54dd1ce1 100644 --- a/pool/_RPC_api.gno +++ b/pool/_RPC_api.gno @@ -3,9 +3,9 @@ package pool import ( b64 "encoding/base64" "encoding/json" - "strings" - "std" + "strconv" + "strings" "time" "gno.land/p/demo/ufmt" @@ -21,7 +21,7 @@ type RpcPool struct { BalancesToken1 string `json:"balanceToken1"` // fee is the fee tier of the pool - Fee uint16 `json:"fee"` + Fee uint32 `json:"fee"` // tickSpacing is the spacing between ticks TickSpacing int32 `json:"tickSpacing"` @@ -53,8 +53,8 @@ type RpcPool struct { Positions []RpcPosition `json:"positions"` } -type RpcTicks map[int32]RpcTickInfo // tick => RpcTickInfo type RpcTickBitmaps map[int16]string // tick(wordPos) => bitmap(tickWord ^ mask) +type RpcTicks map[int32]RpcTickInfo // tick => RpcTickInfo type RpcTickInfo struct { LiquidityGross string `json:"liquidityGross"` @@ -63,10 +63,10 @@ type RpcTickInfo struct { FeeGrowthOutside0X128 string `json:"feeGrowthOutside0X128"` FeeGrowthOutside1X128 string `json:"feeGrowthOutside1X128"` - //TickCumulativeOutside bigint `json:"tickCumulativeOutside"` + TickCumulativeOutside int64 `json:"tickCumulativeOutside"` - //SecondsPerLiquidityOutsideX bigint `json:"secondsPerLiquidityOutsideX"` - //SecondsOutside bigint `json:"secondsOutside"` + SecondsPerLiquidityOutsideX string `json:"secondsPerLiquidityOutsideX"` + SecondsOutside uint32 `json:"secondsOutside"` Initialized bool `json:"initialized"` } @@ -74,8 +74,8 @@ type RpcTickInfo struct { type RpcPosition struct { Owner string `json:"owner"` - TickLower string `json:"tickLower"` - TickUpper string `json:"tickUpper"` + TickLower int32 `json:"tickLower"` + TickUpper int32 `json:"tickUpper"` Liquidity string `json:"liquidity"` @@ -125,52 +125,49 @@ func rpcMakePool(poolPath string) RpcPool { rpcPool.Token0Path = pool.token0Path rpcPool.Token1Path = pool.token1Path - rpcPool.BalancesToken0 = pool.balances.token0.Dec() - rpcPool.BalancesToken1 = pool.balances.token1.Dec() + rpcPool.BalancesToken0 = pool.balances.token0.ToString() + rpcPool.BalancesToken1 = pool.balances.token1.ToString() rpcPool.Fee = pool.fee rpcPool.TickSpacing = pool.tickSpacing - rpcPool.MaxLiquidityPerTick = pool.maxLiquidityPerTick.Dec() + rpcPool.MaxLiquidityPerTick = pool.maxLiquidityPerTick.ToString() - rpcPool.Slot0SqrtPriceX96 = pool.slot0.sqrtPriceX96.Dec() + rpcPool.Slot0SqrtPriceX96 = pool.slot0.sqrtPriceX96.ToString() rpcPool.Slot0Tick = pool.slot0.tick rpcPool.Slot0FeeProtocol = pool.slot0.feeProtocol rpcPool.Slot0Unlocked = pool.slot0.unlocked - rpcPool.FeeGrowthGlobal0X128 = pool.feeGrowthGlobal0X128.Dec() - rpcPool.FeeGrowthGlobal1X128 = pool.feeGrowthGlobal1X128.Dec() + rpcPool.FeeGrowthGlobal0X128 = pool.feeGrowthGlobal0X128.ToString() + rpcPool.FeeGrowthGlobal1X128 = pool.feeGrowthGlobal1X128.ToString() - rpcPool.ProtocolFeesToken0 = pool.protocolFees.token0.Dec() - rpcPool.ProtocolFeesToken1 = pool.protocolFees.token1.Dec() + rpcPool.ProtocolFeesToken0 = pool.protocolFees.token0.ToString() + rpcPool.ProtocolFeesToken1 = pool.protocolFees.token1.ToString() - rpcPool.Liquidity = pool.liquidity.Dec() + rpcPool.Liquidity = pool.liquidity.ToString() rpcPool.Ticks = RpcTicks{} - for tick, tickInfo := range pool.ticks { rpcPool.Ticks[tick] = RpcTickInfo{ - LiquidityGross: tickInfo.liquidityGross.NilToZero().Dec(), - LiquidityNet: tickInfo.liquidityNet.NilToZero().Dec(), - FeeGrowthOutside0X128: tickInfo.feeGrowthOutside0X128.NilToZero().Dec(), - FeeGrowthOutside1X128: tickInfo.feeGrowthOutside1X128.NilToZero().Dec(), - //TickCumulativeOutside: tickInfo.tickCumulativeOutside, - //SecondsPerLiquidityOutsideX: tickInfo.secondsPerLiquidityOutsideX128, - //SecondsOutside: tickInfo.secondsOutside, - Initialized: tickInfo.initialized, + LiquidityGross: tickInfo.liquidityGross.ToString(), + LiquidityNet: tickInfo.liquidityNet.ToString(), + FeeGrowthOutside0X128: tickInfo.feeGrowthOutside0X128.ToString(), + FeeGrowthOutside1X128: tickInfo.feeGrowthOutside1X128.ToString(), + TickCumulativeOutside: tickInfo.tickCumulativeOutside, + SecondsPerLiquidityOutsideX: tickInfo.secondsPerLiquidityOutsideX128.ToString(), + SecondsOutside: tickInfo.secondsOutside, + Initialized: tickInfo.initialized, } } - tickBitmaps := pool.tickBitmaps rpcPool.TickBitmaps = RpcTickBitmaps{} - for tick, tickBitmap := range tickBitmaps { - rpcPool.TickBitmaps[tick] = tickBitmap.NilToZero().Dec() + for tick, tickBitmap := range pool.tickBitmaps { + rpcPool.TickBitmaps[tick] = tickBitmap.ToString() } Positions := pool.positions rpcPositions := []RpcPosition{} - for posKey, posInfo := range Positions { owner, tickLower, tickUpper := posKeyDivide(posKey) @@ -178,9 +175,9 @@ func rpcMakePool(poolPath string) RpcPool { Owner: owner, TickLower: tickLower, TickUpper: tickUpper, - Liquidity: posInfo.liquidity.Dec(), - Token0Owed: posInfo.tokensOwed0.Dec(), - Token1Owed: posInfo.tokensOwed1.Dec(), + Liquidity: posInfo.liquidity.ToString(), + Token0Owed: posInfo.tokensOwed0.ToString(), + Token1Owed: posInfo.tokensOwed1.ToString(), }) } rpcPool.Positions = rpcPositions @@ -188,7 +185,7 @@ func rpcMakePool(poolPath string) RpcPool { return rpcPool } -func posKeyDivide(posKey string) (string, string, string) { +func posKeyDivide(posKey string) (string, int32, int32) { // base64 decode kDec, _ := b64.StdEncoding.DecodeString(posKey) posKey = string(kDec) @@ -198,7 +195,10 @@ func posKeyDivide(posKey string) (string, string, string) { panic(ufmt.Sprintf("[POOL] _RPC_api.gno__posKeyDivide() || invalid posKey(%s)", posKey)) } - owner, tickLower, tickUpper := res[0], res[1], res[2] + owner, _tickLower, _tickUpper := res[0], res[1], res[2] + + tickLower, _ := strconv.Atoi(_tickLower) + tickUpper, _ := strconv.Atoi(_tickUpper) - return owner, tickLower, tickUpper + return owner, int32(tickLower), int32(tickUpper) } diff --git a/pool/_RPC_dry.gno b/pool/_RPC_dry.gno index 7f6cbc66..0594f054 100644 --- a/pool/_RPC_dry.gno +++ b/pool/_RPC_dry.gno @@ -4,42 +4,59 @@ import ( "std" "gno.land/p/demo/common" - "gno.land/p/demo/u256" + "gno.land/p/demo/ufmt" "gno.land/r/demo/consts" + + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) func DrySwap( token0Path string, token1Path string, - pFee uint16, + fee uint32, recipient std.Address, zeroForOne bool, - amountSpecified_ bigint, - sqrtPriceLimitX96_ bigint, -) (bigint, bigint, bool) { + _amountSpecified string, // int256 + _sqrtPriceLimitX96 string, // uint160 +) (string, string, bool) { // int256 x2 - if amountSpecified_ == 0 { - return 0, 0, false + if _amountSpecified == "0" { + return "0", "0", false } - pool := GetPool(token0Path, token1Path, pFee) - slot0Start := pool.slot0 + amountSpecified, err := i256.FromDecimal(_amountSpecified) + if err != nil { + panic(ufmt.Sprintf("[POOL] _RPC_dry.gno__DrySwap() || u256.FromDecimal(_amountSpecified[%s]) failed", _amountSpecified)) + } + sqrtPriceLimitX96, err := u256.FromDecimal(_sqrtPriceLimitX96) + if err != nil { + panic(ufmt.Sprintf("[POOL] _RPC_dry.gno__DrySwap() || u256.FromDecimal(_sqrtPriceLimitX96[%s]) failed", _sqrtPriceLimitX96)) + } - amountSpecified := u256.IntFromBigint(amountSpecified_) - sqrtPriceLimitX96 := u256.FromDecimal(string(sqrtPriceLimitX96_)) + pool := GetPool(token0Path, token1Path, fee) + slot0Start := pool.slot0 if zeroForOne { - if !(sqrtPriceLimitX96.Lt(slot0Start.sqrtPriceX96) && sqrtPriceLimitX96.Gt(u256.FromBigint(consts.MIN_SQRT_RATIO))) { - return 0, 0, false + min_sqrt_ratio := u256.UnsafeFromDecimal(consts.MIN_SQRT_RATIO) + cond1 := sqrtPriceLimitX96.Lt(slot0Start.sqrtPriceX96) + cond2 := sqrtPriceLimitX96.Gt(min_sqrt_ratio) + + if !(cond1 && cond2) { + return "0", "0", false } } else { - if !(sqrtPriceLimitX96.Gt(slot0Start.sqrtPriceX96) && sqrtPriceLimitX96.Lt(u256.FromBigint(consts.MAX_SQRT_RATIO))) { - return 0, 0, false + max_sqrt_ratio := u256.UnsafeFromDecimal(consts.MAX_SQRT_RATIO) + cond1 := sqrtPriceLimitX96.Gt(slot0Start.sqrtPriceX96) + cond2 := sqrtPriceLimitX96.Lt(max_sqrt_ratio) + + if !(cond1 && cond2) { + return "0", "0", false } } - slot0Start.unlocked = false + pool.slot0.unlocked = false var cache SwapCache if zeroForOne { @@ -54,37 +71,34 @@ func DrySwap( } } - exactInput := amountSpecified.Gt(u256.Zero().Int()) + exactInput := amountSpecified.Gt(i256.Zero()) var state SwapState if zeroForOne { state = SwapState{ amountSpecifiedRemaining: amountSpecified, - amountCalculated: u256.Zero().Int(), + amountCalculated: i256.Zero(), sqrtPriceX96: slot0Start.sqrtPriceX96, tick: slot0Start.tick, - feeGrowthGlobalX128: pool.feeGrowthGlobal0X128.Clone(), + feeGrowthGlobalX128: pool.feeGrowthGlobal0X128, protocolFee: u256.Zero(), liquidity: cache.liquidityStart, } } else { state = SwapState{ amountSpecifiedRemaining: amountSpecified, - amountCalculated: u256.Zero().Int(), + amountCalculated: i256.Zero(), sqrtPriceX96: slot0Start.sqrtPriceX96, tick: slot0Start.tick, - feeGrowthGlobalX128: pool.feeGrowthGlobal1X128.Clone(), + feeGrowthGlobalX128: pool.feeGrowthGlobal1X128, protocolFee: u256.Zero(), liquidity: cache.liquidityStart, } } // continue swapping as long as we haven't used the entire input/output and haven't reached the price limit - origAmountSpecified := amountSpecified.Clone() - for !state.amountSpecifiedRemaining.IsZero() && !state.sqrtPriceX96.Eq(sqrtPriceLimitX96) { - + for !(state.amountSpecifiedRemaining.IsZero()) && !(state.sqrtPriceX96.Eq(sqrtPriceLimitX96)) { var step StepComputations - step.sqrtPriceStartX96 = state.sqrtPriceX96 step.tickNext, step.initialized = pool.tickBitmapNextInitializedTickWithInOneWord( @@ -102,6 +116,7 @@ func DrySwap( // get the price for the next tick step.sqrtPriceNextX96 = common.TickMathGetSqrtRatioAtTick(step.tickNext) + isLower := step.sqrtPriceNextX96.Lt(sqrtPriceLimitX96) isHigher := step.sqrtPriceNextX96.Gt(sqrtPriceLimitX96) @@ -117,34 +132,37 @@ func DrySwap( sqrtRatioTargetX96, state.liquidity, state.amountSpecifiedRemaining, - uint32(pool.fee), + uint64(pool.fee), ) + amountInWithFee := i256.FromUint256(new(u256.Uint).Add(step.amountIn, step.feeAmount)) if exactInput { - state.amountSpecifiedRemaining.Sub(state.amountSpecifiedRemaining, new(u256.Uint).Add(step.amountIn, step.feeAmount).Int()) - state.amountCalculated.Sub(state.amountCalculated, step.amountOut.Int()) + state.amountSpecifiedRemaining = i256.Zero().Sub(state.amountSpecifiedRemaining, amountInWithFee) + state.amountCalculated = i256.Zero().Sub(state.amountCalculated, i256.FromUint256(step.amountOut)) } else { - state.amountSpecifiedRemaining.Add(state.amountSpecifiedRemaining, step.amountOut.Int()) - state.amountCalculated.Add(state.amountCalculated, new(u256.Uint).Add(step.amountIn, step.feeAmount).Int()) + state.amountSpecifiedRemaining = i256.Zero().Add(state.amountSpecifiedRemaining, i256.FromUint256(step.amountOut)) + state.amountCalculated = i256.Zero().Add(state.amountCalculated, amountInWithFee) } // if the protocol fee is on, calculate how much is owed, decrement feeAmount, and increment protocolFee if cache.feeProtocol > 0 { delta := new(u256.Uint).Div(step.feeAmount, u256.NewUint(uint64(cache.feeProtocol))) - step.feeAmount.Sub(step.feeAmount, delta) - state.protocolFee.Add(state.protocolFee, delta) + step.feeAmount = new(u256.Uint).Sub(step.feeAmount, delta) + state.protocolFee = new(u256.Uint).Add(state.protocolFee, delta) } // update global fee tracker if state.liquidity.Gt(u256.Zero()) { - // save fee - update := new(u256.Uint).Mul(step.feeAmount, u256.FromDecimal(string(consts.Q128))) - update.Div(update, state.liquidity) - state.feeGrowthGlobalX128.Add(state.feeGrowthGlobalX128.Clone(), update) + _q128 := u256.UnsafeFromDecimal(consts.Q128) + + value1 := new(u256.Uint).Mul(step.feeAmount, _q128) + value2 := new(u256.Uint).Div(value1, state.liquidity) + + state.feeGrowthGlobalX128 = new(u256.Uint).Add(state.feeGrowthGlobalX128, value2) } // shift tick if we reached the next price - if state.sqrtPriceX96 == step.sqrtPriceNextX96 { + if state.sqrtPriceX96.Eq(step.sqrtPriceNextX96) { // if the tick is initialized, run the tick transition if step.initialized { var fee0, fee1 *u256.Uint @@ -157,6 +175,7 @@ func DrySwap( fee0 = pool.feeGrowthGlobal0X128 fee1 = state.feeGrowthGlobalX128 } + liquidityNet := pool.tickCross( step.tickNext, fee0, @@ -165,7 +184,7 @@ func DrySwap( // if we're moving leftward, we interpret liquidityNet as the opposite sign if zeroForOne { - liquidityNet = liquidityNet.Neg() + liquidityNet = i256.Zero().Neg(liquidityNet) } state.liquidity = liquidityMathAddDelta(state.liquidity, liquidityNet) @@ -176,43 +195,39 @@ func DrySwap( } else { state.tick = step.tickNext } - } else if state.sqrtPriceX96 != step.sqrtPriceStartX96 { + } else if !(state.sqrtPriceX96.Eq(step.sqrtPriceStartX96)) { // recompute unless we're on a lower tick boundary (i.e. already transitioned ticks), and haven't moved state.tick = common.TickMathGetTickAtSqrtRatio(state.sqrtPriceX96) } } // END LOOP - var amount0, amount1 *u256.Int + var amount0, amount1 *i256.Int if zeroForOne == exactInput { - amount0 = new(u256.Int).Sub(origAmountSpecified, state.amountSpecifiedRemaining) + amount0 = i256.Zero().Sub(amountSpecified, state.amountSpecifiedRemaining) amount1 = state.amountCalculated } else { amount0 = state.amountCalculated - amount1 = new(u256.Int).Sub(origAmountSpecified, state.amountSpecifiedRemaining) + amount1 = i256.Zero().Sub(amountSpecified, state.amountSpecifiedRemaining) } - // backUP - resAmount0 := amount0.Clone() - resAmount1 := amount1.Clone() - if zeroForOne { - if !(pool.balances.token1.Gte(amount1.Abs())) { + if pool.balances.token1.Lt(amount1.Abs()) { // NOT ENOUGH BALANCE for output token1 - return 0, 0, false + return "0", "0", false } - } else { - if !(pool.balances.token0.Gte(amount0.Abs())) { + if pool.balances.token0.Lt(amount0.Abs()) { // NOT ENOUGH BALANCE for output token0 - return 0, 0, false + return "0", "0", false } } - // just not enough balance + // JUST NOT ENOUGH BALANCE if amount0.IsZero() && amount1.IsZero() { - return 0, 0, false + return "0", "0", false } - return resAmount0.Bigint(), resAmount1.Bigint(), true + pool.slot0.unlocked = true + return amount0.ToString(), amount1.ToString(), true } diff --git a/pool/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno b/pool/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno index 8f949c60..8a4f3a9e 100644 --- a/pool/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno +++ b/pool/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno @@ -20,9 +20,11 @@ var ( // wugnotPath string = "gno.land/r/demo/wugnot" // from consts // gnsPath string = "gno.land/r/demo/gns" // from consts - fee100 uint16 = 100 - fee500 uint16 = 500 - fee3000 uint16 = 3000 + fee100 uint32 = 100 + fee500 uint32 = 500 + fee3000 uint32 = 3000 + + maxApprove uint64 = 18446744073709551615 ) /* HELPER */ diff --git a/pool/_TEST_get_test.gno b/pool/_TEST_get_test.gno deleted file mode 100644 index 86755ecf..00000000 --- a/pool/_TEST_get_test.gno +++ /dev/null @@ -1,232 +0,0 @@ -package pool - -import ( - "std" - "testing" - - "gno.land/r/demo/consts" - - "gno.land/r/demo/bar" - "gno.land/r/demo/baz" - "gno.land/r/demo/foo" - - "gno.land/r/demo/gns" -) - -var ( - test_tickLower = int32(9000) - test_tickUpper = int32(11000) - test_liquidityExpect = bigint(100_000_000) -) - -// 1. Init Pool -func TestInit(t *testing.T) { - std.TestSetPrevAddr(gsa) - InitManual() -} - -// 2. Create Foo:Bar Pool -func TestCreateFooBarPool(t *testing.T) { - std.TestSetPrevAddr(test1) - gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) - - CreatePool(fooPath, barPath, fee500, 130621891405341611593710811006) - shouldEQ(t, len(pools), 1) -} - -// 3. Create Bar:Baz Pool -func TestCreateBarBazPool(t *testing.T) { - std.TestSetPrevAddr(test1) - gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) - - CreatePool(barPath, bazPath, fee500, 130621891405341611593710811006) - shouldEQ(t, len(pools), 2) -} - -// 4. Mint Foo:Bar Liquidity by test1 -func TestMintFooBarLiquidity(t *testing.T) { - std.TestSetPrevAddr(test1) - foo.Approve(a2u(consts.POOL_ADDR), 2958014) - bar.Approve(a2u(consts.POOL_ADDR), 8040315) - - std.TestSetPrevRealm(consts.POSITION_PATH) - std.TestSetOrigCaller(test1) - amount0, amount1 := Mint( - fooPath, - barPath, - fee500, - consts.POSITION_ADDR, - -test_tickUpper, - -test_tickLower, - test_liquidityExpect, - ) - shouldEQ(t, amount0, bigint(8040315)) - shouldEQ(t, amount1, bigint(2958014)) -} - -// 5. Mint Bar:Baz Liquidity by test1 -func TestMintBarBazLiquidity(t *testing.T) { - std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), 2958014) - baz.Approve(a2u(consts.POOL_ADDR), 8040315) - - std.TestSetPrevRealm(consts.POSITION_PATH) - std.TestSetOrigCaller(test1) - amount0, amount1 := Mint( - barPath, - bazPath, - fee500, - consts.POSITION_ADDR, - test_tickLower, - test_tickUpper, - test_liquidityExpect, - ) - shouldEQ(t, amount0, bigint(2958014)) - shouldEQ(t, amount1, bigint(8040315)) -} - -// RPC GET TESTS -var poolPath = "gno.land/r/demo/bar:gno.land/r/demo/foo:500" -var positionKey = "ZzEwd3dhNTN4Z3U0Mzk3a3Z6ejdha3hhcjkzNzB6amRwd3V4NXRoOV9fLTExMDAwX18tOTAwMA==" -var tick = int32(-11000) -var tickBitmap = int16(-5) - -func TestPoolGetSlot0SqrtPriceX96(t *testing.T) { - sqrt := PoolGetSlot0SqrtPriceX96(poolPath) - shouldEQ(t, string(sqrt), "48055510970269007215549348797") -} - -func TestPoolGetSlot0Tick(t *testing.T) { - tick := PoolGetSlot0Tick(poolPath) - shouldEQ(t, tick, int32(-10000)) -} - -func TestPoolGetSlot0FeeProtocol(t *testing.T) { - fee := PoolGetSlot0FeeProtocol(poolPath) - shouldEQ(t, fee, uint8(0)) -} - -func TestPoolGetToken0Balance(t *testing.T) { - balance := PoolGetToken0Balance(poolPath) - shouldEQ(t, balance, bigint(8040315)) -} - -func TestPoolGetToken1Balance(t *testing.T) { - balance := PoolGetToken1Balance(poolPath) - shouldEQ(t, balance, bigint(2958014)) -} - -func TestPoolGetToken0ProtocolFee(t *testing.T) { - protocolFee := PoolGetToken0ProtocolFee(poolPath) - shouldEQ(t, protocolFee, bigint(0)) -} - -func TestPoolGetToken1ProtocolFee(t *testing.T) { - protocolFee := PoolGetToken1ProtocolFee(poolPath) - shouldEQ(t, protocolFee, bigint(0)) -} - -func TestPoolGetPositionLiquidity(t *testing.T) { - liquidity := PoolGetPositionLiquidity(poolPath, positionKey) - shouldEQ(t, liquidity, test_liquidityExpect) -} - -func TestPoolGetPositionFeeGrowthInside0LastX128(t *testing.T) { - feeGrowth := PoolGetPositionFeeGrowthInside0LastX128(poolPath, positionKey) - shouldEQ(t, feeGrowth, bigint(0)) -} - -func TestPoolGetPositionFeeGrowthInside1LastX128(t *testing.T) { - feeGrowth := PoolGetPositionFeeGrowthInside1LastX128(poolPath, positionKey) - shouldEQ(t, feeGrowth, bigint(0)) -} - -func TestPoolGetPositionTokensOwed0(t *testing.T) { - tokensOwed := PoolGetPositionTokensOwed0(poolPath, positionKey) - shouldEQ(t, tokensOwed, bigint(0)) -} - -func TestPoolGetPositionTokensOwed1(t *testing.T) { - tokensOwed := PoolGetPositionTokensOwed1(poolPath, positionKey) - shouldEQ(t, tokensOwed, bigint(0)) -} - -func TestPoolGetTickLiquidityGross(t *testing.T) { - liquidityGross := PoolGetTickLiquidityGross(poolPath, tick) - shouldEQ(t, liquidityGross, test_liquidityExpect) -} - -func TestPoolGetTickLiquidityNet(t *testing.T) { - liquidityNet := PoolGetTickLiquidityNet(poolPath, tick) - shouldEQ(t, liquidityNet, test_liquidityExpect) -} - -func TestPoolGetTickFeeGrowthOutside0X128(t *testing.T) { - feeGrowth := PoolGetTickFeeGrowthOutside0X128(poolPath, tick) - shouldEQ(t, feeGrowth, bigint(0)) -} - -func TestPoolGetTickFeeGrowthOutside1X128(t *testing.T) { - feeGrowth := PoolGetTickFeeGrowthOutside1X128(poolPath, tick) - shouldEQ(t, feeGrowth, bigint(0)) -} - -func TestPoolGetTickTickCumulativeOutside(t *testing.T) { - cumulative := PoolGetTickTickCumulativeOutside(poolPath, tick) - shouldEQ(t, cumulative, bigint(0)) -} - -func TestPoolGetTickSecondsPerLiquidityOutsideX128(t *testing.T) { - seconds := PoolGetTickSecondsPerLiquidityOutsideX128(poolPath, tick) - shouldEQ(t, seconds, bigint(0)) -} - -func TestPoolGetTickSecondsOutside(t *testing.T) { - liquidityGross := PoolGetTickSecondsOutside(poolPath, tick) - shouldEQ(t, liquidityGross, bigint(0)) -} - -func TestPoolGetTickInitialized(t *testing.T) { - initialized := PoolGetTickInitialized(poolPath, tick) - shouldEQ(t, initialized, true) -} - -func TestPoolGetTickBitmap(t *testing.T) { - bitmap := PoolGetTickBitmap(poolPath, tickBitmap) - shouldEQ(t, string(bitmap), "1532495540865888858358347027150309183618739122183602176") -} - -func TestPoolGetToken0Path(t *testing.T) { - token0Path := PoolGetToken0Path(poolPath) - shouldEQ(t, token0Path, barPath) -} - -func TestPoolGetToken1Path(t *testing.T) { - token1Path := PoolGetToken1Path(poolPath) - shouldEQ(t, token1Path, fooPath) -} - -func TestPoolGetFee(t *testing.T) { - fee := PoolGetFee(poolPath) - shouldEQ(t, fee, fee500) -} - -func TestPoolGetTickSpacing(t *testing.T) { - spacing := PoolGetTickSpacing(poolPath) - shouldEQ(t, spacing, int32(10)) -} - -func TestPoolGetFeeGrowthGlobal0X128(t *testing.T) { - feeGrowth := PoolGetFeeGrowthGlobal0X128(poolPath) - shouldEQ(t, feeGrowth, bigint(0)) -} - -func TestPoolGetFeeGrowthGlobal1X128(t *testing.T) { - feeGrowth := PoolGetFeeGrowthGlobal1X128(poolPath) - shouldEQ(t, feeGrowth, bigint(0)) -} - -func TestPoolGetLiquidity(t *testing.T) { - liquidity := PoolGetLiquidity(poolPath) - shouldEQ(t, liquidity, test_liquidityExpect) -} diff --git a/pool/_TEST_pool_dryswap_and_swap_test.gno b/pool/_TEST_pool_dryswap_and_swap_test.gno index 628c6e88..827aea8c 100644 --- a/pool/_TEST_pool_dryswap_and_swap_test.gno +++ b/pool/_TEST_pool_dryswap_and_swap_test.gno @@ -13,11 +13,11 @@ import ( ) var ( - sqrtPrice bigint = 130621891405341611593710811006 + sqrtPrice = "130621891405341611593710811006" tickLower = int32(9000) tickUpper = int32(11000) - liquidityExpect = bigint(100_000_000_000) + liquidityExpect = "100000000000" currentTick = int32(10000) ) @@ -38,7 +38,7 @@ func TestDrySwap_ZeroForOneTrue_AmountSpecified_Positive_16000(t *testing.T) { std.TestSetOrigCaller(test1) // no mint == no liquidity => swap will fail - _, _, ok := DrySwap(fooPath, barPath, fee500, "_", true, 16000, consts.MIN_PRICE) + _, _, ok := DrySwap(fooPath, barPath, fee500, "_", true, "16000", consts.MIN_PRICE) shouldEQ(t, ok, false) // not enough mint == swap will fail @@ -48,9 +48,8 @@ func TestDrySwap_ZeroForOneTrue_AmountSpecified_Positive_16000(t *testing.T) { std.TestSetPrevRealm(consts.POSITION_PATH) std.TestSetOrigCaller(test1) - Mint(fooPath, barPath, fee500, consts.POSITION_ADDR, -tickUpper, -tickLower, 10) - DrySwap(fooPath, barPath, fee500, "_", true, 16000, consts.MIN_PRICE) - _, _, ok = DrySwap(fooPath, barPath, fee500, "_", true, 16000, consts.MIN_PRICE) + Mint(fooPath, barPath, fee500, consts.POSITION_ADDR, -tickUpper, -tickLower, "10") + _, _, ok = DrySwap(fooPath, barPath, fee500, "_", true, "16000", consts.MIN_PRICE) shouldEQ(t, ok, false) std.TestSetPrevAddr(test1) @@ -69,30 +68,30 @@ func TestDrySwap_ZeroForOneTrue_AmountSpecified_Positive_16000(t *testing.T) { fee500, // fee500 "_", // recipient true, // zeroForOne - 16000, // amountSpecified + "16000", // amountSpecified consts.MIN_PRICE, // sqrtPriceLimitX96 ) - shouldEQ(t, poolIn, bigint(16000)) - shouldEQ(t, poolOut, bigint(-5883)) + shouldEQ(t, poolIn, "16000") + shouldEQ(t, poolOut, "-5883") } -func TestDrySwap_ZeroForOneTrue_AmountSpecified_Negative_16000(t *testing.T) { - // zeroForOne true - // amountSpecified -16000 +// func TestDrySwap_ZeroForOneTrue_AmountSpecified_Negative_16000(t *testing.T) { +// // zeroForOne true +// // amountSpecified -16000 - poolIn, poolOut, _ := DrySwap( - fooPath, // fooPath - barPath, // barPath - fee500, // fee500 - "_", // recipient - true, // zeroForOne - -16000, // amountSpecified - consts.MIN_PRICE, // sqrtPriceLimitX96 - ) +// poolIn, poolOut, _ := DrySwap( +// fooPath, // fooPath +// barPath, // barPath +// fee500, // fee500 +// "_", // recipient +// true, // zeroForOne +// "-16000", // amountSpecified +// consts.MIN_PRICE, // sqrtPriceLimitX96 +// ) - shouldEQ(t, poolIn, bigint(43511)) - shouldEQ(t, poolOut, bigint(-16000)) -} +// shouldEQ(t, poolIn, "43511") +// shouldEQ(t, poolOut, "-16000") +// } // func TestDrySwap_ZeroForOneFalse_AmountSpecified_Positive_16000(t *testing.T) { // // zeroForOne false @@ -104,12 +103,12 @@ func TestDrySwap_ZeroForOneTrue_AmountSpecified_Negative_16000(t *testing.T) { // fee500, // fee500 // "_", // recipient // false, // zeroForOne -// 16000, // amountSpecified +// "16000", // amountSpecified // consts.MAX_PRICE, // sqrtPriceLimitX96 // ) -// shouldEQ(t, poolOut, bigint(-43468)) -// shouldEQ(t, poolIn, bigint(16000)) +// shouldEQ(t, poolOut, "-43468") +// shouldEQ(t, poolIn, "16000") // } // func TestDrySwap_ZeroForOneFalse_AmountSpecified_Negative_16000(t *testing.T) { @@ -121,9 +120,9 @@ func TestDrySwap_ZeroForOneTrue_AmountSpecified_Negative_16000(t *testing.T) { // fee500, // fee500 // "_", // recipient // false, // zeroForOne -// -16000, // amountSpecified +// "-16000", // amountSpecified // consts.MAX_PRICE, // sqrtPriceLimitX96 // ) -// shouldEQ(t, poolOut, bigint(-16000)) -// shouldEQ(t, poolIn, bigint(5888)) +// shouldEQ(t, poolOut, "-16000") +// shouldEQ(t, poolIn, "5888") // } diff --git a/pool/_TEST_pool_multi_token_test.gno_OK b/pool/_TEST_pool_multi_token_test.gno_OK index 4c9f63f7..e69de29b 100644 --- a/pool/_TEST_pool_multi_token_test.gno_OK +++ b/pool/_TEST_pool_multi_token_test.gno_OK @@ -1,327 +0,0 @@ -package pool - -import ( - "std" - "testing" - - "gno.land/r/demo/consts" -) - -var ( - test_tickLower = int32(9000) - test_tickUpper = int32(11000) - test_liquidityExpect = bigint(100_000_000) - - test_tickLower2 = int32(50000) - test_tickUpper2 = int32(100000) -) - -// 1. Init Pool -func TestInit(t *testing.T) { - std.TestSetOrigCaller(test1) - InitManual() -} - -// 2. Create Foo:Bar Pool -func TestCreateFooBarPool(t *testing.T) { - std.TestSetOrigCaller(test1) - CreatePool(fooPath, barPath, fee500, 130621891405341611593710811006) - shouldEQ(t, len(pools), 1) -} - -// 3. Create Bar:Baz Pool -func TestCreateBarBazPool(t *testing.T) { - std.TestSetOrigCaller(test1) - CreatePool(barPath, bazPath, fee500, 130621891405341611593710811006) - shouldEQ(t, len(pools), 2) -} - -// 4. Mint Foo:Bar Liquidity by test1 -func TestMintFooBarLiquidity(t *testing.T) { - std.TestSetPrevRealm(consts.POSITION_PATH) - std.TestSetOrigCaller(test1) - - Mint( - fooPath, - barPath, - fee500, - consts.POSITION_ADDR, - -test_tickUpper, - -test_tickLower, - test_liquidityExpect, - ) -} - -// 5. Mint Bar:Baz Liquidity by test1 -func TestMintBarBazLiquidity(t *testing.T) { - std.TestSetPrevRealm(consts.POSITION_PATH) - std.TestSetOrigCaller(test1) - - Mint( - barPath, - bazPath, - fee500, - consts.POSITION_ADDR, - test_tickLower, - test_tickUpper, - test_liquidityExpect, - ) -} - -// 6. Swap Foo:Bar Foo > Bar by test1 -func TestSwapFooBarFooToBar(t *testing.T) { - std.TestSetPrevRealm(consts.ROUTER_PATH) - std.TestSetOrigCaller(test1) - - oldtest1Token1Balance := balanceOfByRegisterCall(fooPath, test1) - oldtest1Token0Balance := balanceOfByRegisterCall(barPath, test1) - oldPoolToken1Balance := balanceOfByRegisterCall(fooPath, consts.POOL_ADDR) - oldPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) - - poolIn, poolOut := Swap( - fooPath, - barPath, - fee500, - test1, - true, - bigint(16000), - consts.MIN_PRICE, - std.GetOrigCaller(), - ) - pool := GetPool(fooPath, barPath, fee500) - - shouldEQ(t, poolIn, bigint(16000)) - shouldEQ(t, poolOut, bigint(-5882)) - - newtest1Token1Balance := balanceOfByRegisterCall(fooPath, test1) - newtest1Token0Balance := balanceOfByRegisterCall(barPath, test1) - newPoolToken1Balance := balanceOfByRegisterCall(fooPath, consts.POOL_ADDR) - newPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) - - shouldEQ(t, oldtest1Token0Balance-newtest1Token0Balance, 16000) - shouldEQ(t, newtest1Token1Balance-oldtest1Token1Balance, 5882) - shouldEQ(t, newPoolToken0Balance-oldPoolToken0Balance, 16000) - shouldEQ(t, oldPoolToken1Balance-newPoolToken1Balance, 5882) - -} - -// 7. Swap Bar:Baz Bar > Baz by test1 -func TestSwapBarBazBarToBaz(t *testing.T) { - std.TestSetPrevRealm(consts.ROUTER_PATH) - std.TestSetOrigCaller(test1) - - oldtest1Token0Balance := balanceOfByRegisterCall(barPath, test1) - oldtest1BazBalance := balanceOfByRegisterCall(bazPath, test1) - oldPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) - oldPoolBazBalance := balanceOfByRegisterCall(bazPath, consts.POOL_ADDR) - - poolIn, poolOut := Swap( - barPath, - bazPath, - fee500, - test1, - true, - bigint(16000), - consts.MIN_PRICE, - std.GetOrigCaller(), - ) - shouldEQ(t, poolIn, bigint(16000)) - shouldEQ(t, poolOut, bigint(-43457)) - - newtest1Token0Balance := balanceOfByRegisterCall(barPath, test1) - newtest1BazBalance := balanceOfByRegisterCall(bazPath, test1) - newPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) - newPoolBazBalance := balanceOfByRegisterCall(bazPath, consts.POOL_ADDR) - - shouldEQ(t, oldtest1Token0Balance-newtest1Token0Balance, 16000) - shouldEQ(t, newtest1BazBalance-oldtest1BazBalance, 43457) - shouldEQ(t, newPoolToken0Balance-oldPoolToken0Balance, 16000) - shouldEQ(t, oldPoolBazBalance-newPoolBazBalance, 43457) -} - -// 8. Collect Foo:Bar Fees by test1 -func TestCollectFooBarFees(t *testing.T) { - - std.TestSetPrevRealm(consts.POSITION_PATH) - std.TestSetOrigCaller(test1) - - oldtest1Token1Balance := balanceOfByRegisterCall(fooPath, test1) - oldtest1Token0Balance := balanceOfByRegisterCall(barPath, test1) - oldPoolToken1Balance := balanceOfByRegisterCall(fooPath, consts.POOL_ADDR) - oldPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) - - // burn 0 to collect swap fees - Burn(fooPath, barPath, fee500, -test_tickUpper, -test_tickLower, 0) - - c0, c1 := Collect( - fooPath, - barPath, - fee500, - test1, - -test_tickUpper, - -test_tickLower, - 100_000, - 100_000, - ) - - shouldNEQ(t, c0, bigint(0)) // swap was foo > bar, so only foo has fees - shouldEQ(t, c1, bigint(0)) // swap was foo > bar, so bar has no fees - - newtest1Token1Balance := balanceOfByRegisterCall(fooPath, test1) - newtest1Token0Balance := balanceOfByRegisterCall(barPath, test1) - newPoolToken1Balance := balanceOfByRegisterCall(fooPath, consts.POOL_ADDR) - newPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) - - shouldEQ(t, newtest1Token1Balance-oldtest1Token1Balance, uint64(c1)) - shouldEQ(t, newtest1Token0Balance-oldtest1Token0Balance, uint64(c0)) - shouldEQ(t, oldPoolToken1Balance-newPoolToken1Balance, uint64(c1)) - shouldEQ(t, oldPoolToken0Balance-newPoolToken0Balance, uint64(c0)) -} - -// 9. Collect Bar:Baz Fees by test1 -func TestCollectBarBazFees(t *testing.T) { - std.TestSetPrevRealm(consts.POSITION_PATH) - std.TestSetOrigCaller(test1) - - oldtest1Token0Balance := balanceOfByRegisterCall(barPath, test1) - oldtest1BazBalance := balanceOfByRegisterCall(bazPath, test1) - oldPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) - oldPoolBazBalance := balanceOfByRegisterCall(bazPath, consts.POOL_ADDR) - - // burn 0 to collect swap fees - Burn(barPath, bazPath, fee500, test_tickLower, test_tickUpper, 0) - - c0, c1 := Collect( - barPath, - bazPath, - fee500, - test1, - test_tickLower, - test_tickUpper, - 100_000, - 100_000, - ) - - shouldNEQ(t, c0, bigint(0)) // swap was foo > bar, so only foo has fees - shouldEQ(t, c1, bigint(0)) // swap was foo > bar, so bar has no fees - - newtest1Token0Balance := balanceOfByRegisterCall(barPath, test1) - newtest1BazBalance := balanceOfByRegisterCall(bazPath, test1) - newPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) - newPoolBazBalance := balanceOfByRegisterCall(bazPath, consts.POOL_ADDR) - - shouldEQ(t, newtest1Token0Balance-oldtest1Token0Balance, uint64(c0)) - shouldEQ(t, newtest1BazBalance-oldtest1BazBalance, uint64(c1)) - shouldEQ(t, oldPoolToken0Balance-newPoolToken0Balance, uint64(c0)) - shouldEQ(t, oldPoolBazBalance-newPoolBazBalance, uint64(c1)) -} - -// 10. Burn Foo:Bar Liquidity by test1 -func TestBurnFooBarLiquidity(t *testing.T) { - std.TestSetOrigCaller(test1) - std.TestSetPrevRealm(consts.POSITION_PATH) - - pool := GetPool(fooPath, barPath, fee500) - poolOldLiquidity := pool.PoolGetLiquidity() - - b0, b1 := Burn( - fooPath, - barPath, - fee500, - -test_tickUpper, - -test_tickLower, - test_liquidityExpect, - ) - shouldEQ(t, b0, bigint(8056307)) - shouldEQ(t, b1, bigint(2952131)) -} - -// 11. Burn Bar:Baz Liquidity by test1 -func TestBurnBarBazLiquidity(t *testing.T) { - std.TestSetOrigCaller(test1) - std.TestSetPrevRealm(consts.POSITION_PATH) - - pool := GetPool(barPath, bazPath, fee500) - poolOldLiquidity := pool.PoolGetLiquidity() - - b0, b1 := Burn( - barPath, - bazPath, - fee500, - test_tickLower, - test_tickUpper, - test_liquidityExpect, - ) - shouldNEQ(t, b0, bigint(0)) - shouldNEQ(t, b1, bigint(0)) -} - -// 12. Collect Foo:Bar burned Liquidity by test1 -func TestCollectFooBarLiquidity(t *testing.T) { - std.TestSetOrigCaller(test1) - std.TestSetPrevRealm(consts.POSITION_PATH) - - oldtest1Token1Balance := balanceOfByRegisterCall(fooPath, test1) - oldtest1Token0Balance := balanceOfByRegisterCall(barPath, test1) - oldPoolToken1Balance := balanceOfByRegisterCall(fooPath, consts.POOL_ADDR) - oldPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) - - c0, c1 := Collect( - fooPath, - barPath, - fee500, - test1, - -test_tickUpper, - -test_tickLower, - 100_000, - 100_000, - ) - - shouldNEQ(t, c0, bigint(0)) - shouldNEQ(t, c1, bigint(0)) - - newtest1Token1Balance := balanceOfByRegisterCall(fooPath, test1) - newtest1Token0Balance := balanceOfByRegisterCall(barPath, test1) - newPoolToken1Balance := balanceOfByRegisterCall(fooPath, consts.POOL_ADDR) - newPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) - - shouldEQ(t, newtest1Token1Balance-oldtest1Token1Balance, uint64(c0)) - shouldEQ(t, newtest1Token0Balance-oldtest1Token0Balance, uint64(c1)) - shouldEQ(t, oldPoolToken1Balance-newPoolToken1Balance, uint64(c0)) - shouldEQ(t, oldPoolToken0Balance-newPoolToken0Balance, uint64(c1)) -} - -// 13. Collect Bar:Baz burned Liquidity by test1 -func TestCollectBarBazLiquidity(t *testing.T) { - std.TestSetOrigCaller(test1) - std.TestSetPrevRealm(consts.POSITION_PATH) - - oldtest1Token0Balance := balanceOfByRegisterCall(barPath, test1) - oldtest1BazBalance := balanceOfByRegisterCall(bazPath, test1) - oldPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) - oldPoolBazBalance := balanceOfByRegisterCall(bazPath, consts.POOL_ADDR) - - c0, c1 := Collect( - barPath, - bazPath, - fee500, - test1, - test_tickLower, - test_tickUpper, - 100_000, - 100_000, - ) - - shouldNEQ(t, c0, bigint(0)) - shouldNEQ(t, c1, bigint(0)) - - newtest1Token0Balance := balanceOfByRegisterCall(barPath, test1) - newtest1BazBalance := balanceOfByRegisterCall(bazPath, test1) - newPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) - newPoolBazBalance := balanceOfByRegisterCall(bazPath, consts.POOL_ADDR) - - shouldEQ(t, newtest1Token0Balance-oldtest1Token0Balance, uint64(c0)) - shouldEQ(t, newtest1BazBalance-oldtest1BazBalance, uint64(c1)) - shouldEQ(t, oldPoolToken0Balance-newPoolToken0Balance, uint64(c0)) - shouldEQ(t, oldPoolBazBalance-newPoolBazBalance, uint64(c1)) -} diff --git a/pool/_TEST_pool_native_swap_test.gn_OK b/pool/_TEST_pool_native_swap_test.gn_OK index 4ef5fd67..2ab3c71c 100644 --- a/pool/_TEST_pool_native_swap_test.gn_OK +++ b/pool/_TEST_pool_native_swap_test.gn_OK @@ -13,9 +13,8 @@ import ( ) var ( - test_tickLower = int32(9000) - test_tickUpper = int32(11000) - test_liquidityExpect = bigint(100_000_000) + test_tickLower = int32(9000) + test_tickUpper = int32(11000) ) // 1. Init & Create Pool @@ -25,7 +24,7 @@ func TestPoolInitCreatePool(t *testing.T) { std.TestSetPrevAddr(test1) gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) - CreatePool(fooPath, consts.WRAPPED_WUGNOT, fee500, 130621891405341611593710811006) // x2.7 + CreatePool(fooPath, consts.WRAPPED_WUGNOT, fee500, "130621891405341611593710811006") // x2.7 } // 2. Mint LP and Get GNFT @@ -60,11 +59,11 @@ func TestMint(t *testing.T) { consts.POSITION_ADDR, test_tickLower, test_tickUpper, - bigint(10000000), + "10000000", ) - shouldEQ(t, amount0, bigint(295801)) - shouldEQ(t, amount1, bigint(804031)) + shouldEQ(t, amount0, "295801") + shouldEQ(t, amount1, "804031") } func TestSwapBuyNative(t *testing.T) { @@ -73,7 +72,7 @@ func TestSwapBuyNative(t *testing.T) { test1OldT0Bal := balanceOfByRegisterCall(pool.token0Path, test1) test1OldT1Bal := balanceOfByRegisterCall(pool.token1Path, test1) shouldEQ(t, test1OldT0Bal, 499999999704199) // foo - shouldEQ(t, test1OldT1Bal, bigint(0)) // wugnot + shouldEQ(t, test1OldT1Bal, "0") // wugnot std.TestSetPrevAddr(test1) foo.Approve(a2u(consts.POOL_ADDR), 10000) @@ -86,12 +85,12 @@ func TestSwapBuyNative(t *testing.T) { fee500, test1, true, - bigint(10000), + "10000", consts.MIN_PRICE, std.GetOrigCaller(), ) - shouldEQ(t, amount0, bigint(10000)) - shouldEQ(t, amount1, bigint(-27123)) + shouldEQ(t, amount0, "10000") + shouldEQ(t, amount1, "-27123") test1NewT0Bal := balanceOfByRegisterCall(pool.token0Path, test1) test1NewT1Bal := balanceOfByRegisterCall(pool.token1Path, test1) @@ -118,12 +117,12 @@ func TestSwapSellNative(t *testing.T) { fee500, test1, false, - bigint(10000), + "10000", consts.MAX_PRICE, std.GetOrigCaller(), ) - shouldEQ(t, amount0, bigint(-3687)) - shouldEQ(t, amount1, bigint(10000)) + shouldEQ(t, amount0, "-3687") + shouldEQ(t, amount1, "10000") test1NewT0Bal := balanceOfByRegisterCall(pool.token0Path, test1) test1NewT1Bal := balanceOfByRegisterCall(pool.token1Path, test1) diff --git a/pool/_TEST_pool_single_lp_test.gno b/pool/_TEST_pool_single_lp_test.gno new file mode 100644 index 00000000..10ba3639 --- /dev/null +++ b/pool/_TEST_pool_single_lp_test.gno @@ -0,0 +1,471 @@ +package pool + +import ( +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + "std" + "testing" + +======== +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + "encoding/gjson" + "std" + "strconv" + "testing" + + "gno.land/r/demo/consts" + +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + "gno.land/p/demo/u256" +======== + u256 "gno.land/p/big/uint256" +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno +) + +var ( + test_tickLower = int32(9000) + test_tickUpper = int32(11000) + test_liquidityExpectStr = "1000" + test_liquidityExpect256 = u256.NewUint(1000) + + test_tickLower2 = int32(50000) + test_tickUpper2 = int32(100000) +) + +// 1. Init & Create Pool using Factory Contract by Gnoswap Admin +func TestInitCreatePool(t *testing.T) { + std.TestSetOrigCaller(test1) + InitManual() + +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + std.TestSetOrigCaller(test1) + CreatePool(barPath, fooPath, fee500, 130621891405341611593710811006) + + // sqrtPrice + // 130621891405341611593710811006 // tick = 10000 + shouldPanic(t, func() { CreatePool(barPath, fooPath, 500, 130621891405341611593710811006) }) +======== + std.TestSetPrevAddr(test1) + gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) + CreatePool(barPath, fooPath, fee500, "130621891405341611593710811006") // x2.7 +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno +} + +// 2. Mint by test1 +func TestMint(t *testing.T) { +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK +======== + std.TestSetPrevAddr(test1) + + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + std.TestSetPrevRealm(consts.POSITION_PATH) + std.TestSetOrigCaller(test1) + + Mint( + fooPath, + barPath, + fee500, + consts.POSITION_ADDR, + test_tickLower, + test_tickUpper, + test_liquidityExpectStr, + ) +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + + pool := GetPool(barPath, fooPath, fee500) + test_liquidity := pool.PoolGetLiquidity() + shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect)), true) +======== + shouldEQ(t, amount0, "29") + shouldEQ(t, amount1, "80") + + pool := GetPool(barPath, fooPath, fee500) + test_liquidity := pool.PoolGetLiquidity() + shouldEQ(t, test_liquidity.Dec(), test_liquidityExpectStr) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + + m81, m82 := Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + m101, m102 := Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + + shouldNEQ(t, m81, "0") + shouldNEQ(t, m82, "0") + shouldEQ(t, m81, m101) + shouldEQ(t, m82, m102) + + test_liquidity = pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*10)), true) +======== + shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(10)))) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + + // tickLower > currentTick == don't add to current liquidity + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower2, test_tickUpper2, test_liquidityExpectStr) + + // tickUpper < current tick == don't add to current liquidity + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, -test_tickUpper2, -test_tickLower2, test_liquidityExpectStr) + + // tickUpper < tickLower == don't add to current liquidity + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, -test_tickUpper, -test_tickLower, test_liquidityExpectStr) + + // test_liquidity = pool.PoolGetLiquidity() + shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(10)))) + + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + + test_liquidity = pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*10)), true) + + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) + + test_liquidity = pool.PoolGetLiquidity() + shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*20)), true) +======== + shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(20)))) + +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno +} + +// 3. Burn by test1 +func TestBurn(t *testing.T) { + std.TestSetPrevRealm(consts.POSITION_PATH) + std.TestSetOrigCaller(test1) + + b11, b12 := Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpectStr) + b21, b22 := Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpectStr) + shouldEQ(t, b11, b21) + shouldEQ(t, b12, b22) + + pool := GetPool(barPath, fooPath, fee500) + test_liquidity := pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*18)), true) +======== + shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(18)))) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(8)).ToString()) + test_liquidity = pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*10)), true) +======== + shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(10)))) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, "1") + test_liquidity = pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + shouldEQ(t, test_liquidity.Eq(u256.FromBigint(9999)), true) +======== + shouldEQ(t, test_liquidity.ToString(), "9999") +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, "999") + test_liquidity = pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*9)), true) +======== + shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(9)))) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(9)).ToString()) + test_liquidity = pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + shouldEQ(t, test_liquidity.IsZero(), true) +======== + shouldEQ(t, test_liquidity.ToString(), "0") +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno +} + +// 4. Collect +func TestCollect(t *testing.T) { + std.TestSetPrevRealm(consts.POSITION_PATH) + std.TestSetOrigCaller(test1) + + // withdraw all token before test `Collect` + Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "50000000", "50000000") + + // pool should have zero liquidity + pool := GetPool(barPath, fooPath, fee500) + test_liquidity := pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + shouldEQ(t, test_liquidity.IsZero(), true) +======== + shouldEQ(t, test_liquidity.ToString(), "0") +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + c11, c12 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "50000000", "50000000") + + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + c21, c22 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "50000000", "50000000") + + shouldEQ(t, c11, c21) // 443 + shouldEQ(t, c12, c22) // 1206 + + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + c31, c32 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "100", "100") + shouldEQ(t, c31, "100") + shouldEQ(t, c32, "100") + + c41, c42 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "50000000", "50000000") + shouldEQ(t, c41, "343") // 343 = c21 - 100 + shouldEQ(t, c42, "1106") // 1106 = c22 - 100 + + // Mint > No Burn => nothing to collect + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + // Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpectStr*15) + c51, c52 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "50000000", "50000000") + shouldEQ(t, c51, "0") + shouldEQ(t, c52, "0") + + // Burn Now => something to collect + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + c61, c62 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "50000000", "50000000") + shouldNEQ(t, c61, "0") + shouldNEQ(t, c62, "0") +} + +// 5. Swap by test1 +func TestSwap(t *testing.T) { + pool := GetPool(barPath, fooPath, fee500) + test_liquidity := pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + shouldEQ(t, test_liquidity.IsZero(), true) +======== + shouldEQ(t, test_liquidity.ToString(), "0") +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + + std.TestSetPrevRealm(consts.POSITION_PATH) + std.TestSetOrigCaller(test1) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(20000)).ToString()) + + // Swap several times + std.TestSetPrevRealm(consts.ROUTER_PATH) + std.TestSetOrigCaller(test1) + test_price := consts.MIN_PRICE + { + poolOldToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) + poolOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) + + userOldToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) + userOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) + + amount0, amount1 := Swap( + fooPath, // token0Path + barPath, // token1Path + fee500, // fee + test1, // recipient + true, // zeroForOne + "10000", // _amountSpecified + test_price, // _sqrtPriceLimitX96 + std.GetOrigCaller(), // payer + ) + shouldNEQ(t, amount0, "0") + shouldNEQ(t, amount1, "0") + intAmount0, _ := strconv.Atoi(amount0) + intAmount1, _ := strconv.Atoi(amount1) + + poolNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) + poolNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) + + userNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) + userNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) + + shouldEQ(t, userOldToken0Bal-userNewToken0Bal, int64(intAmount0)) + shouldEQ(t, userNewToken1Bal-userOldToken1Bal, int64(-intAmount1)) + shouldEQ(t, poolNewToken0Bal-poolOldToken0Bal, int64(intAmount0)) + shouldEQ(t, poolOldToken1Bal-poolNewToken1Bal, int64(-intAmount1)) + } + + { + poolOldToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) + poolOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) + + userOldToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) + userOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) + + amount0, amount1 := Swap(barPath, fooPath, fee500, test1, true, "5000", test_price, std.GetOrigCaller()) // give enough amount to take fees away + intAmount0, _ := strconv.Atoi(amount0) + intAmount1, _ := strconv.Atoi(amount1) + + poolNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) + poolNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) + + userNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) + userNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) + + shouldEQ(t, userOldToken0Bal-userNewToken0Bal, int64(intAmount0)) + shouldEQ(t, userNewToken1Bal-userOldToken1Bal, int64(-intAmount1)) + shouldEQ(t, poolNewToken0Bal-poolOldToken0Bal, int64(intAmount0)) + shouldEQ(t, poolOldToken1Bal-poolNewToken1Bal, int64(-intAmount1)) + } + + { + poolOldToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) + poolOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) + + userOldToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) + userOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) + + amount0, amount1 := Swap(barPath, fooPath, fee500, test1, true, "1000", test_price, std.GetOrigCaller()) // give enough amount to take fees away + intAmount0, _ := strconv.Atoi(amount0) + intAmount1, _ := strconv.Atoi(amount1) + + poolNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) + poolNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) + + userNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) + userNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) + + shouldEQ(t, userOldToken0Bal-userNewToken0Bal, int64(intAmount0)) + shouldEQ(t, userNewToken1Bal-userOldToken1Bal, int64(-intAmount1)) + shouldEQ(t, poolNewToken0Bal-poolOldToken0Bal, int64(intAmount0)) + shouldEQ(t, poolOldToken1Bal-poolNewToken1Bal, int64(-intAmount1)) + } + + // Swap token1 -> token0 + { + poolOldToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) + poolOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) + + userOldToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) + userOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) + + amount0, amount1 := Swap(barPath, fooPath, fee500, test1, false, "16000", consts.MAX_PRICE, std.GetOrigCaller()) // give enough amount to take fees away + intAmount0, _ := strconv.Atoi(amount0) + intAmount1, _ := strconv.Atoi(amount1) + + poolNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) + poolNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) + + userNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) + userNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) + + shouldEQ(t, userOldToken0Bal-userNewToken0Bal, int64(intAmount0)) + shouldEQ(t, userNewToken1Bal-userOldToken1Bal, int64(-intAmount1)) + shouldEQ(t, poolNewToken0Bal-poolOldToken0Bal, int64(intAmount0)) + shouldEQ(t, poolOldToken1Bal-poolNewToken1Bal, int64(-intAmount1)) + } +} + +// 6. SetFeeProtocol by Gnoswap Admin +func TestSetFeeProtocol(t *testing.T) { + // non admin call + std.TestSetOrigCaller(test1) + shouldPanic(t, func() { SetFeeProtocol(2, 2) }) + + // admin call + std.TestSetOrigCaller(test1) + SetFeeProtocol(6, 8) + + for _, pool := range pools { + shouldEQ(t, pool.PoolGetSlot0().feeProtocol, 134) + } +} + +// 7. CollectProtocol by Gnoswap Admin +func TestCollectProtocol(t *testing.T) { + std.TestSetOrigCaller(test1) + + SetFeeProtocol(6, 8) + pool := GetPool(barPath, fooPath, fee500) + test_slot0 := pool.PoolGetSlot0() + shouldEQ(t, test_slot0.feeProtocol, 134) + + // Make ProtocolFee via Swap by test1 ( Mint by test1 ) + std.TestSetOrigCaller(test1) + { + + std.TestSetPrevRealm(consts.ROUTER_PATH) + std.TestSetOrigCaller(test1) + Swap(barPath, fooPath, fee500, test1, true, "200000", consts.MIN_PRICE, std.GetOrigCaller()) // swap token0 -> token1 => fee only in token0 + + test1OldToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) + test1OldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) + +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + std.TestSetPrevAddr(test1) + amount0, amount1 := CollectProtocol(barPath, fooPath, fee500, test1, u256.NewUint(100000), u256.NewUint(100000)) +======== + std.TestSetPrevAddr(gsa) + amount0, amount1 := CollectProtocol(barPath, fooPath, fee500, test1, "100000", "100000") +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + + test1NewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) + test1NewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) + + _token0Diff := test1NewToken0Bal - test1OldToken0Bal + _token1Diff := test1NewToken1Bal - test1OldToken1Bal + +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + { + std.TestSetPrevRealm(consts.ROUTER_PATH) + std.TestSetOrigCaller(test1) + Swap(barPath, fooPath, fee500, test1, false, 200000, consts.MAX_SQRT_RATIO-1, std.GetOrigCaller()) // swap token0 -> token1 => fee only in token0 + + test1OldToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) + test1OldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) + + std.TestSetPrevAddr(test1) + amount0, amount1 := CollectProtocol(barPath, fooPath, fee500, test1, u256.NewUint(100000), u256.NewUint(100000)) + + test1NewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) + test1NewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) +======== + token0DiffStr := strconv.Itoa(int(_token0Diff)) + token1DiffStr := strconv.Itoa(int(_token1Diff)) + + shouldEQ(t, token0DiffStr, amount0) + shouldEQ(t, token1DiffStr, amount1) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + } +} + +/* GETTER_API TEST */ +func TestApiGetPools(t *testing.T) { + gpls := ApiGetPools() + jsonStr := gjson.Parse(gpls) + +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK + shouldEQ(t, jsonStr.Get("stat.height").Int(), GetHeight()) + shouldEQ(t, jsonStr.Get("stat.timestamp").Int(), GetTimestamp()) +======== + // shouldEQ(t, jsonStr.Get("stat.height").Int(), std.GetHeight()) + // shouldEQ(t, jsonStr.Get("stat.timestamp").Int(), time.Now().Unix()) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + + // shouldEQ(t, len(jsonStr.Get("response").Array()), 1) +} diff --git a/pool/_TEST_pool_single_lp_test.gno_OK b/pool/_TEST_pool_single_lp_test.gno_OK index eeb1689c..10ba3639 100644 --- a/pool/_TEST_pool_single_lp_test.gno_OK +++ b/pool/_TEST_pool_single_lp_test.gno_OK @@ -1,20 +1,31 @@ package pool import ( +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK "std" "testing" +======== +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno "encoding/gjson" + "std" + "strconv" + "testing" "gno.land/r/demo/consts" +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK "gno.land/p/demo/u256" +======== + u256 "gno.land/p/big/uint256" +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno ) var ( - test_tickLower = int32(9000) - test_tickUpper = int32(11000) - test_liquidityExpect = bigint(1000) + test_tickLower = int32(9000) + test_tickUpper = int32(11000) + test_liquidityExpectStr = "1000" + test_liquidityExpect256 = u256.NewUint(1000) test_tickLower2 = int32(50000) test_tickUpper2 = int32(100000) @@ -25,16 +36,30 @@ func TestInitCreatePool(t *testing.T) { std.TestSetOrigCaller(test1) InitManual() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK std.TestSetOrigCaller(test1) CreatePool(barPath, fooPath, fee500, 130621891405341611593710811006) // sqrtPrice // 130621891405341611593710811006 // tick = 10000 shouldPanic(t, func() { CreatePool(barPath, fooPath, 500, 130621891405341611593710811006) }) +======== + std.TestSetPrevAddr(test1) + gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) + CreatePool(barPath, fooPath, fee500, "130621891405341611593710811006") // x2.7 +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno } // 2. Mint by test1 func TestMint(t *testing.T) { +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK +======== + std.TestSetPrevAddr(test1) + + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno std.TestSetPrevRealm(consts.POSITION_PATH) std.TestSetOrigCaller(test1) @@ -45,42 +70,70 @@ func TestMint(t *testing.T) { consts.POSITION_ADDR, test_tickLower, test_tickUpper, - test_liquidityExpect, + test_liquidityExpectStr, ) +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK pool := GetPool(barPath, fooPath, fee500) test_liquidity := pool.PoolGetLiquidity() shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect)), true) +======== + shouldEQ(t, amount0, "29") + shouldEQ(t, amount1, "80") - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - - m81, m82 := Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - m101, m102 := Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - - shouldNEQ(t, m81, bigint(0)) - shouldNEQ(t, m82, bigint(0)) + pool := GetPool(barPath, fooPath, fee500) + test_liquidity := pool.PoolGetLiquidity() + shouldEQ(t, test_liquidity.Dec(), test_liquidityExpectStr) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno + + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + + m81, m82 := Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + m101, m102 := Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + + shouldNEQ(t, m81, "0") + shouldNEQ(t, m82, "0") shouldEQ(t, m81, m101) shouldEQ(t, m82, m102) test_liquidity = pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*10)), true) +======== + shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(10)))) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno // tickLower > currentTick == don't add to current liquidity - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower2, test_tickUpper2, test_liquidityExpect) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower2, test_tickUpper2, test_liquidityExpectStr) // tickUpper < current tick == don't add to current liquidity - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, -test_tickUpper2, -test_tickLower2, test_liquidityExpect) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, -test_tickUpper2, -test_tickLower2, test_liquidityExpectStr) // tickUpper < tickLower == don't add to current liquidity - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, -test_tickUpper, -test_tickLower, test_liquidityExpect) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, -test_tickUpper, -test_tickLower, test_liquidityExpectStr) + + // test_liquidity = pool.PoolGetLiquidity() + shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(10)))) + + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) test_liquidity = pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*10)), true) Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) @@ -96,6 +149,10 @@ func TestMint(t *testing.T) { test_liquidity = pool.PoolGetLiquidity() shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*20)), true) +======== + shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(20)))) + +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno } // 3. Burn by test1 @@ -103,30 +160,50 @@ func TestBurn(t *testing.T) { std.TestSetPrevRealm(consts.POSITION_PATH) std.TestSetOrigCaller(test1) - b11, b12 := Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpect) - b21, b22 := Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpect) + b11, b12 := Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpectStr) + b21, b22 := Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpectStr) shouldEQ(t, b11, b21) shouldEQ(t, b12, b22) pool := GetPool(barPath, fooPath, fee500) test_liquidity := pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*18)), true) +======== + shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(18)))) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno - Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpect*8) + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(8)).ToString()) test_liquidity = pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*10)), true) +======== + shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(10)))) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno - Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, 1) + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, "1") test_liquidity = pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK shouldEQ(t, test_liquidity.Eq(u256.FromBigint(9999)), true) +======== + shouldEQ(t, test_liquidity.ToString(), "9999") +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno - Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, 999) + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, "999") test_liquidity = pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*9)), true) +======== + shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(9)))) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno - Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpect*9) + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(9)).ToString()) test_liquidity = pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK shouldEQ(t, test_liquidity.IsZero(), true) +======== + shouldEQ(t, test_liquidity.ToString(), "0") +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno } // 4. Collect @@ -135,62 +212,70 @@ func TestCollect(t *testing.T) { std.TestSetOrigCaller(test1) // withdraw all token before test `Collect` - Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, 50000000, 50000000) + Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "50000000", "50000000") // pool should have zero liquidity pool := GetPool(barPath, fooPath, fee500) test_liquidity := pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK shouldEQ(t, test_liquidity.IsZero(), true) +======== + shouldEQ(t, test_liquidity.ToString(), "0") +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect*15) - Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpect*15) - c11, c12 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, 50000000, 50000000) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + c11, c12 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "50000000", "50000000") - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect*15) - Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpect*15) - c21, c22 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, 50000000, 50000000) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + c21, c22 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "50000000", "50000000") - shouldEQ(t, c11, c21) - shouldEQ(t, c12, c22) + shouldEQ(t, c11, c21) // 443 + shouldEQ(t, c12, c22) // 1206 - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect*15) - Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpect*15) - c31, c32 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, 100, 100) - shouldEQ(t, c31, bigint(100)) - shouldEQ(t, c32, bigint(100)) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + c31, c32 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "100", "100") + shouldEQ(t, c31, "100") + shouldEQ(t, c32, "100") - c41, c42 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, 50000000, 50000000) - shouldEQ(t, c41, c21-bigint(100)) - shouldEQ(t, c42, c22-bigint(100)) + c41, c42 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "50000000", "50000000") + shouldEQ(t, c41, "343") // 343 = c21 - 100 + shouldEQ(t, c42, "1106") // 1106 = c22 - 100 // Mint > No Burn => nothing to collect - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect*15) - // Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpect*15) - c51, c52 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, 50000000, 50000000) - shouldEQ(t, c51, bigint(0)) - shouldEQ(t, c52, bigint(0)) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + // Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpectStr*15) + c51, c52 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "50000000", "50000000") + shouldEQ(t, c51, "0") + shouldEQ(t, c52, "0") // Burn Now => something to collect - Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, test_liquidityExpect*15) - c61, c62 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, 50000000, 50000000) - shouldNEQ(t, c61, bigint(0)) - shouldNEQ(t, c62, bigint(0)) + Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) + c61, c62 := Collect(barPath, fooPath, fee500, test1, test_tickLower, test_tickUpper, "50000000", "50000000") + shouldNEQ(t, c61, "0") + shouldNEQ(t, c62, "0") } // 5. Swap by test1 func TestSwap(t *testing.T) { pool := GetPool(barPath, fooPath, fee500) test_liquidity := pool.PoolGetLiquidity() +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK shouldEQ(t, test_liquidity.IsZero(), true) +======== + shouldEQ(t, test_liquidity.ToString(), "0") +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno std.TestSetPrevRealm(consts.POSITION_PATH) std.TestSetOrigCaller(test1) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect*20000) + Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(20000)).ToString()) // Swap several times std.TestSetPrevRealm(consts.ROUTER_PATH) std.TestSetOrigCaller(test1) - test_price := bigint(consts.MIN_PRICE) + test_price := consts.MIN_PRICE { poolOldToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) poolOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) @@ -199,18 +284,19 @@ func TestSwap(t *testing.T) { userOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) amount0, amount1 := Swap( - fooPath, - barPath, - fee500, - test1, - true, - bigint(10000), - test_price, - std.GetOrigCaller(), + fooPath, // token0Path + barPath, // token1Path + fee500, // fee + test1, // recipient + true, // zeroForOne + "10000", // _amountSpecified + test_price, // _sqrtPriceLimitX96 + std.GetOrigCaller(), // payer ) - - shouldNEQ(t, amount0, bigint(0)) - shouldNEQ(t, amount1, bigint(0)) + shouldNEQ(t, amount0, "0") + shouldNEQ(t, amount1, "0") + intAmount0, _ := strconv.Atoi(amount0) + intAmount1, _ := strconv.Atoi(amount1) poolNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) poolNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) @@ -218,10 +304,10 @@ func TestSwap(t *testing.T) { userNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) userNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - shouldEQ(t, userOldToken0Bal-userNewToken0Bal, int64(amount0)) - shouldEQ(t, userNewToken1Bal-userOldToken1Bal, int64(-amount1)) - shouldEQ(t, poolNewToken0Bal-poolOldToken0Bal, int64(amount0)) - shouldEQ(t, poolOldToken1Bal-poolNewToken1Bal, int64(-amount1)) + shouldEQ(t, userOldToken0Bal-userNewToken0Bal, int64(intAmount0)) + shouldEQ(t, userNewToken1Bal-userOldToken1Bal, int64(-intAmount1)) + shouldEQ(t, poolNewToken0Bal-poolOldToken0Bal, int64(intAmount0)) + shouldEQ(t, poolOldToken1Bal-poolNewToken1Bal, int64(-intAmount1)) } { @@ -231,7 +317,9 @@ func TestSwap(t *testing.T) { userOldToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) userOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - amount0, amount1 := Swap(barPath, fooPath, fee500, test1, true, 5000, test_price, std.GetOrigCaller()) // give enough amount to take fees away + amount0, amount1 := Swap(barPath, fooPath, fee500, test1, true, "5000", test_price, std.GetOrigCaller()) // give enough amount to take fees away + intAmount0, _ := strconv.Atoi(amount0) + intAmount1, _ := strconv.Atoi(amount1) poolNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) poolNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) @@ -239,10 +327,10 @@ func TestSwap(t *testing.T) { userNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) userNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - shouldEQ(t, userOldToken0Bal-userNewToken0Bal, int64(amount0)) - shouldEQ(t, userNewToken1Bal-userOldToken1Bal, int64(-amount1)) - shouldEQ(t, poolNewToken0Bal-poolOldToken0Bal, int64(amount0)) - shouldEQ(t, poolOldToken1Bal-poolNewToken1Bal, int64(-amount1)) + shouldEQ(t, userOldToken0Bal-userNewToken0Bal, int64(intAmount0)) + shouldEQ(t, userNewToken1Bal-userOldToken1Bal, int64(-intAmount1)) + shouldEQ(t, poolNewToken0Bal-poolOldToken0Bal, int64(intAmount0)) + shouldEQ(t, poolOldToken1Bal-poolNewToken1Bal, int64(-intAmount1)) } { @@ -252,7 +340,9 @@ func TestSwap(t *testing.T) { userOldToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) userOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - amount0, amount1 := Swap(barPath, fooPath, fee500, test1, true, 1000, test_price, std.GetOrigCaller()) // give enough amount to take fees away + amount0, amount1 := Swap(barPath, fooPath, fee500, test1, true, "1000", test_price, std.GetOrigCaller()) // give enough amount to take fees away + intAmount0, _ := strconv.Atoi(amount0) + intAmount1, _ := strconv.Atoi(amount1) poolNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) poolNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) @@ -260,10 +350,10 @@ func TestSwap(t *testing.T) { userNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) userNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - shouldEQ(t, userOldToken0Bal-userNewToken0Bal, int64(amount0)) - shouldEQ(t, userNewToken1Bal-userOldToken1Bal, int64(-amount1)) - shouldEQ(t, poolNewToken0Bal-poolOldToken0Bal, int64(amount0)) - shouldEQ(t, poolOldToken1Bal-poolNewToken1Bal, int64(-amount1)) + shouldEQ(t, userOldToken0Bal-userNewToken0Bal, int64(intAmount0)) + shouldEQ(t, userNewToken1Bal-userOldToken1Bal, int64(-intAmount1)) + shouldEQ(t, poolNewToken0Bal-poolOldToken0Bal, int64(intAmount0)) + shouldEQ(t, poolOldToken1Bal-poolNewToken1Bal, int64(-intAmount1)) } // Swap token1 -> token0 @@ -274,7 +364,9 @@ func TestSwap(t *testing.T) { userOldToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) userOldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - amount0, amount1 := Swap(barPath, fooPath, fee500, test1, false, 16000, consts.MAX_PRICE, std.GetOrigCaller()) // give enough amount to take fees away + amount0, amount1 := Swap(barPath, fooPath, fee500, test1, false, "16000", consts.MAX_PRICE, std.GetOrigCaller()) // give enough amount to take fees away + intAmount0, _ := strconv.Atoi(amount0) + intAmount1, _ := strconv.Atoi(amount1) poolNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, consts.POOL_ADDR) poolNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, consts.POOL_ADDR) @@ -282,10 +374,10 @@ func TestSwap(t *testing.T) { userNewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) userNewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - shouldEQ(t, userOldToken0Bal-userNewToken0Bal, int64(amount0)) - shouldEQ(t, userNewToken1Bal-userOldToken1Bal, int64(-amount1)) - shouldEQ(t, poolNewToken0Bal-poolOldToken0Bal, int64(amount0)) - shouldEQ(t, poolOldToken1Bal-poolNewToken1Bal, int64(-amount1)) + shouldEQ(t, userOldToken0Bal-userNewToken0Bal, int64(intAmount0)) + shouldEQ(t, userNewToken1Bal-userOldToken1Bal, int64(-intAmount1)) + shouldEQ(t, poolNewToken0Bal-poolOldToken0Bal, int64(intAmount0)) + shouldEQ(t, poolOldToken1Bal-poolNewToken1Bal, int64(-intAmount1)) } } @@ -319,21 +411,26 @@ func TestCollectProtocol(t *testing.T) { std.TestSetPrevRealm(consts.ROUTER_PATH) std.TestSetOrigCaller(test1) - Swap(barPath, fooPath, fee500, test1, true, 200000, consts.MIN_PRICE, std.GetOrigCaller()) // swap token0 -> token1 => fee only in token0 + Swap(barPath, fooPath, fee500, test1, true, "200000", consts.MIN_PRICE, std.GetOrigCaller()) // swap token0 -> token1 => fee only in token0 test1OldToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) test1OldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK std.TestSetPrevAddr(test1) amount0, amount1 := CollectProtocol(barPath, fooPath, fee500, test1, u256.NewUint(100000), u256.NewUint(100000)) +======== + std.TestSetPrevAddr(gsa) + amount0, amount1 := CollectProtocol(barPath, fooPath, fee500, test1, "100000", "100000") +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno test1NewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) test1NewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - shouldEQ(t, test1NewToken0Bal-test1OldToken0Bal, int64(amount0)) - shouldEQ(t, test1NewToken1Bal-test1OldToken1Bal, int64(amount1)) - } + _token0Diff := test1NewToken0Bal - test1OldToken0Bal + _token1Diff := test1NewToken1Bal - test1OldToken1Bal +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK { std.TestSetPrevRealm(consts.ROUTER_PATH) std.TestSetOrigCaller(test1) @@ -347,6 +444,13 @@ func TestCollectProtocol(t *testing.T) { test1NewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) test1NewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) +======== + token0DiffStr := strconv.Itoa(int(_token0Diff)) + token1DiffStr := strconv.Itoa(int(_token1Diff)) + + shouldEQ(t, token0DiffStr, amount0) + shouldEQ(t, token1DiffStr, amount1) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno } } @@ -355,8 +459,13 @@ func TestApiGetPools(t *testing.T) { gpls := ApiGetPools() jsonStr := gjson.Parse(gpls) +<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK shouldEQ(t, jsonStr.Get("stat.height").Int(), GetHeight()) shouldEQ(t, jsonStr.Get("stat.timestamp").Int(), GetTimestamp()) +======== + // shouldEQ(t, jsonStr.Get("stat.height").Int(), std.GetHeight()) + // shouldEQ(t, jsonStr.Get("stat.timestamp").Int(), time.Now().Unix()) +>>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno - shouldEQ(t, len(jsonStr.Get("response").Array()), 1) + // shouldEQ(t, len(jsonStr.Get("response").Array()), 1) } diff --git a/pool/bit_math.gno b/pool/bit_math.gno index 54b8cd69..ceaeced1 100644 --- a/pool/bit_math.gno +++ b/pool/bit_math.gno @@ -1,10 +1,9 @@ package pool import ( - "gno.land/p/demo/ufmt" "gno.land/r/demo/consts" - "gno.land/p/demo/u256" + u256 "gno.land/p/big/uint256" ) type bitShift struct { @@ -13,26 +12,21 @@ type bitShift struct { } func bitMathMostSignificantBit(x *u256.Uint) uint8 { - require( - !x.IsZero(), - ufmt.Sprintf("[POOL] bit_math.gno__bitMathMostSignificantBit() || expected x(%d) != 0", x), - ) - shifts := []bitShift{ - {u256.FromBigint(0x100000000000000000000000000000000), 128}, - {u256.FromBigint(0x10000000000000000), 64}, - {u256.FromBigint(0x100000000), 32}, - {u256.FromBigint(0x10000), 16}, - {u256.FromBigint(0x100), 8}, - {u256.FromBigint(0x10), 4}, - {u256.FromBigint(0x4), 2}, - {u256.FromBigint(0x2), 1}, + {u256.UnsafeFromDecimal(consts.Q128), 128}, // 2^128 + {u256.UnsafeFromDecimal(consts.Q64), 64}, // 2^64 + {u256.NewUint(0x100000000), 32}, + {u256.NewUint(0x10000), 16}, + {u256.NewUint(0x100), 8}, + {u256.NewUint(0x10), 4}, + {u256.NewUint(0x4), 2}, + {u256.NewUint(0x2), 1}, } r := uint8(0) for _, s := range shifts { if x.Gte(s.bitPattern) { - x.Rsh(x, s.shift) + x = new(u256.Uint).Rsh(x, s.shift) r += uint8(s.shift) } } @@ -41,28 +35,25 @@ func bitMathMostSignificantBit(x *u256.Uint) uint8 { } func bitMathLeastSignificantBit(x *u256.Uint) uint8 { - require( - !x.IsZero(), - ufmt.Sprintf("[POOL] bit_math.gno__bitMathLeastSignificantBit() || expected x(%d) != 0", x), - ) - shifts := []bitShift{ - {u256.FromBigint(consts.MAX_UINT128), 128}, - {u256.FromBigint(consts.MAX_UINT64), 64}, - {u256.FromBigint(consts.MAX_UINT32), 32}, - {u256.FromBigint(consts.MAX_UINT16), 16}, - {u256.FromBigint(consts.MAX_UINT8), 8}, - {u256.FromBigint(0xf), 4}, - {u256.FromBigint(0x3), 2}, - {u256.FromBigint(0x1), 1}, + {u256.UnsafeFromDecimal(consts.MAX_UINT128), 128}, + {u256.UnsafeFromDecimal(consts.MAX_UINT64), 64}, + {u256.UnsafeFromDecimal(consts.MAX_UINT32), 32}, + {u256.UnsafeFromDecimal(consts.MAX_UINT16), 16}, + {u256.UnsafeFromDecimal(consts.MAX_UINT8), 8}, + {u256.NewUint(0xf), 4}, + {u256.NewUint(0x3), 2}, + {u256.NewUint(0x1), 1}, } r := uint8(255) for _, s := range shifts { - if !new(u256.Uint).And(x, s.bitPattern).IsZero() { + if new(u256.Uint).And(x, s.bitPattern).Gt(u256.Zero()) { r -= uint8(s.shift) } else { - x.Rsh(x, s.shift) + // x >>= s.shift + // x = x >> s.shift + x = new(u256.Uint).Rsh(x, s.shift) } } diff --git a/pool/liquidity_math.gno b/pool/liquidity_math.gno index 4a8ce5a4..5cca0d53 100644 --- a/pool/liquidity_math.gno +++ b/pool/liquidity_math.gno @@ -1,19 +1,24 @@ package pool import ( - "gno.land/p/demo/ufmt" - - "gno.land/p/demo/u256" + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) -func liquidityMathAddDelta(x *u256.Uint, y *u256.Int) *u256.Uint { - if y.IsNeg() { +func liquidityMathAddDelta(x *u256.Uint, y *i256.Int) *u256.Uint { + if y.Lt(i256.Zero()) { z := new(u256.Uint).Sub(x, y.Abs()) - require(z.Lt(x), ufmt.Sprintf("[POOL] liquidity_math.gno__liquidityMathAddDelta() || z(%d) < x(%d)", z, x)) - return z + + if !(z.Lt(x)) { + panic("LS") + } + return z // z < x } else { - z := new(u256.Uint).Add(x, y.Uint()) - require(z.Gte(x), ufmt.Sprintf("[POOL] liquidity_math.gno__liquidityMathAddDelta() || z(%d) >= x(%d)", z, x)) - return z + z := new(u256.Uint).Add(x, y.Abs()) + + if !(z.Gte(x)) { + panic("LA") + } + return z // z >= x } } diff --git a/pool/pool.gno b/pool/pool.gno index 00d43a85..caf0539c 100644 --- a/pool/pool.gno +++ b/pool/pool.gno @@ -8,65 +8,59 @@ import ( "gno.land/r/demo/consts" - g "gno.land/r/demo/gov" + gv "gno.land/r/demo/gov" - "gno.land/p/demo/u256" + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) // only position contract can call this function func Mint( token0Path string, token1Path string, - fee uint16, + fee uint32, recipient std.Address, tickLower int32, tickUpper int32, - liquidityAmount_ bigint, -) (bigint, bigint /* *u256.Int, *u256.Int */) { - requirePrevRealmPath(consts.POSITION_PATH, ufmt.Sprintf("[POOL] pool.gno__Mint() || expected PrevRealmPath(%s), got %s", consts.POSITION_PATH, PrevRealmPath())) + _liquidityAmount string, // uint128 +) (string, string) { // uint256 x2 + requirePrevRealmPath(consts.POSITION_PATH, ufmt.Sprintf("[POOL] pool.gno__Mint() || expected std.PrevRealm().PkgPath()(%s), got %s", consts.POSITION_PATH, std.PrevRealm().PkgPath())) - requirePositive(liquidityAmount_, ufmt.Sprintf("[POOL] pool.gno__Mint() || expected liquidityAmount(%d) > 0", liquidityAmount_)) - - liquidityAmount := u256.IntFromBigint(liquidityAmount_) + liquidityAmount, err := u256.FromDecimal(_liquidityAmount) + if err != nil { + panic(ufmt.Sprintf("[POOL] pool.gno__Mint() || u256.FromDecimal(_liquidityAmount[%s]) failed", _liquidityAmount)) + } pool := GetPool(token0Path, token1Path, fee) - _, amount0, amount1 := pool.modifyPosition( + _, amount0, amount1 := pool.modifyPosition( // int256 x2 ModifyPositionParams{ - recipient, // owner - tickLower, // tickLower - tickUpper, // tickUpper - liquidityAmount, // liquidityDelta + recipient, // owner + tickLower, // tickLower + tickUpper, // tickUpper + i256.FromUint256(liquidityAmount), // liquidityDelta }, ) + println("amount0:", amount0.ToString()) + println("amount1:", amount1.ToString()) + panic("FIX 0 3") - if amount0.IsNeg() { - panic(ufmt.Sprintf("[POOL] pool.gno__Mint() || expected amount0(%d) >= 0", amount0)) - } - - if amount1.IsNeg() { - panic(ufmt.Sprintf("[POOL] pool.gno__Mint() || expected amount1(%d) >= 0", amount1)) - } - - balance0Before := u256.Zero().Int() - balance1Before := u256.Zero().Int() - - if amount0.Signum() > 0 { - balance0Before := u256.NewUint(balanceOfByRegisterCall(pool.token0Path, GetOrigPkgAddr())).Int() + if amount0.Gt(i256.Zero()) { + balance0Before := balanceOfByRegisterCall(pool.token0Path, GetOrigPkgAddr()) - from := GetOrigCaller() // token should be transferred from actual user(GetOrigCaller), not from the realm(PrevRealm) + from := std.GetOrigCaller() // token should be transferred from actual user(std.GetOrigCaller), not from the realm(PrevRealm) to := GetOrigPkgAddr() - ok := transferFromByRegisterCall(pool.token0Path, from, to, uint64(amount0.Int64())) + ok := transferFromByRegisterCall(pool.token0Path, from, to, amount0.Uint64()) require( ok, ufmt.Sprintf( - "[POOL] pool.gno__Mint() || transferFromByRegisterCall(pool.token0Path(%s), from(%s), to(%s), uint64(amount0))(%d) failed", - pool.token0Path, from.String(), to.String(), uint64(amount0.Int64()), + "[POOL] pool.gno__Mint() || transferFromByRegisterCall(pool.token0Path(%s), from(%s), to(%s), amount0.Uint64())(%d) failed", + pool.token0Path, from.String(), to.String(), amount0.Uint64(), ), ) require( - new(u256.Int).Add(balance0Before, amount0).Lte(u256.NewUint(balanceOfByRegisterCall(pool.token0Path, GetOrigPkgAddr())).Int()), + balance0Before+amount0.Uint64() <= balanceOfByRegisterCall(pool.token0Path, GetOrigPkgAddr()), ufmt.Sprintf( "[POOL] pool.gno__Mint() || balance0Before(%d) + amount0(%d) <= balanceOfByRegisterCall(pool.token0Path(%s), GetOrigPkgAddr()(%s))(%d)", balance0Before, amount0, pool.token0Path, GetOrigPkgAddr().String(), balanceOfByRegisterCall(pool.token0Path, GetOrigPkgAddr()), @@ -74,23 +68,23 @@ func Mint( ) } - if amount1.Signum() > 0 { - balance1Before = u256.NewUint(balanceOfByRegisterCall(pool.token1Path, GetOrigPkgAddr())).Int() + if amount1.Gt(i256.Zero()) { + balance1Before := balanceOfByRegisterCall(pool.token1Path, GetOrigPkgAddr()) - from := GetOrigCaller() // token should be transferred from actual user(GetOrigCaller), not from the realm(PrevRealm) + from := std.GetOrigCaller() // token should be transferred from actual user(std.GetOrigCaller), not from the realm(PrevRealm) to := GetOrigPkgAddr() - ok := transferFromByRegisterCall(pool.token1Path, from, to, uint64(amount1.Int64())) + ok := transferFromByRegisterCall(pool.token1Path, from, to, amount1.Uint64()) require( ok, ufmt.Sprintf( - "[POOL] pool.gno__Mint() || transferFromByRegisterCall(pool.token1Path(%s), from(%s), to(%s), uint64(amount1))(%d) failed", - pool.token1Path, from.String(), to.String(), uint64(amount1.Int64()), + "[POOL] pool.gno__Mint() || transferFromByRegisterCall(pool.token1Path(%s), from(%s), to(%s), amount1.Uint64())(%d) failed", + pool.token1Path, from.String(), to.String(), amount1.Uint64(), ), ) require( - new(u256.Int).Add(balance1Before, amount1).Lte(u256.NewUint(balanceOfByRegisterCall(pool.token1Path, GetOrigPkgAddr())).Int()), + balance1Before+amount1.Uint64() <= balanceOfByRegisterCall(pool.token1Path, GetOrigPkgAddr()), ufmt.Sprintf( "[POOL] pool.gno__Mint() || balance1Before(%d) + amount1(%d) <= balanceOfByRegisterCall(pool.token1Path(%s), GetOrigPkgAddr()(%s))(%d)", balance1Before, amount1, pool.token1Path, GetOrigPkgAddr().String(), balanceOfByRegisterCall(pool.token1Path, GetOrigPkgAddr()), @@ -98,152 +92,151 @@ func Mint( ) } - pool.balances.token0.AddInt(pool.balances.token0, amount0) - pool.balances.token1.AddInt(pool.balances.token1, amount1) + pool.balances.token0 = new(u256.Uint).Add(pool.balances.token0, amount0.Abs()) + pool.balances.token1 = new(u256.Uint).Add(pool.balances.token1, amount1.Abs()) - return amount0.Bigint(), amount1.Bigint() + return amount0.ToString(), amount1.ToString() } // only position contract can call this function func Burn( token0Path string, token1Path string, - fee uint16, + fee uint32, tickLower int32, tickUpper int32, - amount bigint, -) (bigint, bigint) { - requirePrevRealmPath(consts.POSITION_PATH, ufmt.Sprintf("[POOL] pool.gno__Burn() || expected PrevRealmPath(%s), got %s", consts.POSITION_PATH, PrevRealmPath())) + _liquidityAmount string, // uint128 +) (string, string) { // uint256 x2 + requirePrevRealmPath(consts.POSITION_PATH, ufmt.Sprintf("[POOL] pool.gno__Burn() || expected PrevRealmPath(%s), got %s", consts.POSITION_PATH, std.PrevRealm().PkgPath())) - burnAmount := u256.FromBigint(amount).Int().Neg() + liquidityAmount, err := u256.FromDecimal(_liquidityAmount) + if err != nil { + panic(ufmt.Sprintf("[POOL] pool.gno__Burn() || u256.FromDecimal(_liquidityAmount[%s]) failed", _liquidityAmount)) + } pool := GetPool(token0Path, token1Path, fee) - - position, amount0Int, amount1Int := pool.modifyPosition( + position, amount0Int, amount1Int := pool.modifyPosition( // in256 x2 ModifyPositionParams{ - PrevRealmAddr(), // msg.sender + std.PrevRealm().Addr(), // msg.sender tickLower, tickUpper, - burnAmount, + i256.Zero().Neg(i256.FromUint256(liquidityAmount)), }, ) + amount0 := amount0Int.Abs() + amount1 := amount1Int.Abs() - amount0 := amount0Int.Neg().Uint() - amount1 := amount1Int.Neg().Uint() - - position.tokensOwed0.Add(position.tokensOwed0, amount0) - position.tokensOwed1.Add(position.tokensOwed1, amount1) + if amount0.Gt(u256.Zero()) || amount1.Gt(u256.Zero()) { + position.tokensOwed0 = new(u256.Uint).Add(position.tokensOwed0, amount0) + position.tokensOwed1 = new(u256.Uint).Add(position.tokensOwed1, amount1) + } - positionKey := positionGetKey(PrevRealmAddr(), tickLower, tickUpper) + positionKey := positionGetKey(std.PrevRealm().Addr(), tickLower, tickUpper) pool.positions[positionKey] = position // actual token transfer happens in Collect() - return amount0.Bigint(), amount1.Bigint() + return amount0.ToString(), amount1.ToString() } // only position contract can call this function func Collect( token0Path string, token1Path string, - fee uint16, + fee uint32, recipient std.Address, tickLower int32, tickUpper int32, - amount0Requested_ bigint, - amount1Requested_ bigint, -) (bigint, bigint) { - requirePrevRealmPath(consts.POSITION_PATH, ufmt.Sprintf("[POOL] pool.gno__Collect() || expected PrevRealmPath(%s), got %s", consts.POSITION_PATH, PrevRealmPath())) + _amount0Requested string, // uint128 + _amount1Requested string, // uint128 +) (string, string) { // uint128 x2 - amount0Requested := u256.FromBigint(amount0Requested_) - amount1Requested := u256.FromBigint(amount1Requested_) + requirePrevRealmPath(consts.POSITION_PATH, ufmt.Sprintf("[POOL] pool.gno__Collect() || expected PrevRealmPath(%s), got %s", consts.POSITION_PATH, std.PrevRealm().PkgPath())) + amount0Requested, err := u256.FromDecimal(_amount0Requested) + if err != nil { + panic(ufmt.Sprintf("[POOL] pool.gno__Collect() || u256.FromDecimal(_amount0Requested[%s]) failed", _amount0Requested)) + } + amount1Requested, err := u256.FromDecimal(_amount1Requested) + if err != nil { + panic(ufmt.Sprintf("[POOL] pool.gno__Collect() || u256.FromDecimal(_amount1Requested[%s]) failed", _amount1Requested)) + } pool := GetPool(token0Path, token1Path, fee) - positionKey := positionGetKey(PrevRealmAddr(), tickLower, tickUpper) + positionKey := positionGetKey(std.PrevRealm().Addr(), tickLower, tickUpper) position, exist := pool.positions[positionKey] requireExist(exist, ufmt.Sprintf("[POOL] pool.gno__Collect() || position(%s) does not exist", positionKey)) // Smallest of three: amount0Requested, position.tokensOwed0, pool.balances.token0 - // println("amount0Requested:", amount0Requested.Dec()) - // println("position.tokensOwed0:", position.tokensOwed0.Dec()) - // println("pool.balances.token0:", pool.balances.token0.Dec()) - // println() - - amount0 := amount0Requested.Min(position.tokensOwed0) - amount0 = amount0.Min(pool.balances.token0) - amount1 := amount1Requested.Min(position.tokensOwed1) - amount1 = amount1.Min(pool.balances.token1) - - // backup calculated amount - resAmount0 := amount0.Clone() - resAmount1 := amount1.Clone() - - // adjust position - _amount0 := resAmount0.Clone() - _amount1 := resAmount1.Clone() - position.tokensOwed0.Sub(position.tokensOwed0, _amount0) - position.tokensOwed1.Sub(position.tokensOwed1, _amount1) - - // adjust pool - _amount0 = resAmount0.Clone() - _amount1 = resAmount1.Clone() - pool.balances.token0.Sub(pool.balances.token0, _amount0) - pool.balances.token1.Sub(pool.balances.token1, _amount1) - - // tranfer - _amount0 = resAmount0.Clone() - _amount1 = resAmount1.Clone() - transferByRegisterCall(pool.token0Path, recipient, _amount0.Uint64()) - transferByRegisterCall(pool.token1Path, recipient, _amount1.Uint64()) + amount0 := u256Min(amount0Requested, position.tokensOwed0) + amount0 = u256Min(amount0, pool.balances.token0) + + // Update state first then transfer + position.tokensOwed0 = new(u256.Uint).Sub(position.tokensOwed0, amount0) + pool.balances.token0 = new(u256.Uint).Sub(pool.balances.token0, amount0) + transferByRegisterCall(pool.token0Path, recipient, amount0.Uint64()) + + // Smallest of three: amount0Requested, position.tokensOwed0, pool.balances.token0 + amount1 := u256Min(amount1Requested, position.tokensOwed1) + amount1 = u256Min(amount1, pool.balances.token1) + + // Update state first then transfer + position.tokensOwed1 = new(u256.Uint).Sub(position.tokensOwed1, amount1) + pool.balances.token1 = new(u256.Uint).Sub(pool.balances.token1, amount1) + transferByRegisterCall(pool.token1Path, recipient, amount1.Uint64()) pool.positions[positionKey] = position - return resAmount0.Bigint(), resAmount1.Bigint() + return amount0.ToString(), amount1.ToString() } func Swap( token0Path string, token1Path string, - fee uint16, + fee uint32, recipient std.Address, zeroForOne bool, - amountSpecified_ bigint, - sqrtPriceLimitX96_ bigint, + _amountSpecified string, // int256 + _sqrtPriceLimitX96 string, // uint160 payer std.Address, // router -) (bigint, bigint) { - requirePrevRealmPath(consts.ROUTER_PATH, ufmt.Sprintf("[POOL] pool.gno__Swap() || expected PrevRealmPath(%s), got %s", consts.ROUTER_PATH, PrevRealmPath())) +) (string, string) { // int256 x2 + requirePrevRealmPath(consts.ROUTER_PATH, ufmt.Sprintf("[POOL] pool.gno__Swap() || expected PrevRealmPath(%s), got %s", consts.ROUTER_PATH, std.PrevRealm().PkgPath())) - // early panic - require(amountSpecified_ != 0, ufmt.Sprintf("[POOL] pool.gno__Swap() || amountSpecified(%d) != 0", amountSpecified_)) + if _amountSpecified == "0" { + panic("[POOL] pool.gno__Swap() || _amountSpecified == 0") + } - amountSpecified := u256.IntFromBigint(amountSpecified_) - sqrtPriceLimitX96 := u256.FromBigint(sqrtPriceLimitX96_) + amountSpecified, err := i256.FromDecimal(_amountSpecified) + if err != nil { + panic(ufmt.Sprintf("[POOL] pool.gno__Swap() || u256.FromDecimal(_amountSpecified[%s]) failed", _amountSpecified)) + } + sqrtPriceLimitX96, err := u256.FromDecimal(_sqrtPriceLimitX96) + if err != nil { + panic(ufmt.Sprintf("[POOL] pool.gno__Swap() || u256.FromDecimal(_sqrtPriceLimitX96[%s]) failed", _sqrtPriceLimitX96)) + } pool := GetPool(token0Path, token1Path, fee) slot0Start := pool.slot0 require(slot0Start.unlocked, ufmt.Sprintf("[POOL] pool.gno__Swap() || slot0 must be unlocked")) - // println("SQRT:", slot0Start.sqrtPriceX96.Dec()) - var feeProtocol uint8 var feeGrowthGlobalX128 *u256.Uint if zeroForOne { - require( - sqrtPriceLimitX96.Lt(slot0Start.sqrtPriceX96) && sqrtPriceLimitX96.Gt(u256.FromBigint(consts.MIN_SQRT_RATIO)), - ufmt.Sprintf("[POOL] pool.gno__Swap() || sqrtPriceLimitX96(%d) < slot0Start.sqrtPriceX96(%d) && sqrtPriceLimitX96(%d) > consts.MIN_SQRT_RATIO(%d)", - sqrtPriceLimitX96, slot0Start.sqrtPriceX96, sqrtPriceLimitX96, consts.MIN_SQRT_RATIO), - ) + min_sqrt_ratio := u256.UnsafeFromDecimal(consts.MIN_SQRT_RATIO) + cond1 := sqrtPriceLimitX96.Lt(slot0Start.sqrtPriceX96) + cond2 := sqrtPriceLimitX96.Gt(min_sqrt_ratio) + require(cond1 && cond2, ufmt.Sprintf("[POOL] pool.gno__Swap() || sqrtPriceLimitX96(%s) < slot0Start.sqrtPriceX96(%s) && sqrtPriceLimitX96(%s) > consts.MIN_SQRT_RATIO(%s)", sqrtPriceLimitX96.ToString(), slot0Start.sqrtPriceX96.ToString(), sqrtPriceLimitX96.ToString(), consts.MIN_SQRT_RATIO)) + feeProtocol = slot0Start.feeProtocol % 16 - feeGrowthGlobalX128 = pool.feeGrowthGlobal0X128 + feeGrowthGlobalX128 = pool.feeGrowthGlobal0X128.Clone() } else { - require( - sqrtPriceLimitX96.Gt(slot0Start.sqrtPriceX96) && sqrtPriceLimitX96.Lt(u256.FromBigint(consts.MAX_SQRT_RATIO)), - ufmt.Sprintf("[POOL] pool.gno__Swap() || sqrtPriceLimitX96(%d) > slot0Start.sqrtPriceX96(%d) && sqrtPriceLimitX96(%d) < consts.MAX_SQRT_RATIO(%d)", - sqrtPriceLimitX96, slot0Start.sqrtPriceX96, sqrtPriceLimitX96, consts.MAX_SQRT_RATIO), - ) + max_sqrt_ratio := u256.UnsafeFromDecimal(consts.MAX_SQRT_RATIO) + cond1 := sqrtPriceLimitX96.Gt(slot0Start.sqrtPriceX96) + cond2 := sqrtPriceLimitX96.Lt(max_sqrt_ratio) + require(cond1 && cond2, ufmt.Sprintf("[POOL] pool.gno__Swap() || sqrtPriceLimitX96(%s) > slot0Start.sqrtPriceX96(%s) && sqrtPriceLimitX96(%s) < consts.MAX_SQRT_RATIO(%s)", sqrtPriceLimitX96.ToString(), slot0Start.sqrtPriceX96.ToString(), sqrtPriceLimitX96.ToString(), consts.MAX_SQRT_RATIO)) + feeProtocol = slot0Start.feeProtocol / 16 - feeGrowthGlobalX128 = pool.feeGrowthGlobal1X128 + feeGrowthGlobalX128 = pool.feeGrowthGlobal1X128.Clone() } pool.slot0.unlocked = false @@ -261,36 +254,34 @@ func Swap( } } - exactInput := amountSpecified.Gt(u256.Zero().Int()) + exactInput := amountSpecified.Gt(i256.Zero()) var state SwapState if zeroForOne { state = SwapState{ amountSpecifiedRemaining: amountSpecified, - amountCalculated: u256.Zero().Int(), + amountCalculated: i256.Zero(), sqrtPriceX96: slot0Start.sqrtPriceX96, tick: slot0Start.tick, - feeGrowthGlobalX128: pool.feeGrowthGlobal0X128.Clone(), + feeGrowthGlobalX128: pool.feeGrowthGlobal0X128, protocolFee: u256.Zero(), liquidity: cache.liquidityStart, } } else { state = SwapState{ amountSpecifiedRemaining: amountSpecified, - amountCalculated: u256.Zero().Int(), + amountCalculated: i256.Zero(), sqrtPriceX96: slot0Start.sqrtPriceX96, tick: slot0Start.tick, - feeGrowthGlobalX128: pool.feeGrowthGlobal1X128.Clone(), + feeGrowthGlobalX128: pool.feeGrowthGlobal1X128, protocolFee: u256.Zero(), liquidity: cache.liquidityStart, } } // continue swapping as long as we haven't used the entire input/output and haven't reached the price limit - origAmountSpecified := amountSpecified.Clone() - for !state.amountSpecifiedRemaining.IsZero() && !state.sqrtPriceX96.Eq(sqrtPriceLimitX96) { + for !(state.amountSpecifiedRemaining.IsZero()) && !(state.sqrtPriceX96.Eq(sqrtPriceLimitX96)) { var step StepComputations - step.sqrtPriceStartX96 = state.sqrtPriceX96 step.tickNext, step.initialized = pool.tickBitmapNextInitializedTickWithInOneWord( @@ -306,11 +297,12 @@ func Swap( step.tickNext = consts.MAX_TICK } + // get the price for the next tick step.sqrtPriceNextX96 = common.TickMathGetSqrtRatioAtTick(step.tickNext) + isLower := step.sqrtPriceNextX96.Lt(sqrtPriceLimitX96) isHigher := step.sqrtPriceNextX96.Gt(sqrtPriceLimitX96) - // get the price for the next tick var sqrtRatioTargetX96 *u256.Uint if (zeroForOne && isLower) || (!zeroForOne && isHigher) { sqrtRatioTargetX96 = sqrtPriceLimitX96 @@ -323,34 +315,37 @@ func Swap( sqrtRatioTargetX96, state.liquidity, state.amountSpecifiedRemaining, - uint32(pool.fee), + uint64(pool.fee), ) + amountInWithFee := i256.FromUint256(new(u256.Uint).Add(step.amountIn, step.feeAmount)) if exactInput { - state.amountSpecifiedRemaining.Sub(state.amountSpecifiedRemaining, new(u256.Uint).Add(step.amountIn, step.feeAmount).Int()) - state.amountCalculated.Sub(state.amountCalculated, step.amountOut.Int()) + state.amountSpecifiedRemaining = i256.Zero().Sub(state.amountSpecifiedRemaining, amountInWithFee) + state.amountCalculated = i256.Zero().Sub(state.amountCalculated, i256.FromUint256(step.amountOut)) } else { - state.amountSpecifiedRemaining.Add(state.amountSpecifiedRemaining, step.amountOut.Int()) - state.amountCalculated.Add(state.amountCalculated, new(u256.Uint).Add(step.amountIn, step.feeAmount).Int()) + state.amountSpecifiedRemaining = i256.Zero().Add(state.amountSpecifiedRemaining, i256.FromUint256(step.amountOut)) + state.amountCalculated = i256.Zero().Add(state.amountCalculated, amountInWithFee) } // if the protocol fee is on, calculate how much is owed, decrement feeAmount, and increment protocolFee if cache.feeProtocol > 0 { delta := new(u256.Uint).Div(step.feeAmount, u256.NewUint(uint64(cache.feeProtocol))) - step.feeAmount.Sub(step.feeAmount, delta) - state.protocolFee.Add(state.protocolFee, delta) + step.feeAmount = new(u256.Uint).Sub(step.feeAmount, delta) + state.protocolFee = new(u256.Uint).Add(state.protocolFee, delta) } // update global fee tracker if state.liquidity.Gt(u256.Zero()) { - // save fee - update := new(u256.Uint).Mul(step.feeAmount, u256.FromDecimal(string(consts.Q128))) - update.Div(update, state.liquidity) - state.feeGrowthGlobalX128.Add(state.feeGrowthGlobalX128.Clone(), update) + _q128 := u256.UnsafeFromDecimal(consts.Q128) + + value1 := new(u256.Uint).Mul(step.feeAmount, _q128) + value2 := new(u256.Uint).Div(value1, state.liquidity) + + state.feeGrowthGlobalX128 = new(u256.Uint).Add(state.feeGrowthGlobalX128, value2) } // shift tick if we reached the next price - if state.sqrtPriceX96 == step.sqrtPriceNextX96 { + if state.sqrtPriceX96.Eq(step.sqrtPriceNextX96) { // if the tick is initialized, run the tick transition if step.initialized { var fee0, fee1 *u256.Uint @@ -372,7 +367,7 @@ func Swap( // if we're moving leftward, we interpret liquidityNet as the opposite sign if zeroForOne { - liquidityNet = liquidityNet.Neg() + liquidityNet = i256.Zero().Neg(liquidityNet) } state.liquidity = liquidityMathAddDelta(state.liquidity, liquidityNet) @@ -383,120 +378,132 @@ func Swap( } else { state.tick = step.tickNext } - } else if state.sqrtPriceX96 != step.sqrtPriceStartX96 { + } else if !(state.sqrtPriceX96.Eq(step.sqrtPriceStartX96)) { // recompute unless we're on a lower tick boundary (i.e. already transitioned ticks), and haven't moved state.tick = common.TickMathGetTickAtSqrtRatio(state.sqrtPriceX96) } } // END LOOP - println("END") pool.slot0.sqrtPriceX96 = state.sqrtPriceX96 if state.tick != slot0Start.tick { pool.slot0.tick = state.tick } - if cache.liquidityStart != state.liquidity { + if !(cache.liquidityStart.Eq(state.liquidity)) { pool.liquidity = state.liquidity } if zeroForOne { pool.feeGrowthGlobal0X128 = state.feeGrowthGlobalX128 if state.protocolFee.Gt(u256.Zero()) { - pool.protocolFees.token0.Add(pool.protocolFees.token0, state.protocolFee) + pool.protocolFees.token0 = new(u256.Uint).Add(pool.protocolFees.token0, state.protocolFee) } } else { pool.feeGrowthGlobal1X128 = state.feeGrowthGlobalX128 if state.protocolFee.Gt(u256.Zero()) { - pool.protocolFees.token1.Add(pool.protocolFees.token1, state.protocolFee) + pool.protocolFees.token1 = new(u256.Uint).Add(pool.protocolFees.token1, state.protocolFee) } } - var amount0, amount1 *u256.Int + var amount0, amount1 *i256.Int if zeroForOne == exactInput { - amount0 = new(u256.Int).Sub(origAmountSpecified, state.amountSpecifiedRemaining) + amount0 = i256.Zero().Sub(amountSpecified, state.amountSpecifiedRemaining) amount1 = state.amountCalculated } else { amount0 = state.amountCalculated - amount1 = new(u256.Int).Sub(origAmountSpecified, state.amountSpecifiedRemaining) + amount1 = i256.Zero().Sub(amountSpecified, state.amountSpecifiedRemaining) } - // backUP - resAmount0 := amount0.Clone() - resAmount1 := amount1.Clone() - if zeroForOne { - // payer > pool + uAmount0 := amount0.Abs().Uint64() + + // FROM payer TO pool balance0Before := balanceOfByRegisterCall(pool.token0Path, GetOrigPkgAddr()) - ok := transferFromByRegisterCall(pool.token0Path, payer, consts.POOL_ADDR, uint64(amount0.Int64())) + ok := transferFromByRegisterCall(pool.token0Path, payer, consts.POOL_ADDR, uAmount0) + + // payer -> pool OK require( ok, ufmt.Sprintf( - "[POOL] pool.gno__Swap() || transferFromByRegisterCall(pool.token0Path(%s), payer(%s), consts.POOL_ADDR(%s), uint64(amount0))(%d) failed", - pool.token0Path, payer.String(), consts.POOL_ADDR.String(), uint64(amount0.Int64()), + "[POOL] pool.gno__Swap() || transferFromByRegisterCall(pool.token0Path(%s), payer(%s), consts.POOL_ADDR(%s), uAmount0(%d)) failed", + pool.token0Path, payer.String(), consts.POOL_ADDR.String(), uAmount0, ), ) + // pool token0 balance updated require( - new(u256.Int).Add(u256.NewUint(balance0Before).Int(), amount0).Lte(u256.NewUint(balanceOfByRegisterCall(pool.token0Path, GetOrigPkgAddr())).Int()), + (balance0Before+uAmount0) <= balanceOfByRegisterCall(pool.token0Path, GetOrigPkgAddr()), ufmt.Sprintf( - "[POOL] pool.gno__Swap() || balance0Before(%d) + amount0(%d) <= balanceOfByRegisterCall(pool.token0Path(%s), GetOrigPkgAddr()(%s))(%d)", - balance0Before, amount0, pool.token0Path, GetOrigPkgAddr().String(), balanceOfByRegisterCall(pool.token0Path, GetOrigPkgAddr()), + "[POOL] pool.gno__Swap() || (balance0Before(%d) + uAmount0(%d)) <= balanceOfByRegisterCall(pool.token0Path(%s), GetOrigPkgAddr()(%s))(%d)", + balance0Before, uAmount0, pool.token0Path, GetOrigPkgAddr().String(), balanceOfByRegisterCall(pool.token0Path, GetOrigPkgAddr()), ), ) - pool.balances.token0.AddInt(pool.balances.token0, amount0) - if amount1.IsNeg() { // pool > recipient - require(pool.balances.token1.Gt(amount1.Abs()), ufmt.Sprintf("[POOL] pool.gno__Swap() || pool.balances.token1(%d) > -amount1(%d)", pool.balances.token1, amount1.Neg())) - ok := transferByRegisterCall(pool.token1Path, recipient, amount1.Abs().Uint64()) + pool.balances.token0 = new(u256.Uint).Add(pool.balances.token0, amount0.Abs()) + require(pool.balances.token0.Gte(u256.Zero()), ufmt.Sprintf("[POOL] pool.gno__Swap() || pool.balances.token0(%d) >= 0", pool.balances.token0)) + + // FROM pool TO recipient + if amount1.IsNeg() { + require(pool.balances.token1.Gte(amount1.Abs()), ufmt.Sprintf("[POOL] pool.gno__Swap() || pool.balances.token1(%d) >= amount1.Abs(%d)", pool.balances.token1, amount1.Abs())) + + uAmount1 := amount1.Abs().Uint64() + ok := transferByRegisterCall(pool.token1Path, recipient, uAmount1) require( ok, ufmt.Sprintf( - "[POOL] pool.gno__Swap() || transferByRegisterCall(pool.token1Path(%s), recipient(%s), uint64(-amount1))(%d) failed", - pool.token1Path, recipient.String(), amount1.Abs().Uint64(), + "[POOL] pool.gno__Swap() || transferByRegisterCall(pool.token1Path(%s), recipient(%s), uAmount1(%d)) failed", + pool.token1Path, recipient.String(), uAmount1, ), ) - pool.balances.token1.AddInt(pool.balances.token1, amount1) + pool.balances.token1 = new(u256.Uint).Sub(pool.balances.token1, amount1.Abs()) } + require(pool.balances.token1.Gte(u256.Zero()), ufmt.Sprintf("[POOL] pool.gno__Swap() || pool.balances.token1(%d) >= 0", pool.balances.token1)) + } else { - // payer > pool + uAmount1 := amount1.Abs().Uint64() + + // FROM payer TO pool balance1Before := balanceOfByRegisterCall(pool.token1Path, GetOrigPkgAddr()) - ok := transferFromByRegisterCall(pool.token1Path, payer, consts.POOL_ADDR, uint64(amount1.Int64())) + ok := transferFromByRegisterCall(pool.token1Path, payer, consts.POOL_ADDR, uAmount1) require( ok, ufmt.Sprintf( - "[POOL] pool.gno__Swap() || transferFromByRegisterCall(pool.token1Path(%s), payer(%s), consts.POOL_ADDR(%s), uint64(amount1))(%d) failed", - pool.token1Path, payer.String(), consts.POOL_ADDR.String(), uint64(amount1.Int64()), + "[POOL] pool.gno__Swap() || transferFromByRegisterCall(pool.token1Path(%s), payer(%s), consts.POOL_ADDR(%s), uAmount1(%d)) failed", + pool.token1Path, payer.String(), consts.POOL_ADDR.String(), uAmount1, ), ) require( - new(u256.Int).Add(u256.NewUint(balance1Before).Int(), amount1).Lte(u256.NewUint(balanceOfByRegisterCall(pool.token1Path, GetOrigPkgAddr())).Int()), + (balance1Before+uAmount1) <= balanceOfByRegisterCall(pool.token1Path, GetOrigPkgAddr()), ufmt.Sprintf( - "[POOL] pool.gno__Swap() || balance1Before(%d) + amount1(%d) <= balanceOfByRegisterCall(pool.token1Path(%s), GetOrigPkgAddr()(%s))(%d)", - balance1Before, amount1, pool.token1Path, GetOrigPkgAddr().String(), balanceOfByRegisterCall(pool.token1Path, GetOrigPkgAddr()), + "[POOL] pool.gno__Swap() || (balance1Before(%d) + uAmount1(%d)) <= balanceOfByRegisterCall(pool.token1Path(%s), GetOrigPkgAddr()(%s))(%d)", + balance1Before, uAmount1, pool.token1Path, GetOrigPkgAddr().String(), balanceOfByRegisterCall(pool.token1Path, GetOrigPkgAddr()), ), ) - pool.balances.token1.AddInt(pool.balances.token1, amount1) - if amount0.IsNeg() { // pool > recipient - require(pool.balances.token0.Gt(amount0.Abs()), ufmt.Sprintf("[POOL] pool.gno__Swap() || pool.balances.token0(%d) > -amount0(%d)", pool.balances.token0, amount0.Neg())) + pool.balances.token1 = new(u256.Uint).Add(pool.balances.token1, amount1.Abs()) + require(pool.balances.token1.Gte(u256.Zero()), ufmt.Sprintf("[POOL] pool.gno__Swap() || pool.balances.token1(%d) >= 0", pool.balances.token1)) + + // FROM pool TO recipient + if amount0.IsNeg() { + require(pool.balances.token0.Gte(amount0.Abs()), ufmt.Sprintf("[POOL] pool.gno__Swap() || pool.balances.token0(%d) >= amount0.Abs(%d)", pool.balances.token0, amount0.Abs())) - ok := transferByRegisterCall(pool.token0Path, recipient, amount0.Abs().Uint64()) + uAmount0 := amount0.Abs().Uint64() + ok := transferByRegisterCall(pool.token0Path, recipient, uAmount0) require( ok, ufmt.Sprintf( - "[POOL] pool.gno__Swap() || transferByRegisterCall(pool.token0Path(%s), recipient(%s), uint64(-amount0))(%d) failed", - pool.token0Path, recipient.String(), amount0.Abs().Uint64(), + "[POOL] pool.gno__Swap() || transferByRegisterCall(pool.token0Path(%s), recipient(%s), uAmount0(%d)) failed", + pool.token0Path, recipient.String(), uAmount0, ), ) - pool.balances.token0.AddInt(pool.balances.token0, amount0) + pool.balances.token0 = new(u256.Uint).Sub(pool.balances.token0, amount0.Abs()) } + require(pool.balances.token0.Gte(u256.Zero()), ufmt.Sprintf("[POOL] pool.gno__Swap() || pool.balances.token0(%d) >= 0", pool.balances.token0)) } - pool.slot0.unlocked = true - - return resAmount0.Bigint(), resAmount1.Bigint() + return amount0.ToString(), amount1.ToString() } // ADMIN @@ -504,7 +511,7 @@ func SetFeeProtocol( feeProtocol0 uint8, feeProtocol1 uint8, ) { - require(isAdmin(PrevRealmAddr()), ufmt.Sprintf("[POOL] pool.gno__SetFeeProtocol() || caller(%s) must be admin", PrevRealmAddr())) + require(isAdmin(std.PrevRealm().Addr()), ufmt.Sprintf("[POOL] pool.gno__SetFeeProtocol() || caller(%s) must be admin", std.PrevRealm().Addr())) require( (feeProtocol0 == 0 || (feeProtocol0 >= 4 && feeProtocol0 <= 10)) && (feeProtocol1 == 0 || (feeProtocol1 >= 4 && feeProtocol1 <= 10)), @@ -520,223 +527,75 @@ func SetFeeProtocol( } // update governace value - g.SetGovParameter("protocoL_fees", feeProtocol0+(feeProtocol1<<4)) + gv.SetGovParameter("protocoL_fees", feeProtocol0+(feeProtocol1<<4)) } // ADMIN func CollectProtocol( token0Path string, token1Path string, - fee uint16, + fee uint32, recipient std.Address, - amount0Requested *u256.Uint, - amount1Requested *u256.Uint, -) (bigint, bigint) { - require(isAdmin(PrevRealmAddr()), ufmt.Sprintf("[POOL] pool.gno__CollectProtocol() || caller(%s) must be admin", PrevRealmAddr())) + _amount0Requested string, // uint128 + _amount1Requested string, // uint128 +) (string, string) { // uint128 x2 + require(isAdmin(std.PrevRealm().Addr()), ufmt.Sprintf("[POOL] pool.gno__CollectProtocol() || caller(%s) must be admin", std.PrevRealm().Addr())) + + amount0Requested, err := u256.FromDecimal(_amount0Requested) + if err != nil { + panic(ufmt.Sprintf("[POOL] pool.gno__CollectProtocol() || u256.FromDecimal(_amount0Requested[%s]) failed", _amount0Requested)) + } + amount1Requested, err := u256.FromDecimal(_amount1Requested) + if err != nil { + panic(ufmt.Sprintf("[POOL] pool.gno__CollectProtocol() || u256.FromDecimal(_amount1Requested[%s]) failed", _amount1Requested)) + } pool := GetPool(token0Path, token1Path, fee) - amount0 := amount0Requested.Min(pool.protocolFees.token0) - amount1 := amount1Requested.Min(pool.protocolFees.token1) + amount0 := u256Min(amount0Requested, pool.protocolFees.token0) + amount1 := u256Min(amount1Requested, pool.protocolFees.token1) - // after - amount0, amount1 = pool.saveProtocolFees(amount0.Clone(), amount1.Clone()) + amount0, amount1 = pool.saveProtocolFees(amount0, amount1) + uAmount0 := amount0.Uint64() + uAmount1 := amount1.Uint64() - ok := transferByRegisterCall(pool.token0Path, recipient, uint64(amount0.Uint64())) + ok := transferByRegisterCall(pool.token0Path, recipient, uAmount0) require( ok, ufmt.Sprintf( - "[POOL] pool.gno__CollectProtocol() || transferByRegisterCall(pool.token0Path(%s), recipient(%s), uint64(amount0))(%d) failed", - pool.token0Path, recipient.String(), uint64(amount0.Uint64()), + "[POOL] pool.gno__CollectProtocol() || transferByRegisterCall(pool.token0Path(%s), recipient(%s), uAmount0)(%d) failed", + pool.token0Path, recipient.String(), uAmount0, ), ) - ok = transferByRegisterCall(pool.token1Path, recipient, uint64(amount1.Uint64())) + ok = transferByRegisterCall(pool.token1Path, recipient, uAmount1) require( ok, ufmt.Sprintf( - "[POOL] pool.gno__CollectProtocol() || transferByRegisterCall(pool.token1Path(%s), recipient(%s), uint64(amount1))(%d) failed", - pool.token1Path, recipient.String(), uint64(amount1.Uint64()), + "[POOL] pool.gno__CollectProtocol() || transferByRegisterCall(pool.token1Path(%s), recipient(%s), uAmount1)(%d) failed", + pool.token1Path, recipient.String(), uAmount1, ), ) - return amount0.Bigint(), amount1.Bigint() -} - -// XXXXX: i made some mistake on int/uint while refactoring this part, please double check it before merge -func (pool *Pool) modifyPosition(params ModifyPositionParams) (PositionInfo, *u256.Int, *u256.Int) { - position := pool.updatePosition( - params.owner, - params.tickLower, - params.tickUpper, - params.liquidityDelta, - pool.slot0.tick, - ) - // println("MODI_position.tokensOwed0", position.tokensOwed0.Dec()) - // println("MODI_position.tokensOwed1", position.tokensOwed1.Dec()) - // println() - - amount0 := u256.Zero().Int() - amount1 := u256.Zero().Int() - - if !params.liquidityDelta.IsZero() { - if pool.slot0.tick < params.tickLower { - amount0 = sqrtPriceMathGetAmount0Delta( - common.TickMathGetSqrtRatioAtTick(params.tickLower), - common.TickMathGetSqrtRatioAtTick(params.tickUpper), - params.liquidityDelta.Clone(), - ) - } else if pool.slot0.tick < params.tickUpper { - liquidityBefore := pool.liquidity - - amount0 = sqrtPriceMathGetAmount0Delta( - pool.slot0.sqrtPriceX96, - common.TickMathGetSqrtRatioAtTick(params.tickUpper), - params.liquidityDelta.Clone(), - ) - - amount1 = sqrtPriceMathGetAmount1Delta( - common.TickMathGetSqrtRatioAtTick(params.tickLower), - pool.slot0.sqrtPriceX96, - params.liquidityDelta.Clone(), - ) - - pool.liquidity = liquidityMathAddDelta(liquidityBefore, params.liquidityDelta.Clone()) - - } else { - amount1 = sqrtPriceMathGetAmount1Delta( - common.TickMathGetSqrtRatioAtTick(params.tickLower), - common.TickMathGetSqrtRatioAtTick(params.tickUpper), - params.liquidityDelta.Clone(), - ) - } - } - - return position, amount0, amount1 -} - -func (pool *Pool) updatePosition( - owner std.Address, - tickLower int32, - tickUpper int32, - _liquidityDelta *u256.Int, - tick int32, -) PositionInfo { - // println(">> liquidityDelta", _liquidityDelta.Dec()) - // println(">> tick:", tick) - liquidityDelta := _liquidityDelta.Clone() - - var _feeGrowthGlobal0X128 *u256.Uint = pool.feeGrowthGlobal0X128 - var _feeGrowthGlobal1X128 *u256.Uint = pool.feeGrowthGlobal1X128 - - var flippedLower, flippedUpper bool - - if !liquidityDelta.IsZero() { - // println("tickLower", tickLower) - // println("tick", tick) - // println("liquidityDelta", liquidityDelta.Dec()) - // println("_feeGrowthGlobal0X128", _feeGrowthGlobal0X128.Dec()) - // println("_feeGrowthGlobal1X128", _feeGrowthGlobal1X128.Dec()) - // println("pool.maxLiquidityPerTick", pool.maxLiquidityPerTick.Dec()) - flippedLower = pool.tickUpdate( - tickLower, - tick, - liquidityDelta, - _feeGrowthGlobal0X128, - _feeGrowthGlobal1X128, - false, - pool.maxLiquidityPerTick, - ) - - // println("tickUpper", tickUpper) - // println("tick", tick) - // println("liquidityDelta", liquidityDelta.Dec()) - // println("_feeGrowthGlobal0X128", _feeGrowthGlobal0X128.Dec()) - // println("_feeGrowthGlobal1X128", _feeGrowthGlobal1X128.Dec()) - // println("pool.maxLiquidityPerTick", pool.maxLiquidityPerTick.Dec()) - flippedUpper = pool.tickUpdate( - tickUpper, - tick, - liquidityDelta, - _feeGrowthGlobal0X128, - _feeGrowthGlobal1X128, - true, - pool.maxLiquidityPerTick, - ) - - if flippedLower { - // println("3") - // println("tickLower:", tickLower) - // println("pool.tickSpacing:", pool.tickSpacing) - pool.tickBitmapFlipTick(tickLower, pool.tickSpacing) - } - - if flippedUpper { - // println("4") - pool.tickBitmapFlipTick(tickUpper, pool.tickSpacing) - } - } - // NO LIQ, ONLY BURN 0 - - // println("tickLower", tickLower) - // println("tickUpper", tickUpper) - // println("tick", tick) - // println("_feeGrowthGlobal0X128", _feeGrowthGlobal0X128.Dec()) - // println("_feeGrowthGlobal1X128", _feeGrowthGlobal1X128.Dec()) - feeGrowthInside0X128, feeGrowthInside1X128 := pool.tickGetFeeGrowthInside( - tickLower, - tickUpper, - tick, - _feeGrowthGlobal0X128, - _feeGrowthGlobal1X128, - ) - - positionKey := positionGetKey(owner, tickLower, tickUpper) - - // println("positionKey", positionKey) - // println("liquidityDelta", liquidityDelta.Dec()) - // println("feeGrowthInside0X128", feeGrowthInside0X128.Dec()) // XXX - // println("feeGrowthInside1X128", feeGrowthInside1X128.Dec()) - position := pool.positionUpdateWithKey( - positionKey, - liquidityDelta, - feeGrowthInside0X128, - feeGrowthInside1X128, - ) - // println(">> position.tokensOwed0", position.tokensOwed0.Dec()) - - if liquidityDelta.IsNeg() { - if flippedLower { - pool.tickClear(tickLower) - } - - if flippedUpper { - pool.tickClear(tickUpper) - } - } - - return position + return amount0.ToString(), amount1.ToString() } func (pool *Pool) saveProtocolFees(amount0, amount1 *u256.Uint) (*u256.Uint, *u256.Uint) { - if !amount0.IsZero() && amount0.Eq(pool.protocolFees.token0) { - amount0.Sub(amount0, u256.One()) + cond01 := amount0.Gt(u256.Zero()) + cond02 := amount0.Eq(pool.protocolFees.token0) + if cond01 && cond02 { + amount0 = new(u256.Uint).Sub(amount0, u256.One()) } - if !amount1.IsZero() && amount1.Eq(pool.protocolFees.token1) { - amount1.Sub(amount1, u256.One()) + cond11 := amount1.Gt(u256.Zero()) + cond12 := amount1.Eq(pool.protocolFees.token1) + if cond11 && cond12 { + amount1 = new(u256.Uint).Sub(amount1, u256.One()) } - pool.protocolFees.token0.Sub(pool.protocolFees.token0, amount0) - pool.protocolFees.token1.Sub(pool.protocolFees.token1, amount1) + pool.protocolFees.token0 = new(u256.Uint).Sub(pool.protocolFees.token0, amount0) + pool.protocolFees.token1 = new(u256.Uint).Sub(pool.protocolFees.token1, amount1) // return rest fee return amount0, amount1 } - -func abs(x bigint) uint64 { - if x < 0 { - return uint64(-x) - } - return uint64(x) -} diff --git a/pool/pool_manager.gno b/pool/pool_manager.gno index 49524e59..ba05eb0e 100644 --- a/pool/pool_manager.gno +++ b/pool/pool_manager.gno @@ -5,42 +5,49 @@ import ( "strconv" "gno.land/p/demo/common" - "gno.land/p/demo/u256" "gno.land/p/demo/ufmt" "gno.land/r/demo/consts" - gns "gno.land/r/demo/gns" + "gno.land/r/demo/gns" + + u256 "gno.land/p/big/uint256" ) var ( admins []std.Address initialized bool = false - feeAmountTickSpacing map[uint16]int32 = make(map[uint16]int32) // map[feeAmount]tick_spacing + feeAmountTickSpacing map[uint32]int32 = make(map[uint32]int32) // map[feeAmount]tick_spacing pools map[string]*Pool = make(map[string]*Pool) // map[poolPath]*Pool ) func InitManual() { + // MUST BE ORIGIN CALLER + std.AssertOriginCall() require(!initialized, ufmt.Sprintf("[POOl] pool_manager.gno__InitManual() || expected initialized(%t) == false", initialized)) + require(std.GetOrigCaller() == consts.GNOSWAP_ADMIN, ufmt.Sprintf("[POOl] pool_manager.gno__InitManual() || expected std.GetOrigCaller(%s) == consts.GNOSWAP_ADMIN(%s)", std.GetOrigCaller().String(), consts.GNOSWAP_ADMIN.String())) feeAmountTickSpacing[100] = 2 // 0.01% feeAmountTickSpacing[500] = 10 // 0.05% feeAmountTickSpacing[3000] = 60 // 0.3% feeAmountTickSpacing[10000] = 200 // 1% - admins = append(admins, PrevRealmAddr()) + admins = append(admins, std.PrevRealm().Addr()) initialized = true } func CreatePool( token0Path string, token1Path string, - fee uint16, - sqrtPriceX96_ bigint, + fee uint32, + _sqrtPriceX96 string, // uint ) *Pool { require(initialized, ufmt.Sprintf("[POOl] pool_manager.gno__gno__CreatePool() || expected initialized(%t) == true", initialized)) require(token0Path != token1Path, ufmt.Sprintf("[POOl] pool_manager.gno__CreatePool() || expected token0Path(%s) != token1Path(%s)", token0Path, token1Path)) - sqrtPriceX96 := u256.FromBigint(sqrtPriceX96_) + sqrtPriceX96, err := u256.FromDecimal(_sqrtPriceX96) + if err != nil { + panic("CREATE POOL SQRT STRING") + } if token1Path < token0Path { token0Path, token1Path = token1Path, token0Path @@ -50,7 +57,7 @@ func CreatePool( // check tickSpacing for fee tickSpacing := feeAmountTickSpacing[fee] - requirePositive(bigint(tickSpacing), ufmt.Sprintf("[POOL] pool_manager.gno__CreatePool() || expected tickSpacing(%d) > 0", tickSpacing)) + // requirePositive(bigint(tickSpacing), ufmt.Sprintf("[POOL] pool_manager.gno__CreatePool() || expected tickSpacing(%d) > 0", tickSpacing)) // calculate poolPath poolPath := GetPoolPath(token0Path, token1Path, fee) @@ -60,8 +67,6 @@ func CreatePool( requireExist(!exist, ufmt.Sprintf("[POOl] pool_manager.gno__CreatePool() || expected poolPath(%s) not to exist", poolPath)) if !exist { - // recipient is same address that receives protocol fee - // r3v4_xxx: change admin address when publish gns.TransferFrom(a2u(std.GetOrigCaller()), a2u(consts.GNOSWAP_ADMIN), consts.POOL_CREATION_FEE) pool = newPool(token0Path, token1Path, fee, tickSpacing, sqrtPriceX96) @@ -71,7 +76,7 @@ func CreatePool( return pool } -func GetPool(token0Path, token1Path string, fee uint16) *Pool { +func GetPool(token0Path, token1Path string, fee uint32) *Pool { poolPath := GetPoolPath(token0Path, token1Path, fee) pool, exist := pools[poolPath] requireExist(exist, ufmt.Sprintf("[POOL] pool_manager.gno__GetPool() || expected poolPath(%s) to exist", poolPath)) @@ -86,7 +91,7 @@ func GetPoolFromPoolPath(poolPath string) *Pool { return pool } -func GetPoolPath(token0Path, token1Path string, fee uint16) string { +func GetPoolPath(token0Path, token1Path string, fee uint32) string { if token0Path < token1Path { return token0Path + ":" + token1Path + ":" + strconv.Itoa(int(fee)) } else { @@ -95,7 +100,7 @@ func GetPoolPath(token0Path, token1Path string, fee uint16) string { } func AddAdmin(addr std.Address) { - caller := PrevRealmAddr() + caller := std.PrevRealm().Addr() if isAdmin(caller) { admins = append(admins, addr) } else { @@ -104,7 +109,7 @@ func AddAdmin(addr std.Address) { } func RemoveAdmin(addr std.Address) { - caller := PrevRealmAddr() + caller := std.PrevRealm().Addr() if isAdmin(caller) { if len(admins) == 1 { @@ -124,7 +129,7 @@ func RemoveAdmin(addr std.Address) { func newPool( token0Path string, token1Path string, - fee uint16, + fee uint32, tickSpacing int32, sqrtPriceX96 *u256.Uint, ) *Pool { diff --git a/pool/position.gno b/pool/position.gno index 8856181a..e17454b5 100644 --- a/pool/position.gno +++ b/pool/position.gno @@ -4,9 +4,11 @@ import ( "encoding/base64" "std" - "gno.land/p/demo/u256" "gno.land/p/demo/ufmt" "gno.land/r/demo/consts" + + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) func positionGetKey( @@ -22,10 +24,15 @@ func positionGetKey( func (pool *Pool) positionUpdateWithKey( positionKey string, - liquidityDelta *u256.Int, - feeGrowthInside0X128 *u256.Uint, - feeGrowthInside1X128 *u256.Uint, + liquidityDelta *i256.Int, // int128 + feeGrowthInside0X128 *u256.Uint, // uint256 + feeGrowthInside1X128 *u256.Uint, // uint256 ) PositionInfo { + // START INIT PARAM + liquidityDelta = liquidityDelta.NilToZero() + feeGrowthInside0X128 = feeGrowthInside0X128.NilToZero() + feeGrowthInside1X128 = feeGrowthInside1X128.NilToZero() + // END INIT PARAM position := pool.positions[positionKey] @@ -37,42 +44,47 @@ func (pool *Pool) positionUpdateWithKey( func positionUpdate( self PositionInfo, - liquidityDelta *u256.Int, - feeGrowthInside0X128 *u256.Uint, - feeGrowthInside1X128 *u256.Uint, + liquidityDelta *i256.Int, // int128 + feeGrowthInside0X128 *u256.Uint, // uint256 + feeGrowthInside1X128 *u256.Uint, // uint256 ) PositionInfo { - liquidityNext := u256.NewInt(0) - - // check nil + // START INIT PARAM self.liquidity = self.liquidity.NilToZero() self.feeGrowthInside0LastX128 = self.feeGrowthInside0LastX128.NilToZero() self.feeGrowthInside1LastX128 = self.feeGrowthInside1LastX128.NilToZero() self.tokensOwed0 = self.tokensOwed0.NilToZero() self.tokensOwed1 = self.tokensOwed1.NilToZero() - // + liquidityDelta = liquidityDelta.NilToZero() + feeGrowthInside0X128 = feeGrowthInside0X128.NilToZero() + feeGrowthInside1X128 = feeGrowthInside1X128.NilToZero() + // END INIT PARAM + + var liquidityNext *u256.Uint if liquidityDelta.IsZero() { - liquidityNext = self.liquidity.Int() + liquidityNext = self.liquidity } else { - liquidityNext = liquidityMathAddDelta(self.liquidity, liquidityDelta).Int() + liquidityNext = liquidityMathAddDelta(self.liquidity, liquidityDelta) } tokensOwed0 := new(u256.Uint).Sub(feeGrowthInside0X128, self.feeGrowthInside0LastX128) tokensOwed0 = tokensOwed0.Mul(tokensOwed0, self.liquidity) - tokensOwed0 = tokensOwed0.Div(tokensOwed0, u256.FromBigint(consts.Q128)) + tokensOwed0 = tokensOwed0.Div(tokensOwed0, u256.UnsafeFromDecimal(consts.Q128)) tokensOwed1 := new(u256.Uint).Sub(feeGrowthInside1X128, self.feeGrowthInside1LastX128) tokensOwed1 = tokensOwed1.Mul(tokensOwed1, self.liquidity) - tokensOwed1 = tokensOwed1.Div(tokensOwed1, u256.FromBigint(consts.Q128)) + tokensOwed1 = tokensOwed1.Div(tokensOwed1, u256.UnsafeFromDecimal(consts.Q128)) - if !liquidityDelta.IsZero() { - self.liquidity = liquidityNext.Uint() + if !(liquidityDelta.IsZero()) { + self.liquidity = liquidityNext } self.feeGrowthInside0LastX128 = feeGrowthInside0X128 self.feeGrowthInside1LastX128 = feeGrowthInside1X128 - self.tokensOwed0.Add(self.tokensOwed0, tokensOwed0) - self.tokensOwed1.Add(self.tokensOwed1, tokensOwed1) + if tokensOwed0.Gt(u256.Zero()) || tokensOwed1.Gt(u256.Zero()) { + self.tokensOwed0 = self.tokensOwed0.Add(self.tokensOwed0, tokensOwed0) + self.tokensOwed1 = self.tokensOwed1.Add(self.tokensOwed1, tokensOwed1) + } return self } diff --git a/pool/position_modify.gno b/pool/position_modify.gno index bc60b4de..69023ec4 100644 --- a/pool/position_modify.gno +++ b/pool/position_modify.gno @@ -2,9 +2,11 @@ package pool import ( "gno.land/p/demo/common" + + i256 "gno.land/p/big/int256" ) -func (pool *Pool) modifyPosition(params ModifyPositionParams) (PositionInfo, bigint, bigint) { +func (pool *Pool) modifyPosition(params ModifyPositionParams) (PositionInfo, *i256.Int, *i256.Int) { position := pool.updatePosition( params.owner, params.tickLower, @@ -12,10 +14,9 @@ func (pool *Pool) modifyPosition(params ModifyPositionParams) (PositionInfo, big params.liquidityDelta, pool.slot0.tick, ) + var amount0, amount1 *i256.Int - var amount0, amount1 bigint - - if params.liquidityDelta != 0 { + if !(params.liquidityDelta.IsZero()) { if pool.slot0.tick < params.tickLower { amount0 = sqrtPriceMathGetAmount0Delta( common.TickMathGetSqrtRatioAtTick(params.tickLower), @@ -23,21 +24,32 @@ func (pool *Pool) modifyPosition(params ModifyPositionParams) (PositionInfo, big params.liquidityDelta, ) } else if pool.slot0.tick < params.tickUpper { + println("HERE") liquidityBefore := pool.liquidity + println("tickUpper:", params.tickUpper) + println("common.TickMathGetSqrtRatioAtTick(params.tickUpper):", common.TickMathGetSqrtRatioAtTick(params.tickUpper).ToString()) + println() + println("tickLower:", params.tickLower) + println("common.TickMathGetSqrtRatioAtTick(params.tickLower):", common.TickMathGetSqrtRatioAtTick(params.tickLower).ToString()) + println() + amount0 = sqrtPriceMathGetAmount0Delta( pool.slot0.sqrtPriceX96, common.TickMathGetSqrtRatioAtTick(params.tickUpper), params.liquidityDelta, ) + println("amount0:", amount0.ToString()) amount1 = sqrtPriceMathGetAmount1Delta( common.TickMathGetSqrtRatioAtTick(params.tickLower), pool.slot0.sqrtPriceX96, params.liquidityDelta, ) + println("amount1:", amount1.ToString()) pool.liquidity = liquidityMathAddDelta(liquidityBefore, params.liquidityDelta) + panic("FIX 0 666") } else { amount1 = sqrtPriceMathGetAmount1Delta( @@ -48,5 +60,10 @@ func (pool *Pool) modifyPosition(params ModifyPositionParams) (PositionInfo, big } } + // if position is out of range, one of amount0 or amount1 can be nil + // handle as 0 + amount0 = amount0.NilToZero() + amount1 = amount1.NilToZero() + return position, amount0, amount1 } diff --git a/pool/position_update.gno b/pool/position_update.gno index 37aac2d3..fb8872f0 100644 --- a/pool/position_update.gno +++ b/pool/position_update.gno @@ -2,20 +2,22 @@ package pool import ( "std" + + i256 "gno.land/p/big/int256" ) func (pool *Pool) updatePosition( owner std.Address, tickLower int32, tickUpper int32, - liquidityDelta bigint, + liquidityDelta *i256.Int, // int128 tick int32, ) PositionInfo { - var _feeGrowthGlobal0X128 bigint = pool.feeGrowthGlobal0X128 - var _feeGrowthGlobal1X128 bigint = pool.feeGrowthGlobal1X128 + _feeGrowthGlobal0X128 := pool.feeGrowthGlobal0X128 + _feeGrowthGlobal1X128 := pool.feeGrowthGlobal1X128 var flippedLower, flippedUpper bool - if liquidityDelta != 0 { + if !(liquidityDelta.IsZero()) { flippedLower = pool.tickUpdate( tickLower, tick, @@ -64,7 +66,7 @@ func (pool *Pool) updatePosition( feeGrowthInside1X128, ) - if liquidityDelta < 0 { + if liquidityDelta.IsNeg() { if flippedLower { pool.tickClear(tickLower) } @@ -73,5 +75,6 @@ func (pool *Pool) updatePosition( pool.tickClear(tickUpper) } } + return position } diff --git a/pool/sqrt_price_math.gno b/pool/sqrt_price_math.gno index 9ed6a9a9..599c00ac 100644 --- a/pool/sqrt_price_math.gno +++ b/pool/sqrt_price_math.gno @@ -1,186 +1,190 @@ package pool -// XXXXXXXXX -// u256 Add/Sub are overflow protected, but Bitwise operations are not. -// Functions in this file are supposed to be overflow protected. -// swap_math.gno is assuming that these functions are overflow protected. -// XXXXXXXXX - import ( - "gno.land/p/demo/u256" - "gno.land/p/demo/ufmt" - "gno.land/r/demo/consts" + + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" + _ "gno.land/p/big/uint512" ) func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( - sqrtPX96 *u256.Uint, - liquidity *u256.Uint, - amount *u256.Uint, + sqrtPX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint128 + amount *u256.Uint, // uint256 add bool, -) *u256.Uint { +) *u256.Uint { // uint160 if amount.IsZero() { return sqrtPX96 } numerator1 := new(u256.Uint).Lsh(liquidity, 96) - product := new(u256.Uint).Mul(amount, sqrtPX96) - var denominator *u256.Uint - if add { - if new(u256.Uint).Div(product, amount).Eq(sqrtPX96) { - denominator = new(u256.Uint).Add(numerator1, product) - if denominator.Gte(numerator1) { - res := new(u256.Uint).Mul(numerator1, sqrtPX96) - res.Div(res, denominator) - return res - } + denominator := new(u256.Uint).Add(numerator1, product) + + if denominator.IsZero() { + panic("pool_sqrt price math #1") } - denominator1 := new(u256.Uint).Div(numerator1, sqrtPX96) - denominator1.Add(denominator1, amount) - return new(u256.Uint).Div(numerator1, denominator1) + res := new(u256.Uint).Mul(numerator1, sqrtPX96) + res = res.Div(res, denominator) + return res } - require(new(u256.Uint).Div(product, amount).Eq(sqrtPX96) && numerator1.Gt(product), "[POOL] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || condition must return true") - denominator = new(u256.Uint).Sub(numerator1, product) + denominator := new(u256.Uint).Sub(numerator1, product) - res := new(u256.Uint).Mul(numerator1, sqrtPX96) - res.Div(res, denominator) - return res + if !(denominator.Gt(u256.Zero())) { + panic("pool_sqrt price math #2") + } + + _tmp := new(u256.Uint).Div(numerator1, sqrtPX96) + _tmp = _tmp.Add(_tmp, amount) + return new(u256.Uint).Div(numerator1, _tmp) } func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown( - sqrtPX96 *u256.Uint, - liquidity *u256.Uint, - amount *u256.Uint, + sqrtPX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint1288 + amount *u256.Uint, // uint256 add bool, -) *u256.Uint { - var quotient *u256.Uint - if add { - if amount.Gte(u256.FromBigint(consts.MAX_UINT160)) { - scaledAmount := new(u256.Uint).Lsh(amount, 96) - quotient = scaledAmount.Div(scaledAmount, liquidity) - } else { - scaledAmount := new(u256.Uint).Mul(amount, u256.FromBigint(consts.Q96)) - quotient = scaledAmount.Div(scaledAmount, liquidity) - } - return new(u256.Uint).Add(sqrtPX96, quotient) +) *u256.Uint { // uint160 + quotient := u256.Zero() + if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { + quotient = quotient.Lsh(amount, 96) + quotient = quotient.Div(quotient, liquidity) } else { - if amount.Gte(u256.FromBigint(consts.MAX_UINT160)) { - scaledAmount := new(u256.Uint).Lsh(amount, 96) - quotient = scaledAmount.Div(scaledAmount, liquidity) - } else { - scaledAmount := new(u256.Uint).Mul(amount, u256.FromBigint(consts.Q96)) - quotient = scaledAmount.Div(scaledAmount, liquidity) - } - - require(sqrtPX96.Gt(quotient), ufmt.Sprintf("[POOL] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown() || sqrtPX96(%d) must be greater than quotient(%d)", sqrtPX96, quotient)) - return new(u256.Uint).Sub(sqrtPX96, quotient) + _tmp := new(u256.Uint).Div(u256.UnsafeFromDecimal(consts.Q96), liquidity) + quotient = new(u256.Uint).Mul(amount, _tmp) } // quotient mutst be positive when amount and liquidity are positive - if add { result := new(u256.Uint).Add(sqrtPX96, quotient) - require( - result.Gte(sqrtPX96), - ufmt.Sprintf( - "[POOL] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown() || expected result >= sqrtPX96, got: %d", - result, - ), - ) + if !(result.Gte(sqrtPX96)) { + panic("pool_sqrt price math #3") + } return result } result := new(u256.Uint).Sub(sqrtPX96, quotient) + if !(result.Gte(u256.Zero())) { + panic("pool_sqrt price math #4") + } return result } func sqrtPriceMathGetNextSqrtPriceFromInput( - sqrtPX96 *u256.Uint, - liquidity *u256.Uint, - amountIn *u256.Uint, - zeroForOne bool, -) (sqrtQ *u256.Uint) { + sqrtPX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint128 + amountIn *u256.Uint, // uint256 + zeroForOne bool, // bool +) *u256.Uint { // uint160 if zeroForOne { - return sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true) + amount0Result := sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true) + return amount0Result } - return sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true) + amount1Result := sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true) + return amount1Result } func sqrtPriceMathGetNextSqrtPriceFromOutput( - sqrtPX96 *u256.Uint, - liquidity *u256.Uint, - amountOut *u256.Uint, - zeroForOne bool, -) (sqrtQ *u256.Uint) { + sqrtPX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint128 + amountOut *u256.Uint, // uint256 + zeroForOne bool, // bool +) *u256.Uint { // uint160 if zeroForOne { - return sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) + amount1Result := sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) + return amount1Result } - return sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false) + amount0Result := sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false) + return amount0Result } func sqrtPriceMathGetAmount0DeltaHelper( - sqrtRatioAX96 *u256.Uint, - sqrtRatioBX96 *u256.Uint, - liquidity *u256.Uint, -) *u256.Uint { + sqrtRatioAX96 *u256.Uint, // uint160 + sqrtRatioBX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint160 +) *u256.Uint { // uint256 if sqrtRatioAX96.Gt(sqrtRatioBX96) { sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96 } numerator1 := new(u256.Uint).Lsh(liquidity, 96) + println("numerator1:", numerator1.ToString()) numerator2 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) + println("numerator2:", numerator2.ToString()) + + // res := new(u256.Uint).Mul(numerator1, numerator2) + // res = res.Div(res, sqrtRatioBX96) + // res = res.Div(res, sqrtRatioAX96) + value1 := new(u256.Uint).Mul(numerator1, numerator2) + println("value1:", value1.ToString()) + { + ov1, c := new(u256.Uint).MulOverflow(numerator1, numerator2) + println("ov1:", ov1.ToString(), "c:", c) + + } + + value2 := new(u256.Uint).Div(value1, sqrtRatioBX96) + println("value2:", value2.ToString()) + + res := new(u256.Uint).Div(value2, sqrtRatioAX96) + println("res:", res.ToString()) - res := new(u256.Uint).Mul(numerator1, numerator2) - res.Div(res, sqrtRatioBX96) - res.Div(res, sqrtRatioAX96) + panic("Q") return res } func sqrtPriceMathGetAmount1DeltaHelper( - sqrtRatioAX96 *u256.Uint, - sqrtRatioBX96 *u256.Uint, - liquidity *u256.Uint, -) *u256.Uint { + sqrtRatioAX96 *u256.Uint, // uint160 + sqrtRatioBX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint160 +) *u256.Uint { // uint256 if sqrtRatioAX96.Gt(sqrtRatioBX96) { sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96 } - res := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - res.Mul(res, liquidity) - res.Div(res, u256.FromBigint(consts.Q96)) + _tmp := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) + res := new(u256.Uint).Mul(liquidity, _tmp) + res = res.Div(res, u256.UnsafeFromDecimal(consts.Q96)) + return res } func sqrtPriceMathGetAmount0Delta( - sqrtRatioAX96 *u256.Uint, - sqrtRatioBX96 *u256.Uint, - liquidity *u256.Int, -) *u256.Int { + sqrtRatioAX96 *u256.Uint, // uint160 + sqrtRatioBX96 *u256.Uint, // uint160 + liquidity *i256.Int, // int128 +) *i256.Int { // int256 + if liquidity.IsNeg() { - return sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()).Int().Neg() + u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + i := i256.FromUint256(u) + return i256.Zero().Neg(i) } - - return sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Uint()).Int() + u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + return i256.FromUint256(u) } func sqrtPriceMathGetAmount1Delta( - sqrtRatioAX96 *u256.Uint, - sqrtRatioBX96 *u256.Uint, - liquidity *u256.Int, -) *u256.Int { + sqrtRatioAX96 *u256.Uint, // uint160 + sqrtRatioBX96 *u256.Uint, // uint160 + liquidity *i256.Int, // int128 +) *i256.Int { // int256 if liquidity.IsNeg() { - return sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()).Int().Neg() + u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + i := i256.FromUint256(u) + return i256.Zero().Neg(i) } - return sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Uint()).Int() + u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + return i256.FromUint256(u) } diff --git a/pool/swap_math.gno b/pool/swap_math.gno index d418af00..61b7ec8a 100644 --- a/pool/swap_math.gno +++ b/pool/swap_math.gno @@ -1,25 +1,30 @@ package pool import ( - "gno.land/p/demo/u256" + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) func swapMathComputeSwapStep( - sqrtRatioCurrentX96 *u256.Uint, - sqrtRatioTargetX96 *u256.Uint, - liquidity *u256.Uint, - amountRemaining *u256.Int, - feePips uint32, + sqrtRatioCurrentX96 *u256.Uint, // uint160 + sqrtRatioTargetX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint128 + amountRemaining *i256.Int, // int256 + feePips uint64, ) (sqrtRatioNextX96, amountIn, amountOut, feeAmount *u256.Uint) { isToken1Expensive := sqrtRatioCurrentX96.Gte(sqrtRatioTargetX96) // POSTIVIE == EXACT_IN => Estimated AmountOut // NEGATIVE == EXACT_OUT => Estimated AmountIn - exactIn := !amountRemaining.IsNeg() + exactIn := !(amountRemaining.IsNeg()) // amountRemaining >= 0 if exactIn { - amountRemainingLessFee := new(u256.Uint).Mul(amountRemaining.Uint(), u256.NewUint(uint64(1000000-feePips))) - amountRemainingLessFee.Div(amountRemainingLessFee, u256.NewUint(1000000)) + amountRemainingLessFee := u256.Zero() + + // amountRemainingLessFee := amountRemaining * bigint(uint64(1000000-feePips)) / 1000000 + _amountRemaining := amountRemaining.Abs() + amountRemainingLessFee = amountRemainingLessFee.Mul(_amountRemaining, u256.NewUint(1000000-feePips)) + amountRemainingLessFee = amountRemainingLessFee.Div(amountRemainingLessFee, u256.NewUint(1000000)) if isToken1Expensive { amountIn = sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity) @@ -56,7 +61,7 @@ func swapMathComputeSwapStep( } } - max := sqrtRatioTargetX96 == sqrtRatioNextX96 + max := sqrtRatioTargetX96.Eq(sqrtRatioNextX96) if isToken1Expensive { if max && exactIn { @@ -88,22 +93,15 @@ func swapMathComputeSwapStep( amountOut = amountRemaining.Abs() } - if exactIn && !sqrtRatioNextX96.Eq(sqrtRatioTargetX96) { - feeAmount = new(u256.Uint).Sub(amountRemaining.Uint(), amountIn) + if exactIn && !(sqrtRatioNextX96.Eq(sqrtRatioTargetX96)) { + feeAmount = new(u256.Uint).Sub(amountRemaining.Abs(), amountIn) } else { - feeAmount = new(u256.Uint).Mul(amountIn, u256.NewUint(uint64(feePips))) - feeAmount.Div(feeAmount, u256.NewUint(uint64(1000000-feePips))) + feeAmount = new(u256.Uint).Mul(amountIn, u256.NewUint(feePips)) + feeAmount = feeAmount.Div(feeAmount, u256.NewUint(1000000-feePips)) } - if !exactIn && !amountOut.IsZero() { - amountOut++ + if !exactIn && !(amountOut.IsZero()) { + amountOut = amountOut.Add(amountOut, u256.NewUint(1)) } return sqrtRatioNextX96, amountIn, amountOut, feeAmount } - -func absBigint(x bigint) bigint { - if x < 0 { - return -x - } - return x -} diff --git a/pool/tick.gno b/pool/tick.gno index 947d1736..8cfe7f16 100644 --- a/pool/tick.gno +++ b/pool/tick.gno @@ -1,75 +1,54 @@ package pool import ( - "gno.land/p/demo/u256" - "gno.land/p/demo/ufmt" "gno.land/r/demo/consts" + + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) func tickTickSpacingToMaxLiquidityPerTick(tickSpacing int32) *u256.Uint { minTick := (consts.MIN_TICK / tickSpacing) * tickSpacing maxTick := (consts.MAX_TICK / tickSpacing) * tickSpacing - numTicks := u256.NewUint(uint64(((maxTick - minTick) / tickSpacing) + 1)) + numTicks := uint64((maxTick-minTick)/tickSpacing) + 1 + + // requireUnsigned(consts.MAX_UINT128/numTicks, ufmt.Sprintf("[POOL] tick.gno__tickTickSpacingToMaxLiquidityPerTick() || consts.MAX_UINT128(%d) / numTicks(%d) >= 0(%d)", consts.MAX_UINT128, numTicks, consts.MAX_UINT128/numTicks)) + // return consts.MAX_UINT128 / numTicks - return new(u256.Uint).Div(u256.FromBigint(consts.MAX_UINT128), numTicks) + _maxUint128 := u256.UnsafeFromDecimal(consts.MAX_UINT128) + return new(u256.Uint).Div(_maxUint128, u256.NewUint(numTicks)) } func (pool *Pool) tickGetFeeGrowthInside( tickLower int32, tickUpper int32, tickCurrent int32, - feeGrowthGlobal0X128 *u256.Uint, - feeGrowthGlobal1X128 *u256.Uint, -) (feeGrowthInside0X128, feeGrowthInside1X128 *u256.Uint) { - // init return values - feeGrowthInside0X128 = u256.Zero() - feeGrowthInside1X128 = u256.Zero() - - // println("tickLower", tickLower) - // println("tickUpper", tickUpper) - // println("tickCurrent", tickCurrent) - // println("feeGrowthGlobal0X128", feeGrowthGlobal0X128.Dec()) - // println("feeGrowthGlobal1X128", feeGrowthGlobal1X128.Dec()) - // println() - - // END INIT - + feeGrowthGlobal0X128 *u256.Uint, // uint256 + feeGrowthGlobal1X128 *u256.Uint, // uint256 +) (feeGrowthInside0X128, feeGrowthInside1X128 *u256.Uint) { // uint256 lower := pool.ticks[tickLower] upper := pool.ticks[tickUpper] - feeGrowthBelow0X128 := u256.Zero() - feeGrowthBelow1X128 := u256.Zero() - - // println("CHK", tickLower) - // println("0x", lower.feeGrowthOutside0X128.Dec()) - // println("1x", lower.feeGrowthOutside1X128.Dec()) + var feeGrowthBelow0X128, feeGrowthBelow1X128 *u256.Uint if tickCurrent >= tickLower { - feeGrowthBelow0X128 = lower.feeGrowthOutside0X128.NilToZero() - feeGrowthBelow1X128 = lower.feeGrowthOutside1X128.NilToZero() + feeGrowthBelow0X128 = lower.feeGrowthOutside0X128 + feeGrowthBelow1X128 = lower.feeGrowthOutside1X128 } else { - feeGrowthBelow0X128.Sub(feeGrowthGlobal0X128, lower.feeGrowthOutside0X128.NilToZero()) - feeGrowthBelow1X128.Sub(feeGrowthGlobal1X128, lower.feeGrowthOutside1X128.NilToZero()) + feeGrowthBelow0X128 = new(u256.Uint).Sub(feeGrowthGlobal0X128, lower.feeGrowthOutside0X128) + feeGrowthBelow1X128 = new(u256.Uint).Sub(feeGrowthGlobal1X128, lower.feeGrowthOutside1X128) } - // println("feeGrowthBelow0X128", feeGrowthBelow0X128.Dec()) - // println("feeGrowthBelow1X128", feeGrowthBelow1X128.Dec()) - - feeGrowthAbove0X128 := u256.Zero() - feeGrowthAbove1X128 := u256.Zero() - + var feeGrowthAbove0X128, feeGrowthAbove1X128 *u256.Uint if tickCurrent < tickUpper { - feeGrowthAbove0X128 = upper.feeGrowthOutside0X128.NilToZero() - feeGrowthAbove1X128 = upper.feeGrowthOutside1X128.NilToZero() + feeGrowthAbove0X128 = upper.feeGrowthOutside0X128 + feeGrowthAbove1X128 = upper.feeGrowthOutside1X128 } else { - feeGrowthAbove0X128.Sub(feeGrowthGlobal0X128, upper.feeGrowthOutside0X128.NilToZero()) - feeGrowthAbove1X128.Sub(feeGrowthGlobal1X128, upper.feeGrowthOutside1X128.NilToZero()) + feeGrowthAbove0X128 = new(u256.Uint).Sub(feeGrowthGlobal0X128, upper.feeGrowthOutside0X128) + feeGrowthAbove1X128 = new(u256.Uint).Sub(feeGrowthGlobal1X128, upper.feeGrowthOutside1X128) } - feeGrowthInside0X128.Sub(feeGrowthGlobal0X128, feeGrowthBelow0X128) - feeGrowthInside0X128.Sub(feeGrowthInside0X128, feeGrowthAbove0X128) - - feeGrowthInside1X128.Sub(feeGrowthGlobal1X128, feeGrowthBelow1X128) - feeGrowthInside1X128.Sub(feeGrowthInside1X128, feeGrowthAbove1X128) + feeGrowthInside0X128 = new(u256.Uint).Sub(new(u256.Uint).Sub(feeGrowthGlobal0X128, feeGrowthBelow0X128), feeGrowthAbove0X128) + feeGrowthInside1X128 = new(u256.Uint).Sub(new(u256.Uint).Sub(feeGrowthGlobal1X128, feeGrowthBelow1X128), feeGrowthAbove1X128) return feeGrowthInside0X128, feeGrowthInside1X128 } @@ -77,29 +56,36 @@ func (pool *Pool) tickGetFeeGrowthInside( func (pool *Pool) tickUpdate( tick int32, tickCurrent int32, - liquidityDelta *u256.Int, - feeGrowthGlobal0X128 *u256.Uint, - feeGrowthGlobal1X128 *u256.Uint, + liquidityDelta *i256.Int, // int128 + feeGrowthGlobal0X128 *u256.Uint, // uint256 + feeGrowthGlobal1X128 *u256.Uint, // uint256 upper bool, - maxLiquidity *u256.Uint, + maxLiquidity *u256.Uint, // uint256 ) (flipped bool) { + // START PARAM INIT + liquidityDelta = liquidityDelta.NilToZero() + feeGrowthGlobal0X128 = feeGrowthGlobal0X128.NilToZero() + feeGrowthGlobal1X128 = feeGrowthGlobal1X128.NilToZero() + // END PARAM INIT + + // START STRUCT INIT info := pool.ticks[tick] + info.liquidityGross = info.liquidityGross.NilToZero() + info.liquidityNet = info.liquidityNet.NilToZero() + info.feeGrowthOutside0X128 = info.feeGrowthOutside0X128.NilToZero() info.feeGrowthOutside1X128 = info.feeGrowthOutside1X128.NilToZero() - info.liquidityNet = info.liquidityNet.NilToZero() + + info.secondsPerLiquidityOutsideX128 = info.secondsPerLiquidityOutsideX128.NilToZero() + // END STRUCT INIT liquidityGrossBefore := info.liquidityGross + liquidityGrossAfter := liquidityMathAddDelta(liquidityGrossBefore, liquidityDelta) - if liquidityGrossBefore == nil { - liquidityGrossBefore = u256.Zero() + if !(liquidityGrossAfter.Lte(maxLiquidity)) { + panic("tick panic #1") } - // println("liquidityGrossBefore", liquidityGrossBefore.Dec()) - - liquidityGrossAfter := liquidityMathAddDelta(liquidityGrossBefore, liquidityDelta) - require(!liquidityGrossAfter.Lte(maxLiquidity), ufmt.Sprintf("[POOL] tick.gno__tickUpdate() || liquidityGrossAfter(%s) <= maxLiquidity(%s)", liquidityGrossAfter.Dec(), maxLiquidity.Dec())) - // println("liquidityGrossAfter", liquidityGrossAfter.Dec()) - flipped = (liquidityGrossAfter.IsZero()) != (liquidityGrossBefore.IsZero()) if liquidityGrossBefore.IsZero() { @@ -111,23 +97,13 @@ func (pool *Pool) tickUpdate( info.initialized = true } - // println("info.feeGrowthOutside0X128", info.feeGrowthOutside0X128.Dec()) - // println("info.feeGrowthOutside1X128", info.feeGrowthOutside1X128.Dec()) - info.liquidityGross = liquidityGrossAfter if upper { - // println("11") - // println("info.liquidityNet", info.liquidityNet.Dec()) - // println("liquidityDelta", liquidityDelta.Dec()) - info.liquidityNet.Sub(info.liquidityNet, liquidityDelta) + info.liquidityNet = i256.Zero().Sub(info.liquidityNet, liquidityDelta) } else { - // println("22") - // println("info.liquidityNet", info.liquidityNet.Dec()) - // println("liquidityDelta", liquidityDelta.Dec()) - info.liquidityNet.Add(info.liquidityNet, liquidityDelta) + info.liquidityNet = i256.Zero().Add(info.liquidityNet, liquidityDelta) } - // println("info.liquidityNet", info.liquidityNet.Dec()) pool.ticks[tick] = info @@ -140,14 +116,10 @@ func (pool *Pool) tickClear(tick int32) { func (pool *Pool) tickCross( tick int32, - feeGrowthGlobal0X128 *u256.Uint, - feeGrowthGlobal1X128 *u256.Uint, -) *u256.Int { + feeGrowthGlobal0X128 *u256.Uint, // uint256 + feeGrowthGlobal1X128 *u256.Uint, // uint256 +) *i256.Int { info := pool.ticks[tick] - - info.feeGrowthOutside0X128 = info.feeGrowthOutside0X128.NilToZero() - info.feeGrowthOutside1X128 = info.feeGrowthOutside1X128.NilToZero() - info.feeGrowthOutside0X128 = new(u256.Uint).Sub(feeGrowthGlobal0X128, info.feeGrowthOutside0X128) info.feeGrowthOutside1X128 = new(u256.Uint).Sub(feeGrowthGlobal1X128, info.feeGrowthOutside1X128) diff --git a/pool/tick_bitmap.gno b/pool/tick_bitmap.gno index 2282b042..44f19f9e 100644 --- a/pool/tick_bitmap.gno +++ b/pool/tick_bitmap.gno @@ -2,8 +2,9 @@ package pool import ( "gno.land/p/demo/ufmt" + "gno.land/r/demo/consts" - "gno.land/p/demo/u256" + u256 "gno.land/p/big/uint256" ) func tickBitmapPosition(tick int32) (int16, uint8) { @@ -17,27 +18,22 @@ func (pool *Pool) tickBitmapFlipTick( tick int32, tickSpacing int32, ) { - require(tick%tickSpacing == 0, ufmt.Sprintf("[POOL] tick_bitmap.gno__tickBitmapFlipTick() || tick(%d) MOD tickSpacing(%d) != 0 (got:%d)", tick, tickSpacing, tick%tickSpacing)) - wordPos, bitPos := tickBitmapPosition(tick / tickSpacing) - mask := u256.NewUint(1) - mask.Lsh(mask, uint(bitPos)) // 2 ** bitPos - // println("wordPos", wordPos) - // println("bitPos", bitPos) - // println("mask", mask.Dec()) + require( + tick%tickSpacing == 0, + ufmt.Sprintf( + "[POOL] tick_bitmap.gno__tickBitmapFlipTick() || tick(%d) %% tickSpacing(%d) == 0(%d)", + tick, tickSpacing, tick%tickSpacing, + ), + ) - // XXXXXXXXXXXXXXXX - // mask.Lsh is exptected to check overflow with the signed integer type. - // Lets add an overflow proteced shift method for Uint so we dont have to make it a signed integer. - // not implemented, should be done in a separate pr + wordPos, bitPos := tickBitmapPosition(tick / tickSpacing) - //requireUnsigned(mask, ufmt.Sprintf("[POOL] tick_bitmap.gno__tickBitmapFlipTick() || mask(%d) > 0", mask)) + // mask := bigint(1) << uint64(bitPos) // 2 ** bitPos + mask := new(u256.Uint).Lsh(u256.NewUint(1), uint(bitPos)) - // check init value + // pool.tickBitmaps[wordPos] ^= mask pool.tickBitmaps[wordPos] = pool.tickBitmaps[wordPos].NilToZero() - - // println("pool.tickBitmaps[wordPos]:", pool.tickBitmaps[wordPos].Dec()) - pool.tickBitmaps[wordPos].Xor(pool.tickBitmaps[wordPos], mask) - // println("pool.tickBitmaps[wordPos]:", pool.tickBitmaps[wordPos].Dec()) + pool.tickBitmaps[wordPos] = new(u256.Uint).Xor(pool.tickBitmaps[wordPos], mask) } func (pool *Pool) tickBitmapNextInitializedTickWithInOneWord( @@ -53,21 +49,21 @@ func (pool *Pool) tickBitmapNextInitializedTickWithInOneWord( if lte { wordPos, bitPos := tickBitmapPosition(compress) - mask := new(u256.Uint).Lsh(u256.One(), uint(bitPos)) - mask.UnsafeSub(mask, u256.One()) - mask.Add(mask, (new(u256.Uint).Lsh(u256.One(), uint(bitPos)))) + // mask := (bigint(1) << uint64(bitPos)) - bigint(1) + (bigint(1) << uint64(bitPos)) + shift1LeftByBitPos := new(u256.Uint).Lsh(u256.NewUint(1), uint(bitPos)) - // XXXXXXXX overflow check Lsh! - // requireUnsigned(mask, ufmt.Sprintf("[POOL] tick_bitmap.gno__tickBitmapNextInitializedTickWithInOneWord__mask(%d) >= 0__#1", mask)) + mask := shift1LeftByBitPos.Clone() + mask = new(u256.Uint).UnsafeSub(mask, u256.NewUint(1)) + mask = new(u256.Uint).Add(mask, shift1LeftByBitPos.Clone()) + // masked := pool.tickBitmaps[wordPos] & mask pool.tickBitmaps[wordPos] = pool.tickBitmaps[wordPos].NilToZero() masked := new(u256.Uint).And(pool.tickBitmaps[wordPos], mask) - initialized := !masked.IsZero() + initialized := !(masked.IsZero()) if initialized { next := (compress - int32(bitPos-bitMathMostSignificantBit(masked))) * tickSpacing - return next, initialized } @@ -77,34 +73,35 @@ func (pool *Pool) tickBitmapNextInitializedTickWithInOneWord( wordPos, bitPos := tickBitmapPosition(compress + 1) - _mask := new(u256.Uint).Lsh(u256.One(), uint(bitPos)) - _mask.UnsafeSub(_mask, u256.One()) + shift1LeftByBitPos := new(u256.Uint).Lsh(u256.NewUint(1), uint(bitPos)) + _mask := shift1LeftByBitPos.Clone() + _mask = new(u256.Uint).UnsafeSub(_mask, u256.NewUint(1)) mask := bigintBitwiseNotForUint256BitmapIndexing(_mask) - // XXXXXXXX overflow check Lsh! - // requireUnsigned(mask, ufmt.Sprintf("[POOL] tick_bitmap.gno__tickBitmapNextInitializedTickWithInOneWord__mask(%d) >= 0__#2", mask)) - + pool.tickBitmaps[wordPos] = pool.tickBitmaps[wordPos].NilToZero() masked := new(u256.Uint).And(pool.tickBitmaps[wordPos], mask) - // XXXXXXXX overflow check And! - //requireUnsigned(masked, ufmt.Sprintf("[POOL] tick_bitmap.gno__tickBitmapNextInitializedTickWithInOneWord__masked(%d) >= 0__#2", masked)) - - initialized := !masked.IsZero() + initialized := !(masked.IsZero()) if initialized { next := (compress + 1 + int32(bitMathLeastSignificantBit(masked)-bitPos)) * tickSpacing return next, initialized } else { - next := (compress + 1 + int32(int64(consts.MAX_UINT8-bigint(uint64(bitPos))))) * tickSpacing + next := (compress + 1 + int32(255-bitPos)) * tickSpacing + return next, initialized } } func bigintBitwiseNotForUint256BitmapIndexing(x *u256.Uint) *u256.Uint { + // REF: https://stackoverflow.com/a/77071037 + // Create a mask with all bits set to 1 - mask := u256.FromBigint(consts.MAX_UINT256) - mask.Sub(mask, u256.One()) + mask := u256.UnsafeFromDecimal(consts.MAX_UINT256) + mask = new(u256.Uint).Sub(mask, u256.NewUint(1)) // XOR with mask to perform bitwise NOT + // result := x ^ mask + result := new(u256.Uint).Xor(x, mask) return result } diff --git a/pool/token_register.gno b/pool/token_register.gno index 813f3552..7d06c22d 100644 --- a/pool/token_register.gno +++ b/pool/token_register.gno @@ -29,6 +29,17 @@ func GetRegisteredTokens() []string { return tokens } +func GetRegisterToken(pkgPath string) GRC20Interface { + pkgPath = handleNative(pkgPath) + + _, found := registered[pkgPath] + if !found { + panic(ufmt.Sprintf("[POOL] pool_register.gno__GetRegisterToken() || pkgPath(%s) not found", pkgPath)) + } + + return registered[pkgPath] +} + func RegisterGRC20Interface(pkgPath string, igrc20 GRC20Interface) { caller := std.GetOrigCaller() if caller != consts.GNOSWAP_ADMIN { @@ -78,6 +89,7 @@ func transferByRegisterCall(pkgPath string, to std.Address, amount uint64) bool } else { panic("[POOl] pool_register.gno__transferByRegisterCall() || expected locked to be false") } + return true } diff --git a/pool/type.gno b/pool/type.gno index 14087fac..5f665775 100644 --- a/pool/type.gno +++ b/pool/type.gno @@ -3,11 +3,12 @@ package pool import ( "std" - "gno.land/p/demo/u256" + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) type Slot0 struct { - sqrtPriceX96 *u256.Uint + sqrtPriceX96 *u256.Uint // uint160 tick int32 feeProtocol uint8 unlocked bool @@ -19,63 +20,63 @@ type Balances struct { } type ProtocolFees struct { - token0 *u256.Uint - token1 *u256.Uint + token0 *u256.Uint // uint128 + token1 *u256.Uint // uint128 } type ModifyPositionParams struct { owner std.Address tickLower int32 tickUpper int32 - liquidityDelta *u256.Int + liquidityDelta *i256.Int // int128 } type SwapCache struct { feeProtocol uint8 - liquidityStart *u256.Uint + liquidityStart *u256.Uint // uint128 } type SwapState struct { - amountSpecifiedRemaining *u256.Int - amountCalculated *u256.Int - sqrtPriceX96 *u256.Uint + amountSpecifiedRemaining *i256.Int // int256 + amountCalculated *i256.Int // int256 + sqrtPriceX96 *u256.Uint // uint160 tick int32 - feeGrowthGlobalX128 *u256.Uint - protocolFee *u256.Uint - liquidity *u256.Uint + feeGrowthGlobalX128 *u256.Uint // uint256 + protocolFee *u256.Uint // uint128 + liquidity *u256.Uint // uint128 } type StepComputations struct { - sqrtPriceStartX96 *u256.Uint + sqrtPriceStartX96 *u256.Uint // uint160 tickNext int32 initialized bool - sqrtPriceNextX96 *u256.Uint - amountIn *u256.Uint - amountOut *u256.Uint - feeAmount *u256.Uint + sqrtPriceNextX96 *u256.Uint // uint160 + amountIn *u256.Uint // uint256 + amountOut *u256.Uint // uint256 + feeAmount *u256.Uint // uint256 } type PositionInfo struct { - liquidity *u256.Uint + liquidity *u256.Uint // uint128 - feeGrowthInside0LastX128 *u256.Uint - feeGrowthInside1LastX128 *u256.Uint + feeGrowthInside0LastX128 *u256.Uint // uint256 + feeGrowthInside1LastX128 *u256.Uint // uint256 - tokensOwed0 *u256.Uint - tokensOwed1 *u256.Uint + tokensOwed0 *u256.Uint // uint128 + tokensOwed1 *u256.Uint // uint128 } type TickInfo struct { - liquidityGross *u256.Uint - liquidityNet *u256.Int + liquidityGross *u256.Uint // uint128 + liquidityNet *i256.Int // int128 - feeGrowthOutside0X128 *u256.Uint - feeGrowthOutside1X128 *u256.Uint + feeGrowthOutside0X128 *u256.Uint // uint256 + feeGrowthOutside1X128 *u256.Uint // uint256 - //tickCumulativeOutside bigint + tickCumulativeOutside int64 // int56 - //secondsPerLiquidityOutsideX128 bigint - // secondsOutside bigint + secondsPerLiquidityOutsideX128 *u256.Uint // uint160 + secondsOutside uint32 // uint32 initialized bool } @@ -93,26 +94,26 @@ type Pool struct { balances Balances // fee is the fee tier of the pool - fee uint16 + fee uint32 // tickSpacing is the spacing between ticks tickSpacing int32 // maxLiquidityPerTick is the maximum amount of liquidity that can be added per tick - maxLiquidityPerTick *u256.Uint + maxLiquidityPerTick *u256.Uint // uint128 // slot0 is the current tick and price of the pool slot0 Slot0 - feeGrowthGlobal0X128 *u256.Uint - feeGrowthGlobal1X128 *u256.Uint + feeGrowthGlobal0X128 *u256.Uint // uint256 + feeGrowthGlobal1X128 *u256.Uint // uint256 // protocolFees is the amount of fees collected by the protocol // collected by CollectFeeProtocol() protocolFees ProtocolFees // liquidity is the total amount of liquidity in the pool - liquidity *u256.Uint + liquidity *u256.Uint // uint128 // ticks is a mapping from tick index to tick ticks Ticks diff --git a/pool/utils.gno b/pool/utils.gno index a6f867d7..b0c6b1b6 100644 --- a/pool/utils.gno +++ b/pool/utils.gno @@ -6,29 +6,28 @@ import ( "gno.land/p/demo/ufmt" "gno.land/r/demo/users" - "gno.land/p/demo/ufmt" + "gno.land/r/demo/consts" - "gno.land/p/demo/u256" + u256 "gno.land/p/big/uint256" ) -/* -func checkTicks(tickLower, tickUpper *u256.Int) { - require(tickLower.Lt(tickUpper), ufmt.Sprintf("[POOL] pool.gno__checkTicks() || tickLower(%d) < tickUpper(%d)", tickLower, tickUpper)) - require(tickLower.Gte(MIN_TICK), ufmt.Sprintf("[POOL] pool.gno__checkTicks() || tickLower(%d) >= MIN_TICK(%d)", tickLower, MIN_TICK)) - require(tickUpper.Lte(MAX_TICK), ufmt.Sprintf("[POOL] pool.gno__checkTicks() || tickUpper(%d) <= MAX_TICK(%d)", tickUpper, MAX_TICK)) + +func checkTicks(tickLower, tickUpper int32) { + require(tickLower < tickUpper, ufmt.Sprintf("[POOL] utils.gno__checkTicks() || tickLower(%d) < tickUpper(%d)", tickLower, tickUpper)) + require(tickLower >= consts.MIN_TICK, ufmt.Sprintf("[POOL] utils.gno__checkTicks() || tickLower(%d) >= consts.MIN_TICK(%d)", tickLower, consts.MIN_TICK)) + require(tickUpper <= consts.MAX_TICK, ufmt.Sprintf("[POOL] utils.gno__checkTicks() || tickUpper(%d) <= consts.MAX_TICK(%d)", tickUpper, consts.MAX_TICK)) } -*/ + func a2u(addr std.Address) users.AddressOrName { return users.AddressOrName(addr) } -/* -func min(num1, num2 bigint) bigint { - if num1 < num2 { +func u256Min(num1, num2 *u256.Uint) *u256.Uint { + if num1.Lt(num2) { return num1 } + return num2 } -*/ func removeDuplicateString(strSlice []string) []string { // map to store unique keys diff --git a/pool/withdrawal_fee.gno b/pool/withdrawal_fee.gno index 48af294d..b9964a6e 100644 --- a/pool/withdrawal_fee.gno +++ b/pool/withdrawal_fee.gno @@ -6,38 +6,55 @@ import ( "gno.land/r/demo/consts" "gno.land/p/demo/ufmt" + + u256 "gno.land/p/big/uint256" ) var ( - withdrawalFee = bigint(1) + withdrawalFee = uint64(1) ) func HandleWithdrawalFee( tokenId uint64, token0Path string, - amount0 bigint, + _amount0 string, // uint256 token1Path string, - amount1 bigint, -) (bigint, bigint) { + _amount1 string, // uint256 +) (string, string) { // uint256 x2 requirePrevRealmPath(consts.POSITION_PATH, ufmt.Sprintf("[POOL] withdrawal_fee.gno__HandleWithdrawFee() || expected std.PrevRealm().PkgPath()(%s), got %s", consts.POSITION_PATH, std.PrevRealm().PkgPath())) + amount0, err := u256.FromDecimal(_amount0) + if err != nil { + ufmt.Sprintf("[POOL] withdrawal_fee.gno__HandleWithdrawFee() ||u256.FromDecimal(%s) failed", _amount0) + } + amount1, err := u256.FromDecimal(_amount1) + if err != nil { + ufmt.Sprintf("[POOL] withdrawal_fee.gno__HandleWithdrawFee() ||u256.FromDecimal(%s) failed", _amount1) + } + if withdrawalFee == 0 { - return amount0, amount1 + return _amount0, _amount1 } - feeAmount0 := amount0 * withdrawalFee / bigint(100) - feeAmount1 := amount1 * withdrawalFee / bigint(100) + feeAmount0 := new(u256.Uint).Mul(amount0, u256.NewUint(withdrawalFee)) + feeAmount0 = new(u256.Uint).Div(feeAmount0, u256.NewUint(100)) + + feeAmount1 := new(u256.Uint).Mul(amount1, u256.NewUint(withdrawalFee)) + feeAmount1 = new(u256.Uint).Div(feeAmount1, u256.NewUint(100)) - ok := transferFromByRegisterCall(token0Path, std.GetOrigCaller(), consts.FEE_COLLECTOR, uint64(feeAmount0)) + ok := transferFromByRegisterCall(token0Path, std.GetOrigCaller(), consts.FEE_COLLECTOR, feeAmount0.Uint64()) require(ok, ufmt.Sprintf("[POOL] withdrawal_fee.gno__HandleWithdrawFee() || expected transferFromByRegisterCall(%s, %s, %s, %s) == true", token0Path, std.GetOrigCaller(), consts.FEE_COLLECTOR, feeAmount0)) - ok = transferFromByRegisterCall(token1Path, std.GetOrigCaller(), consts.FEE_COLLECTOR, uint64(feeAmount1)) + ok = transferFromByRegisterCall(token1Path, std.GetOrigCaller(), consts.FEE_COLLECTOR, feeAmount1.Uint64()) require(ok, ufmt.Sprintf("[POOL] withdrawal_fee.gno__HandleWithdrawFee() || expected transferFromByRegisterCall(%s, %s, %s, %s) == true", token1Path, std.GetOrigCaller(), consts.FEE_COLLECTOR, feeAmount1)) - return amount0 - feeAmount0, amount1 - feeAmount1 + afterAmount0 := new(u256.Uint).Sub(amount0, feeAmount0) + afterAmount1 := new(u256.Uint).Sub(amount1, feeAmount1) + + return afterAmount0.ToString(), afterAmount1.ToString() } -func SetWithdrawalFee(fee bigint) { +func SetWithdrawalFee(fee uint64) { // MUST BE ORIGIN CALL std.AssertOriginCall() diff --git a/position/_GET_no_receiver.gno.gno b/position/_GET_no_receiver.gno.gno index 193287fd..f4ee6321 100644 --- a/position/_GET_no_receiver.gno.gno +++ b/position/_GET_no_receiver.gno.gno @@ -2,6 +2,8 @@ package position import ( "std" + + u256 "gno.land/p/big/uint256" ) // type Position @@ -9,7 +11,7 @@ func PositionGetPosition(tokenId uint64) Position { return positions[tokenId] } -func PositionGetPositionNonce(tokenId uint64) bigint { +func PositionGetPositionNonce(tokenId uint64) *u256.Uint { return positions[tokenId].nonce } @@ -29,22 +31,22 @@ func PositionGetPositionTickUpper(tokenId uint64) int32 { return positions[tokenId].tickUpper } -func PositionGetPositionLiquidity(tokenId uint64) bigint { +func PositionGetPositionLiquidity(tokenId uint64) *u256.Uint { return positions[tokenId].liquidity } -func PositionGetPositionFeeGrowthInside0LastX128(tokenId uint64) bigint { +func PositionGetPositionFeeGrowthInside0LastX128(tokenId uint64) *u256.Uint { return positions[tokenId].feeGrowthInside0LastX128 } -func PositionGetPositionFeeGrowthInside1LastX128(tokenId uint64) bigint { +func PositionGetPositionFeeGrowthInside1LastX128(tokenId uint64) *u256.Uint { return positions[tokenId].feeGrowthInside1LastX128 } -func PositionGetPositionTokensOwed0(tokenId uint64) bigint { +func PositionGetPositionTokensOwed0(tokenId uint64) *u256.Uint { return positions[tokenId].tokensOwed0 } -func PositionGetPositionTokensOwed1(tokenId uint64) bigint { +func PositionGetPositionTokensOwed1(tokenId uint64) *u256.Uint { return positions[tokenId].tokensOwed1 } diff --git a/position/_GET_no_receiver_string.gno b/position/_GET_no_receiver_string.gno new file mode 100644 index 00000000..6048a62a --- /dev/null +++ b/position/_GET_no_receiver_string.gno @@ -0,0 +1,26 @@ +package position + +// type Position +func PositionGetPositionNonceStr(tokenId uint64) string { + return positions[tokenId].nonce.ToString() +} + +func PositionGetPositionLiquidityStr(tokenId uint64) string { + return positions[tokenId].liquidity.ToString() +} + +func PositionGetPositionFeeGrowthInside0LastX128Str(tokenId uint64) string { + return positions[tokenId].feeGrowthInside0LastX128.ToString() +} + +func PositionGetPositionFeeGrowthInside1LastX128Str(tokenId uint64) string { + return positions[tokenId].feeGrowthInside1LastX128.ToString() +} + +func PositionGetPositionTokensOwed0Str(tokenId uint64) string { + return positions[tokenId].tokensOwed0.ToString() +} + +func PositionGetPositionTokensOwed1Str(tokenId uint64) string { + return positions[tokenId].tokensOwed1.ToString() +} diff --git a/position/_RPC_api.gno b/position/_RPC_api.gno index f2448fc3..c8caac11 100644 --- a/position/_RPC_api.gno +++ b/position/_RPC_api.gno @@ -11,6 +11,8 @@ import ( "gno.land/r/demo/consts" pl "gno.land/r/demo/pool" + + u256 "gno.land/p/big/uint256" ) type RpcPosition struct { @@ -20,16 +22,16 @@ type RpcPosition struct { PoolKey string `json:"poolKey"` TickLower int32 `json:"tickLower"` TickUpper int32 `json:"tickUpper"` - Liquidity bigint `json:"liquidity"` - FeeGrowthInside0LastX128 bigint `json:"feeGrowthInside0LastX128"` - FeeGrowthInside1LastX128 bigint `json:"feeGrowthInside1LastX128"` - TokensOwed0 bigint `json:"tokensOwed0"` - TokensOwed1 bigint `json:"tokensOwed1"` - - Token0Balance bigint `json:"token0Balance"` - Token1Balance bigint `json:"token1Balance"` - FeeUnclaimed0 bigint `json:"feeUnclaimed0"` - FeeUnclaimed1 bigint `json:"feeUnclaimed1"` + Liquidity string `json:"liquidity"` + FeeGrowthInside0LastX128 string `json:"feeGrowthInside0LastX128"` + FeeGrowthInside1LastX128 string `json:"feeGrowthInside1LastX128"` + TokensOwed0 string `json:"tokensOwed0"` + TokensOwed1 string `json:"tokensOwed1"` + + Token0Balance string `json:"token0Balance"` + Token1Balance string `json:"token1Balance"` + FeeUnclaimed0 string `json:"feeUnclaimed0"` + FeeUnclaimed1 string `json:"feeUnclaimed1"` } type ResponseQueryBase struct { @@ -85,7 +87,8 @@ func rpcMakePosition(lpTokenId uint64) RpcPosition { position.liquidity, ) - var unclaimedFee0, unclaimedFee1 bigint // if position is burned, unclaimedFee0 and unclaimedFee1 will be 0 + unclaimedFee0 := u256.Zero() + unclaimedFee1 := u256.Zero() if !burned { unclaimedFee0, unclaimedFee1 := unclaimedFee(lpTokenId) } @@ -97,19 +100,19 @@ func rpcMakePosition(lpTokenId uint64) RpcPosition { PoolKey: position.poolKey, TickLower: position.tickLower, TickUpper: position.tickUpper, - Liquidity: position.liquidity, - FeeGrowthInside0LastX128: position.feeGrowthInside0LastX128, - FeeGrowthInside1LastX128: position.feeGrowthInside1LastX128, - TokensOwed0: position.tokensOwed0, - TokensOwed1: position.tokensOwed1, - Token0Balance: token0Balance, - Token1Balance: token1Balance, - FeeUnclaimed0: unclaimedFee0, - FeeUnclaimed1: unclaimedFee1, + Liquidity: position.liquidity.ToString(), + FeeGrowthInside0LastX128: position.feeGrowthInside0LastX128.ToString(), + FeeGrowthInside1LastX128: position.feeGrowthInside1LastX128.ToString(), + TokensOwed0: position.tokensOwed0.ToString(), + TokensOwed1: position.tokensOwed1.ToString(), + Token0Balance: token0Balance.ToString(), + Token1Balance: token1Balance.ToString(), + FeeUnclaimed0: unclaimedFee0.ToString(), + FeeUnclaimed1: unclaimedFee1.ToString(), } } -func unclaimedFee(tokenId uint64) (bigint, bigint) { +func unclaimedFee(tokenId uint64) (*u256.Uint, *u256.Uint) { // ref: https://blog.uniswap.org/uniswap-v3-math-primer-2#calculating-uncollected-fees liquidity := positions[tokenId].liquidity @@ -133,11 +136,11 @@ func unclaimedFee(tokenId uint64) (bigint, bigint) { feeGrowthInside0LastX128 := positions[tokenId].feeGrowthInside0LastX128 feeGrowthInside1LastX128 := positions[tokenId].feeGrowthInside1LastX128 - var tickLowerFeeGrowthBelow0, tickLowerFeeGrowthBelow1, tickUpperFeeGrowthAbove0, tickUpperFeeGrowthAbove1 bigint + var tickLowerFeeGrowthBelow0, tickLowerFeeGrowthBelow1, tickUpperFeeGrowthAbove0, tickUpperFeeGrowthAbove1 *u256.Uint if currentTick >= tickUpper { - tickUpperFeeGrowthAbove0 = feeGrowthGlobal0X128 - tickUpperFeeGrowthOutside0X128 - tickUpperFeeGrowthAbove1 = feeGrowthGlobal1X128 - tickUpperFeeGrowthOutside1X128 + tickUpperFeeGrowthAbove0 = new(u256.Uint).Sub(feeGrowthGlobal0X128, tickUpperFeeGrowthOutside0X128) + tickUpperFeeGrowthAbove1 = new(u256.Uint).Sub(feeGrowthGlobal1X128, tickUpperFeeGrowthOutside1X128) } else { tickUpperFeeGrowthAbove0 = tickUpperFeeGrowthOutside0X128 tickUpperFeeGrowthAbove1 = tickUpperFeeGrowthOutside1X128 @@ -147,15 +150,23 @@ func unclaimedFee(tokenId uint64) (bigint, bigint) { tickLowerFeeGrowthBelow0 = tickLowerFeeGrowthOutside0X128 tickLowerFeeGrowthBelow1 = tickLowerFeeGrowthOutside1X128 } else { - tickLowerFeeGrowthBelow0 = feeGrowthGlobal0X128 - tickLowerFeeGrowthOutside0X128 - tickLowerFeeGrowthBelow1 = feeGrowthGlobal1X128 - tickLowerFeeGrowthOutside1X128 + tickLowerFeeGrowthBelow0 = new(u256.Uint).Sub(feeGrowthGlobal0X128, tickLowerFeeGrowthOutside0X128) + tickLowerFeeGrowthBelow1 = new(u256.Uint).Sub(feeGrowthGlobal1X128, tickLowerFeeGrowthOutside1X128) } - feeGrowthInside0X128 := (feeGrowthGlobal0X128 - tickLowerFeeGrowthBelow0 - tickUpperFeeGrowthAbove0) - feeGrowthInside1X128 := (feeGrowthGlobal1X128 - tickLowerFeeGrowthBelow1 - tickUpperFeeGrowthAbove1) + feeGrowthInside0X128 := new(u256.Uint).Sub(feeGrowthGlobal0X128, tickLowerFeeGrowthBelow0) + feeGrowthInside0X128 = new(u256.Uint).Sub(feeGrowthInside0X128, tickUpperFeeGrowthAbove0) + + feeGrowthInside1X128 := new(u256.Uint).Sub(feeGrowthGlobal1X128, tickLowerFeeGrowthBelow1) + feeGrowthInside1X128 = new(u256.Uint).Sub(feeGrowthInside1X128, tickUpperFeeGrowthAbove1) + + value01 := new(u256.Uint).Sub(feeGrowthInside0X128, feeGrowthInside0LastX128) + value02 := new(u256.Uint).Mul(liquidity, value01) + unclaimedFee0 := new(u256.Uint).Div(value02, u256.UnsafeFromDecimal(consts.Q128)) - unclaimedFee0 := (liquidity * (feeGrowthInside0X128 - feeGrowthInside0LastX128)) / consts.Q128 - unclaimedFee1 := (liquidity * (feeGrowthInside1X128 - feeGrowthInside1LastX128)) / consts.Q128 + value11 := new(u256.Uint).Sub(feeGrowthInside1X128, feeGrowthInside1LastX128) + value12 := new(u256.Uint).Mul(liquidity, value11) + unclaimedFee1 := new(u256.Uint).Div(value12, u256.UnsafeFromDecimal(consts.Q128)) return unclaimedFee0, unclaimedFee1 } diff --git a/position/_RPC_dry.gno b/position/_RPC_dry.gno index 9ae0b191..3af363e2 100644 --- a/position/_RPC_dry.gno +++ b/position/_RPC_dry.gno @@ -1,19 +1,34 @@ package position import ( + "gno.land/p/demo/ufmt" + "gno.land/p/demo/common" + + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) func DryMint( tickCurrent int32, tickLower int32, tickUpper int32, - amount0Desired bigint, - amount1Desired bigint, -) (amount0, amount1 bigint) { - sqrtRatioX96 := p.TickMathGetSqrtRatioAtTick(tickCurrent).Bigint() - sqrtLowerX96 := p.TickMathGetSqrtRatioAtTick(tickLower).Bigint() - sqrtUpperX96 := p.TickMathGetSqrtRatioAtTick(tickUpper).Bigint() + _amount0Desired string, + _amount1Desired string, +) (string, string) { + // FROM: position__liquidity_management.gno + sqrtRatioX96 := common.TickMathGetSqrtRatioAtTick(tickCurrent) + sqrtLowerX96 := common.TickMathGetSqrtRatioAtTick(tickLower) + sqrtUpperX96 := common.TickMathGetSqrtRatioAtTick(tickUpper) + + amount0Desired, err := u256.FromDecimal(_amount0Desired) + if err != nil { + ufmt.Sprintf("[POSITION] liquidity_management.gno__DryMint() || u256.FromDecimal(amount0: %s) failed", _amount0Desired) + } + amount1Desired, err := u256.FromDecimal(_amount1Desired) + if err != nil { + ufmt.Sprintf("[POSITION] liquidity_management.gno__DryMint() || u256.FromDecimal(amount1: %s) failed", _amount1Desired) + } liquidity := common.GetLiquidityForAmounts( sqrtRatioX96, @@ -22,33 +37,37 @@ func DryMint( amount0Desired, amount1Desired, ) + i256Liquidity := i256.FromUint256(liquidity) - if liquidity != 0 { + // FROM: pool__position_modify.gno + var amount0, amount1 *i256.Int + if !(liquidity.IsZero()) { // != 0 if tickCurrent < tickLower { amount0 = sqrtPriceMathGetAmount0Delta( sqrtLowerX96, sqrtUpperX96, - liquidity, + i256Liquidity, ) } else if tickCurrent < tickUpper { amount0 = sqrtPriceMathGetAmount0Delta( sqrtRatioX96, sqrtUpperX96, - liquidity, + i256Liquidity, ) amount1 = sqrtPriceMathGetAmount1Delta( sqrtLowerX96, sqrtRatioX96, - liquidity, + i256Liquidity, ) } else { amount1 = sqrtPriceMathGetAmount1Delta( sqrtLowerX96, sqrtUpperX96, - liquidity, + i256Liquidity, ) } } - return amount0, amount1 + + return amount0.ToString(), amount1.ToString() } diff --git a/position/_TEST_0_INIT_TOKEN_REGISTER_test.gno b/position/_TEST_0_INIT_TOKEN_REGISTER_test.gno index 412cd3a0..4c4b0fd4 100644 --- a/position/_TEST_0_INIT_TOKEN_REGISTER_test.gno +++ b/position/_TEST_0_INIT_TOKEN_REGISTER_test.gno @@ -39,6 +39,8 @@ func (FooToken) Approve() func(spender users.AddressOrName, amount uint64) { return foo.Approve } +var _ pl.GRC20Interface = FooToken{} + type BarToken struct{} func (BarToken) Transfer() func(to users.AddressOrName, amount uint64) { @@ -54,6 +56,8 @@ func (BarToken) Approve() func(spender users.AddressOrName, amount uint64) { return bar.Approve } +var _ pl.GRC20Interface = BarToken{} + type BazToken struct{} func (BazToken) Transfer() func(to users.AddressOrName, amount uint64) { @@ -69,6 +73,8 @@ func (BazToken) Approve() func(spender users.AddressOrName, amount uint64) { return baz.Approve } +var _ pl.GRC20Interface = BazToken{} + type QuxToken struct{} func (QuxToken) Transfer() func(to users.AddressOrName, amount uint64) { @@ -84,6 +90,8 @@ func (QuxToken) Approve() func(spender users.AddressOrName, amount uint64) { return qux.Approve } +var _ pl.GRC20Interface = QuxToken{} + type WugnotToken struct{} func (WugnotToken) Transfer() func(to users.AddressOrName, amount uint64) { @@ -99,6 +107,8 @@ func (WugnotToken) Approve() func(spender users.AddressOrName, amount uint64) { return wugnot.Approve } +var _ pl.GRC20Interface = WugnotToken{} + type OBLToken struct{} func (OBLToken) Transfer() func(to users.AddressOrName, amount uint64) { @@ -114,6 +124,8 @@ func (OBLToken) Approve() func(spender users.AddressOrName, amount uint64) { return obl.Approve } +var _ pl.GRC20Interface = OBLToken{} + type GNSToken struct{} func (GNSToken) Transfer() func(to users.AddressOrName, amount uint64) { @@ -132,8 +144,10 @@ func (GNSToken) Approve() func(spender users.AddressOrName, amount uint64) { return gns.Approve } +var _ pl.GRC20Interface = GNSToken{} + func init() { - std.TestSetOrigCaller(consts.GNOSWAP_ADMIN) + std.TestSetPrevAddr(consts.GNOSWAP_ADMIN) pl.RegisterGRC20Interface("gno.land/r/demo/bar", BarToken{}) pl.RegisterGRC20Interface("gno.land/r/demo/foo", FooToken{}) diff --git a/position/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno b/position/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno index e6737eae..892de222 100644 --- a/position/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno +++ b/position/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno @@ -24,11 +24,11 @@ var ( // wugnotPath string = "gno.land/r/demo/wugnot" // from consts // gnsPath string = "gno.land/r/demo/gns" // from consts - fee100 uint16 = 100 - fee500 uint16 = 500 - fee3000 uint16 = 3000 + fee100 uint32 = 100 + fee500 uint32 = 500 + fee3000 uint32 = 3000 - max_timeout bigint = 9999999999 + max_timeout int64 = 9999999999 ) /* HELPER */ diff --git a/position/_TEST_position_api_test.gno b/position/_TEST_position_api_test.gnoa similarity index 63% rename from position/_TEST_position_api_test.gno rename to position/_TEST_position_api_test.gnoa index 7d3b238e..8e067836 100644 --- a/position/_TEST_position_api_test.gno +++ b/position/_TEST_position_api_test.gnoa @@ -15,12 +15,6 @@ import ( pl "gno.land/r/demo/pool" ) -var ( - test_tickLower = int32(9000) - test_tickUpper = int32(11000) - test_liquidityExpect = bigint(1000) -) - // 1. Init & Create Pool func TestPoolInitCreatePool(t *testing.T) { std.TestSetPrevAddr(gsa) @@ -29,22 +23,22 @@ func TestPoolInitCreatePool(t *testing.T) { std.TestSetPrevAddr(test1) gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) - pl.CreatePool(fooPath, barPath, fee500, 130621891405341611593710811006) // tick = 10000 + pl.CreatePool(fooPath, barPath, fee500, "130621891405341611593710811006") // tick = 10000 } // 2. Mint LP and Get GNFT func TestMint(t *testing.T) { std.TestSetPrevAddr(test1) - foo.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) // COLLECT_FEE - bar.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) // COLLECT_FEE + foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) // COLLECT_FEE + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) // COLLECT_FEE // test1 mints => will get tid 1 nft std.TestSetOrigCaller(test1) - Mint(fooPath, barPath, fee500, int32(9000), int32(11000), bigint(1_000_000), bigint(1_000_000), bigint(1), bigint(1), bigint(1234567890)) + Mint(fooPath, barPath, fee500, int32(9000), int32(11000), "1000000", "1000000", "1", "1", max_timeout) // test1 mints => will get tid 2 nft std.TestSetOrigCaller(test1) - Mint(fooPath, barPath, fee500, int32(4000), int32(6000), bigint(1_000_000), bigint(1_000_000), bigint(0), bigint(0), bigint(1234567890)) + Mint(fooPath, barPath, fee500, int32(4000), int32(6000), "1000000", "1000000", "0", "0", max_timeout) } // 3. Swap to make position fee @@ -57,7 +51,7 @@ func TestSwap(t *testing.T) { fee500, test1, true, - bigint(123_456), + "123456", consts.MIN_PRICE, test1, ) @@ -68,8 +62,8 @@ func TestCollectFeeAfterSwap(t *testing.T) { std.TestSetOrigCaller(test1) tokneId, fee0, fee1, fromPath := CollectFee(1) shouldEQ(t, tokneId, uint64(1)) - shouldEQ(t, fee0, bigint(61)) - shouldEQ(t, fee1, bigint(0)) + shouldEQ(t, fee0, "61") + shouldEQ(t, fee1, "0") shouldEQ(t, fromPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } diff --git a/position/_TEST_position_increase_decrease_test.gnoa b/position/_TEST_position_increase_decrease_test.gnoa index f935dfd6..42a84e62 100644 --- a/position/_TEST_position_increase_decrease_test.gnoa +++ b/position/_TEST_position_increase_decrease_test.gnoa @@ -22,13 +22,13 @@ func TestPoolInitCreatePool(t *testing.T) { std.TestSetPrevAddr(test1) gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) - pl.CreatePool(barPath, fooPath, fee500, common.TickMathGetSqrtRatioAtTick(10000)) // x2.71814592682522526700950038502924144268035888671875 + pl.CreatePool(barPath, fooPath, fee500, common.TickMathGetSqrtRatioAtTick(10000).ToString()) // x2.71814592682522526700950038502924144268035888671875 } func TestMintPosition(t *testing.T) { std.TestSetPrevAddr(test1) bar.Approve(a2u(consts.POOL_ADDR), 18394891) - foo.Approve(a2u(consts.POOL_ADDR), 49999999) // r3v4_xxx: liquidity_management.gno #26 + foo.Approve(a2u(consts.POOL_ADDR), 49999999) tokenId, liquidity, amount0, amount1 := Mint( barPath, @@ -36,40 +36,40 @@ func TestMintPosition(t *testing.T) { fee500, 8000, 12000, - bigint(50_000_000), - bigint(50_000_000), - bigint(0), - bigint(0), + "50000000", + "50000000", + "0", + "0", max_timeout, ) shouldEQ(t, tokenId, 1) shouldEQ(t, getNextId(), 2) - shouldEQ(t, amount0, bigint(18394891)) - shouldEQ(t, amount1, bigint(49999999)) // r3v4_xxx: liquidity_management.gno #26 + shouldEQ(t, amount0, "18394891") + shouldEQ(t, amount1, "49999999") } func TestIncreaseLiquidity(t *testing.T) { std.TestSetPrevAddr(test1) bar.Approve(a2u(consts.POOL_ADDR), 3678978) - foo.Approve(a2u(consts.POOL_ADDR), 9999999) // r3v4_xxx: liquidity_management.gno #26 + foo.Approve(a2u(consts.POOL_ADDR), 9999999) pool := getPoolFromLpTokenId(uint64(1)) oldLiquidity := pool.PoolGetLiquidity() _, _, m0, m1 := IncreaseLiquidity( - uint64(1), // tokenId - bigint(10_000_000), // amount0Desired - bigint(10_000_000), // amount1Desired - bigint(0), // amount0Min - bigint(0), // amount1Min - max_timeout, // deadline + uint64(1), // tokenId + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min + max_timeout, // deadline ) - shouldEQ(t, m0, bigint(3678978)) - shouldEQ(t, m1, bigint(9999999)) // r3v4_xxx: liquidity_management.gno #26 + shouldEQ(t, m0, "3678978") + shouldEQ(t, m1, "9999999") newLiquidity := pool.PoolGetLiquidity() - shouldGT(t, oldLiquidity, newLiquidity) + shouldEQ(t, newLiquidity.Gt(oldLiquidity), true) } func TestCollectFeeBeforeSwap(t *testing.T) { @@ -77,8 +77,8 @@ func TestCollectFeeBeforeSwap(t *testing.T) { tokenId, fee0, fee1, poolPath := CollectFee(1) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, fee0, bigint(0)) - shouldEQ(t, fee1, bigint(0)) + shouldEQ(t, fee0, "0") + shouldEQ(t, fee1, "0") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } @@ -94,7 +94,7 @@ func TestSwap(t *testing.T) { fee500, test1, true, - bigint(1_234_567), + "1234567", consts.MIN_PRICE, test1, ) @@ -103,13 +103,13 @@ func TestSwap(t *testing.T) { func TestCollectFeeAfterSwap(t *testing.T) { std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) - foo.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) tokenId, fee0, fee1, poolPath := CollectFee(1) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, fee0, bigint(611)) // this is input token - shouldEQ(t, fee1, bigint(0)) // this it output token + shouldEQ(t, fee0, "611") // this is input token + shouldEQ(t, fee1, "0") // this it output token shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } @@ -119,13 +119,13 @@ func TestCollectFee2(t *testing.T) { tokenId, fee0, fee1, poolPath := CollectFee(1) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, fee0, bigint(0)) // this is input token - shouldEQ(t, fee1, bigint(0)) // this it output token + shouldEQ(t, fee0, "0") // this is input token + shouldEQ(t, fee1, "0") // this it output token shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") - fee0, fee1 = unclaimedFee(uint64(1)) - shouldEQ(t, fee0, bigint(0)) - shouldEQ(t, fee1, bigint(0)) + afterFee0, afterFee1 := unclaimedFee(uint64(1)) + shouldEQ(t, afterFee0.ToString(), "0") + shouldEQ(t, afterFee1.ToString(), "0") } func TestSwap2(t *testing.T) { @@ -137,7 +137,7 @@ func TestSwap2(t *testing.T) { fee500, test1, true, - bigint(1_000_000), + "1000000", consts.MIN_PRICE, test1, ) @@ -146,14 +146,14 @@ func TestSwap2(t *testing.T) { std.TestSetPrevRealm("") std.TestSetOrigCaller(test1) - fee0, fee1 := unclaimedFee(uint64(1)) - shouldEQ(t, fee0, bigint(499)) - shouldEQ(t, fee1, bigint(0)) + oldFee0, oldFee1 := unclaimedFee(uint64(1)) + shouldEQ(t, oldFee0.ToString(), "499") + shouldEQ(t, oldFee1.ToString(), "0") tokenId, fee0, fee1, poolPath := CollectFee(1) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, fee0, bigint(495)) // 499 -> 495 ≈ cause of protocol fee - shouldEQ(t, fee1, bigint(0)) + shouldEQ(t, fee0, "495") // 499 -> 495 ≈ cause of protocol fee + shouldEQ(t, fee1, "0") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } @@ -164,19 +164,19 @@ func TestDecreaseLiquidity(t *testing.T) { oldLiquidity := getPoolFromLpTokenId(uint64(1)).PoolGetLiquidity() tokenId, liquidity, amount0, amount1, targetPoolPath := DecreaseLiquidity( - uint64(1), // tokenId - bigint(10_000_000), // liquidity - bigint(0), // amount0Min - bigint(0), // amount1Min - max_timeout, // deadline + uint64(1), // tokenId + "10000000", // liquidity + "0", // amount0Min + "0", // amount1Min + max_timeout, // deadline ) - newLiquidity := getPoolFromLpTokenId(uint64(1)).PoolGetLiquidity() - shouldLT(t, oldLiquidity, newLiquidity) + // newLiquidity := getPoolFromLpTokenId(uint64(1)).PoolGetLiquidity() + // shouldLT(t, oldLiquidity, newLiquidity) - // check fee left - tokenId, fee0, fee1, poolPath := CollectFee(1) - shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, fee0, bigint(0)) - shouldEQ(t, fee1, bigint(0)) + // // check fee left + // tokenId, fee0, fee1, poolPath := CollectFee(1) + // shouldEQ(t, tokenId, uint64(1)) + // shouldEQ(t, fee0, "0") + // shouldEQ(t, fee1, "0") } diff --git a/position/_TEST_position_test.gnoa b/position/_TEST_position_test.gno similarity index 72% rename from position/_TEST_position_test.gnoa rename to position/_TEST_position_test.gno index 16e73c77..464d7515 100644 --- a/position/_TEST_position_test.gnoa +++ b/position/_TEST_position_test.gno @@ -1,11 +1,10 @@ package position import ( + "encoding/gjson" "std" "testing" - "encoding/gjson" - "gno.land/r/demo/consts" pl "gno.land/r/demo/pool" @@ -13,9 +12,8 @@ import ( "gno.land/r/demo/bar" "gno.land/r/demo/foo" - "gno.land/r/demo/gns" - "gno.land/r/demo/gnft" + "gno.land/r/demo/gns" ) func TestPoolInitCreatePool(t *testing.T) { @@ -25,7 +23,7 @@ func TestPoolInitCreatePool(t *testing.T) { std.TestSetPrevAddr(test1) gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) - pl.CreatePool(barPath, fooPath, fee500, 130621891405341611593710811006) // tick = 10000 + pl.CreatePool(barPath, fooPath, fee500, "130621891405341611593710811006") // tick = 10000 } func TestMintPosition01InRange(t *testing.T) { @@ -39,16 +37,16 @@ func TestMintPosition01InRange(t *testing.T) { fee500, 8000, 12000, - bigint(50000000), - bigint(50000000), - bigint(0), - bigint(0), + "50000000", + "50000000", + "0", + "0", max_timeout, ) shouldEQ(t, tokenId, 1) shouldEQ(t, getNextId(), 2) - shouldEQ(t, amount0, bigint(18394891)) - shouldEQ(t, amount1, bigint(49999999)) + shouldEQ(t, amount0, "18394891") + shouldEQ(t, amount1, "49999999") } func TestMintPosition02LowerRange(t *testing.T) { @@ -62,16 +60,16 @@ func TestMintPosition02LowerRange(t *testing.T) { fee500, 5000, 8000, - bigint(50000000), - bigint(50000000), - bigint(0), - bigint(0), + "50000000", + "50000000", + "0", + "0", max_timeout, ) shouldEQ(t, tokenId, 2) shouldEQ(t, getNextId(), 3) - shouldEQ(t, amount0, bigint(0)) - shouldEQ(t, amount1, bigint(49999999)) + shouldEQ(t, amount0, "0") + shouldEQ(t, amount1, "49999999") } func TestMintPosition03UpperRange(t *testing.T) { @@ -85,23 +83,23 @@ func TestMintPosition03UpperRange(t *testing.T) { fee500, 12000, 14000, - bigint(50000000), - bigint(50000000), - bigint(0), - bigint(0), + "50000000", + "50000000", + "0", + "0", max_timeout, ) shouldEQ(t, tokenId, 3) shouldEQ(t, getNextId(), 4) - shouldEQ(t, amount0, bigint(49999999)) - shouldEQ(t, amount1, bigint(0)) + shouldEQ(t, amount0, "49999999") + shouldEQ(t, amount1, "0") } func TestCollectFeeBeforeSwap(t *testing.T) { tokenId, fee0, fee1, poolPath := CollectFee(1) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, fee0, bigint(0)) - shouldEQ(t, fee1, bigint(0)) + shouldEQ(t, fee0, "0") + shouldEQ(t, fee1, "0") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } @@ -117,35 +115,36 @@ func TestSwap(t *testing.T) { fee500, test1, true, - bigint(1_234_567), + "1234567", consts.MIN_PRICE, test1, ) + shouldEQ(t, amount0, "1234567") + shouldEQ(t, amount1, "-3332779") } func TestCollectFeeAfterSwap(t *testing.T) { std.TestSetPrevAddr(test1) - foo.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) // COLLECT_FEE - bar.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) // COLLECT_FEE + foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) // COLLECT_FEE + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) // COLLECT_FEE tokenId, fee0, fee1, poolPath := CollectFee(1) shouldEQ(t, tokenId, uint64(1)) - shouldNEQ(t, fee0, bigint(0)) // this is input token - shouldEQ(t, fee1, bigint(0)) // this it output token + shouldNEQ(t, fee0, "0") // this is input token + shouldEQ(t, fee1, "0") // this it output token shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") - } func TestDecreaseLiquidityUpperPosition(t *testing.T) { - std.TestSetOrigCaller(test1) + std.TestSetPrevAddr(test1) ownerOfPosition := gnft.OwnerOf(tid(3)) shouldEQ(t, ownerOfPosition, std.GetOrigCaller()) - tokenId, liquidity, amount0, amount1, poolPath := DecreaseLiquidity(uint64(3), consts.MAX_UINT256, 0, 0, max_timeout) + tokenId, liquidity, amount0, amount1, poolPath := DecreaseLiquidity(uint64(3), consts.MAX_UINT256, "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(3)) - shouldEQ(t, amount0, bigint(49999999)) - shouldEQ(t, amount1, bigint(0)) + shouldEQ(t, amount0, "49999999") + shouldEQ(t, amount1, "0") ownerOfPosition = gnft.OwnerOf(tid(3)) shouldEQ(t, ownerOfPosition, std.GetOrigCaller()) diff --git a/position/_TEST_position_test_two_position_used_single_swap_test.gnoa b/position/_TEST_position_test_two_position_used_single_swap_test.gnoa index 2cb345f4..41659dec 100644 --- a/position/_TEST_position_test_two_position_used_single_swap_test.gnoa +++ b/position/_TEST_position_test_two_position_used_single_swap_test.gnoa @@ -13,7 +13,6 @@ import ( "gno.land/r/demo/gns" ) - func TestPoolInitCreatePool(t *testing.T) { std.TestSetOrigCaller(gsa) pl.InitManual() @@ -21,7 +20,7 @@ func TestPoolInitCreatePool(t *testing.T) { std.TestSetPrevAddr(test1) gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) - pl.CreatePool(barPath, fooPath, fee500, 130621891405341611593710811006) // tick = 10000 + pl.CreatePool(barPath, fooPath, fee500, "130621891405341611593710811006") // tick = 10000 } func TestMintPosition01WideInRange(t *testing.T) { @@ -35,17 +34,17 @@ func TestMintPosition01WideInRange(t *testing.T) { fee500, 8000, 12000, - bigint(50000000), - bigint(50000000), - bigint(0), - bigint(0), + "50000000", + "50000000", + "0", + "0", max_timeout, ) shouldEQ(t, tokenId, 1) shouldEQ(t, getNextId(), 2) - shouldEQ(t, liquidity, bigint(318704392)) - shouldEQ(t, amount0, bigint(18394891)) - shouldEQ(t, amount1, bigint(49999999)) + shouldEQ(t, liquidity, "318704392") + shouldEQ(t, amount0, "18394891") + shouldEQ(t, amount1, "49999999") } func TestMintPositionTightInRange(t *testing.T) { @@ -59,32 +58,32 @@ func TestMintPositionTightInRange(t *testing.T) { fee500, 9500, 10500, - bigint(50000000), - bigint(50000000), - bigint(0), - bigint(0), + "50000000", + "50000000", + "0", + "0", max_timeout, ) shouldEQ(t, tokenId, 2) shouldEQ(t, getNextId(), 3) - shouldEQ(t, liquidity, bigint(1228379121)) - shouldEQ(t, amount0, bigint(18394891)) - shouldEQ(t, amount1, bigint(49999999)) + shouldEQ(t, liquidity, "1228379121") + shouldEQ(t, amount0, "18394891") + shouldEQ(t, amount1, "49999999") } func TestCollectFeeBeforeSwapPos1(t *testing.T) { tokenId, fee0, fee1, poolPath := CollectFee(1) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, fee0, bigint(0)) - shouldEQ(t, fee1, bigint(0)) + shouldEQ(t, fee0, "0") + shouldEQ(t, fee1, "0") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } func TestCollectFeeBeforeSwapPos2(t *testing.T) { tokenId, fee0, fee1, poolPath := CollectFee(2) shouldEQ(t, tokenId, uint64(2)) - shouldEQ(t, fee0, bigint(0)) - shouldEQ(t, fee1, bigint(0)) + shouldEQ(t, fee0, "0") + shouldEQ(t, fee1, "0") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } @@ -100,30 +99,30 @@ func TestSwap(t *testing.T) { fee500, test1, true, - bigint(1_234_567), + "1234567", consts.MIN_PRICE, test1, ) } -// IF POSITION 2 DOESN'T EXIST, POSITION 1 WILL EARN '617' as fee +// FYI, IF POSITION 2 DOESN'T EXIST, POSITION 1 WILL EARN '617' as fee func TestCollectFeeAfterSwapPos1(t *testing.T) { std.TestSetPrevAddr(test1) - foo.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) // COLLECT_FEE - bar.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) // COLLECT_FEE + foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) // COLLECT_FEE + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) // COLLECT_FEE tokenId, fee0, fee1, poolPath := CollectFee(1) shouldEQ(t, tokenId, uint64(1)) // shouldEQ(t, fee0, bigint(617)) - shouldEQ(t, fee0, bigint(126)) - shouldEQ(t, fee1, bigint(0)) + shouldEQ(t, fee0, "126") + shouldEQ(t, fee1, "0") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } func TestCollectFeeAfterSwapPos2(t *testing.T) { tokenId, fee0, fee1, poolPath := CollectFee(2) shouldEQ(t, tokenId, uint64(2)) - shouldEQ(t, fee0, bigint(486)) - shouldEQ(t, fee1, bigint(0)) + shouldEQ(t, fee0, "486") + shouldEQ(t, fee1, "0") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } diff --git a/position/liquidity_management.gno b/position/liquidity_management.gno index 98249075..9d7818c5 100644 --- a/position/liquidity_management.gno +++ b/position/liquidity_management.gno @@ -2,13 +2,16 @@ package position import ( "gno.land/p/demo/common" + "gno.land/p/demo/ufmt" "gno.land/r/demo/consts" pl "gno.land/r/demo/pool" + + u256 "gno.land/p/big/uint256" ) -func addLiquidity(params AddLiquidityParams) (bigint, bigint, bigint) { +func addLiquidity(params AddLiquidityParams) (*u256.Uint, *u256.Uint, *u256.Uint) { // uint128, uint256, uint256 pool := pl.GetPoolFromPoolPath(params.poolKey) sqrtPriceX96 := pool.PoolGetSlot0SqrtPriceX96() @@ -22,21 +25,35 @@ func addLiquidity(params AddLiquidityParams) (bigint, bigint, bigint) { params.amount0Desired, params.amount1Desired, ) - // r3v4_xxx: adjust for rounding errors - // liquidity += 2 pToken0, pToken1, pFee := poolKeyDivide(params.poolKey) - amount0, amount1 := pl.Mint( - pToken0, - pToken1, - pFee, - consts.POSITION_ADDR, - params.tickLower, - params.tickUpper, - liquidity, + amount0, amount1 := pl.Mint( // string(uint256), string(uint256) + pToken0, // token0Path string + pToken1, // token1Path string + pFee, // fee uint16 + consts.POSITION_ADDR, // recipient std.Address + params.tickLower, // tickLower int32 + params.tickUpper, // tickUpper int32 + liquidity.ToString(), // _liquidityAmount string(uint128) ) - - require(amount0 >= params.amount0Min && amount1 >= params.amount1Min, "[POSITION] liquidity_management.gno__addLiquidity() || LM_Price Slippage Check") - - return liquidity, amount0, amount1 + println("amount0:", amount0) + println("amount1:", amount1) + panic("FIX 0 2") + + amount0Uint, err := u256.FromDecimal(amount0) + if err != nil { + ufmt.Sprintf("[POSITION] liquidity_management.gno__addLiquidity() || u256.FromDecimal(amount0: %s) failed (err: %s)", amount0, err.Error()) + } + amount1Uint, err := u256.FromDecimal(amount1) + if err != nil { + ufmt.Sprintf("[POSITION] liquidity_management.gno__addLiquidity() || u256.FromDecimal(amount1: %s) failed (err: %s)", amount1, err.Error()) + } + + amount0Cond := amount0Uint.Gte(params.amount0Min) + amount1Cond := amount1Uint.Gte(params.amount1Min) + if !(amount0Cond && amount1Cond) { + panic("[POSITION] liquidity_management.gno__addLiquidity() || LM_Price Slippage Check") + } + + return liquidity, amount0Uint, amount1Uint } diff --git a/position/position.gno b/position/position.gno index ada81e45..7f877d71 100644 --- a/position/position.gno +++ b/position/position.gno @@ -4,12 +4,13 @@ import ( "std" "gno.land/p/demo/ufmt" + "gno.land/r/demo/gnft" + + u256 "gno.land/p/big/uint256" "gno.land/r/demo/consts" pl "gno.land/r/demo/pool" - - "gno.land/r/demo/gnft" ) var ( @@ -20,22 +21,39 @@ var ( func Mint( token0 string, token1 string, - fee uint16, + fee uint32, tickLower int32, tickUpper int32, - amount0Desired bigint, - amount1Desired bigint, - amount0Min bigint, - amount1Min bigint, - deadline bigint, -) (uint64, bigint, bigint, bigint) { // tokenId, liquidity, amount0, amount1 + _amount0Desired string, // *u256.Uint + _amount1Desired string, // *u256.Uint + _amount0Min string, // *u256.Uint + _amount1Min string, // *u256.Uint + deadline int64, +) (uint64, string, string, string) { // tokenId, liquidity, amount0, amount1 ( *u256.Uint x3 ) if token1 < token0 { token0, token1 = token1, token0 - amount0Desired, amount1Desired = amount1Desired, amount0Desired - amount0Min, amount1Min = amount1Min, amount0Min + _amount0Desired, _amount1Desired = _amount1Desired, _amount0Desired + _amount0Min, _amount1Min = _amount1Min, _amount0Min tickLower, tickUpper = -tickUpper, -tickLower } + amount0Desired, err := u256.FromDecimal(_amount0Desired) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__Mint() || u256.FromDecimal(_amount0Desired: %s) failed", _amount0Desired)) + } + amount1Desired, err := u256.FromDecimal(_amount1Desired) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__Mint() || u256.FromDecimal(_amount1Desired: %s) failed", _amount1Desired)) + } + amount0Min, err := u256.FromDecimal(_amount0Min) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__Mint() || u256.FromDecimal(_amount0Min: %s) failed", _amount0Min)) + } + amount1Min, err := u256.FromDecimal(_amount1Min) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__Mint() || u256.FromDecimal(_amount1Min: %s) failed", _amount1Min)) + } + mintParams := MintParams{ token0: token0, token1: token1, @@ -52,7 +70,7 @@ func Mint( return mint(mintParams) } -func mint(params MintParams) (uint64, bigint, bigint, bigint) { +func mint(params MintParams) (uint64, string, string, string) { checkDeadline(params.deadline) pool := pl.GetPool(params.token0, params.token1, params.fee) @@ -67,6 +85,9 @@ func mint(params MintParams) (uint64, bigint, bigint, bigint) { amount1Min: params.amount1Min, }, ) + println("amount0", amount0.ToString()) + println("amount1", amount1.ToString()) + panic("FIX 0") tokenId := nextId nextId++ // nextId = nextId + 1 @@ -77,30 +98,48 @@ func mint(params MintParams) (uint64, bigint, bigint, bigint) { feeGrowthInside0LastX128, feeGrowthInside1LastX128 := pool.PoolGetPositionFeeGrowthInside0LastX128(positionKey), pool.PoolGetPositionFeeGrowthInside1LastX128(positionKey) position := Position{ - nonce: 0, + nonce: u256.Zero(), operator: std.PrevRealm().Addr(), poolKey: pl.GetPoolPath(params.token0, params.token1, params.fee), tickLower: params.tickLower, tickUpper: params.tickUpper, liquidity: liquidity, - feeGrowthInside0LastX128: feeGrowthInside0LastX128.Bigint(), - feeGrowthInside1LastX128: feeGrowthInside1LastX128.Bigint(), - tokensOwed0: 0, - tokensOwed1: 0, + feeGrowthInside0LastX128: feeGrowthInside0LastX128, + feeGrowthInside1LastX128: feeGrowthInside1LastX128, + tokensOwed0: u256.Zero(), + tokensOwed1: u256.Zero(), } positions[tokenId] = position - return tokenId, liquidity, amount0, amount1 + return tokenId, liquidity.ToString(), amount0.ToString(), amount1.ToString() } func IncreaseLiquidity( tokenId uint64, - amount0Desired bigint, - amount1Desired bigint, - amount0Min bigint, - amount1Min bigint, - deadline bigint, -) (uint64, bigint, bigint, bigint) { // tokenId, liquidity, amount0, amount1 + _amount0Desired string, // uint256 + _amount1Desired string, // uint256 + _amount0Min string, // uint256 + _amount1Min string, // uint256 + deadline int64, +) (uint64, string, string, string) { // tokenId, liquidity, amount0, amount1 + + amount0Desired, err := u256.FromDecimal(_amount0Desired) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__IncreaseLiquidity() || u256.FromDecimal(_amount0Desired: %s) failed", _amount0Desired)) + } + amount1Desired, err := u256.FromDecimal(_amount1Desired) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__IncreaseLiquidity() || u256.FromDecimal(_amount1Desired: %s) failed", _amount1Desired)) + } + amount0Min, err := u256.FromDecimal(_amount0Min) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__IncreaseLiquidity() || u256.FromDecimal(_amount0Min: %s) failed", _amount0Min)) + } + amount1Min, err := u256.FromDecimal(_amount1Min) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__IncreaseLiquidity() || u256.FromDecimal(_amount1Min: %s) failed", _amount1Min)) + } + increaseLiquidityParams := IncreaseLiquidityParams{ tokenId: tokenId, amount0Desired: amount0Desired, @@ -113,7 +152,7 @@ func IncreaseLiquidity( return increaseLiquidity(increaseLiquidityParams) } -func increaseLiquidity(params IncreaseLiquidityParams) (uint64, bigint, bigint, bigint) { +func increaseLiquidity(params IncreaseLiquidityParams) (uint64, string, string, string) { // verify tokenId exists require(exists(params.tokenId), ufmt.Sprintf("[POSITION] position.gno__increaseLiquidity() || tokenId(%d) doesn't exist", params.tokenId)) @@ -138,21 +177,32 @@ func increaseLiquidity(params IncreaseLiquidityParams) (uint64, bigint, bigint, ) pool := pl.GetPoolFromPoolPath(position.poolKey) - positionKey := positionKeyCompute(GetOrigPkgAddr(), position.tickLower, position.tickUpper) - feeGrowthInside0LastX128, feeGrowthInside1LastX128 := pool.PoolGetPositionFeeGrowthInside0LastX128(positionKey), pool.PoolGetPositionFeeGrowthInside1LastX128(positionKey) - position.tokensOwed0 += (feeGrowthInside0LastX128 - position.feeGrowthInside0LastX128) * position.liquidity / consts.Q128 - position.tokensOwed1 += (feeGrowthInside1LastX128 - position.feeGrowthInside1LastX128) * position.liquidity / consts.Q128 + { + // position.tokensOwed0 += (feeGrowthInside0LastX128 - position.feeGrowthInside0LastX128) * position.liquidity / consts.Q128 + value1 := new(u256.Uint).Sub(feeGrowthInside0LastX128.Clone(), position.feeGrowthInside0LastX128.Clone()) + value2 := new(u256.Uint).Mul(value1, position.liquidity) + value3 := new(u256.Uint).Div(value2, u256.UnsafeFromDecimal(consts.Q128)) + position.tokensOwed0 = new(u256.Uint).Add(position.tokensOwed0, value3) + } + + { + // position.tokensOwed1 += (feeGrowthInside1LastX128 - position.feeGrowthInside1LastX128) * position.liquidity / consts.Q128 + value1 := new(u256.Uint).Sub(feeGrowthInside1LastX128.Clone(), position.feeGrowthInside1LastX128.Clone()) + value2 := new(u256.Uint).Mul(value1, position.liquidity) + value3 := new(u256.Uint).Div(value2, u256.UnsafeFromDecimal(consts.Q128)) + position.tokensOwed1 = new(u256.Uint).Add(position.tokensOwed1, value3) + } position.feeGrowthInside0LastX128 = feeGrowthInside0LastX128 position.feeGrowthInside1LastX128 = feeGrowthInside1LastX128 - position.liquidity += liquidity + position.liquidity = new(u256.Uint).Add(position.liquidity, liquidity) positions[params.tokenId] = position - return params.tokenId, liquidity, amount0, amount1 + return params.tokenId, liquidity.ToString(), amount0.ToString(), amount1.ToString() } // *IMPORTANT* @@ -160,11 +210,24 @@ func increaseLiquidity(params IncreaseLiquidityParams) (uint64, bigint, bigint, // HOWEVER, internally it also execute CollectFee() to collect fee which DOES NOT INCLUDE IN RETURN VALUE func DecreaseLiquidity( tokenId uint64, - liquidity bigint, - amount0Min bigint, - amount1Min bigint, - deadline bigint, -) (uint64, bigint, bigint, bigint, string) { // tokenId, liquidity, amount0, amount1, poolPath + _liquidity string, // uint128 + _amount0Min string, // uint256 + _amount1Min string, // uint256 + deadline int64, +) (uint64, string, string, string, string) { // tokenId, liquidity, amount0, amount1, poolPath + liquidity, err := u256.FromDecimal(_liquidity) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__DecreaseLiquidity() || u256.FromDecimal(_liquidity: %s) failed", _liquidity)) + } + amount0Min, err := u256.FromDecimal(_amount0Min) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__DecreaseLiquidity() || u256.FromDecimal(_amount0Min: %s) failed", _amount0Min)) + } + amount1Min, err := u256.FromDecimal(_amount1Min) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__DecreaseLiquidity() || u256.FromDecimal(_amount1Min: %s) failed", _amount1Min)) + } + decreaseLiquidityParams := DecreaseLiquidityParams{ tokenId: tokenId, liquidity: liquidity, @@ -176,7 +239,7 @@ func DecreaseLiquidity( return decreaseLiquidity(decreaseLiquidityParams) } -func decreaseLiquidity(params DecreaseLiquidityParams) (uint64, bigint, bigint, bigint, string) { +func decreaseLiquidity(params DecreaseLiquidityParams) (uint64, string, string, string, string) { // verify tokenId require(exists(params.tokenId), ufmt.Sprintf("[POSITION] position.gno__decreaseLiquidity() || tokenId(%d) doesn't exist", params.tokenId)) @@ -186,7 +249,7 @@ func decreaseLiquidity(params DecreaseLiquidityParams) (uint64, bigint, bigint, checkDeadline(params.deadline) - require(params.liquidity >= 0, ufmt.Sprintf("[POSITION] position.gno__decreaseLiquidity() || liquidity(%d) >= 0", params.liquidity)) + require(params.liquidity.Gte(u256.Zero()), ufmt.Sprintf("[POSITION] position.gno__decreaseLiquidity() || liquidity(%d) >= 0", params.liquidity)) // BEFORE DECREASE LIQUIDITY, COLLECT FEE FIRST CollectFee(params.tokenId) @@ -194,7 +257,7 @@ func decreaseLiquidity(params DecreaseLiquidityParams) (uint64, bigint, bigint, position := positions[params.tokenId] positionLiquidity := position.liquidity - if positionLiquidity < params.liquidity { + if positionLiquidity.Lt(params.liquidity) { // if too many liquidity requested, decrease to entire liquidity params.liquidity = positionLiquidity } @@ -202,31 +265,82 @@ func decreaseLiquidity(params DecreaseLiquidityParams) (uint64, bigint, bigint, pToken0, pToken1, pFee := poolKeyDivide(position.poolKey) pool := pl.GetPoolFromPoolPath(position.poolKey) - burnedAmount0, burnedAmount1 := pl.Burn(pToken0, pToken1, pFee, position.tickLower, position.tickUpper, params.liquidity) - require(burnedAmount0 >= params.amount0Min && burnedAmount1 >= params.amount1Min, ufmt.Sprintf("[POSITION] position.gno__decreaseLiquidity() || burnedAmount0(%d) >= amount0Min(%d) && burnedAmount1(%d) >= amount1Min(%d)", burnedAmount0, params.amount0Min, burnedAmount1, params.amount1Min)) + // BURN HERE + _burnedAmount0, _burnedAmount1 := pl.Burn(pToken0, pToken1, pFee, position.tickLower, position.tickUpper, params.liquidity.Clone().ToString()) + + burnedAmount0, err := u256.FromDecimal(_burnedAmount0) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__decreaseLiquidity() || u256.FromDecimal(_burnedAmount0: %s) failed", _burnedAmount0)) + } + burnedAmount1, err := u256.FromDecimal(_burnedAmount1) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__decreaseLiquidity() || u256.FromDecimal(_burnedAmount1: %s) failed", _burnedAmount1)) + } + + require(burnedAmount0.Gte(params.amount0Min) && burnedAmount1.Gte(params.amount1Min), ufmt.Sprintf("[POSITION] position.gno__decreaseLiquidity() || burnedAmount0(%s) >= amount0Min(%s) && burnedAmount1(%s) >= amount1Min(%s)", burnedAmount0.ToString(), params.amount0Min.ToString(), burnedAmount1.ToString(), params.amount1Min.ToString())) positionKey := positionKeyCompute(GetOrigPkgAddr(), position.tickLower, position.tickUpper) feeGrowthInside0LastX128, feeGrowthInside1LastX128 := pool.PoolGetPositionFeeGrowthInside0LastX128(positionKey), pool.PoolGetPositionFeeGrowthInside1LastX128(positionKey) - tokensOwed0 += (feeGrowthInside0LastX128.Bigint() - position.feeGrowthInside0LastX128) * position.liquidity / Q128 - tokensOwed1 += (feeGrowthInside1LastX128.Bigint() - position.feeGrowthInside1LastX128) * position.liquidity / Q128 + { + value1 := new(u256.Uint).Sub(feeGrowthInside0LastX128, position.feeGrowthInside0LastX128) + value2 := new(u256.Uint).Mul(value1, position.liquidity) + value3 := new(u256.Uint).Div(value2, u256.UnsafeFromDecimal(consts.Q128)) + value4 := new(u256.Uint).Add(burnedAmount0, value3) - position.feeGrowthInside0LastX128 = feeGrowthInside0LastX128.Bigint() - position.feeGrowthInside1LastX128 = feeGrowthInside1LastX128.Bigint() + position.tokensOwed0 = new(u256.Uint).Add(position.tokensOwed0, value4) + } - amount0, amount1 := p.Collect( + { + value1 := new(u256.Uint).Sub(feeGrowthInside1LastX128, position.feeGrowthInside1LastX128) + value2 := new(u256.Uint).Mul(value1, position.liquidity) + value3 := new(u256.Uint).Div(value2, u256.UnsafeFromDecimal(consts.Q128)) + value4 := new(u256.Uint).Add(burnedAmount1, value3) + + position.tokensOwed1 = new(u256.Uint).Add(position.tokensOwed1, value4) + } + + // positions[params.tokenId].feeGrowthInside0LastX128 = feeGrowthInside0LastX128 // r3v4_xxx: panic: unexpected zero object id + // r3v4_xxx: weird hacky patch + if feeGrowthInside0LastX128.IsZero() { + position.feeGrowthInside0LastX128 = u256.Zero() + } else { + _cloneFromDecimal := u256.UnsafeFromDecimal(feeGrowthInside0LastX128.ToString()) + position.feeGrowthInside0LastX128 = _cloneFromDecimal + } + + if feeGrowthInside1LastX128.IsZero() { + position.feeGrowthInside1LastX128 = u256.Zero() + } else { + _cloneFromDecimal := u256.UnsafeFromDecimal(feeGrowthInside1LastX128.ToString()) + position.feeGrowthInside1LastX128 = _cloneFromDecimal + } + + position.liquidity = new(u256.Uint).Sub(positionLiquidity, params.liquidity) + positions[params.tokenId] = position + + // GIVE BACK TO USER + _amount0, _amount1 := pl.Collect( pToken0, pToken1, pFee, std.GetOrigCaller(), position.tickLower, position.tickUpper, - burnedAmount0, - burnedAmount1, + _burnedAmount0, + _burnedAmount1, ) + amount0, err := u256.FromDecimal(_amount0) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__decreaseLiquidity() || u256.FromDecimal(_amount0: %s) failed", _amount0)) + } + amount1, err := u256.FromDecimal(_amount1) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__decreaseLiquidity() || u256.FromDecimal(_amount1: %s) failed", _amount1)) + } - position.tokensOwed0 -= amount0 - position.tokensOwed1 -= amount1 + position.tokensOwed0 = new(u256.Uint).Sub(position.tokensOwed0, amount0) + position.tokensOwed1 = new(u256.Uint).Sub(position.tokensOwed1, amount1) positions[params.tokenId] = position @@ -235,10 +349,10 @@ func decreaseLiquidity(params DecreaseLiquidityParams) (uint64, bigint, bigint, burnPosition(params.tokenId) // just update flag } - return params.tokenId, params.liquidity, amount0, amount1, position.poolKey + return params.tokenId, params.liquidity.ToString(), _amount0, _amount1, position.poolKey } -func CollectFee(tokenId uint64) (uint64, bigint, bigint, string) { // tokenId, tokensOwed0, tokensOwed1, poolPath +func CollectFee(tokenId uint64) (uint64, string, string, string) { // tokenId, tokensOwed0, tokensOwed1, poolPath // verify tokenId exists require(exists(tokenId), ufmt.Sprintf("[POSITION] position.gno__CollectFee() || tokenId(%d) doesn't exist", tokenId)) @@ -254,35 +368,54 @@ func CollectFee(tokenId uint64) (uint64, bigint, bigint, string) { // tokenId, t fee, position.tickLower, position.tickUpper, - 0, // burn '0' liquidity to collect fee + "0", // burn '0' liquidity to collect fee ) tokensOwed0, tokensOwed1 := position.tokensOwed0, position.tokensOwed1 + positionKey := positionKeyCompute(GetOrigPkgAddr(), position.tickLower, position.tickUpper) pool := pl.GetPoolFromPoolPath(position.poolKey) feeGrowthInside0LastX128, feeGrowthInside1LastX128 := pool.PoolGetPositionFeeGrowthInside0LastX128(positionKey), pool.PoolGetPositionFeeGrowthInside1LastX128(positionKey) - position.tokensOwed0 += burnAmount0 + ((feeGrowthInside0LastX128.Bigint() - position.feeGrowthInside0LastX128) * position.liquidity / Q128) - position.tokensOwed1 += burnAmount1 + ((feeGrowthInside1LastX128.Bigint() - position.feeGrowthInside1LastX128) * position.liquidity / Q128) + { + value1 := new(u256.Uint).Sub(feeGrowthInside0LastX128, position.feeGrowthInside0LastX128) + value2 := new(u256.Uint).Mul(value1, position.liquidity) + value3 := new(u256.Uint).Div(value2, u256.UnsafeFromDecimal(consts.Q128)) + tokensOwed0 = new(u256.Uint).Add(tokensOwed0, value3) + } - position.feeGrowthInside0LastX128 = feeGrowthInside0LastX128.Bigint() - position.feeGrowthInside1LastX128 = feeGrowthInside1LastX128.Bigint() + { + value1 := new(u256.Uint).Sub(feeGrowthInside1LastX128, position.feeGrowthInside1LastX128) + value2 := new(u256.Uint).Mul(value1, position.liquidity) + value3 := new(u256.Uint).Div(value2, u256.UnsafeFromDecimal(consts.Q128)) + tokensOwed1 = new(u256.Uint).Add(tokensOwed1, value3) + } - position.liquidity = 0 - positions[tokenId] = position + position.feeGrowthInside0LastX128 = feeGrowthInside0LastX128 + position.feeGrowthInside1LastX128 = feeGrowthInside1LastX128 - collectAmount0, collectAmount1 := p.Collect( - pToken0, - pToken1, - pFee, - GetOrigCaller(), + amount0, amount1 := pl.Collect( + token0, + token1, + fee, + std.GetOrigCaller(), position.tickLower, position.tickUpper, - consts.MAX_UINT64, // r3v4_xxx: current grc20 handles amount by `uint64` - consts.MAX_UINT64, // r3v4_xxx: current grc20 handles amount by `uint64` + consts.MAX_UINT64, // string, r3v4_xxx: current grc20 handles amount by `uint64` + consts.MAX_UINT64, // string, r3v4_xxx: current grc20 handles amount by `uint64` ) - position.tokensOwed0, position.tokensOwed1 = tokensOwed0-amount0, tokensOwed1-amount1 + amount0Uint, err := u256.FromDecimal(amount0) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__CollectFee() || u256.FromDecimal(amount0: %s) failed (err: %s)", amount0, err.Error())) + } + amount1Uint, err := u256.FromDecimal(amount1) + if err != nil { + panic(ufmt.Sprintf("[POSITION] position.gno__CollectFee() || u256.FromDecimal(amount1: %s) failed (err: %s)", amount1, err.Error())) + } + + position.tokensOwed0 = new(u256.Uint).Sub(tokensOwed0, amount0Uint) + position.tokensOwed1 = new(u256.Uint).Sub(tokensOwed1, amount1Uint) positions[tokenId] = position // handle withdrawal fee @@ -330,5 +463,5 @@ func deleteFromPositions(m map[uint64]Position, key uint64) map[uint64]Position } func (p Position) isClear() bool { - return p.liquidity == 0 && p.tokensOwed0 == 0 && p.tokensOwed1 == 0 + return p.liquidity.IsZero() && p.tokensOwed0.IsZero() && p.tokensOwed1.IsZero() } diff --git a/position/sqrt_price_math.gno b/position/sqrt_price_math.gno index e24ceb19..1e63f055 100644 --- a/position/sqrt_price_math.gno +++ b/position/sqrt_price_math.gno @@ -1,191 +1,172 @@ package position import ( - "gno.land/p/demo/ufmt" "gno.land/r/demo/consts" + + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( - sqrtPX96 bigint, - liquidity bigint, - amount bigint, + sqrtPX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint128 + amount *u256.Uint, // uint256 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 { +) *u256.Uint { // uint160 + if amount.IsZero() { 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 + numerator1 := new(u256.Uint).Lsh(liquidity, 96) + product := new(u256.Uint).Mul(amount, sqrtPX96) 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 - } + denominator := new(u256.Uint).Add(numerator1, product) + + if denominator.IsZero() { + panic("position_sqrt price math #1") } - 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) + res := new(u256.Uint).Mul(numerator1, sqrtPX96) + res = res.Div(res, denominator) + return res } - 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)) + denominator := new(u256.Uint).Sub(numerator1, product) + + if !(denominator.Gt(u256.Zero())) { + panic("position_sqrt price math #2") + } - requireUnsigned(numerator1*sqrtPX96/denominator, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp() || numerator1 * sqrtPX96 / denominator(%s) >= 0", numerator1*sqrtPX96/denominator)) - return numerator1 * sqrtPX96 / denominator + _tmp := new(u256.Uint).Div(numerator1, sqrtPX96) + _tmp = _tmp.Add(_tmp, amount) + return new(u256.Uint).Div(numerator1, _tmp) } func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown( - sqrtPX96 bigint, - liquidity bigint, - amount bigint, + sqrtPX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint1288 + amount *u256.Uint, // uint256 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)) +) *u256.Uint { // uint160 + quotient := u256.Zero() + if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { + quotient = quotient.Lsh(amount, 96) + quotient = quotient.Div(quotient, liquidity) + } else { + _tmp := new(u256.Uint).Div(u256.UnsafeFromDecimal(consts.Q96), liquidity) + quotient = new(u256.Uint).Mul(amount, _tmp) + } - var quotient bigint + // quotient mutst be positive when amount and liquidity are positive if add { - if amount <= consts.MAX_UINT160 { - quotient = (amount << 96) / liquidity - } else { - quotient = amount * consts.Q96 / liquidity - } - requireUnsigned(quotient, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown() || quotient(%s) >= 0", quotient)) - return sqrtPX96 + quotient - } else { - if amount <= consts.MAX_UINT160 { - quotient = (amount << 96) / liquidity - } else { - quotient = amount * consts.Q96 / liquidity + result := new(u256.Uint).Add(sqrtPX96, quotient) + + if !(result.Gte(sqrtPX96)) { + panic("position_sqrt price math #3") } - 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 + return result } + + result := new(u256.Uint).Sub(sqrtPX96, quotient) + if !(result.Gte(u256.Zero())) { + panic("position_sqrt price math #4") + } + + return result } 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)) - + sqrtPX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint128 + amountIn *u256.Uint, // uint256 + zeroForOne bool, // bool +) *u256.Uint { // uint160 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) + amount0Result := sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true) + return amount0Result } - requireUnsigned(sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true), "[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromInput() || condition must return `v` >= 0__#2") - return sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true) + amount1Result := sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true) + return amount1Result } 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)) - + sqrtPX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint128 + amountOut *u256.Uint, // uint256 + zeroForOne bool, // bool +) *u256.Uint { // uint160 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) + amount1Result := sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) + return amount1Result } - requireUnsigned(sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false), "[POSITION] sqrt_price_math.gno__sqrtPriceMathGetNextSqrtPriceFromOutput() || condition must return `v` >= 0__#2") - return sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false) + amount0Result := sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false) + return amount0Result } func sqrtPriceMathGetAmount0DeltaHelper( - sqrtRatioAX96 bigint, - sqrtRatioBX96 bigint, - liquidity bigint, -) bigint { - if sqrtRatioAX96 > sqrtRatioBX96 { + sqrtRatioAX96 *u256.Uint, // uint160 + sqrtRatioBX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint160 +) *u256.Uint { // uint256 + if sqrtRatioAX96.Gt(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)) + numerator1 := new(u256.Uint).Lsh(liquidity, 96) + numerator2 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - numerator2 := sqrtRatioBX96 - sqrtRatioAX96 - requireUnsigned(numerator2, ufmt.Sprintf("[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount0DeltaHelper() || numerator2(%s) >= 0", numerator2)) + res := new(u256.Uint).Mul(numerator1, numerator2) + res = res.Div(res, sqrtRatioBX96) + res = res.Div(res, sqrtRatioAX96) - requireUnsigned((numerator1*numerator2/sqrtRatioBX96)/sqrtRatioAX96, "[POSITION] sqrt_price_math.gno__sqrtPriceMathGetAmount0DeltaHelper() || condition must return `v` >= 0") - return (numerator1 * numerator2 / sqrtRatioBX96) / sqrtRatioAX96 + return res } 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 *u256.Uint, // uint160 + sqrtRatioBX96 *u256.Uint, // uint160 + liquidity *u256.Uint, // uint160 +) *u256.Uint { // uint256 + if sqrtRatioAX96.Gt(sqrtRatioBX96) { sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96 } - return liquidity * (sqrtRatioBX96 - sqrtRatioAX96) / consts.Q96 + _tmp := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) + res := new(u256.Uint).Mul(liquidity, _tmp) + res = res.Div(res, u256.UnsafeFromDecimal(consts.Q96)) + + return res } 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) + sqrtRatioAX96 *u256.Uint, // uint160 + sqrtRatioBX96 *u256.Uint, // uint160 + liquidity *i256.Int, // int128 +) *i256.Int { // int256 + if liquidity.IsNeg() { + u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + i := i256.FromUint256(u) + return i256.Zero().Neg(i) } - - return sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity) + u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + return i256.FromUint256(u) } 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) + sqrtRatioAX96 *u256.Uint, // uint160 + sqrtRatioBX96 *u256.Uint, // uint160 + liquidity *i256.Int, // int128 +) *i256.Int { // int256 + if liquidity.IsNeg() { + u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + i := i256.FromUint256(u) + return i256.Zero().Neg(i) } - return sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity) -} - -func requireUnsigned(x bigint, msg string) { - if x < 0 { - panic(msg) - } + u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + return i256.FromUint256(u) } diff --git a/position/test_helper.gno b/position/test_helper.gno index ff623327..e1e0606a 100644 --- a/position/test_helper.gno +++ b/position/test_helper.gno @@ -16,8 +16,6 @@ func tid(tokenId interface{}) grc721.TokenID { } switch tokenId.(type) { - case bigint: - return grc721.TokenID(string(tokenId.(bigint))) case string: return grc721.TokenID(tokenId.(string)) case int: diff --git a/position/type.gno b/position/type.gno index d3bd4330..eccd7612 100644 --- a/position/type.gno +++ b/position/type.gno @@ -2,10 +2,12 @@ package position import ( "std" + + u256 "gno.land/p/big/uint256" ) type Position struct { - nonce bigint + nonce *u256.Uint // uint96 operator std.Address @@ -14,13 +16,13 @@ type Position struct { tickLower int32 tickUpper int32 - liquidity bigint + liquidity *u256.Uint // uint128 - feeGrowthInside0LastX128 bigint - feeGrowthInside1LastX128 bigint + feeGrowthInside0LastX128 *u256.Uint // uint256 + feeGrowthInside1LastX128 *u256.Uint // uint256 - tokensOwed0 bigint - tokensOwed1 bigint + tokensOwed0 *u256.Uint // uint128 + tokensOwed1 *u256.Uint // uint128 burned bool } @@ -28,46 +30,46 @@ type Position struct { type MintParams struct { token0 string token1 string - fee uint16 + fee uint32 tickLower int32 tickUpper int32 - amount0Desired bigint - amount1Desired bigint - amount0Min bigint - amount1Min bigint - deadline bigint + amount0Desired *u256.Uint // uint256 + amount1Desired *u256.Uint // uint256 + amount0Min *u256.Uint // uint256 + amount1Min *u256.Uint // uint256 + deadline int64 } type AddLiquidityParams struct { poolKey string tickLower int32 tickUpper int32 - amount0Desired bigint - amount1Desired bigint - amount0Min bigint - amount1Min bigint + amount0Desired *u256.Uint // uint256 + amount1Desired *u256.Uint // uint256 + amount0Min *u256.Uint // uint256 + amount1Min *u256.Uint // uint256 } type IncreaseLiquidityParams struct { tokenId uint64 - amount0Desired bigint - amount1Desired bigint - amount0Min bigint - amount1Min bigint - deadline bigint + amount0Desired *u256.Uint // uint256 + amount1Desired *u256.Uint // uint256 + amount0Min *u256.Uint // uint256 + amount1Min *u256.Uint // uint256 + deadline int64 } type DecreaseLiquidityParams struct { tokenId uint64 - liquidity bigint - amount0Min bigint - amount1Min bigint - deadline bigint + liquidity *u256.Uint // uint128 + amount0Min *u256.Uint // uint256 + amount1Min *u256.Uint // uint256 + deadline int64 } type CollectParams struct { tokenId uint64 recipient std.Address - amount0Max bigint - amount1Max bigint + amount0Max *u256.Uint // uint128 + amount1Max *u256.Uint // uint128 } diff --git a/position/util.gno b/position/utils.gno similarity index 51% rename from position/util.gno rename to position/utils.gno index 575ea2fc..d9493179 100644 --- a/position/util.gno +++ b/position/utils.gno @@ -17,23 +17,22 @@ func require(condition bool, message string) { } } -func checkDeadline(deadline bigint) { - require(bigint(time.Now().Unix()) <= deadline, ufmt.Sprintf("[POSITION] util.gno__checkDeadline() || transaction too old__time.Now().Unix()(%d) <= deadline(%d)", time.Now().Unix(), deadline)) +func checkDeadline(deadline int64) { + require(time.Now().Unix() <= deadline, ufmt.Sprintf("[POSITION] utils.gno__checkDeadline() || transaction too old__time.Now().Unix()(%d) <= deadline(%d)", time.Now().Unix(), deadline)) } func a2u(addr std.Address) users.AddressOrName { return users.AddressOrName(addr) } -func poolKeyDivide(poolKey string) (string, string, uint16) { +func poolKeyDivide(poolKey string) (string, string, uint32) { res := strings.Split(poolKey, ":") if len(res) != 3 { panic(ufmt.Sprintf("[POSITION] util.gno__poolKeyDivide() || invalid poolKey(%s)", poolKey)) } - pToken0, pToken1, stringFee := res[0], res[1], res[2] + pToken0, pToken1, pFeeStr := res[0], res[1], res[2] - pFee, err := strconv.Atoi(stringFee) - - return pToken0, pToken1, uint16(pFee) + pFee, _ := strconv.Atoi(pFeeStr) + return pToken0, pToken1, uint32(pFee) } diff --git a/router/_RPC_api.gno b/router/_RPC_api.gno index ddac16f8..b50d2276 100644 --- a/router/_RPC_api.gno +++ b/router/_RPC_api.gno @@ -3,8 +3,6 @@ package router import ( "encoding/json" "std" - "strconv" - "strings" "time" "gno.land/p/demo/common" @@ -12,11 +10,13 @@ import ( "gno.land/r/demo/consts" pl "gno.land/r/demo/pool" + + u256 "gno.land/p/big/uint256" ) type TokenRatio struct { Token string `json:"token"` - Ratio bigint `json:"ratio"` + Ratio string `json:"ratio"` } type ResponseQueryBase struct { @@ -50,9 +50,9 @@ func ApiGetRatiosFromBase() string { } func findRatios(maxHops int) []TokenRatio { - var tokenRatio = make(map[string]bigint, 0) + var tokenRatio = make(map[string]*u256.Uint, 0) // WGNOT - tokenRatio[consts.WRAPPED_WUGNOT] = consts.Q96 // ~= 1 + tokenRatio[consts.WRAPPED_WUGNOT] = u256.UnsafeFromDecimal(consts.Q96) // ~= 1 tokens := getTokenList() @@ -67,24 +67,25 @@ func findRatios(maxHops int) []TokenRatio { if len(routes) == 0 { // NO ROUTES FOUND => SET RATIO TO 0 - tokenRatio[token] = 0 + tokenRatio[token] = u256.Zero() } else { - numRoutes := len(routes) + numRoutes := uint64(len(routes)) - var _tokenRatioX96 bigint + var _tokenRatioX96 *u256.Uint for _, route := range routes { - numHops := len(route.route) + numHops := uint64(len(route.route)) switch numHops { case 1, 2, 3: - priceRatio := calculateTokenRatio(token, route.route, 0, 1) - _tokenRatioX96 += priceRatio + priceRatio := calculateTokenRatio(token, route.route, 0, u256.One()) + // _tokenRatioX96 += priceRatio + _tokenRatioX96 = new(u256.Uint).Add(_tokenRatioX96, priceRatio) default: - _tokenRatioX96 = 0 + _tokenRatioX96 = u256.Zero() } } - avgPriceX96 := _tokenRatioX96 / bigint(numRoutes) + avgPriceX96 := new(u256.Uint).Div(_tokenRatioX96, u256.NewUint(numRoutes)) tokenRatio[token] = avgPriceX96 } @@ -95,14 +96,14 @@ func findRatios(maxHops int) []TokenRatio { for token, ratio := range tokenRatio { tokenRatios = append(tokenRatios, TokenRatio{ Token: token, - Ratio: ratio, + Ratio: ratio.ToString(), }) } return tokenRatios } -func calculateTokenRatio(currentToken string, routes []PoolWithMeta, proceed int, priceX96 bigint) bigint { +func calculateTokenRatio(currentToken string, routes []PoolWithMeta, proceed int, priceX96 *u256.Uint) *u256.Uint { poolPath := routes[len(routes)-proceed-1].poolPath pool := pl.GetPoolFromPoolPath(poolPath) @@ -124,7 +125,7 @@ func calculateTokenRatio(currentToken string, routes []PoolWithMeta, proceed int } else { // wrong condition // panic("[ROUTER] _RPC_api.gno__calculateTokenRatio() || wrong condition") - return 0 + return u256.Zero() } @@ -133,9 +134,9 @@ func calculateTokenRatio(currentToken string, routes []PoolWithMeta, proceed int if proceed == len(routes) { // numHops for { // remove as much X96 as possible tempPriceX96 := priceX96 - priceX96 /= consts.Q96 + priceX96 = new(u256.Uint).Div(priceX96, u256.UnsafeFromDecimal(consts.Q96)) - if priceX96 < consts.MIN_PRICE { + if priceX96.Lt(u256.UnsafeFromDecimal(consts.MIN_PRICE)) { return tempPriceX96 } } @@ -163,15 +164,3 @@ func getTokenList() []string { return uniqueTokenList } - -func poolPathWithFeeDivide(poolPath string) (string, string, int) { - poolPathSplit := strings.Split(poolPath, ":") - require(len(poolPathSplit) == 3, ufmt.Sprintf("[ROUTER] _RPC_api.gno__poolPathWithFeeDivide() || len(poolPathSplit) != 3, poolPath: %s", poolPath)) - - feeInt, err := strconv.Atoi(poolPathSplit[2]) - if err != nil { - panic(ufmt.Sprintf("[ROUTER] _RPC_api.gno__poolPathWithFeeDivide() || cannot convert fee(%s) to int", poolPathSplit[2])) - } - - return poolPathSplit[0], poolPathSplit[1], feeInt -} diff --git a/router/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno b/router/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno index ea302b7c..937b4832 100644 --- a/router/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno +++ b/router/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno @@ -20,11 +20,11 @@ var ( // wugnotPath string = "gno.land/r/demo/wugnot" // from consts // gnsPath string = "gno.land/r/demo/gns" // from consts - fee100 uint16 = 100 - fee500 uint16 = 500 - fee3000 uint16 = 3000 + fee100 uint32 = 100 + fee500 uint32 = 500 + fee3000 uint32 = 3000 - max_timeout bigint = 9999999999 + max_timeout int64 = 9999999999 ) /* HELPER */ diff --git a/router/_TEST_router_swap_route_1route_1hop_out_range_test.gnoa b/router/_TEST_router_swap_route_1route_1hop_out_range_test.gnoa index fc20ced7..4d2313e8 100644 --- a/router/_TEST_router_swap_route_1route_1hop_out_range_test.gnoa +++ b/router/_TEST_router_swap_route_1route_1hop_out_range_test.gnoa @@ -24,7 +24,7 @@ func TestInitManual(t *testing.T) { func TestCreatePool(t *testing.T) { std.TestSetPrevAddr(test1) gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) - pl.CreatePool(barPath, bazPath, fee500, 130621891405341611593710811006) // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 + pl.CreatePool(barPath, bazPath, fee500, "130621891405341611593710811006") // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 jsonOutput := pl.ApiGetPools() jsonStr := gjson.Parse(jsonOutput) @@ -34,30 +34,30 @@ func TestCreatePool(t *testing.T) { func TestPositionMint(t *testing.T) { // bar_baz_500 by test1 std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) - baz.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + baz.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) // Mint - tokenId, liquidity, amount0, amount1 := pn.Mint(barPath, bazPath, fee500, int32(12000), int32(15000), bigint(100_000), bigint(100_000), 0, 0, max_timeout) + tokenId, liquidity, amount0, amount1 := pn.Mint(barPath, bazPath, fee500, int32(12000), int32(15000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(1)) - // shouldEQ(t, liquidity, bigint(1308151)) - shouldEQ(t, amount0, bigint(99999)) // ONLY BAR - shouldEQ(t, amount1, bigint(0)) // NO BAZ + // shouldEQ(t, liquidity, "1308151") + shouldEQ(t, amount0, "99999") // ONLY BAR + shouldEQ(t, amount1, "0") // NO BAZ } func TestDrySwapRouteBarBazExactIn(t *testing.T) { std.TestSetOrigCaller(test1) dryResult := DrySwapRoute( - barPath, // inputToken - bazPath, // outputToken - bigint(1000), // amountSpecified - "EXACT_IN", // swapType + barPath, // inputToken + bazPath, // outputToken + "1000", // amountSpecified + "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:500", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, bigint(-1)) + shouldEQ(t, dryResult, "-1") } func TestSwapRouteBarBazExactIn(t *testing.T) { @@ -67,13 +67,13 @@ func TestSwapRouteBarBazExactIn(t *testing.T) { t, func() { SwapRoute( - barPath, // inputToken - bazPath, // outputToken - bigint(1000), // amountSpecified - "EXACT_IN", // swapType + barPath, // inputToken + bazPath, // outputToken + "1000", // amountSpecified + "EXACT_IN", // swapType "gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr - "100", // quoteArr - 2710, // tokenAmountLimit ( too few recieved (expected 2710, got 300)) + "100", // quoteArr + "2710", // tokenAmountLimit ( too few recieved (expected 2710, got 300)) ) }) } diff --git a/router/_TEST_router_swap_route_1route_1hop_test.gno b/router/_TEST_router_swap_route_1route_1hop_test.gno new file mode 100644 index 00000000..70d174f9 --- /dev/null +++ b/router/_TEST_router_swap_route_1route_1hop_test.gno @@ -0,0 +1,178 @@ +package router + +import ( + "encoding/gjson" + "std" + "testing" + + "gno.land/r/demo/consts" + + pl "gno.land/r/demo/pool" + pn "gno.land/r/demo/position" + + "gno.land/r/demo/bar" + "gno.land/r/demo/baz" + + "gno.land/r/demo/gns" +) + +func TestInitManual(t *testing.T) { + std.TestSetPrevAddr(gsa) + pl.InitManual() +} + +func TestCreatePool(t *testing.T) { + std.TestSetPrevAddr(test1) + gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) + pl.CreatePool(barPath, bazPath, fee500, "130621891405341611593710811006") // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 + + jsonOutput := pl.ApiGetPools() + jsonStr := gjson.Parse(jsonOutput) + shouldEQ(t, len(jsonStr.Get("response").Array()), 1) +} + +func TestPositionMint(t *testing.T) { + // bar_baz_500 by test1 + std.TestSetPrevAddr(test1) + bar.Approve(a2u(consts.POOL_ADDR), 36789) + baz.Approve(a2u(consts.POOL_ADDR), 99999) + + // Mint + tokenId, liquidity, amount0, amount1 := pn.Mint(barPath, bazPath, fee500, int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) + shouldEQ(t, tokenId, uint64(1)) + shouldEQ(t, amount0, "36789") + shouldEQ(t, amount1, "99999") +} + +func TestDrySwapRouteBarBazExactIn(t *testing.T) { + std.TestSetPrevAddr(test1) + + dryResult := DrySwapRoute( + barPath, // inputToken + bazPath, // outputToken + "1000", // amountSpecified + "EXACT_IN", // swapType + "gno.land/r/demo/bar:gno.land/r/demo/baz:500", // strRouteArr + "100", // quoteArr + ) + + shouldEQ(t, dryResult, "2711") +} + +func TestSwapRouteBarBazExactIn(t *testing.T) { + std.TestSetPrevAddr(test1) + + bar.Approve(a2u(consts.POOL_ADDR), uint64(1000)) + baz.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) // ITS FOR 0.15% fee + + swapResult := SwapRoute( + barPath, // inputToken + bazPath, // outputToken + "1000", // amountSpecified + "EXACT_IN", // swapType + "gno.land/r/demo/bar:gno.land/r/demo/baz:500", // strRouteArr + "100", // quoteArr + "2700", // tokenAmountLimit + ) + shouldEQ(t, swapResult, "2707") +} + +func TestDrySwapRouteBarBazExactOut(t *testing.T) { + std.TestSetPrevAddr(test1) + + dryResult := DrySwapRoute( + barPath, // inputToken + bazPath, // outputToken + "1000", // amountSpecified + "EXACT_OUT", // swapType + "gno.land/r/demo/bar:gno.land/r/demo/baz:500", // strRouteArr + "100", // quoteArr + ) + + shouldEQ(t, dryResult, "369") +} + +func TestSwapRouteBarBazExactOut(t *testing.T) { + std.TestSetPrevAddr(test1) + + bar.Approve(a2u(consts.POOL_ADDR), uint64(1000)) + baz.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) // ITS FOR 0.15% fee + + swapResult := SwapRoute( + barPath, // inputToken + bazPath, // outputToken + "1000", // amountSpecified + "EXACT_OUT", // swapType + "gno.land/r/demo/bar:gno.land/r/demo/baz:500", // strRouteArr + "100", // quoteArr + "370", // tokenAmountLimit + ) + + shouldEQ(t, swapResult, "369") +} + +func TestDrySwapRouteBazBarExactIn(t *testing.T) { + std.TestSetPrevAddr(test1) + + dryResult := DrySwapRoute( + bazPath, // inputToken + barPath, // outputToken + "1000", // amountSpecified + "EXACT_IN", // swapType + "gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr + "100", // quoteArr + ) + + shouldEQ(t, dryResult, "368") +} + +func TestSwapRouteBazBarExactIn(t *testing.T) { + std.TestSetPrevAddr(test1) + + baz.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + bar.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) // ITS FOR 0.15% fee + + swapResult := SwapRoute( + bazPath, // inputToken + barPath, // outputToken + "1000", // amountSpecified + "EXACT_IN", // swapType + "gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr + "100", // quoteArr + "360", // tokenAmountLimit + ) + + shouldEQ(t, swapResult, "368") +} + +func TestDrySwapRouteBazBarExactOut(t *testing.T) { + std.TestSetPrevAddr(test1) + + dryResult := DrySwapRoute( + bazPath, // inputToken + barPath, // outputToken + "3000", // amountSpecified + "EXACT_IN", // swapType + "gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr + "100", // quoteArr + ) + + shouldEQ(t, dryResult, "1104") +} + +func TestSwapRouteBazBarExactOut(t *testing.T) { + std.TestSetPrevAddr(test1) + bar.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) + + swapResult := SwapRoute( + bazPath, // inputToken + barPath, // outputToken + "3000", // amountSpecified + "EXACT_IN", // swapType + "gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr + "100", // quoteArr + "1100", // tokenAmountLimit + ) + + shouldEQ(t, swapResult, "1103") +} diff --git a/router/_TEST_router_swap_route_1route_1hop_test.gnoa b/router/_TEST_router_swap_route_1route_1hop_test.gnoa deleted file mode 100644 index b2c25784..00000000 --- a/router/_TEST_router_swap_route_1route_1hop_test.gnoa +++ /dev/null @@ -1,172 +0,0 @@ -package router - -import ( - "encoding/gjson" - "std" - "testing" - - "gno.land/r/demo/consts" - - pl "gno.land/r/demo/pool" - pn "gno.land/r/demo/position" - - "gno.land/r/demo/bar" - "gno.land/r/demo/baz" - - "gno.land/r/demo/gns" -) - -func TestInitManual(t *testing.T) { - std.TestSetPrevAddr(gsa) - pl.InitManual() -} - -func TestCreatePool(t *testing.T) { - std.TestSetPrevAddr(test1) - gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) - pl.CreatePool(barPath, bazPath, fee500, 130621891405341611593710811006) // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 - - jsonOutput := pl.ApiGetPools() - jsonStr := gjson.Parse(jsonOutput) - shouldEQ(t, len(jsonStr.Get("response").Array()), 1) -} - -func TestPositionMint(t *testing.T) { - // bar_baz_500 by test1 - std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), 36789) - baz.Approve(a2u(consts.POOL_ADDR), 99999) - - // Mint - tokenId, liquidity, amount0, amount1 := pn.Mint(barPath, bazPath, fee500, int32(9000), int32(11000), bigint(100_000), bigint(100_000), 0, 0, max_timeout) - shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, amount0, bigint(36789)) - shouldEQ(t, amount1, bigint(99999)) -} - -func TestDrySwapRouteBarBazExactIn(t *testing.T) { - std.TestSetPrevAddr(test1) - - dryResult := DrySwapRoute( - barPath, // inputToken - bazPath, // outputToken - bigint(1000), // amountSpecified - "EXACT_IN", // swapType - "gno.land/r/demo/bar:gno.land/r/demo/baz:500", // strRouteArr - "100", // quoteArr - ) - - shouldEQ(t, dryResult, bigint(2711)) -} - -func TestSwapRouteBarBazExactIn(t *testing.T) { - std.TestSetPrevAddr(test1) - - bar.Approve(a2u(consts.POOL_ADDR), uint64(1000)) - baz.Approve(a2u(consts.ROUTER_ADDR), uint64(consts.MAX_UINT64)) // ITS FOR 0.15% fee - - swapResult := SwapRoute( - barPath, // inputToken - bazPath, // outputToken - bigint(1000), // amountSpecified - "EXACT_IN", // swapType - "gno.land/r/demo/bar:gno.land/r/demo/baz:500", // strRouteArr - "100", // quoteArr - 2700, // tokenAmountLimit - ) - shouldEQ(t, swapResult, bigint(2707)) -} - -// func TestDrySwapRouteBarBazExactOut(t *testing.T) { -// std.TestSetPrevAddr(test1) - -// dryResult := DrySwapRoute( -// barPath, // inputToken -// bazPath, // outputToken -// bigint(1000), // amountSpecified -// "EXACT_OUT", // swapType -// "gno.land/r/demo/bar:gno.land/r/demo/baz:500", // strRouteArr -// "100", // quoteArr -// ) - -// shouldEQ(t, dryResult, bigint(369)) -// } - -// func TestSwapRouteBarBazExactOut(t *testing.T) { -// std.TestSetPrevAddr(test1) - -// swapResult := SwapRoute( -// barPath, // inputToken -// bazPath, // outputToken -// bigint(1000), // amountSpecified -// "EXACT_OUT", // swapType -// "gno.land/r/demo/bar:gno.land/r/demo/baz:500", // strRouteArr -// "100", // quoteArr -// 370, // tokenAmountLimit -// ) - -// shouldEQ(t, swapResult, bigint(369)) -// } - -// func TestDrySwapRouteBazBarExactIn(t *testing.T) { -// std.TestSetOrigCaller(test1) - -// dryResult := DrySwapRoute( -// bazPath, // inputToken -// barPath, // outputToken -// bigint(1000), // amountSpecified -// "EXACT_IN", // swapType -// "gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr -// "100", // quoteArr -// ) - -// shouldEQ(t, dryResult, bigint(368)) -// } - -// func TestSwapRouteBazBarExactIn(t *testing.T) { -// std.TestSetOrigCaller(test1) - -// swapResult := SwapRoute( -// bazPath, // inputToken -// barPath, // outputToken -// bigint(1000), // amountSpecified -// "EXACT_IN", // swapType -// "gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr -// "100", // quoteArr -// 360, // tokenAmountLimit -// ) - -// shouldEQ(t, swapResult, bigint(368)) -// } - -// func TestDrySwapRouteBazBarExactOut(t *testing.T) { -// std.TestSetOrigCaller(test1) - -// dryResult := DrySwapRoute( -// bazPath, // inputToken -// barPath, // outputToken -// bigint(3000), // amountSpecified -// "EXACT_IN", // swapType -// "gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr -// "100", // quoteArr -// ) - -// shouldEQ(t, dryResult, bigint(1103)) -// } - -// func TestSwapRouteBazBarExactOut(t *testing.T) { -// std.TestSetPrevAddr(test1) -// bar.Approve(a2u(consts.ROUTER_ADDR), uint64(consts.MAX_UINT64)) - -// swapResult := SwapRoute( -// bazPath, // inputToken -// barPath, // outputToken -// bigint(3000), // amountSpecified -// "EXACT_IN", // swapType -// "gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr -// "100", // quoteArr -// 1100, // tokenAmountLimit -// ) - -// shouldEQ(t, swapResult, bigint(1103)) -// } diff --git a/router/_TEST_router_swap_route_1route_2hop_native_in_out_test.gnoa b/router/_TEST_router_swap_route_1route_2hop_native_in_out_test.gnoa index 62375868..4e8daaec 100644 --- a/router/_TEST_router_swap_route_1route_2hop_native_in_out_test.gnoa +++ b/router/_TEST_router_swap_route_1route_2hop_native_in_out_test.gnoa @@ -26,9 +26,9 @@ func TestCreatePool(t *testing.T) { std.TestSetPrevAddr(test1) gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*3) - pl.CreatePool(barPath, bazPath, fee500, 130621891405341611593710811006) // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 - pl.CreatePool(bazPath, quxPath, fee500, 130621891405341611593710811006) // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 - pl.CreatePool(quxPath, consts.WRAPPED_WUGNOT, fee500, 130621891405341611593710811006) // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 + pl.CreatePool(barPath, bazPath, fee500, "130621891405341611593710811006") // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 + pl.CreatePool(bazPath, quxPath, fee500, "130621891405341611593710811006") // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 + pl.CreatePool(quxPath, consts.WRAPPED_WUGNOT, fee500, "130621891405341611593710811006") // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 // 1 bar ≈ 19.683 gnot jsonOutput := pl.ApiGetPools() @@ -41,10 +41,10 @@ func TestPositionMintBarBaz(t *testing.T) { bar.Approve(a2u(consts.POOL_ADDR), 36789) baz.Approve(a2u(consts.POOL_ADDR), 99999) - tokenId, liquidity, amount0, amount1 := pn.Mint(barPath, bazPath, fee500, int32(9000), int32(11000), bigint(100_000), bigint(100_000), 0, 0, max_timeout) + tokenId, liquidity, amount0, amount1 := pn.Mint(barPath, bazPath, fee500, int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, amount0, bigint(36789)) // bar - shouldEQ(t, amount1, bigint(99999)) // baz + shouldEQ(t, amount0, "36789") // bar + shouldEQ(t, amount1, "99999") // baz } func TestPositionMintBazQux(t *testing.T) { @@ -52,10 +52,10 @@ func TestPositionMintBazQux(t *testing.T) { baz.Approve(a2u(consts.POOL_ADDR), 36789) qux.Approve(a2u(consts.POOL_ADDR), 99999) - tokenId, liquidity, amount0, amount1 := pn.Mint(bazPath, quxPath, fee500, int32(9000), int32(11000), bigint(100_000), bigint(100_000), 0, 0, max_timeout) + tokenId, liquidity, amount0, amount1 := pn.Mint(bazPath, quxPath, fee500, int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(2)) - shouldEQ(t, amount0, bigint(36789)) - shouldEQ(t, amount1, bigint(99999)) + shouldEQ(t, amount0, "36789") + shouldEQ(t, amount1, "99999") } @@ -75,10 +75,10 @@ func TestPositionMintQuxGnot(t *testing.T) { qux.Approve(a2u(consts.POOL_ADDR), 36789) wugnot.Approve(a2u(consts.POOL_ADDR), 99999) - tokenId, liquidity, amount0, amount1 := pn.Mint(quxPath, consts.WRAPPED_WUGNOT, fee500, int32(9000), int32(11000), bigint(100_000), bigint(100_000), 0, 0, max_timeout) + tokenId, liquidity, amount0, amount1 := pn.Mint(quxPath, consts.WRAPPED_WUGNOT, fee500, int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(3)) - shouldEQ(t, amount0, bigint(36789)) - shouldEQ(t, amount1, bigint(99999)) + shouldEQ(t, amount0, "36789") + shouldEQ(t, amount1, "99999") } func TestDrySwapRouteBarGnotExactIn(t *testing.T) { @@ -87,12 +87,12 @@ func TestDrySwapRouteBarGnotExactIn(t *testing.T) { dryResult := DrySwapRoute( barPath, // inputToken consts.WRAPPED_WUGNOT, // outputToken - bigint(1000), // amountSpecified + "1000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/qux:500*POOL*gno.land/r/demo/qux:gno.land/r/demo/wugnot:500", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, bigint(19740)) + shouldEQ(t, dryResult, "19740") } func TestDrySwapRouteBarGnotExactOut(t *testing.T) { @@ -101,12 +101,12 @@ func TestDrySwapRouteBarGnotExactOut(t *testing.T) { dryResult := DrySwapRoute( barPath, // inputToken consts.WRAPPED_WUGNOT, // outputToken - bigint(20000), // amountSpecified + "20000", // amountSpecified "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/qux:500*POOL*gno.land/r/demo/qux:gno.land/r/demo/wugnot:500", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, bigint(1011)) + shouldEQ(t, dryResult, "1011") } func TestDrySwapRouteGnotBarExactIn(t *testing.T) { @@ -115,12 +115,12 @@ func TestDrySwapRouteGnotBarExactIn(t *testing.T) { dryResult := DrySwapRoute( consts.WRAPPED_WUGNOT, // intputToken barPath, // outputToken - bigint(5000), // amountSpecified + "5000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/wugnot:gno.land/r/demo/qux:500*POOL*gno.land/r/demo/qux:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, bigint(247)) + shouldEQ(t, dryResult, "247") } func TestDrySwapRouteGnotBarExactOut(t *testing.T) { @@ -129,10 +129,10 @@ func TestDrySwapRouteGnotBarExactOut(t *testing.T) { dryResult := DrySwapRoute( consts.WRAPPED_WUGNOT, // intputToken barPath, // outputToken - bigint(100), // amountSpecified + "100", // amountSpecified "EXACT_OUT", // swapType "gno.land/r/demo/wugnot:gno.land/r/demo/qux:500*POOL*gno.land/r/demo/qux:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, bigint(1986)) + shouldEQ(t, dryResult, "1986") } diff --git a/router/_TEST_router_swap_route_1route_3hop_native_middle_test.gnoa b/router/_TEST_router_swap_route_1route_3hop_native_middle_test.gnoa index cee5bc07..230d105f 100644 --- a/router/_TEST_router_swap_route_1route_3hop_native_middle_test.gnoa +++ b/router/_TEST_router_swap_route_1route_3hop_native_middle_test.gnoa @@ -24,8 +24,8 @@ func TestCreatePool(t *testing.T) { std.TestSetPrevAddr(test1) gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*2) - pl.CreatePool(consts.GNS_PATH, consts.WRAPPED_WUGNOT, fee100, 130621891405341611593710811006) // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 - pl.CreatePool(consts.WRAPPED_WUGNOT, barPath, fee100, 130621891405341611593710811006) // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 + pl.CreatePool(consts.GNS_PATH, consts.WRAPPED_WUGNOT, fee100, "130621891405341611593710811006") // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 + pl.CreatePool(consts.WRAPPED_WUGNOT, barPath, fee100, "130621891405341611593710811006") // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 // 1 gns ≈ 7.29 bar jsonOutput := pl.ApiGetPools() @@ -49,10 +49,10 @@ func TestPositionMintGnsGnot(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), 36789) wugnot.Approve(a2u(consts.POOL_ADDR), 99999) - tokenId, liquidity, amount0, amount1 := pn.Mint(consts.GNS_PATH, consts.WRAPPED_WUGNOT, fee100, int32(9000), int32(11000), bigint(100_000), bigint(100_000), 0, 0, max_timeout) + tokenId, liquidity, amount0, amount1 := pn.Mint(consts.GNS_PATH, consts.WRAPPED_WUGNOT, fee100, int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, amount0 > 0, true) // 36789 - shouldEQ(t, amount1 > 0, true) // 99999 + shouldEQ(t, amount0, "36789") // 36789 + shouldEQ(t, amount1, "99999") // 99999 } func TestPositionMintGnotBar(t *testing.T) { @@ -68,13 +68,13 @@ func TestPositionMintGnotBar(t *testing.T) { std.TestSetPrevAddr(test1) wugnot.Deposit() - wugnot.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) - bar.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) + wugnot.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) - tokenId, liquidity, amount0, amount1 := pn.Mint(consts.WRAPPED_WUGNOT, barPath, fee100, int32(9000), int32(11000), bigint(100_000), bigint(100_000), 0, 0, max_timeout) + tokenId, liquidity, amount0, amount1 := pn.Mint(consts.WRAPPED_WUGNOT, barPath, fee100, int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(2)) - shouldEQ(t, amount0 > 0, true) // 99999 - shouldEQ(t, amount1 > 0, true) // 36865 + shouldEQ(t, amount0, "99999") // 99999 + shouldEQ(t, amount1, "36789") // 36789 } func TestDrySwapRouteGnsBarExactIn(t *testing.T) { @@ -83,12 +83,12 @@ func TestDrySwapRouteGnsBarExactIn(t *testing.T) { dryResult := DrySwapRoute( consts.GNS_PATH, // inputToken barPath, // outputToken - bigint(1000), // amountSpecified + "1000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/gns:gno.land/r/demo/wugnot:100*POOL*gno.land/r/demo/wugnot:gno.land/r/demo/bar:100", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, bigint(7339)) + shouldEQ(t, dryResult, "7339") } func TestSwapRouteGnsBarExactIn(t *testing.T) { @@ -100,11 +100,11 @@ func TestSwapRouteGnsBarExactIn(t *testing.T) { swapResult := SwapRoute( consts.GNS_PATH, // inputToken barPath, // outputToken - bigint(1000), // amountSpecified + "1000", // amountSpecified "EXACT_IN", // swapType "gno.land/r/demo/gns:gno.land/r/demo/wugnot:100*POOL*gno.land/r/demo/wugnot:gno.land/r/demo/bar:100", // strRouteArr "100", // quoteArr "0", // tokenAmountLimit ) - shouldEQ(t, swapResult, bigint(7328)) + shouldEQ(t, swapResult, "7328") } diff --git a/router/_TEST_router_swap_route_2route_2hop_test.gno b/router/_TEST_router_swap_route_2route_2hop_test.gnoa similarity index 64% rename from router/_TEST_router_swap_route_2route_2hop_test.gno rename to router/_TEST_router_swap_route_2route_2hop_test.gnoa index be56562e..83ba26bb 100644 --- a/router/_TEST_router_swap_route_2route_2hop_test.gno +++ b/router/_TEST_router_swap_route_2route_2hop_test.gnoa @@ -25,8 +25,8 @@ func TestCreatePool(t *testing.T) { std.TestSetPrevAddr(test1) gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*2) - pl.CreatePool(barPath, bazPath, uint16(500), 130621891405341611593710811006) // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 - pl.CreatePool(bazPath, quxPath, uint16(500), 130621891405341611593710811006) // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 + pl.CreatePool(barPath, bazPath, uint16(500), "130621891405341611593710811006") // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 + pl.CreatePool(bazPath, quxPath, uint16(500), "130621891405341611593710811006") // tick = 10_000, ratio = 2.71814592682522526700950038502924144268035888671875 jsonOutput := pl.ApiGetPools() jsonStr := gjson.Parse(jsonOutput) @@ -37,28 +37,28 @@ func TestPositionMint(t *testing.T) { // bar_baz_500 by test1 std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) - baz.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) - qux.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + baz.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + qux.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) // Mint - pn.Mint(barPath, bazPath, uint16(500), int32(9000), int32(11000), bigint(100_000), bigint(100_000), 0, 0, max_timeout) - pn.Mint(bazPath, quxPath, uint16(500), int32(9000), int32(11000), bigint(100_000), bigint(100_000), 0, 0, max_timeout) + pn.Mint(barPath, bazPath, uint16(500), int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) + pn.Mint(bazPath, quxPath, uint16(500), int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) } func TestDrySwapRouteBarQuxExactIn(t *testing.T) { std.TestSetOrigCaller(test1) dryResult := DrySwapRoute( - barPath, // inputToken - quxPath, // outputToken - bigint(1000), // amountSpecified - "EXACT_IN", // swapType + barPath, // inputToken + quxPath, // outputToken + "1000", // amountSpecified + "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/qux:500,gno.land/r/demo/bar:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/qux:500", // strRouteArr "50,50", // quoteArr ) - shouldEQ(t, dryResult, bigint(7346)) + shouldEQ(t, dryResult, "7346") } func TestSwapRouteBarQuxExactIn(t *testing.T) { @@ -68,93 +68,93 @@ func TestSwapRouteBarQuxExactIn(t *testing.T) { qux.Approve(a2u(consts.ROUTER_ADDR), 10000) swapResult := SwapRoute( - barPath, // inputToken - quxPath, // outputToken - bigint(1000), // amountSpecified - "EXACT_IN", // swapType + barPath, // inputToken + quxPath, // outputToken + "1000", // amountSpecified + "EXACT_IN", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/qux:500,gno.land/r/demo/bar:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/qux:500", // strRouteArr "50,50", // quoteArr - 1, // tokenAmountLimit + "1", // tokenAmountLimit ) - shouldEQ(t, swapResult, bigint(7318)) + shouldEQ(t, swapResult, "7318") } func TestDrySwapRouteBarQuxExactOut(t *testing.T) { std.TestSetPrevAddr(test1) dryResult := DrySwapRoute( - barPath, // inputToken - quxPath, // outputToken - bigint(1000), // amountSpecified - "EXACT_OUT", // swapType + barPath, // inputToken + quxPath, // outputToken + "1000", // amountSpecified + "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/qux:500,gno.land/r/demo/bar:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/qux:500", // strRouteArr "50,50", // quoteArr ) - shouldEQ(t, dryResult, bigint(136)) + shouldEQ(t, dryResult, "136") } func TestSwapRouteBarQuxExactOut(t *testing.T) { std.TestSetPrevAddr(test1) swapResult := SwapRoute( - barPath, // inputToken - quxPath, // outputToken - bigint(1000), // amountSpecified - "EXACT_OUT", // swapType + barPath, // inputToken + quxPath, // outputToken + "1000", // amountSpecified + "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/qux:500,gno.land/r/demo/bar:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/qux:500", // strRouteArr "50,50", // quoteArr - 99999, // tokenAmountLimit + "99999", // tokenAmountLimit ) - shouldEQ(t, swapResult, bigint(136)) + shouldEQ(t, swapResult, "136") } func TestDrySwapRouteQuxBarExactIn(t *testing.T) { std.TestSetPrevAddr(test1) dryResult := DrySwapRoute( - quxPath, // inputToken - barPath, // outputToken - bigint(1000), // amountSpecified - "EXACT_IN", // swapType + quxPath, // inputToken + barPath, // outputToken + "1000", // amountSpecified + "EXACT_IN", // swapType "gno.land/r/demo/qux:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:500,gno.land/r/demo/qux:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr "30,70", // quoteArr ) - shouldEQ(t, dryResult, bigint(135)) + shouldEQ(t, dryResult, "135") } func TestSwapRouteQuxBarExactIn(t *testing.T) { std.TestSetPrevAddr(test1) swapResult := SwapRoute( - quxPath, // inputToken - barPath, // outputToken - bigint(1000), // amountSpecified - "EXACT_IN", // swapType + quxPath, // inputToken + barPath, // outputToken + "1000", // amountSpecified + "EXACT_IN", // swapType "gno.land/r/demo/qux:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:500,gno.land/r/demo/qux:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr "30,70", // quoteArr - 1, // tokenAmountLimit + "1", // tokenAmountLimit ) - shouldEQ(t, swapResult, bigint(135)) + shouldEQ(t, swapResult, "135") } func TestDrySwapRouteQuxBarExactOut(t *testing.T) { std.TestSetPrevAddr(test1) dryResult := DrySwapRoute( - quxPath, // inputToken - barPath, // outputToken - bigint(1000), // amountSpecified - "EXACT_OUT", // swapType + quxPath, // inputToken + barPath, // outputToken + "1000", // amountSpecified + "EXACT_OUT", // swapType "gno.land/r/demo/qux:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:500,gno.land/r/demo/qux:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr "30,70", // quoteArr ) - shouldEQ(t, dryResult, bigint(7285)) + shouldEQ(t, dryResult, "7285") } func TestwapRouteQuxBarExactOut(t *testing.T) { @@ -164,14 +164,14 @@ func TestwapRouteQuxBarExactOut(t *testing.T) { bar.Approve(a2u(consts.ROUTER_ADDR), 10000) swapResult := SwapRoute( - quxPath, // inputToken - barPath, // outputToken - bigint(1000), // amountSpecified - "EXACT_OUT", // swapType + quxPath, // inputToken + barPath, // outputToken + "1000", // amountSpecified + "EXACT_OUT", // swapType "gno.land/r/demo/qux:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:500,gno.land/r/demo/qux:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr "30,70", // quoteArr - 99999, // tokenAmountLimit + "99999", // tokenAmountLimit ) - shouldEQ(t, swapResult, bigint(7278)) + shouldEQ(t, swapResult, "7278") } diff --git a/router/_TEST_routes_find_swap_path_test.gnoa b/router/_TEST_routes_find_swap_path_test.gnoa index 97495a71..eb0e6506 100644 --- a/router/_TEST_routes_find_swap_path_test.gnoa +++ b/router/_TEST_routes_find_swap_path_test.gnoa @@ -27,9 +27,9 @@ func TestPoolCreatePool(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*(3+4+3)) // 1 HOPS - pl.CreatePool(barPath, consts.WRAPPED_WUGNOT, fee100, common.TickMathGetSqrtRatioAtTick(10_000)) - pl.CreatePool(barPath, consts.WRAPPED_WUGNOT, fee500, common.TickMathGetSqrtRatioAtTick(20_000)) - pl.CreatePool(barPath, consts.WRAPPED_WUGNOT, fee3000, common.TickMathGetSqrtRatioAtTick(60_000)) // NOT USED BY SMALL LIQ + pl.CreatePool(barPath, consts.WRAPPED_WUGNOT, fee100, common.TickMathGetSqrtRatioAtTick(10_000).ToString()) + pl.CreatePool(barPath, consts.WRAPPED_WUGNOT, fee500, common.TickMathGetSqrtRatioAtTick(20_000).ToString()) + pl.CreatePool(barPath, consts.WRAPPED_WUGNOT, fee3000, common.TickMathGetSqrtRatioAtTick(60_000).ToString()) // NOT USED BY SMALL LIQ // -10_000 0.367897 // -20_000 0.135348 // 0.367897 + 0.135348 = 0.503245 @@ -37,10 +37,10 @@ func TestPoolCreatePool(t *testing.T) { // 1 WGNOT = 0.2516225 BAR // 2 HOPS - pl.CreatePool(consts.WRAPPED_WUGNOT, quxPath, fee100, common.TickMathGetSqrtRatioAtTick(0)) // 1:1 - pl.CreatePool(quxPath, fooPath, fee100, common.TickMathGetSqrtRatioAtTick(50_000)) - pl.CreatePool(quxPath, fooPath, fee500, common.TickMathGetSqrtRatioAtTick(60_000)) - pl.CreatePool(quxPath, fooPath, fee3000, common.TickMathGetSqrtRatioAtTick(100_000)) // NOT USED BY SMALL LIQ + pl.CreatePool(consts.WRAPPED_WUGNOT, quxPath, fee100, common.TickMathGetSqrtRatioAtTick(0).ToString()) // 1:1 + pl.CreatePool(quxPath, fooPath, fee100, common.TickMathGetSqrtRatioAtTick(50_000).ToString()) + pl.CreatePool(quxPath, fooPath, fee500, common.TickMathGetSqrtRatioAtTick(60_000).ToString()) + pl.CreatePool(quxPath, fooPath, fee3000, common.TickMathGetSqrtRatioAtTick(100_000).ToString()) // NOT USED BY SMALL LIQ // 50_000 148.376062 // 60_000 403.307791 // 148.376062 + 403.307791 = 551.683853 @@ -48,9 +48,9 @@ func TestPoolCreatePool(t *testing.T) { // 1 WGNOT = 275.8419265 BAR // 3 HOPS - pl.CreatePool(consts.WRAPPED_WUGNOT, bazPath, fee100, common.TickMathGetSqrtRatioAtTick(6932)) // 1:2 - pl.CreatePool(bazPath, oblPath, fee100, common.TickMathGetSqrtRatioAtTick(6932)) // 1:2 - pl.CreatePool(oblPath, consts.GNS_PATH, fee100, common.TickMathGetSqrtRatioAtTick(6932)) // 1:2 + pl.CreatePool(consts.WRAPPED_WUGNOT, bazPath, fee100, common.TickMathGetSqrtRatioAtTick(6932).ToString()) // 1:2 + pl.CreatePool(bazPath, oblPath, fee100, common.TickMathGetSqrtRatioAtTick(6932).ToString()) // 1:2 + pl.CreatePool(oblPath, consts.GNS_PATH, fee100, common.TickMathGetSqrtRatioAtTick(6932).ToString()) // 1:2 // 1 GNOT = 8 GNS } @@ -67,20 +67,20 @@ func TestPositionMint(t *testing.T) { std.TestSetPrevAddr(test1) wugnot.Deposit() - bar.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) - wugnot.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) - qux.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) - foo.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + wugnot.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + qux.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) - pn.Mint(barPath, consts.WRAPPED_WUGNOT, fee100, 8000, 12000, 100_000_000, 100_000_000, 0, 0, max_timeout) - pn.Mint(barPath, consts.WRAPPED_WUGNOT, fee500, 18000, 22000, 80_000_000, 80_000_000, 0, 0, max_timeout) - pn.Mint(barPath, consts.WRAPPED_WUGNOT, fee3000, 58020, 62040, 10_000_000, 10_000_000, 0, 0, max_timeout) + pn.Mint(barPath, consts.WRAPPED_WUGNOT, fee100, 8000, 12000, "100000000", "100000000", "0", "0", max_timeout) + pn.Mint(barPath, consts.WRAPPED_WUGNOT, fee500, 18000, 22000, "80000000", "80000000", "0", "0", max_timeout) + pn.Mint(barPath, consts.WRAPPED_WUGNOT, fee3000, 58020, 62040, "10000000", "10000000", "0", "0", max_timeout) - pn.Mint(quxPath, fooPath, fee100, 48000, 52000, 100_000_000, 100_000_000, 0, 0, max_timeout) - pn.Mint(quxPath, fooPath, fee500, 58000, 62000, 80_000_000, 80_000_000, 0, 0, max_timeout) - pn.Mint(quxPath, fooPath, fee3000, 98040, 10020, 10_000_000, 10_000_000, 0, 0, max_timeout) + pn.Mint(quxPath, fooPath, fee100, 48000, 52000, "100000000", "100000000", "0", "0", max_timeout) + pn.Mint(quxPath, fooPath, fee500, 58000, 62000, "80000000", "80000000", "0", "0", max_timeout) + pn.Mint(quxPath, fooPath, fee3000, 98040, 10020, "10000000", "10000000", "0", "0", max_timeout) - // pn.Mint(fooPath, consts.GNS_PATH, fee100, 48000, 52000, 100_000_000, 100_000_000, 0, 0, max_timeout) + // pn.Mint(fooPath, consts.GNS_PATH, fee100, 48000, 52000, "100000000", "100000000", "0", "0", max_timeout) } func TestFindRoutes1(t *testing.T) { diff --git a/router/comptue_routes.gno b/router/comptue_routes.gno index abeefa79..41eca047 100644 --- a/router/comptue_routes.gno +++ b/router/comptue_routes.gno @@ -4,6 +4,8 @@ import ( "sort" pl "gno.land/r/demo/pool" + + u256 "gno.land/p/big/uint256" ) type PoolWithMeta struct { @@ -12,13 +14,13 @@ type PoolWithMeta struct { token1Path string fee int tokenPair string - liquidity bigint + liquidity *u256.Uint } type ByLiquidity []PoolWithMeta func (p ByLiquidity) Len() int { return len(p) } func (p ByLiquidity) Swap(i, j int) { p[i], p[j] = p[j], p[i] } -func (p ByLiquidity) Less(i, j int) bool { return p[i].liquidity > p[j].liquidity } +func (p ByLiquidity) Less(i, j int) bool { return p[i].liquidity.Gt(p[j].liquidity) } type BuildRoute struct { route []PoolWithMeta @@ -163,7 +165,6 @@ func (pool PoolWithMeta) hasToken(token string) bool { } func findCandidatePools() []PoolWithMeta { - poolList := pl.PoolGetPoolList() poolWithMetas := []PoolWithMeta{} diff --git a/router/router.gno b/router/router.gno index 7bd7029b..4a22b457 100644 --- a/router/router.gno +++ b/router/router.gno @@ -8,24 +8,38 @@ import ( "gno.land/p/demo/ufmt" "gno.land/r/demo/consts" + + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) func SwapRoute( inputToken string, outputToken string, - amountSpecified bigint, + _amountSpecified string, // int256 swapType SwapType, strRouteArr string, // []string quoteArr string, // []int - tokenAmountLimit bigint, -) bigint { - require(amountSpecified != 0, "[ROUTER] router.gno__SwapRoute() || amountSpecified == 0") + _tokenAmountLimit string, // uint256 +) string { // uint256 + amountSpecified, err := i256.FromDecimal(_amountSpecified) + if err != nil { + panic(ufmt.Sprintf("[ROUTER] router.gno__SwapRoute() || i256.FromDecimal(_amountSpecified(%s) failed", _amountSpecified)) + } + if amountSpecified.IsZero() { + panic("[ROUTER] router.gno__SwapRoute() || amountSpecified == 0") + } + + tokenAmountLimit, err := u256.FromDecimal(_tokenAmountLimit) + if err != nil { + panic(ufmt.Sprintf("[ROUTER] router.gno__SwapRoute() || u256.FromDecimal(_tokenAmountLimit(%s) failed", _tokenAmountLimit)) + } switch swapType { case ExactIn: amountSpecified = amountSpecified case ExactOut: - amountSpecified = -amountSpecified + amountSpecified = i256.Zero().Neg(amountSpecified) default: panic("[ROUTER] router.gno__SwapRoute() || unknown swapType") } @@ -39,14 +53,16 @@ func SwapRoute( require(len(routes) == len(quotes), "[ROUTER] router.gno__SwapRoute() || len(routes) != len(quotes)") // check if quotes are up to 100% - quotesSum := 0 + quotesSum := int64(0) for _, quote := range quotes { intQuote, _ := strconv.Atoi(quote) - quotesSum += intQuote + quotesSum += int64(intQuote) } require(quotesSum == 100, "[ROUTER] router.gno__SwapRoute() || quotesSum != 100") - var resultAmountIn, resultAmountOut bigint + resultAmountIn := u256.Zero() + resultAmountOut := u256.Zero() + for i, route := range routes { numHops := strings.Count(route, "*POOL*") + 1 quote, _ := strconv.Atoi(quotes[i]) @@ -54,16 +70,17 @@ func SwapRoute( // check if route hop is up to 3 require(numHops <= 3, "[ROUTER] router.gno__SwapRoute() || numHops > 3") - toSwap := amountSpecified * bigint(quote) / bigint(100) + toSwap := i256.Zero().Mul(amountSpecified, i256.NewInt(int64(quote))) + toSwap = toSwap.Div(toSwap, i256.NewInt(100)) if numHops == 1 { // SINGLE amountIn, amountOut := handleSingleSwap(route, toSwap, false) - resultAmountIn += amountIn - resultAmountOut += amountOut + resultAmountIn = new(u256.Uint).Add(resultAmountIn, amountIn) + resultAmountOut = new(u256.Uint).Add(resultAmountOut, amountOut) } else if 2 <= numHops && numHops <= 3 { // MULTI amountIn, amountOut := handleMultiSwap(swapType, route, numHops, toSwap, false) - resultAmountIn += amountIn - resultAmountOut += amountOut + resultAmountIn = new(u256.Uint).Add(resultAmountIn, amountIn) + resultAmountOut = new(u256.Uint).Add(resultAmountOut, amountOut) } else { panic("[ROUTER] router.gno__SwapRoute() || numHops should be 1 ~ 3") } @@ -73,15 +90,15 @@ func SwapRoute( resultAmountOut = handleProtocolFee(outputToken, resultAmountOut, false) if swapType == ExactIn { - require(tokenAmountLimit <= resultAmountOut, ufmt.Sprintf("[ROUTER] router.gno__SwapRoute() || too few received (expected minimum output:%d, actual output:%d)", tokenAmountLimit, resultAmountOut)) - return resultAmountOut + require(tokenAmountLimit.Lte(resultAmountOut), ufmt.Sprintf("[ROUTER] router.gno__SwapRoute() || too few received (expected minimum output:%s, actual output:%s)", _tokenAmountLimit, resultAmountOut.ToString())) + return resultAmountOut.ToString() } else { // EXACT_OUT - require(resultAmountIn <= tokenAmountLimit, ufmt.Sprintf("[ROUTER] router.gno__SwapRoute() || too much spend (expected maximum input:%d, actual input:%d)", tokenAmountLimit, resultAmountIn)) - return resultAmountIn + require(resultAmountIn.Lte(tokenAmountLimit), ufmt.Sprintf("[ROUTER] router.gno__SwapRoute() || too much spend (expected maximum input:%s, actual input:%s)", _tokenAmountLimit, resultAmountIn.ToString())) + return resultAmountIn.ToString() } } -func handleSingleSwap(route string, amountSpecified bigint, isDry bool) (amountIn, amountOut bigint) { +func handleSingleSwap(route string, amountSpecified *i256.Int, isDry bool) (*u256.Uint, *u256.Uint) { input, output, fee := getDataForSinglePath(route) singleParams := SingleSwapParams{ tokenIn: input, @@ -96,7 +113,7 @@ func handleSingleSwap(route string, amountSpecified bigint, isDry bool) (amountI return singleSwap(singleParams) } -func handleMultiSwap(swapType SwapType, route string, numHops int, amountSpecified bigint, isDry bool) (amountIn, amountOut bigint) { +func handleMultiSwap(swapType SwapType, route string, numHops int, amountSpecified *i256.Int, isDry bool) (*u256.Uint, *u256.Uint) { switch swapType { case ExactIn: input, output, fee := getDataForMultiPath(route, 0) // first data @@ -133,17 +150,18 @@ func handleMultiSwap(swapType SwapType, route string, numHops int, amountSpecifi } } -func handleProtocolFee(outputToken string, amount bigint, isDry bool) bigint { +func handleProtocolFee(outputToken string, amount *u256.Uint, isDry bool) *u256.Uint { if consts.PROTOCOL_FEE_ROUTER <= 0 { // r3v4_xxx: CHANGABLE BY GOV return amount } - feeAmount := amount * bigint(consts.PROTOCOL_FEE_ROUTER) / 1e4 + feeAmount := new(u256.Uint).Mul(amount, u256.NewUint(consts.PROTOCOL_FEE_ROUTER)) + feeAmount.Div(feeAmount, u256.NewUint(10000)) + if !isDry { - ok := transferFromByRegisterCall(outputToken, std.GetOrigCaller(), consts.FEE_COLLECTOR, uint64(feeAmount)) + ok := transferFromByRegisterCall(outputToken, std.GetOrigCaller(), consts.FEE_COLLECTOR, feeAmount.Uint64()) require(ok, "[ROUTER] router.gno__handleProtocolFee() || transferFromByRegisterCall failed") } - amount -= feeAmount - return amount + return new(u256.Uint).Sub(amount, feeAmount) } diff --git a/router/router_dry.gno b/router/router_dry.gno index 9647906c..e4135f67 100644 --- a/router/router_dry.gno +++ b/router/router_dry.gno @@ -5,63 +5,75 @@ import ( "strings" "gno.land/p/demo/ufmt" + + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) func DrySwapRoute( inputToken string, outputToken string, - amountSpecified bigint, + _amountSpecified string, // int256 swapType SwapType, strRouteArr string, // []string quoteArr string, // []int -) bigint { - require(amountSpecified != 0, "[ROUTER] router.gno__DrySwapRoute() || amountSpecified == 0") +) string { // uint256 + amountSpecified, err := i256.FromDecimal(_amountSpecified) + if err != nil { + panic(ufmt.Sprintf("[ROUTER] router_dry.gno__SwapRoute() || i256.FromDecimal(_amountSpecified(%s) failed", _amountSpecified)) + } + if amountSpecified.IsZero() { + panic("[ROUTER] router_dry.gno__SwapRoute() || amountSpecified == 0") + } switch swapType { case ExactIn: amountSpecified = amountSpecified case ExactOut: - amountSpecified = -amountSpecified + amountSpecified = i256.Zero().Neg(amountSpecified) default: - panic("[ROUTER] router.gno__DrySwapRoute() || unknown swapType") + panic("[ROUTER] router_dry.gno__DrySwapRoute() || unknown swapType") } // check route length ( should be 1 ~ 7 ) routes := strings.Split(strRouteArr, ",") - require(1 <= len(routes) && len(routes) <= 7, ufmt.Sprintf("[ROUTER] router.gno__DrySwapRoute() || len(routes) should be 1 ~ 7 (len(routes)[%d])", len(routes))) + require(1 <= len(routes) && len(routes) <= 7, ufmt.Sprintf("[ROUTER] router_dry.gno__DrySwapRoute() || len(routes) should be 1 ~ 7 (len(routes)[%d])", len(routes))) // check if routes length and quotes length are same quotes := strings.Split(quoteArr, ",") - require(len(routes) == len(quotes), ufmt.Sprintf("[ROUTER] router.gno__DrySwapRoute() || len(routes[%d]) != len(quotes[%d])", len(routes), len(quotes))) + require(len(routes) == len(quotes), ufmt.Sprintf("[ROUTER] router_dry.gno__DrySwapRoute() || len(routes[%d]) != len(quotes[%d])", len(routes), len(quotes))) // check if quotes are up to 100% - quotesSum := 0 + quotesSum := int64(0) for _, quote := range quotes { intQuote, _ := strconv.Atoi(quote) - quotesSum += intQuote + quotesSum += int64(intQuote) } - require(quotesSum == 100, "[ROUTER] router.gno__DrySwapRoute() || quotesSum != 100") + require(quotesSum == 100, "[ROUTER] router_dry.gno__DrySwapRoute() || quotesSum != 100") + + resultAmountIn := u256.Zero() + resultAmountOut := u256.Zero() - var resultAmountIn, resultAmountOut bigint for i, route := range routes { numHops := strings.Count(route, "*POOL*") + 1 quote, _ := strconv.Atoi(quotes[i]) // check if route hop is up to 3 - require(numHops <= 3, "[ROUTER] router.gno__DrySwapRoute() || numHops > 3") + require(numHops <= 3, "[ROUTER] router_dry.gno__DrySwapRoute() || numHops > 3") - toSwap := amountSpecified * bigint(quote) / bigint(100) + toSwap := i256.Zero().Mul(amountSpecified, i256.NewInt(int64(quote))) + toSwap = toSwap.Div(toSwap, i256.NewInt(100)) if numHops == 1 { // SINGLE amountIn, amountOut := handleSingleSwap(route, toSwap, true) - resultAmountIn += amountIn - resultAmountOut += amountOut + resultAmountIn = new(u256.Uint).Add(resultAmountIn, amountIn) + resultAmountOut = new(u256.Uint).Add(resultAmountOut, amountOut) } else if 2 <= numHops && numHops <= 3 { // MULTI amountIn, amountOut := handleMultiSwap(swapType, route, numHops, toSwap, true) - resultAmountIn += amountIn - resultAmountOut += amountOut + resultAmountIn = new(u256.Uint).Add(resultAmountIn, amountIn) + resultAmountOut = new(u256.Uint).Add(resultAmountOut, amountOut) } else { - panic("[ROUTER] router.gno__DrySwapRoute() || numHops should be 1 ~ 3") + panic("[ROUTER] router_dry.gno__DrySwapRoute() || numHops should be 1 ~ 3") } } @@ -71,16 +83,16 @@ func DrySwapRoute( // Interface needs to calculate 0.15 protocol fee if swapType == ExactIn { - if resultAmountIn != amountSpecified { - return -1 // if pool doesn't have enough output token amount to swap against input token amount + if !(i256.FromUint256(resultAmountIn).Eq(amountSpecified)) { + return "-1" // if pool doesn't have enough output token amount to swap against input token amount } - return resultAmountOut + return resultAmountOut.ToString() } if swapType == ExactOut { - if resultAmountOut < amountSpecified { // if pool doesn't user wanted amount of output token - return -1 + if i256.FromUint256(resultAmountOut).Lt(amountSpecified) { // if pool doesn't have enough user wanted amount of output token + return "-1" } - return resultAmountIn + return resultAmountIn.ToString() } } diff --git a/router/swap_inner.gno b/router/swap_inner.gno index 349498e5..8a47c8cf 100644 --- a/router/swap_inner.gno +++ b/router/swap_inner.gno @@ -3,100 +3,120 @@ package router import ( "std" + "gno.land/p/demo/ufmt" + pl "gno.land/r/demo/pool" "gno.land/r/demo/consts" + + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) func _swap( - amountSpecified bigint, + amountSpecified *i256.Int, recipient std.Address, - sqrtPriceLimitX96 bigint, + sqrtPriceLimitX96 *u256.Uint, data SwapCallbackData, -) (amountPoolRecv, amountPoolOut bigint) { +) (*u256.Uint, *u256.Uint) { // poolRecv, poolOut // prepare zeroForOne := data.tokenIn < data.tokenOut - if sqrtPriceLimitX96 == 0 { + if sqrtPriceLimitX96.IsZero() { if zeroForOne { - sqrtPriceLimitX96 = consts.MIN_PRICE + sqrtPriceLimitX96 = u256.UnsafeFromDecimal(consts.MIN_PRICE) } else { - sqrtPriceLimitX96 = consts.MAX_PRICE + sqrtPriceLimitX96 = u256.UnsafeFromDecimal(consts.MAX_PRICE) } } // ROUTER approves POOL as spender - toApproveAmount := consts.MAX_UINT64 - approveByRegisterCall(data.tokenIn, consts.POOL_ADDR, uint64(toApproveAmount)) - approveByRegisterCall(data.tokenOut, consts.POOL_ADDR, uint64(toApproveAmount)) + approveByRegisterCall(data.tokenIn, consts.POOL_ADDR, consts.UINT64_MAX) + approveByRegisterCall(data.tokenOut, consts.POOL_ADDR, consts.UINT64_MAX) - amount0, amount1 := pl.Swap( + amount0Str, amount1Str := pl.Swap( // int256, int256 data.tokenIn, data.tokenOut, data.fee, recipient, zeroForOne, - amountSpecified, - sqrtPriceLimitX96, + amountSpecified.ToString(), + sqrtPriceLimitX96.ToString(), data.payer, ) + amount0, err := i256.FromDecimal(amount0Str) + if err != nil { + panic(ufmt.Sprintf("[ROUTER] router.gno__Swap() || i256.FromDecimal(amount0Str(%s) failed", amount0Str)) + } + amount1, err := i256.FromDecimal(amount1Str) + if err != nil { + panic(ufmt.Sprintf("[ROUTER] router.gno__Swap() || i256.FromDecimal(amount1Str(%s) failed", amount1Str)) + } + + poolRecv := i256Max(amount0, amount1) + poolOut := i256Min(amount0, amount1) - return absBigint(maxBigint(amount0, amount1)), absBigint(minBigint(amount0, amount1)) + return poolRecv.Abs(), poolOut.Abs() } func _swapDry( - amountSpecified bigint, + amountSpecified *i256.Int, recipient std.Address, - sqrtPriceLimitX96 bigint, + sqrtPriceLimitX96 *u256.Uint, data SwapCallbackData, -) (amountPoolRecv, amountPoolOut bigint) { +) (*u256.Uint, *u256.Uint) { // poolRecv, poolOut zeroForOne := data.tokenIn < data.tokenOut - if sqrtPriceLimitX96 == 0 { + if sqrtPriceLimitX96.IsZero() { if zeroForOne { - sqrtPriceLimitX96 = consts.MIN_PRICE + sqrtPriceLimitX96 = u256.UnsafeFromDecimal(consts.MIN_PRICE) } else { - sqrtPriceLimitX96 = consts.MAX_PRICE + sqrtPriceLimitX96 = u256.UnsafeFromDecimal(consts.MAX_PRICE) } } // check possible - amount0, amount1, ok := pl.DrySwap( + amount0Str, amount1Str, ok := pl.DrySwap( data.tokenIn, data.tokenOut, data.fee, recipient, zeroForOne, - amountSpecified, - sqrtPriceLimitX96, + amountSpecified.ToString(), + sqrtPriceLimitX96.ToString(), ) if !ok { - return 0, 0 + return u256.Zero(), u256.Zero() } - return absBigint(maxBigint(amount0, amount1)), absBigint(minBigint(amount0, amount1)) -} - -func max(a, b uint64) uint64 { - if a > b { - return a + amount0, err := i256.FromDecimal(amount0Str) + if err != nil { + panic(ufmt.Sprintf("[ROUTER] router.gno__Swap() || i256.FromDecimal(amount0Str(%s) failed", amount0Str)) + } + amount1, err := i256.FromDecimal(amount1Str) + if err != nil { + panic(ufmt.Sprintf("[ROUTER] router.gno__Swap() || i256.FromDecimal(amount1Str(%s) failed", amount1Str)) } - return b + + poolRecv := i256Max(amount0, amount1) + poolOut := i256Min(amount0, amount1) + + return poolRecv.Abs(), poolOut.Abs() } -func minBigint(a, b bigint) bigint { - if a < b { - return a +func i256Min(x, y *i256.Int) *i256.Int { + if x.Lt(y) { + return x } - return b + return y } -func maxBigint(a, b bigint) bigint { - if a > b { - return a +func i256Max(x, y *i256.Int) *i256.Int { + if x.Gt(y) { + return x } - return b + return y } diff --git a/router/swap_multi.gno b/router/swap_multi.gno index 5ad6a614..d11859b6 100644 --- a/router/swap_multi.gno +++ b/router/swap_multi.gno @@ -4,9 +4,14 @@ import ( "std" "gno.land/r/demo/consts" + + i256 "gno.land/p/big/int256" + u256 "gno.land/p/big/uint256" ) -func multiSwap(params SwapParams, currentPoolIndex, numPools int, swapPath string) (firstAmountIn, lastAmountOut bigint) { +func multiSwap(params SwapParams, currentPoolIndex, numPools int, swapPath string) (*u256.Uint, *u256.Uint) { // firstAmountIn, lastAmountOut + firstAmountIn := u256.Zero() + payer := std.GetOrigCaller() // user for { @@ -22,7 +27,7 @@ func multiSwap(params SwapParams, currentPoolIndex, numPools int, swapPath strin amountIn, amountOut := _swap( params.amountSpecified, recipient, - 0, + u256.Zero(), SwapCallbackData{ params.tokenIn, params.tokenOut, @@ -43,7 +48,7 @@ func multiSwap(params SwapParams, currentPoolIndex, numPools int, swapPath strin params.tokenOut = nextOutput params.fee = nextFee - params.amountSpecified = amountOut + params.amountSpecified = i256.FromUint256(amountOut) } else { return firstAmountIn, amountOut @@ -51,7 +56,9 @@ func multiSwap(params SwapParams, currentPoolIndex, numPools int, swapPath strin } } -func multiSwapNegative(params SwapParams, numPools int, swapPath string) (fisrtAmountIn, lastAmountOut bigint) { +func multiSwapNegative(params SwapParams, numPools int, swapPath string) (*u256.Uint, *u256.Uint) { // firstAmountIn, lastAmountOut + firstAmountIn := u256.Zero() + swapInfo := []SingleSwapParams{} currentPoolIndex := numPools @@ -82,7 +89,9 @@ func multiSwapNegative(params SwapParams, numPools int, swapPath string) (fisrtA params.tokenIn = nextInput params.tokenOut = nextOutput params.fee = nextFee - params.amountSpecified = -amountIn + + _intAmountIn := i256.FromUint256(amountIn) + params.amountSpecified = i256.Zero().Neg(_intAmountIn) } } @@ -101,7 +110,7 @@ func multiSwapNegative(params SwapParams, numPools int, swapPath string) (fisrtA amountIn, amountOut := _swap( swapInfo[currentPoolIndex].amountSpecified, recipient, - 0, + u256.Zero(), SwapCallbackData{ swapInfo[currentPoolIndex].tokenIn, swapInfo[currentPoolIndex].tokenOut, @@ -112,19 +121,21 @@ func multiSwapNegative(params SwapParams, numPools int, swapPath string) (fisrtA // save route's first hop's amountIn to check whether crossed limit or not if currentPoolIndex == len(swapInfo)-1 { - fisrtAmountIn = amountIn + firstAmountIn = amountIn } if currentPoolIndex == 0 { - return fisrtAmountIn, amountOut + return firstAmountIn, amountOut } else { payer = consts.ROUTER_ADDR - swapInfo[currentPoolIndex-1].amountSpecified = amountOut + swapInfo[currentPoolIndex-1].amountSpecified = i256.FromUint256(amountOut) } } } -func multiSwapDry(params SwapParams, currentPoolIndex, numPool int, swapPath string) (firstAmountIn, lastAmountOut bigint) { +func multiSwapDry(params SwapParams, currentPoolIndex, numPool int, swapPath string) (*u256.Uint, *u256.Uint) { // firstAmountIn, lastAmountOut + firstAmountIn := u256.Zero() + payer := std.GetOrigCaller() // user for { @@ -140,7 +151,7 @@ func multiSwapDry(params SwapParams, currentPoolIndex, numPool int, swapPath str amountIn, amountOut := _swapDry( params.amountSpecified, recipient, - 0, + u256.Zero(), SwapCallbackData{ params.tokenIn, params.tokenOut, @@ -161,7 +172,7 @@ func multiSwapDry(params SwapParams, currentPoolIndex, numPool int, swapPath str params.tokenOut = nextOutput params.fee = nextFee - params.amountSpecified = amountOut + params.amountSpecified = i256.FromUint256(amountOut) } else { return firstAmountIn, amountOut } @@ -169,7 +180,8 @@ func multiSwapDry(params SwapParams, currentPoolIndex, numPool int, swapPath str } -func multiSwapNegativeDry(params SwapParams, currentPoolIndex int, swapPath string) (firstAmountIn, lastAmountOut bigint) { +func multiSwapNegativeDry(params SwapParams, currentPoolIndex int, swapPath string) (*u256.Uint, *u256.Uint) { // firstAmountIn, lastAmountOut + firstAmountIn := u256.Zero() payer := consts.ROUTER_ADDR numPools := currentPoolIndex @@ -185,7 +197,7 @@ func multiSwapNegativeDry(params SwapParams, currentPoolIndex int, swapPath stri amountIn, amountOut := _swapDry( params.amountSpecified, recipient, - 0, + u256.Zero(), SwapCallbackData{ params.tokenIn, params.tokenOut, @@ -207,7 +219,8 @@ func multiSwapNegativeDry(params SwapParams, currentPoolIndex int, swapPath stri params.tokenOut = nextOutput params.fee = nextFee - params.amountSpecified = -amountIn + _intAmountIn := i256.FromUint256(amountIn) + params.amountSpecified = i256.Zero().Neg(_intAmountIn) } else { return firstAmountIn, amountOut } diff --git a/router/swap_single.gno b/router/swap_single.gno index ec2ddb77..6d657e85 100644 --- a/router/swap_single.gno +++ b/router/swap_single.gno @@ -2,13 +2,15 @@ package router import ( "std" + + u256 "gno.land/p/big/uint256" ) -func singleSwap(params SingleSwapParams) (amountIn, amountOut bigint) { - amountIn, amountOut = _swap( +func singleSwap(params SingleSwapParams) (*u256.Uint, *u256.Uint) { // amountIn, amountOut + amountIn, amountOut := _swap( params.amountSpecified, std.GetOrigCaller(), // if single swap => user will recieve - 0, // sqrtPriceLimitX96 + u256.Zero(), // sqrtPriceLimitX96 SwapCallbackData{ params.tokenIn, params.tokenOut, @@ -20,11 +22,11 @@ func singleSwap(params SingleSwapParams) (amountIn, amountOut bigint) { return amountIn, amountOut } -func singleSwapDry(params SingleSwapParams) (amountIn, amountOut bigint) { - amountIn, amountOut = _swapDry( +func singleSwapDry(params SingleSwapParams) (*u256.Uint, *u256.Uint) { // amountIn, amountOut + amountIn, amountOut := _swapDry( params.amountSpecified, std.GetOrigCaller(), // if single swap => user will recieve - 0, // sqrtPriceLimitX96 + u256.Zero(), // sqrtPriceLimitX96 SwapCallbackData{ params.tokenIn, params.tokenOut, diff --git a/router/type.gno b/router/type.gno index 84c4764d..d84dff0a 100644 --- a/router/type.gno +++ b/router/type.gno @@ -1,6 +1,10 @@ package router -import "std" +import ( + "std" + + i256 "gno.land/p/big/int256" +) // SWAP TYPE type SwapType string @@ -14,24 +18,24 @@ const ( type SingleSwapParams struct { tokenIn string tokenOut string - fee uint16 - amountSpecified bigint + fee uint32 + amountSpecified *i256.Int } // MUTLI SWAP type SwapParams struct { tokenIn string tokenOut string - fee uint16 + fee uint32 recipient std.Address - amountSpecified bigint + amountSpecified *i256.Int } // SWAP DATA type SwapCallbackData struct { tokenIn string tokenOut string - fee uint16 + fee uint32 payer std.Address } diff --git a/router/util.gno b/router/utils.gno similarity index 57% rename from router/util.gno rename to router/utils.gno index 3366be4e..46178073 100644 --- a/router/util.gno +++ b/router/utils.gno @@ -10,20 +10,35 @@ import ( "gno.land/p/demo/ufmt" ) -func getDataForSinglePath(poolPath string) (token0, token1 string, fee uint16) { +func poolPathWithFeeDivide(poolPath string) (string, string, int) { + poolPathSplit := strings.Split(poolPath, ":") + require(len(poolPathSplit) == 3, ufmt.Sprintf("[ROUTER] _RPC_api.gno__poolPathWithFeeDivide() || len(poolPathSplit) != 3, poolPath: %s", poolPath)) + + feeInt, err := strconv.Atoi(poolPathSplit[2]) + if err != nil { + panic(ufmt.Sprintf("[ROUTER] _RPC_api.gno__poolPathWithFeeDivide() || cannot convert fee(%s) to int", poolPathSplit[2])) + } + + return poolPathSplit[0], poolPathSplit[1], feeInt +} + +func getDataForSinglePath(poolPath string) (string, string, uint32) { datas := strings.Split(poolPath, ":") require(len(datas) == 3, ufmt.Sprintf("[ROUTER] _util.gno__getDataForSinglePath() || len(datas) != 3 (poolPath:%s)", poolPath)) - token0 = datas[0] - token1 = datas[1] - _fee, _ := strconv.Atoi(datas[2]) + token0 := datas[0] + token1 := datas[1] + fee, _ := strconv.Atoi(datas[2]) - return token0, token1, uint16(_fee) + return token0, token1, uint32(fee) } -func getDataForMultiPath(possiblePath string, poolIdx int) (token0, token1 string, fee uint16) { +func getDataForMultiPath(possiblePath string, poolIdx int) (string, string, uint32) { pools := strings.Split(possiblePath, "*POOL*") + var token0, token1 string + var fee uint32 + switch poolIdx { case 0: token0, token1, fee = getDataForSinglePath(pools[0]) @@ -32,7 +47,7 @@ func getDataForMultiPath(possiblePath string, poolIdx int) (token0, token1 strin case 2: token0, token1, fee = getDataForSinglePath(pools[2]) default: - return "", "", 0 + return "", "", uint32(0) } return token0, token1, fee @@ -66,25 +81,9 @@ func require(cond bool, msg string) { } } -func abs(x bigint) uint64 { - if x < 0 { - return uint64(-x) - } - - return uint64(x) -} - func min(a, b int) int { if a < b { return a } return b } - -func absBigint(x bigint) bigint { - if x < 0 { - return -x - } - - return x -} diff --git a/staker/_GET_no_receiver.gno b/staker/_GET_no_receiver.gno index 24fef0b9..6401da52 100644 --- a/staker/_GET_no_receiver.gno +++ b/staker/_GET_no_receiver.gno @@ -4,54 +4,65 @@ import ( "std" "gno.land/p/demo/ufmt" + + u256 "gno.land/p/big/uint256" ) // Incentive func StakerPoolIncentives(poolPath string) []string { incentives, exist := poolIncentives[poolPath] - requireExist(exist, ufmt.Sprintf("[STAKER] _GET_staker.gno__StakerPoolIncentives() || poolPath(%s) incentives does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerPoolIncentives() || poolPath(%s) incentives does not exist", poolPath)) return incentives } func StakerIncentiveTargetPoolPath(incentiveId string) string { incentive, exist := incentives[incentiveId] - requireExist(exist, ufmt.Sprintf("[STAKER] _GET_staker.gno__StakerIncentiveTargetPoolPath() || incentiveId(%s) incentive does not exist", incentiveId)) + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerIncentiveTargetPoolPath() || incentiveId(%s) incentive does not exist", incentiveId)) return incentive.targetPoolPath } func StakerIncentiveRewardToken(incentiveId string) string { incentive, exist := incentives[incentiveId] - requireExist(exist, ufmt.Sprintf("[STAKER] _GET_staker.gno__StakerIncentiveRewardToken() || incentiveId(%s) incentive does not exist", incentiveId)) + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerIncentiveRewardToken() || incentiveId(%s) incentive does not exist", incentiveId)) return incentive.rewardToken } -func StakerIncentiveRewardAmount(incentiveId string) bigint { +// UINT +func StakerIncentiveRewardAmount(incentiveId string) *u256.Uint { incentive, exist := incentives[incentiveId] - requireExist(exist, ufmt.Sprintf("[STAKER] _GET_staker.gno__StakerIncentiveRewardAmount() || incentiveId(%s) incentive does not exist", incentiveId)) + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerIncentiveRewardAmount() || incentiveId(%s) incentive does not exist", incentiveId)) return incentive.rewardAmount } +// STR +func StakerIncentiveRewardAmountStr(incentiveId string) string { + incentive, exist := incentives[incentiveId] + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerIncentiveRewardAmount() || incentiveId(%s) incentive does not exist", incentiveId)) + + return incentive.rewardAmount.ToString() +} + func StakerIncentiveStartTimestamp(incentiveId string) int64 { incentive, exist := incentives[incentiveId] - requireExist(exist, ufmt.Sprintf("[STAKER] _GET_staker.gno__StakerIncentiveStartTimestamp() || incentiveId(%s) incentive does not exist", incentiveId)) + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerIncentiveStartTimestamp() || incentiveId(%s) incentive does not exist", incentiveId)) return incentive.startTimestamp } func StakerIncentiveEndTimestamp(incentiveId string) int64 { incentive, exist := incentives[incentiveId] - requireExist(exist, ufmt.Sprintf("[STAKER] _GET_staker.gno__StakerIncentiveEndTimestamp() || incentiveId(%s) incentive does not exist", incentiveId)) + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerIncentiveEndTimestamp() || incentiveId(%s) incentive does not exist", incentiveId)) return incentive.endTimestamp } func StakerIncentiveRefundee(incentiveId string) std.Address { incentive, exist := incentives[incentiveId] - requireExist(exist, ufmt.Sprintf("[STAKER] _GET_staker.gno__StakerIncentiveRefundee() || incentiveId(%s) incentive does not exist", incentiveId)) + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerIncentiveRefundee() || incentiveId(%s) incentive does not exist", incentiveId)) return incentive.refundee } @@ -59,36 +70,36 @@ func StakerIncentiveRefundee(incentiveId string) std.Address { // Deposit func StakerDepositOwner(lpTokenId uint64) std.Address { deposit, exist := deposits[lpTokenId] - requireExist(exist, ufmt.Sprintf("[STAKER] _GET_staker.gno__StakerDepositOwner() || tokenId(%d) deposit does not exist", lpTokenId)) + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerDepositOwner() || tokenId(%d) deposit does not exist", lpTokenId)) return deposit.owner } func StakerDepositNumberOfStakes(lpTokenId uint64) uint64 { deposit, exist := deposits[lpTokenId] - requireExist(exist, ufmt.Sprintf("[STAKER] _GET_staker.gno__StakerDepositNumberOfStakes() || tokenId(%d) deposit does not exist", lpTokenId)) + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerDepositNumberOfStakes() || tokenId(%d) deposit does not exist", lpTokenId)) return deposit.numberOfStakes } func StakerDepositStakeTimestamp(lpTokenId uint64) int64 { deposit, exist := deposits[lpTokenId] - requireExist(exist, ufmt.Sprintf("[STAKER] _GET_staker.gno__StakerDepositStakeTimestamp() || tokenId(%d) deposit does not exist", lpTokenId)) + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerDepositStakeTimestamp() || tokenId(%d) deposit does not exist", lpTokenId)) return deposit.stakeTimestamp } func StakerDepositTargetPoolPath(lpTokenId uint64) string { deposit, exist := deposits[lpTokenId] - requireExist(exist, ufmt.Sprintf("[STAKER] _GET_staker.gno__StakerDepositTargetPoolPath() || tokenId(%d) deposit does not exist", lpTokenId)) + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerDepositTargetPoolPath() || tokenId(%d) deposit does not exist", lpTokenId)) return deposit.targetPoolPath } // PoolTier -func StakerPoolTier(poolPath string) uint8 { +func StakerPoolTier(poolPath string) uint64 { tier, exist := poolTiers[poolPath] - requireExist(exist, ufmt.Sprintf("[STAKER] _GET_staker.gno__StakerPoolTier() || poolPath(%s) poolTier does not exist", poolPath)) + requireExist(exist, ufmt.Sprintf("[STAKER] _GET_no_receiver__StakerPoolTier() || poolPath(%s) poolTier does not exist", poolPath)) return tier } diff --git a/staker/_RPC_api_stake.gno b/staker/_RPC_api_stake.gno index f65f79d1..4e8ce4b9 100644 --- a/staker/_RPC_api_stake.gno +++ b/staker/_RPC_api_stake.gno @@ -6,6 +6,8 @@ import ( "time" "gno.land/p/demo/ufmt" + + u256 "gno.land/p/big/uint256" ) type LpTokenReward struct { @@ -18,7 +20,7 @@ type Reward struct { IncentiveType string `json:"incentiveType"` TargetPoolPath string `json:"targetPoolPath"` RewardTokenPath string `json:"rewardTokenPath"` - RewardTokenAmount bigint `json:"rewardTokenAmount"` + RewardTokenAmount string `json:"rewardTokenAmount"` } type Stake struct { @@ -57,12 +59,12 @@ func ApiGetRewards() string { // get internal gns reward internalGNS := rewardMathComputeInternalRewardAmount(tokenId, deposit) - if internalGNS > 0 { + if internalGNS.Gt(u256.Zero()) { rewards = append(rewards, Reward{ IncentiveType: "INTERNAL", TargetPoolPath: deposit.targetPoolPath, RewardTokenPath: INTERNAL_REWARD_TOKEN_PATH, - RewardTokenAmount: internalGNS, + RewardTokenAmount: internalGNS.ToString(), }) } @@ -73,10 +75,9 @@ func ApiGetRewards() string { IncentiveType: "EXTERNAL", TargetPoolPath: deposit.targetPoolPath, RewardTokenPath: incentives[incentiveId].rewardToken, - RewardTokenAmount: externalReward, + RewardTokenAmount: externalReward.ToString(), }) } - lpTokenReward := LpTokenReward{ LpTokenId: tokenId, Address: deposit.owner.String(), @@ -111,12 +112,12 @@ func ApiGetRewardByLpTokenId(lpTokenId uint64) string { // get internal gns reward internalGNS := rewardMathComputeInternalRewardAmount(lpTokenId, deposit) - if internalGNS > 0 { + if internalGNS.Gt(u256.Zero()) { rewards = append(rewards, Reward{ IncentiveType: "INTERNAL", TargetPoolPath: deposit.targetPoolPath, RewardTokenPath: INTERNAL_REWARD_TOKEN_PATH, - RewardTokenAmount: internalGNS, + RewardTokenAmount: internalGNS.ToString(), }) } @@ -127,7 +128,7 @@ func ApiGetRewardByLpTokenId(lpTokenId uint64) string { IncentiveType: "EXTERNAL", TargetPoolPath: deposit.targetPoolPath, RewardTokenPath: incentives[incentiveId].rewardToken, - RewardTokenAmount: externalReward, + RewardTokenAmount: externalReward.ToString(), }) } diff --git a/staker/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno b/staker/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno index 3cdc1086..e3fc2639 100644 --- a/staker/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno +++ b/staker/_TEST_0_INIT_VARIABLE_AND_HELPER_test.gno @@ -20,11 +20,11 @@ var ( // wugnotPath string = "gno.land/r/demo/wugnot" // from consts // gnsPath string = "gno.land/r/demo/gns" // from consts - fee100 uint16 = 100 - fee500 uint16 = 500 - fee3000 uint16 = 3000 + fee100 uint32 = 100 + fee500 uint32 = 500 + fee3000 uint32 = 3000 - max_timeout bigint = 9999999999 + max_timeout int64 = 9999999999 ) /* HELPER */ diff --git a/staker/_TEST_staker_collect_reward_test.gno b/staker/_TEST_staker_collect_reward_test.gnoa similarity index 73% rename from staker/_TEST_staker_collect_reward_test.gno rename to staker/_TEST_staker_collect_reward_test.gnoa index 685f0b84..f382ba15 100644 --- a/staker/_TEST_staker_collect_reward_test.gno +++ b/staker/_TEST_staker_collect_reward_test.gnoa @@ -43,7 +43,7 @@ func TestPoolInitCreatePool(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) std.TestSkipHeights(1) - pl.CreatePool(barPath, quxPath, 500, 130621891405341611593710811006) // tick 10_000 ≈ x2.7 + pl.CreatePool(barPath, quxPath, 500, "130621891405341611593710811006") // tick 10_000 ≈ x2.7 std.TestSkipHeights(1) } @@ -54,23 +54,23 @@ func TestPositionMint01(t *testing.T) { std.TestSkipHeights(2) lpTokenId, liquidity, amount0, amount1 := pn.Mint( - barPath, // token0 - quxPath, // token1 - uint16(500), // fee - int32(9000), // tickLower - int32(11000), // tickUpper - bigint(1000), // amount0Desired - bigint(1000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min - bigint(2345678901), // deadline + barPath, // token0 + quxPath, // token1 + uint16(500), // fee + int32(9000), // tickLower + int32(11000), // tickUpper + "1000", // amount0Desired + "1000", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, // deadline ) std.TestSkipHeights(1) shouldEQ(t, lpTokenId, 1) shouldEQ(t, gnft.OwnerOf(tid(lpTokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(367)) - shouldEQ(t, amount1, bigint(999)) + shouldEQ(t, amount0, "367") + shouldEQ(t, amount1, "999") // approve nft to staker std.TestSetPrevAddr(test1) @@ -85,23 +85,23 @@ func TestPositionMint02(t *testing.T) { std.TestSkipHeights(2) lpTokenId, liquidity, amount0, amount1 := pn.Mint( - barPath, // token0 - quxPath, // token1 - uint16(500), // fee - int32(9100), // tickLower - int32(12000), // tickUpper - bigint(5000), // amount0Desired - bigint(5000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min - bigint(2345678901), // deadline + barPath, // token0 + quxPath, // token1 + uint16(500), // fee + int32(9100), // tickLower + int32(12000), // tickUpper + "5000", // amount0Desired + "5000", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, // deadline ) std.TestSkipHeights(1) shouldEQ(t, lpTokenId, 2) shouldEQ(t, gnft.OwnerOf(tid(lpTokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(3978)) - shouldEQ(t, amount1, bigint(4999)) + shouldEQ(t, amount0, "3978") + shouldEQ(t, amount1, "4999") // approve nft to staker std.TestSetPrevAddr(test1) @@ -117,7 +117,7 @@ func TestCreateExternalIncentive(t *testing.T) { CreateExternalIncentive( "gno.land/r/demo/bar:gno.land/r/demo/qux:500", // targetPoolPath "gno.land/r/demo/obl", // rewardToken - 10_000_000_000, // rewardAmount + "10000000000", // rewardAmount time.Now().Unix(), // startTimestamp time.Now().Unix()+TIMESTAMP_90DAYS, // endTimestamp ) @@ -126,7 +126,7 @@ func TestCreateExternalIncentive(t *testing.T) { obl.Approve(a2u(consts.STAKER_ADDR), uint64(10_000_000_000)) std.TestSkipHeights(1) - CreateExternalIncentive("gno.land/r/demo/bar:gno.land/r/demo/qux:500", "gno.land/r/demo/obl", 10_000_000_000, time.Now().Unix(), time.Now().Unix()+TIMESTAMP_90DAYS) + CreateExternalIncentive("gno.land/r/demo/bar:gno.land/r/demo/qux:500", "gno.land/r/demo/obl", "10000000000", time.Now().Unix(), time.Now().Unix()+TIMESTAMP_90DAYS) std.TestSkipHeights(1) } @@ -150,7 +150,7 @@ func TestStakeToken02(t *testing.T) { func TestCollectReward(t *testing.T) { std.TestSetPrevAddr(consts.INTERNAL_REWARD_ACCOUNT) - gns.Approve(a2u(consts.STAKER_ADDR), uint64(consts.MAX_UINT64)) // internal reward distribution + gns.Approve(a2u(consts.STAKER_ADDR), consts.UINT64_MAX) // internal reward distribution std.TestSkipHeights(1) // before claim @@ -165,7 +165,7 @@ func TestCollectReward(t *testing.T) { gnsNew := gns.BalanceOf(a2u(test1)) std.TestSkipHeights(1) - shouldEQ(t, gnsNew, 99500000125) + shouldEQ(t, gnsNew, 99500006126) } func TestUnstakeToken01(t *testing.T) { @@ -176,8 +176,8 @@ func TestUnstakeToken01(t *testing.T) { shouldEQ(t, gnft.OwnerOf(tid(1)), test1) // check reward - shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500000125) // internal - shouldEQ(t, obl.BalanceOf(a2u(test1)), 499980000000642) // external + shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500006126) // internal + shouldEQ(t, obl.BalanceOf(a2u(test1)), 499980000000630) // external } func TestUnstakeToken02(t *testing.T) { @@ -188,8 +188,8 @@ func TestUnstakeToken02(t *testing.T) { shouldEQ(t, gnft.OwnerOf(tid(2)), test1) // check reward - shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500000942) // internal - shouldEQ(t, obl.BalanceOf(a2u(test1)), 499980000004843) // external + shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500046964) // internal + shouldEQ(t, obl.BalanceOf(a2u(test1)), 499980000004831) // external } func TestEndExternalIncentive(t *testing.T) { diff --git a/staker/_TEST_staker_get_test.gnoa b/staker/_TEST_staker_get_test.gnoa index 2506b65e..ad0504c9 100644 --- a/staker/_TEST_staker_get_test.gnoa +++ b/staker/_TEST_staker_get_test.gnoa @@ -28,7 +28,7 @@ func TestPoolInitCreatePool(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) std.TestSkipHeights(1) - pl.CreatePool(barPath, quxPath, 500, 130621891405341611593710811006) // tick 10_000 ≈ x2.7 + pl.CreatePool(barPath, quxPath, 500, "130621891405341611593710811006") // tick 10_000 ≈ x2.7 std.TestSkipHeights(1) } @@ -39,23 +39,23 @@ func TestPositionMint01(t *testing.T) { std.TestSkipHeights(2) lpTokenId, liquidity, amount0, amount1 := pn.Mint( - barPath, // token0 - quxPath, // token1 - uint16(500), // fee - int32(9000), // tickLower - int32(11000), // tickUpper - bigint(1000), // amount0Desired - bigint(1000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min - bigint(2345678901), // deadline + barPath, // token0 + quxPath, // token1 + uint16(500), // fee + int32(9000), // tickLower + int32(11000), // tickUpper + "1000", // amount0Desired + "1000", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, // deadline ) std.TestSkipHeights(1) shouldEQ(t, lpTokenId, 1) shouldEQ(t, gnft.OwnerOf(tid(lpTokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(367)) - shouldEQ(t, amount1, bigint(999)) + shouldEQ(t, amount0, "367") + shouldEQ(t, amount1, "999") // approve nft to staker std.TestSetPrevAddr(test1) @@ -70,23 +70,23 @@ func TestPositionMint02(t *testing.T) { std.TestSkipHeights(2) lpTokenId, liquidity, amount0, amount1 := pn.Mint( - barPath, // token0 - quxPath, // token1 - uint16(500), // fee - int32(9100), // tickLower - int32(12000), // tickUpper - bigint(5000), // amount0Desired - bigint(5000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min - bigint(2345678901), // deadline + barPath, // token0 + quxPath, // token1 + uint16(500), // fee + int32(9100), // tickLower + int32(12000), // tickUpper + "5000", // amount0Desired + "5000", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, // deadline ) std.TestSkipHeights(1) shouldEQ(t, lpTokenId, 2) shouldEQ(t, gnft.OwnerOf(tid(lpTokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(3978)) - shouldEQ(t, amount1, bigint(4999)) + shouldEQ(t, amount0, "3978") + shouldEQ(t, amount1, "4999") // approve nft to staker std.TestSetPrevAddr(test1) @@ -102,7 +102,7 @@ func TestCreateExternalIncentive(t *testing.T) { CreateExternalIncentive( "gno.land/r/demo/bar:gno.land/r/demo/qux:500", // targetPoolPath "gno.land/r/demo/obl", // rewardToken - 10_000_000_000, // rewardAmount + "10000000000", // rewardAmount time.Now().Unix(), // startTimestamp time.Now().Unix()+TIMESTAMP_90DAYS, // endTimestamp ) @@ -111,7 +111,7 @@ func TestCreateExternalIncentive(t *testing.T) { obl.Approve(a2u(consts.STAKER_ADDR), uint64(10_000_000_000)) std.TestSkipHeights(1) - CreateExternalIncentive("gno.land/r/demo/bar:gno.land/r/demo/qux:500", "gno.land/r/demo/obl", 10_000_000_000, time.Now().Unix(), time.Now().Unix()+TIMESTAMP_90DAYS) + CreateExternalIncentive("gno.land/r/demo/bar:gno.land/r/demo/qux:500", "gno.land/r/demo/obl", "10000000000", time.Now().Unix(), time.Now().Unix()+TIMESTAMP_90DAYS) std.TestSkipHeights(1) } diff --git a/staker/_TEST_staker_internal_external_test.gnoa b/staker/_TEST_staker_internal_external_test.gno similarity index 73% rename from staker/_TEST_staker_internal_external_test.gnoa rename to staker/_TEST_staker_internal_external_test.gno index fdcd0301..ca86f0f0 100644 --- a/staker/_TEST_staker_internal_external_test.gnoa +++ b/staker/_TEST_staker_internal_external_test.gno @@ -10,14 +10,14 @@ import ( pl "gno.land/r/demo/pool" pn "gno.land/r/demo/position" - "gno.land/r/demo/gnft" - "gno.land/r/demo/bar" "gno.land/r/demo/baz" "gno.land/r/demo/foo" "gno.land/r/demo/gns" "gno.land/r/demo/obl" "gno.land/r/demo/qux" + + "gno.land/r/demo/gnft" ) func init() { @@ -44,9 +44,9 @@ func TestPoolInitCreatePool(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*3) std.TestSkipHeights(1) - pl.CreatePool(barPath, quxPath, 500, 130621891405341611593710811006) // internal, tier 1 // tick 10_000 ≈ x2.7 - pl.CreatePool(barPath, bazPath, 100, 79228162514264337593543950337) // internal, tier 2 // tick 0 ≈ x1 - pl.CreatePool(fooPath, quxPath, 500, 79228162514264337593543950337) // external // tick 0 ≈ x1 + pl.CreatePool(barPath, quxPath, 500, "130621891405341611593710811006") // internal, tier 1 // tick 10_000 ≈ x2.7 + pl.CreatePool(barPath, bazPath, 100, "79228162514264337593543950337") // internal, tier 2 // tick 0 ≈ x1 + pl.CreatePool(fooPath, quxPath, 500, "79228162514264337593543950337") // external // tick 0 ≈ x1 std.TestSkipHeights(3) } @@ -57,23 +57,23 @@ func TestMintBarQux500(t *testing.T) { std.TestSkipHeights(2) tokenId, liquidity, amount0, amount1 := pn.Mint( - barPath, // token0 - quxPath, // token1 - fee500, // fee - int32(9000), // tickLower - int32(11000), // tickUpper - bigint(100000), // amount0Desired - bigint(100000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min + barPath, // token0 + quxPath, // token1 + fee500, // fee + int32(9000), // tickLower + int32(11000), // tickUpper + "100000", // amount0Desired + "100000", // amount1Desired + "1", // amount0Min + "1", // amount1Min max_timeout, ) std.TestSkipHeights(1) shouldEQ(t, tokenId, 1) shouldEQ(t, gnft.OwnerOf(tid(tokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(36789)) - shouldEQ(t, amount1, bigint(99999)) + shouldEQ(t, amount0, "36789") + shouldEQ(t, amount1, "99999") } func TestMintBarBaz100(t *testing.T) { @@ -83,23 +83,23 @@ func TestMintBarBaz100(t *testing.T) { std.TestSkipHeights(2) tokenId, liquidity, amount0, amount1 := pn.Mint( - barPath, // token0 - bazPath, // token1 - fee100, // fee - int32(-1000), // tickLower - int32(1000), // tickUpper - bigint(100000), // amount0Desired - bigint(100000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min + barPath, // token0 + bazPath, // token1 + fee100, // fee + int32(-1000), // tickLower + int32(1000), // tickUpper + "100000", // amount0Desired + "100000", // amount1Desired + "1", // amount0Min + "1", // amount1Min max_timeout, ) std.TestSkipHeights(1) shouldEQ(t, tokenId, 2) shouldEQ(t, gnft.OwnerOf(tid(tokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(99999)) - shouldEQ(t, amount1, bigint(99999)) + shouldEQ(t, amount0, "99999") + shouldEQ(t, amount1, "99999") } func TestMintFooQux500(t *testing.T) { @@ -109,23 +109,23 @@ func TestMintFooQux500(t *testing.T) { std.TestSkipHeights(2) tokenId, liquidity, amount0, amount1 := pn.Mint( - fooPath, // token0 - quxPath, // token1 - fee500, // fee - int32(-1000), // tickLower - int32(1000), // tickUpper - bigint(100000), // amount0Desired - bigint(100000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min + fooPath, // token0 + quxPath, // token1 + fee500, // fee + int32(-1000), // tickLower + int32(1000), // tickUpper + "100000", // amount0Desired + "100000", // amount1Desired + "1", // amount0Min + "1", // amount1Min max_timeout, ) std.TestSkipHeights(1) shouldEQ(t, tokenId, 3) shouldEQ(t, gnft.OwnerOf(tid(tokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(99999)) - shouldEQ(t, amount1, bigint(99999)) + shouldEQ(t, amount0, "99999") + shouldEQ(t, amount1, "99999") } func TestCreateExternalIncentive(t *testing.T) { @@ -136,7 +136,7 @@ func TestCreateExternalIncentive(t *testing.T) { CreateExternalIncentive( "gno.land/r/demo/foo:gno.land/r/demo/qux:500", // targetPoolPath "gno.land/r/demo/obl", // rewardToken - 100_000_000, // rewardAmount + "100000000", // rewardAmount time.Now().Unix(), // startTimestamp time.Now().Unix()+TIMESTAMP_90DAYS, // endTimestamp ) @@ -175,7 +175,7 @@ func TestStakeExternal(t *testing.T) { func TestCollectRewardToken1(t *testing.T) { std.TestSetPrevAddr(consts.INTERNAL_REWARD_ACCOUNT) - gns.Approve(a2u(consts.STAKER_ADDR), uint64(consts.MAX_UINT64)) // internal reward distribution + gns.Approve(a2u(consts.STAKER_ADDR), consts.UINT64_MAX) // internal reward distribution std.TestSkipHeights(1) // before claim @@ -187,7 +187,7 @@ func TestCollectRewardToken1(t *testing.T) { std.TestSkipHeights(1) gnsNew := gns.BalanceOf(a2u(test1)) - shouldEQ(t, gnsNew, 98500000817) + shouldEQ(t, gnsNew, 98500040838) } func TestCollectRewardToken2(t *testing.T) { @@ -195,13 +195,13 @@ func TestCollectRewardToken2(t *testing.T) { // before claim gnsOld := gns.BalanceOf(a2u(test1)) - shouldEQ(t, gnsOld, 98500000817) + shouldEQ(t, gnsOld, 98500040838) CollectReward(2) std.TestSkipHeights(1) gnsNew := gns.BalanceOf(a2u(test1)) - shouldEQ(t, gnsNew, 98500001308) + shouldEQ(t, gnsNew, 98500065341) } func TestCollectRewardToken1Again(t *testing.T) { @@ -209,7 +209,7 @@ func TestCollectRewardToken1Again(t *testing.T) { // before claim gnsOld := gns.BalanceOf(a2u(test1)) - shouldEQ(t, gnsOld, 98500001308) + shouldEQ(t, gnsOld, 98500065341) // ACCELERATE TIME std.TestSkipHeights(100000) @@ -218,7 +218,7 @@ func TestCollectRewardToken1Again(t *testing.T) { std.TestSkipHeights(1) gnsNew := gns.BalanceOf(a2u(test1)) - shouldEQ(t, gnsNew, 98500001853) + shouldEQ(t, gnsNew, 98500092566) } func TestCollectExternalReward(t *testing.T) { @@ -242,7 +242,6 @@ func TestCollectAll(t *testing.T) { CollectReward(2) CollectReward(3) std.TestSkipHeights(3) - // claimed all remaining reward } @@ -250,17 +249,17 @@ func TestUnstakeToken1(t *testing.T) { std.TestSetPrevAddr(test1) gnsOld := gns.BalanceOf(a2u(test1)) oblOld := obl.BalanceOf(a2u(test1)) - shouldEQ(t, gnsOld, 98500002180) + shouldEQ(t, gnsOld, 98500108901) shouldEQ(t, oblOld, 499999900000035) std.TestSkipHeights(100000) UnstakeToken(1) gnsNew := gns.BalanceOf(a2u(test1)) - shouldEQ(t, gnsNew, 98500002725) + shouldEQ(t, gnsNew, 98500136126) UnstakeToken(2) gnsNew = gns.BalanceOf(a2u(test1)) - shouldEQ(t, gnsNew, 98500003052) + shouldEQ(t, gnsNew, 98500152461) UnstakeToken(3) oblNew := obl.BalanceOf(a2u(test1)) diff --git a/staker/_TEST_staker_one_external_native_test.gnoa b/staker/_TEST_staker_one_external_native_test.gnoa index 79ef04a7..ca72e5f8 100644 --- a/staker/_TEST_staker_one_external_native_test.gnoa +++ b/staker/_TEST_staker_one_external_native_test.gnoa @@ -42,7 +42,7 @@ func TestPoolInitCreatePool(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) std.TestSkipHeights(1) - pl.CreatePool(barPath, fooPath, 500, 130621891405341611593710811006) // tick 10_000 ≈ x2.7 + pl.CreatePool(barPath, fooPath, 500, "130621891405341611593710811006") // tick 10_000 ≈ x2.7 std.TestSkipHeights(1) } @@ -53,23 +53,23 @@ func TestPositionMint01(t *testing.T) { std.TestSkipHeights(2) lpTokenId, liquidity, amount0, amount1 := pn.Mint( - barPath, // token0 - fooPath, // token1 - uint16(500), // fee - int32(9000), // tickLower - int32(11000), // tickUpper - bigint(1000), // amount0Desired - bigint(1000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min - bigint(2345678901), // deadline + barPath, // token0 + fooPath, // token1 + uint16(500), // fee + int32(9000), // tickLower + int32(11000), // tickUpper + "1000", // amount0Desired + "1000", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, // deadline ) std.TestSkipHeights(1) shouldEQ(t, lpTokenId, 1) shouldEQ(t, gnft.OwnerOf(tid(lpTokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(367)) - shouldEQ(t, amount1, bigint(999)) + shouldEQ(t, amount0, "367") + shouldEQ(t, amount1, "999") // approve nft to staker for staking std.TestSetPrevAddr(test1) @@ -84,23 +84,23 @@ func TestPositionMint02(t *testing.T) { std.TestSkipHeights(2) lpTokenId, liquidity, amount0, amount1 := pn.Mint( - barPath, // token0 - fooPath, // token1 - uint16(500), // fee - int32(9100), // tickLower - int32(12000), // tickUpper - bigint(5000), // amount0Desired - bigint(5000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min - bigint(2345678901), // deadline + barPath, // token0 + fooPath, // token1 + uint16(500), // fee + int32(9100), // tickLower + int32(12000), // tickUpper + "5000", // amount0Desired + "5000", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, // deadline ) std.TestSkipHeights(1) shouldEQ(t, lpTokenId, 2) shouldEQ(t, gnft.OwnerOf(tid(lpTokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(3978)) - shouldEQ(t, amount1, bigint(4999)) + shouldEQ(t, amount0, "3978") + shouldEQ(t, amount1, "4999") // approve nft to staker std.TestSetPrevAddr(test1) @@ -127,7 +127,7 @@ func TestCreateExternalIncentive(t *testing.T) { CreateExternalIncentive( "gno.land/r/demo/bar:gno.land/r/demo/foo:500", // targetPoolPath consts.WRAPPED_WUGNOT, // rewardToken - 10_000_000_000, // rewardAmount + "10000000000", // rewardAmount time.Now().Unix(), // startTimestamp time.Now().Unix()+TIMESTAMP_90DAYS, // endTimestamp ) @@ -154,7 +154,7 @@ func TestStakeToken02(t *testing.T) { func TestUnstakeToken01(t *testing.T) { std.TestSetPrevAddr(consts.INTERNAL_REWARD_ACCOUNT) - gns.Approve(a2u(consts.STAKER_ADDR), uint64(consts.MAX_UINT64)) // internal reward distribution + gns.Approve(a2u(consts.STAKER_ADDR), consts.UINT64_MAX) // internal reward distribution std.TestSkipHeights(1) std.TestSetPrevAddr(test1) @@ -164,8 +164,8 @@ func TestUnstakeToken01(t *testing.T) { shouldEQ(t, gnft.OwnerOf(tid(1)), test1) // check reward - shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500000125) // internal - shouldEQ(t, wugnot.BalanceOf(a2u(test1)), 321) // external + shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500006126) // internal + shouldEQ(t, wugnot.BalanceOf(a2u(test1)), 315) // external } func TestUnstakeToken02(t *testing.T) { @@ -176,8 +176,8 @@ func TestUnstakeToken02(t *testing.T) { shouldEQ(t, gnft.OwnerOf(tid(2)), test1) // check reward - shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500000942) // internal - shouldEQ(t, wugnot.BalanceOf(a2u(test1)), 2421) // external + shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500046964) // internal + shouldEQ(t, wugnot.BalanceOf(a2u(test1)), 2415) // external } func TestEndExternalIncentive(t *testing.T) { diff --git a/staker/_TEST_staker_one_external_test.gnoa b/staker/_TEST_staker_one_external_test.gnoa index 1524274f..99a61003 100644 --- a/staker/_TEST_staker_one_external_test.gnoa +++ b/staker/_TEST_staker_one_external_test.gnoa @@ -44,7 +44,7 @@ func TestPoolInitCreatePool(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) std.TestSkipHeights(1) - pl.CreatePool(fooPath, barPath, 500, 130621891405341611593710811006) // tick 10_000 ≈ x2.7 + pl.CreatePool(fooPath, barPath, 500, "130621891405341611593710811006") // tick 10_000 ≈ x2.7 std.TestSkipHeights(1) } @@ -55,23 +55,23 @@ func TestPositionMint01(t *testing.T) { std.TestSkipHeights(2) lpTokenId, liquidity, amount0, amount1 := pn.Mint( - fooPath, // token0 - barPath, // token1 - uint16(500), // fee - int32(9000), // tickLower - int32(11000), // tickUpper - bigint(1000), // amount0Desired - bigint(1000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min - bigint(2345678901), // deadline + fooPath, // token0 + barPath, // token1 + uint16(500), // fee + int32(9000), // tickLower + int32(11000), // tickUpper + "1000", // amount0Desired + "1000", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, // deadline ) std.TestSkipHeights(1) shouldEQ(t, lpTokenId, 1) shouldEQ(t, gnft.OwnerOf(tid(lpTokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(999)) - shouldEQ(t, amount1, bigint(367)) + shouldEQ(t, amount0, "999") + shouldEQ(t, amount1, "367") // approve nft to staker for staking std.TestSetPrevAddr(test1) @@ -86,23 +86,23 @@ func TestPositionMint02(t *testing.T) { std.TestSkipHeights(2) lpTokenId, liquidity, amount0, amount1 := pn.Mint( - fooPath, // token0 - barPath, // token1 - uint16(500), // fee - int32(9100), // tickLower - int32(12000), // tickUpper - bigint(5000), // amount0Desired - bigint(5000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min - bigint(2345678901), // deadline + fooPath, // token0 + barPath, // token1 + uint16(500), // fee + int32(9100), // tickLower + int32(12000), // tickUpper + "5000", // amount0Desired + "5000", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, // deadline ) std.TestSkipHeights(1) shouldEQ(t, lpTokenId, 2) shouldEQ(t, gnft.OwnerOf(tid(lpTokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(4999)) - shouldEQ(t, amount1, bigint(3978)) + shouldEQ(t, amount0, "4999") + shouldEQ(t, amount1, "3978") // approve nft to staker std.TestSetPrevAddr(test1) @@ -118,7 +118,7 @@ func TestCreateExternalIncentive(t *testing.T) { CreateExternalIncentive( "gno.land/r/demo/bar:gno.land/r/demo/foo:500", // targetPoolPath oblPath, // rewardToken - 10_000_000_000, // rewardAmount + "10000000000", // rewardAmount time.Now().Unix(), // startTimestamp time.Now().Unix()+TIMESTAMP_90DAYS, // endTimestamp ) @@ -157,7 +157,7 @@ func TestApiGetRewardTokens(t *testing.T) { func TestUnstakeToken01(t *testing.T) { std.TestSetPrevAddr(consts.INTERNAL_REWARD_ACCOUNT) - gns.Approve(a2u(consts.STAKER_ADDR), uint64(consts.MAX_UINT64)) // internal reward distribution + gns.Approve(a2u(consts.STAKER_ADDR), consts.UINT64_MAX) // internal reward distribution std.TestSkipHeights(1) std.TestSetPrevAddr(test1) @@ -167,8 +167,8 @@ func TestUnstakeToken01(t *testing.T) { shouldEQ(t, gnft.OwnerOf(tid(1)), test1) // check reward - shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500000125) // internal - shouldEQ(t, obl.BalanceOf(a2u(test1)), 499990000000321) // external + shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500006126) // internal + shouldEQ(t, obl.BalanceOf(a2u(test1)), 499990000000315) // external } func TestUnstakeToken02(t *testing.T) { @@ -179,8 +179,8 @@ func TestUnstakeToken02(t *testing.T) { shouldEQ(t, gnft.OwnerOf(tid(2)), test1) // check reward - shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500000942) // internal - shouldEQ(t, obl.BalanceOf(a2u(test1)), 499990000002421) // external + shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500046964) // internal + shouldEQ(t, obl.BalanceOf(a2u(test1)), 499990000002415) // external } func TestEndExternalIncentive(t *testing.T) { diff --git a/staker/_TEST_staker_one_increase_external_test.gnoa b/staker/_TEST_staker_one_increase_external_test.gnoa index 48629318..70a853e0 100644 --- a/staker/_TEST_staker_one_increase_external_test.gnoa +++ b/staker/_TEST_staker_one_increase_external_test.gnoa @@ -44,7 +44,7 @@ func TestPoolInitCreatePool(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) std.TestSkipHeights(1) - pl.CreatePool(fooPath, barPath, 500, 130621891405341611593710811006) // tick 10_000 ≈ x2.7 + pl.CreatePool(fooPath, barPath, 500, "130621891405341611593710811006") // tick 10_000 ≈ x2.7 std.TestSkipHeights(1) } @@ -55,23 +55,23 @@ func TestPositionMint01(t *testing.T) { std.TestSkipHeights(2) lpTokenId, liquidity, amount0, amount1 := pn.Mint( - fooPath, // token0 - barPath, // token1 - uint16(500), // fee - int32(9000), // tickLower - int32(11000), // tickUpper - bigint(1000), // amount0Desired - bigint(1000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min - bigint(2345678901), // deadline + fooPath, // token0 + barPath, // token1 + uint16(500), // fee + int32(9000), // tickLower + int32(11000), // tickUpper + "1000", // amount0Desired + "1000", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, // deadline ) std.TestSkipHeights(1) shouldEQ(t, lpTokenId, 1) shouldEQ(t, gnft.OwnerOf(tid(lpTokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(999)) - shouldEQ(t, amount1, bigint(367)) + shouldEQ(t, amount0, "999") + shouldEQ(t, amount1, "367") // approve nft to staker for staking std.TestSetPrevAddr(test1) @@ -86,23 +86,23 @@ func TestPositionMint02(t *testing.T) { std.TestSkipHeights(2) lpTokenId, liquidity, amount0, amount1 := pn.Mint( - fooPath, // token0 - barPath, // token1 - uint16(500), // fee - int32(9100), // tickLower - int32(12000), // tickUpper - bigint(5000), // amount0Desired - bigint(5000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min - bigint(2345678901), // deadline + fooPath, // token0 + barPath, // token1 + uint16(500), // fee + int32(9100), // tickLower + int32(12000), // tickUpper + "5000", // amount0Desired + "5000", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, // deadline ) std.TestSkipHeights(1) shouldEQ(t, lpTokenId, 2) shouldEQ(t, gnft.OwnerOf(tid(lpTokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(4999)) - shouldEQ(t, amount1, bigint(3978)) + shouldEQ(t, amount0, "4999") + shouldEQ(t, amount1, "3978") // approve nft to staker std.TestSetPrevAddr(test1) @@ -118,7 +118,7 @@ func TestCreateExternalIncentive(t *testing.T) { CreateExternalIncentive( "gno.land/r/demo/bar:gno.land/r/demo/foo:500", // targetPoolPath oblPath, // rewardToken - 10_000_000_000, // rewardAmount + "10000000000", // rewardAmount time.Now().Unix(), // startTimestamp time.Now().Unix()+TIMESTAMP_90DAYS, // endTimestamp ) @@ -126,7 +126,7 @@ func TestCreateExternalIncentive(t *testing.T) { obl.Approve(a2u(consts.STAKER_ADDR), 10_000_000_000) std.TestSkipHeights(1) - CreateExternalIncentive("gno.land/r/demo/bar:gno.land/r/demo/foo:500", oblPath, 10_000_000_000, time.Now().Unix(), time.Now().Unix()+TIMESTAMP_90DAYS) + CreateExternalIncentive("gno.land/r/demo/bar:gno.land/r/demo/foo:500", oblPath, "10000000000", time.Now().Unix(), time.Now().Unix()+TIMESTAMP_90DAYS) std.TestSkipHeights(1) } @@ -162,7 +162,7 @@ func TestApiGetRewardTokens(t *testing.T) { func TestUnstakeToken01(t *testing.T) { std.TestSetPrevAddr(consts.INTERNAL_REWARD_ACCOUNT) - gns.Approve(a2u(consts.STAKER_ADDR), uint64(consts.MAX_UINT64)) // internal reward distribution + gns.Approve(a2u(consts.STAKER_ADDR), consts.UINT64_MAX) // internal reward distribution std.TestSkipHeights(1) std.TestSetPrevAddr(test1) @@ -172,8 +172,8 @@ func TestUnstakeToken01(t *testing.T) { shouldEQ(t, gnft.OwnerOf(tid(1)), test1) // check reward - shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500000125) // internal - shouldEQ(t, obl.BalanceOf(a2u(test1)), 499980000000642) // external + shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500006126) // internal + shouldEQ(t, obl.BalanceOf(a2u(test1)), 499980000000630) // external } func TestUnstakeToken02(t *testing.T) { @@ -184,8 +184,8 @@ func TestUnstakeToken02(t *testing.T) { shouldEQ(t, gnft.OwnerOf(tid(2)), test1) // check reward - shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500000942) // internal - shouldEQ(t, obl.BalanceOf(a2u(test1)), 499980000004843) // external + shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500046964) // internal + shouldEQ(t, obl.BalanceOf(a2u(test1)), 499980000004831) // external } func TestEndExternalIncentive(t *testing.T) { diff --git a/staker/_TEST_staker_rpc_get_test.gnoa b/staker/_TEST_staker_rpc_get_test.gnoa index a813d657..eccc5d41 100644 --- a/staker/_TEST_staker_rpc_get_test.gnoa +++ b/staker/_TEST_staker_rpc_get_test.gnoa @@ -44,7 +44,7 @@ func TestPoolInitCreatePool(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) std.TestSkipHeights(1) - pl.CreatePool(barPath, quxPath, 500, 130621891405341611593710811006) // tick 10_000 ≈ x2.7 + pl.CreatePool(barPath, quxPath, 500, "130621891405341611593710811006") // tick 10_000 ≈ x2.7 std.TestSkipHeights(1) } func TestPositionMint01(t *testing.T) { @@ -54,23 +54,23 @@ func TestPositionMint01(t *testing.T) { std.TestSkipHeights(2) lpTokenId, liquidity, amount0, amount1 := pn.Mint( - barPath, // token0 - quxPath, // token1 - uint16(500), // fee - int32(9000), // tickLower - int32(11000), // tickUpper - bigint(1000), // amount0Desired - bigint(1000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min - bigint(2345678901), // deadline + barPath, // token0 + quxPath, // token1 + fee500, // fee + int32(9000), // tickLower + int32(11000), // tickUpper + "1000", // amount0Desired + "1000", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, ) std.TestSkipHeights(1) shouldEQ(t, lpTokenId, 1) shouldEQ(t, gnft.OwnerOf(tid(lpTokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(367)) - shouldEQ(t, amount1, bigint(999)) + shouldEQ(t, amount0, "367") + shouldEQ(t, amount1, "999") // approve nft to staker for staking std.TestSetPrevAddr(test1) @@ -85,23 +85,23 @@ func TestPositionMint02(t *testing.T) { std.TestSkipHeights(2) lpTokenId, liquidity, amount0, amount1 := pn.Mint( - barPath, // token0 - quxPath, // token1 - uint16(500), // fee - int32(9100), // tickLower - int32(12000), // tickUpper - bigint(5000), // amount0Desired - bigint(5000), // amount1Desired - bigint(1), // amount0Min - bigint(1), // amount1Min - bigint(2345678901), // deadline + barPath, // token0 + quxPath, // token1 + fee500, // fee + int32(9100), // tickLower + int32(12000), // tickUpper + "5000", // amount0Desired + "5000", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, ) std.TestSkipHeights(1) shouldEQ(t, lpTokenId, 2) shouldEQ(t, gnft.OwnerOf(tid(lpTokenId)), std.GetOrigCaller()) // test1 - shouldEQ(t, amount0, bigint(3978)) - shouldEQ(t, amount1, bigint(4999)) + shouldEQ(t, amount0, "3978") + shouldEQ(t, amount1, "4999") // approve nft to staker std.TestSetPrevAddr(test1) @@ -117,7 +117,7 @@ func TestCreateExternalIncentive(t *testing.T) { CreateExternalIncentive( "gno.land/r/demo/bar:gno.land/r/demo/qux:500", // targetPoolPath oblPath, // rewardToken - 10_000_000_000, // rewardAmount + "10000000000", // rewardAmount time.Now().Unix(), // startTimestamp time.Now().Unix()+TIMESTAMP_90DAYS, // endTimestamp ) @@ -125,7 +125,7 @@ func TestCreateExternalIncentive(t *testing.T) { obl.Approve(a2u(consts.STAKER_ADDR), 10_000_000_000) std.TestSkipHeights(1) - CreateExternalIncentive("gno.land/r/demo/bar:gno.land/r/demo/qux:500", oblPath, 10_000_000_000, time.Now().Unix(), time.Now().Unix()+TIMESTAMP_90DAYS) + CreateExternalIncentive("gno.land/r/demo/bar:gno.land/r/demo/qux:500", oblPath, "10000000000", time.Now().Unix(), time.Now().Unix()+TIMESTAMP_90DAYS) std.TestSkipHeights(1) } @@ -163,7 +163,7 @@ func TestApiGetStakes(t *testing.T) { func TestCollectReward(t *testing.T) { std.TestSetPrevAddr(consts.INTERNAL_REWARD_ACCOUNT) - gns.Approve(a2u(consts.STAKER_ADDR), uint64(consts.MAX_UINT64)) // internal reward distribution + gns.Approve(a2u(consts.STAKER_ADDR), consts.UINT64_MAX) // internal reward distribution std.TestSkipHeights(1) // before claim @@ -175,8 +175,7 @@ func TestCollectReward(t *testing.T) { std.TestSkipHeights(1) gnsNew := gns.BalanceOf(a2u(test1)) - shouldEQ(t, gnsNew, 99500000125) - + shouldEQ(t, gnsNew, 99500006126) } func TestUnstakeToken01(t *testing.T) { @@ -187,8 +186,8 @@ func TestUnstakeToken01(t *testing.T) { shouldEQ(t, gnft.OwnerOf(tid(1)), test1) // check reward - shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500000125) // internal - shouldEQ(t, obl.BalanceOf(a2u(test1)), 499980000000642) // external + shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500006126) // internal + shouldEQ(t, obl.BalanceOf(a2u(test1)), 499980000000630) // external } func TestUnstakeToken02(t *testing.T) { @@ -199,9 +198,9 @@ func TestUnstakeToken02(t *testing.T) { shouldEQ(t, gnft.OwnerOf(tid(2)), test1) // check reward - shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500000942) + shouldEQ(t, gns.BalanceOf(a2u(test1)), 99500046964) // internal - shouldEQ(t, obl.BalanceOf(a2u(test1)), 499980000004843) // external + shouldEQ(t, obl.BalanceOf(a2u(test1)), 499980000004831) // external } func TestEndExternalIncentive(t *testing.T) { diff --git a/staker/reward_fee.gno b/staker/reward_fee.gno index 76ceea94..e9bb9f91 100644 --- a/staker/reward_fee.gno +++ b/staker/reward_fee.gno @@ -6,42 +6,45 @@ import ( "gno.land/r/demo/consts" "gno.land/p/demo/ufmt" + + u256 "gno.land/p/big/uint256" ) var ( - rewardFee = bigint(1) + rewardFee = uint64(1) ) func handleRewardFee( tokenPath string, - amount bigint, + amount *u256.Uint, internal bool, -) bigint { +) *u256.Uint { if rewardFee == 0 { return amount } - feeAmount := amount * rewardFee / bigint(100) + feeAmount := new(u256.Uint).Mul(amount, u256.NewUint(rewardFee)) + feeAmount.Div(feeAmount, u256.NewUint(100)) if internal { // if internal, reward is in IRA - ok := transferFromByRegisterCall(tokenPath, consts.INTERNAL_REWARD_ACCOUNT, consts.FEE_COLLECTOR, uint64(feeAmount)) + ok := transferFromByRegisterCall(tokenPath, consts.INTERNAL_REWARD_ACCOUNT, consts.FEE_COLLECTOR, feeAmount.Uint64()) require(ok, ufmt.Sprintf("[STAKER] reward_fee.gno__HandleRewardFee() || expected transferFromByRegisterCall(%s, %s, %s, %s) == true", tokenPath, consts.INTERNAL_REWARD_ACCOUNT, consts.FEE_COLLECTOR, feeAmount)) } else { // if external, reward is in staker contract - ok := transferByRegisterCall(tokenPath, consts.FEE_COLLECTOR, uint64(feeAmount)) + ok := transferByRegisterCall(tokenPath, consts.FEE_COLLECTOR, feeAmount.Uint64()) require(ok, ufmt.Sprintf("[STAKER] reward_fee.gno__HandleRewardFee() || expected transferByRegisterCall(%s, %s, %s) == true", tokenPath, consts.FEE_COLLECTOR, feeAmount)) } - return amount - feeAmount + return new(u256.Uint).Sub(amount, feeAmount) } -func SetRewardFee(fee bigint) { +func SetRewardFee(fee uint64) { // MUST BE ORIGIN CALL std.AssertOriginCall() // MUST BE ADMIN require(consts.GNOSWAP_ADMIN == std.GetOrigCaller(), ufmt.Sprintf("[STAKER] reward_fee.gno__SetFeeProtocol() || caller(%s) must be admin", std.GetOrigCaller())) - require(fee >= 0, ufmt.Sprintf("[STAKER] reward_fee.gno__SetFeeProtocol() || fee(%d) must be >= 0", fee)) + require(fee >= 0, ufmt.Sprintf("[STAKER] reward_fee.gno__SetFeeProtocol() || fee(%s) must be >= 0", fee)) rewardFee = fee } diff --git a/staker/reward_math.gno b/staker/reward_math.gno index e97063c3..a3d93256 100644 --- a/staker/reward_math.gno +++ b/staker/reward_math.gno @@ -8,27 +8,23 @@ import ( "gno.land/p/demo/ufmt" - pos "gno.land/r/demo/position" -) + u256 "gno.land/p/big/uint256" -const ( - TIMESTAMP_90DAYS = 7776000 - TIMESTAMP_180DAYS = 15552000 - TIMESTAMP_360DAYS = 31104000 + pos "gno.land/r/demo/position" ) -type userClaimedReward map[std.Address]map[uint64]map[string]bigint // address -> lpTokenId -> rewardTokenPath -> rewardTokenAmount +type userClaimedReward map[std.Address]map[uint64]map[string]*u256.Uint // address -> lpTokenId -> rewardTokenPath -> rewardTokenAmount var userClaimedRewards = make(userClaimedReward) -func userClaimedRewardAmount(address std.Address, tokenId uint64, rewardTokenPath string, rewardAmount bigint, claimeRequest bool) bigint { +func userClaimedRewardAmount(address std.Address, tokenId uint64, rewardTokenPath string, rewardAmount *u256.Uint, claimeRequest bool) *u256.Uint { userClaimed, ok := userClaimedRewards[address] // if user(address) ever claimed reward if !ok { - userClaimedRewards[address] = make(map[uint64]map[string]bigint) + userClaimedRewards[address] = make(map[uint64]map[string]*u256.Uint) } claimedPosition, ok := userClaimedRewards[address][tokenId] // if user(address) ever claimed reward from tokenId if !ok { - userClaimedRewards[address][tokenId] = make(map[string]bigint) + userClaimedRewards[address][tokenId] = make(map[string]*u256.Uint) } claimedReward, ok := userClaimedRewards[address][tokenId][rewardTokenPath] // if user(address) ever claimed rewardTokenPath @@ -42,18 +38,20 @@ func userClaimedRewardAmount(address std.Address, tokenId uint64, rewardTokenPat } // user ever claimed rewardTokenPath - var claimableAmount bigint + var claimableAmount *u256.Uint if claimeRequest { // if user is claiming rewardTokenPath - claimableAmount = rewardAmount - claimedReward - userClaimedRewards[address][tokenId][rewardTokenPath] += claimableAmount + claimableAmount = new(u256.Uint).Sub(rewardAmount, claimedReward) + userClaimedRewards[address][tokenId][rewardTokenPath] = new(u256.Uint).Add(userClaimedRewards[address][tokenId][rewardTokenPath], claimableAmount) return claimableAmount } else { // if user is not claiming rewardTokenPath - claimableAmount = rewardAmount - claimedReward + claimableAmount = new(u256.Uint).Sub(rewardAmount, claimedReward) return claimableAmount } } -func rewardMathComputeInternalRewardAmount(tokenId uint64, deposit Deposit) bigint { +func rewardMathComputeInternalRewardAmount(tokenId uint64, deposit Deposit) *u256.Uint { + _q96 := u256.UnsafeFromDecimal(consts.Q96) + // r3v4_xxx: calculate amount of `GNS` to be minted by every block // 1. get block creation time (5s for now) // 2. calculate amount of `GNS` to be minted by every block (10_000 for now) @@ -69,12 +67,13 @@ func rewardMathComputeInternalRewardAmount(tokenId uint64, deposit Deposit) bigi _, poolRatioX96 := getPoolTierAndRatio(poolPath) // get pool reward per block - poolRewardPerBlockX96 := (bigint(blockReward) * consts.Q96) * poolRatioX96 + poolRewardPerBlockX96 := new(u256.Uint).Mul(u256.NewUint(uint64(blockReward)), poolRatioX96) // calculate my reward amount based on my liquidity ratio // this reward is 31days or more staking reward liqRatioX96 := getMyLiquidityRatio(poolPath, tokenId) - myWholeRewardX96 := poolRewardPerBlockX96 * liqRatioX96 + myWholeRewardX96 := new(u256.Uint).Mul(poolRewardPerBlockX96, liqRatioX96) + myWholeRewardX96 = new(u256.Uint).Div(myWholeRewardX96, _q96) // calculate my actual reward amount based on staking duration // !IMPORTANT @@ -87,13 +86,10 @@ func rewardMathComputeInternalRewardAmount(tokenId uint64, deposit Deposit) bigi stakedDuration := endTime - startTime rewardRatio := getRewardRatio(stakedDuration) - finalRewardQ := myWholeRewardX96 * bigint(rewardRatio) - finalReward := finalRewardQ / consts.Q96 / consts.Q96 / consts.Q96 / consts.Q96 / consts.Q96 / 100 / 100 - // divide by (Q96 ^ 5) - // #1 ~ 2: used by getPoolTierAndRatio() - // #3 : used by poolRewardPerBlockX96 - // #4 ~ 5: used by getMyLiquidityRatio() + finalRewardBig := new(u256.Uint).Mul(myWholeRewardX96, u256.NewUint(rewardRatio)) + finalReward := new(u256.Uint).Div(finalRewardBig, _q96) + finalReward = new(u256.Uint).Div(finalReward, u256.NewUint(200)) // divide by (100 ^ 2) // #1: to convert `listTierRatio()` return value to percentage // #2: to convert `getRewardRatio()` return value to percentage @@ -101,17 +97,21 @@ func rewardMathComputeInternalRewardAmount(tokenId uint64, deposit Deposit) bigi return finalReward } -func rewardMathComputeExternalRewardAmount(tokenId uint64, deposit Deposit, incentive Incentive) bigint { +func rewardMathComputeExternalRewardAmount(tokenId uint64, deposit Deposit, incentive Incentive) *u256.Uint { + _q96 := u256.UnsafeFromDecimal(consts.Q96) + // 1 month reward amount incentiveDuration := incentive.endTimestamp - incentive.startTimestamp - monthlyReward := bigint(0) + monthlyReward := u256.Zero() switch { case incentiveDuration == TIMESTAMP_90DAYS: - monthlyReward = incentive.rewardAmount / 3 + monthlyReward = new(u256.Uint).Div(incentive.rewardAmount, u256.NewUint(3)) case incentiveDuration > TIMESTAMP_90DAYS: // 1 second reward == total reward amount / reward duration - monthlyReward = incentive.rewardAmount / bigint(incentiveDuration) * 2592000 // 30 days + _rewardPerSecond := new(u256.Uint).Div(incentive.rewardAmount, u256.NewUint(uint64(incentiveDuration))) + // 30 days ≈ 2592000 seconds + monthlyReward = new(u256.Uint).Mul(_rewardPerSecond, u256.NewUint(2592000)) default: panic(ufmt.Sprintf("[STAKER] reward_math.gno || incentiveDuration(%d) should be at least 90 days", incentiveDuration)) } @@ -121,16 +121,18 @@ func rewardMathComputeExternalRewardAmount(tokenId uint64, deposit Deposit, ince // (for now) block creation time = 5 seconds // 518400(2592000/5) blocks ~= 1 month // 1 month reward / 518400 = reward per block - blockRewardInit := monthlyReward / 518400 - // because of `~ 10 days` staking duration, certain block ONBLOC amount won't be distribute 100% as reward) - blockRewardLeft := blockRewardInit / 10 // obl.BalanceOf(INTERNAL_REWARD_ACCOUNT) - blockRewardInit - blockReward := blockRewardInit + blockRewardLeft - blockRewardX96 := bigint(blockReward) * consts.Q96 + blockRewardInit := new(u256.Uint).Div(monthlyReward, u256.NewUint(518400)) + // because of `~ 10 days` staking duration, certain block's ExternalRewardAmount won't be distribute 100% as reward) + blockRewardLeft := new(u256.Uint).Div(blockRewardInit, u256.NewUint(10)) // obl.BalanceOf(INTERNAL_REWARD_ACCOUNT) - blockRewardInit + blockReward := new(u256.Uint).Add(blockRewardInit, blockRewardLeft) + blockRewardX96 := new(u256.Uint).Mul(blockReward, _q96) // calculate my reward amount based on my liquidity ratio // this reward is 31days or more staking reward liqRatioX96 := getMyLiquidityRatio(incentive.targetPoolPath, tokenId) - myWholeRewardX96 := blockRewardX96 * liqRatioX96 + + myWholeRewardX96 := new(u256.Uint).Mul(blockRewardX96, liqRatioX96) + myWholeRewardX96 = new(u256.Uint).Div(myWholeRewardX96, _q96) // calculate my actual reward amount based on staking duration // !IMPORTANT @@ -142,68 +144,77 @@ func rewardMathComputeExternalRewardAmount(tokenId uint64, deposit Deposit, ince stakedDuration := endTime - startTime rewardRatio := getRewardRatio(stakedDuration) - finalRewardQ := myWholeRewardX96 * bigint(rewardRatio) - finalReward := finalRewardQ / consts.Q96 / consts.Q96 / consts.Q96 / 100 - // why do we need to divide by (96 ^ 3) - // #1 : used by blockRewardX96 - // #2 ~ 3: used by func getMyLiquidityRatio() + finalRewardBig := new(u256.Uint).Mul(myWholeRewardX96, u256.NewUint(rewardRatio)) - // why do we need to divide by 100 + finalReward := new(u256.Uint).Div(finalRewardBig, _q96) + finalReward = new(u256.Uint).Div(finalReward, u256.NewUint(100)) + // divide by 100 // to convert `getRewardRatio()` return value to percentage return finalReward } -func getPoolTotalStakedLiquidity(poolPath string) bigint { - poolStakedLiquidity := bigint(0) +func getPoolTotalStakedLiquidity(poolPath string) *u256.Uint { + poolStakedLiquidity := u256.Zero() // get all staked liquidity for tokenId, deposit := range deposits { // key is tokenId // used in this range loop only if deposit.targetPoolPath == poolPath { tokenLiquidity := pos.PositionGetPositionLiquidity(tokenId) - poolStakedLiquidity += tokenLiquidity + poolStakedLiquidity = new(u256.Uint).Add(poolStakedLiquidity, tokenLiquidity) } } return poolStakedLiquidity } -func getMyLiquidityRatio(poolPath string, tokenId uint64) bigint { +func getMyLiquidityRatio(poolPath string, tokenId uint64) *u256.Uint { + _q96 := u256.UnsafeFromDecimal(consts.Q96) + poolStakedLiquidity := getPoolTotalStakedLiquidity(poolPath) // my(current tokenId) liquidity myLiquidity := pos.PositionGetPositionLiquidity(tokenId) // my liquidity ratio - liqRatioX96 := (myLiquidity * consts.Q96 / poolStakedLiquidity * consts.Q96) // 2 times consts.Q96 because of consts.Q96 / consts.Q96 + myLiquidityX96 := new(u256.Uint).Mul(myLiquidity, _q96) + myLiquidityX96 = new(u256.Uint).Mul(myLiquidityX96, u256.NewUint(100)) // mul `100` to bypass #179 being 0 + + poolStakedLiquidityX96 := new(u256.Uint).Mul(poolStakedLiquidity, _q96) - return liqRatioX96 + myLiquidityRatio := new(u256.Uint).Div(myLiquidityX96, poolStakedLiquidityX96) // this value needs to be divided by 100 + myLiquidityRatio = new(u256.Uint).Mul(myLiquidityRatio, _q96) // so first mul consts.Q96 + myLiquidityRatioX96 := new(u256.Uint).Div(myLiquidityRatio, u256.NewUint(100)) // then divided by 100 + + return myLiquidityRatioX96 } // get current pool tier and reward ratio -func getPoolTierAndRatio(poolPath string) (uint8, bigint) { +func getPoolTierAndRatio(poolPath string) (uint64, *u256.Uint) { + _q96 := u256.UnsafeFromDecimal(consts.Q96) + poolPath = poolKeyDivide(poolPath) // current pool's tier tier, ok := poolTiers[poolPath] if !ok { - return 0, 0 + return 0, u256.Zero() } // that tiers ratio ratio := getTierRatio(tier) - ratioX96 := bigint(uint64(ratio)) * consts.Q96 // first consts.Q96 + ratioX96 := new(u256.Uint).Mul(u256.NewUint(ratio), _q96) // first consts.Q96 // finally current pools ratio numTier1, numTier2, numTier3 := getNumPoolTiers() - var weight bigint + var weight *u256.Uint switch tier { case 1: - weight = ratioX96 / bigint(numTier1) * consts.Q96 // second consts.Q96 + weight = new(u256.Uint).Div(ratioX96, u256.NewUint(numTier1)) case 2: - weight = ratioX96 / bigint(numTier2) * consts.Q96 + weight = new(u256.Uint).Div(ratioX96, u256.NewUint(numTier2)) case 3: - weight = ratioX96 / bigint(numTier3) * consts.Q96 + weight = new(u256.Uint).Div(ratioX96, u256.NewUint(numTier3)) default: panic(ufmt.Sprintf("[STAKER] reward_math.gno__getPoolTierAndRatio() || invalid tier(%d)", tier)) } @@ -259,8 +270,8 @@ func getRewardRatio(timestamp int64) uint64 { return ratio } -func getTierRatio(tier uint8) uint8 { - require(tier >= 1 && tier <= 3, ufmt.Sprintf("[STAKER] staker.gno__getTierRatio() || tier(%d) >= 1 && tier(%d) <= 3", tier, tier)) +func getTierRatio(tier uint64) uint64 { + require(tier >= 1 && tier <= 3, ufmt.Sprintf("[STAKER] reward_math.gno__getTierRatio() || tier(%d) >= 1 && tier(%d) <= 3", tier, tier)) ratio1, ratio2, ratio3 := listTierRatio() switch tier { @@ -271,12 +282,12 @@ func getTierRatio(tier uint8) uint8 { case 3: return ratio3 // default 20 default: - panic("[STAKER] staker.gno__getTierRatio() || invalid ratio") + panic("[STAKER] reward_math.gno__getTierRatio() || invalid ratio") } } // return all ratio for each tier -func listTierRatio() (uint8, uint8, uint8) { +func listTierRatio() (uint64, uint64, uint64) { // basic // tier1 50% // tier2 30% @@ -287,7 +298,7 @@ func listTierRatio() (uint8, uint8, uint8) { // we'll divide by 100 later numTier1, numTier2, numTier3 := getNumPoolTiers() - require(numTier1 > 0, ufmt.Sprintf("[STAKER] staker.gno__listTierRatio() || numTier1(%d) > 0 (numTier2:(%d), numTier3:(%d))", numTier1, numTier2, numTier3)) + require(numTier1 > 0, ufmt.Sprintf("[STAKER] reward_math.gno__listTierRatio() || numTier1(%d) > 0 (numTier2:(%d), numTier3:(%d))", numTier1, numTier2, numTier3)) if numTier2 == 0 && numTier3 == 0 { // only tier 1 exists return 100, 0, 0 @@ -298,6 +309,6 @@ func listTierRatio() (uint8, uint8, uint8) { } else if numTier2 >= 1 && numTier3 >= 1 { // all tiers exists return 50, 30, 20 } else { - panic("[STAKER] staker.gno__listTierRatio() || invalid tier ratio") + panic("[STAKER] reward_math.gno__listTierRatio() || invalid tier ratio") } } diff --git a/staker/staker.gno b/staker/staker.gno index cf82e5cd..4d011023 100644 --- a/staker/staker.gno +++ b/staker/staker.gno @@ -7,13 +7,15 @@ import ( "gno.land/p/demo/common" "gno.land/p/demo/ufmt" - "gno.land/r/demo/consts" - "gno.land/r/demo/gnft" "gno.land/r/demo/gns" + "gno.land/r/demo/consts" + pl "gno.land/r/demo/pool" pn "gno.land/r/demo/position" + + u256 "gno.land/p/big/uint256" ) var ( @@ -21,32 +23,33 @@ var ( incentives map[string]Incentive = make(map[string]Incentive) // incentiveId => Incentive deposits map[uint64]Deposit = make(map[uint64]Deposit) // tokenId => Deposit - poolTiers map[string]uint8 = make(map[string]uint8) // poolPath -> tier + poolTiers map[string]uint64 = make(map[string]uint64) // poolPath -> tier +) + +const ( + TIMESTAMP_90DAYS = 7776000 + TIMESTAMP_180DAYS = 15552000 + TIMESTAMP_360DAYS = 31104000 ) func init() { // init pool tiers // tier 1 - poolTiers["gno.land/r/demo/gns:gno.land/r/demo/wugnot:500"] = 1 // r3v4_xxx: - // poolTiers["gno.land/r/demo/bar:gno.land/r/demo/baz:100"] = 1 // dev - - // tier 2 - // poolTiers["GNS/USDT_500"] = 2 - // poolTiers["ATOM/GNS_500"] = 2 - - // tier 3 - // poolTiers["ATOM/GNOT_500"] = 3 - // poolTiers["ATOM/USDT_500"] = 3 - // poolTiers["ATOM/WETH_500"] = 3 + poolTiers["gno.land/r/demo/gns:gno.land/r/demo/wugnot:500"] = 1 // r3v4_xxx: INITIALIZE TIER 1 POOL } func CreateExternalIncentive( targetPoolPath string, rewardToken string, // token path should be registered - rewardAmount bigint, + _rewardAmount string, startTimestamp int64, endTimestamp int64, ) { + rewardAmount, err := u256.FromDecimal(_rewardAmount) + if err != nil { + panic(ufmt.Sprintf("[STAKER] staker.gno__CreateExternalIncentive() || u256.FromDecimal(_rewardAmount: %s) failed", _rewardAmount)) + } + require(time.Now().Unix() <= startTimestamp, ufmt.Sprintf("[STAKER] staker.gno__CreateExternalIncentive() || startTimestamp must be in the future__time.Now().Unix(%d) <= startTimestamp(%d)", time.Now().Unix(), startTimestamp)) externalDuration := uint64(endTimestamp - startTimestamp) @@ -55,7 +58,7 @@ func CreateExternalIncentive( } fromBalanceBefore := balanceOfByRegisterCall(rewardToken, std.GetOrigCaller()) - require(fromBalanceBefore >= uint64(rewardAmount), ufmt.Sprintf("[STAKER] staker.gno__CreateExternalIncentive() || not enough rewardAmount(%d) to create incentive(%d)", fromBalanceBefore, rewardAmount)) + require(fromBalanceBefore >= rewardAmount.Uint64(), ufmt.Sprintf("[STAKER] staker.gno__CreateExternalIncentive() || not enough rewardAmount(%d) to create incentive(%d)", fromBalanceBefore, rewardAmount.Uint64())) poolRewardBalanceBefore := balanceOfByRegisterCall(rewardToken, GetOrigPkgAddr()) @@ -64,16 +67,19 @@ func CreateExternalIncentive( // if same incentiveId exists => increase rewardTokenAmount for _, v := range poolIncentives[targetPoolPath] { if v == incentiveId { - transferFromByRegisterCall(rewardToken, std.GetOrigCaller(), GetOrigPkgAddr(), uint64(rewardAmount)) - incentives[v].rewardAmount += rewardAmount + transferFromByRegisterCall(rewardToken, std.GetOrigCaller(), GetOrigPkgAddr(), rewardAmount.Uint64()) + incentives[v].rewardAmount = new(u256.Uint).Add(incentives[v].rewardAmount, rewardAmount) return } } - transferFromByRegisterCall(rewardToken, std.GetOrigCaller(), GetOrigPkgAddr(), uint64(rewardAmount)) + transferFromByRegisterCall(rewardToken, std.GetOrigCaller(), GetOrigPkgAddr(), rewardAmount.Uint64()) poolRewardBalanceAfter := balanceOfByRegisterCall(rewardToken, GetOrigPkgAddr()) - require(poolRewardBalanceAfter-poolRewardBalanceBefore == uint64(rewardAmount), ufmt.Sprintf("[STAKER] staker.gno__CreateExternalIncentive() || pool reward balance not updated correctly(before:%d, added:%d, final:%d)", poolRewardBalanceBefore, rewardAmount, poolRewardBalanceAfter)) + require( + poolRewardBalanceAfter-poolRewardBalanceBefore == rewardAmount.Uint64(), + ufmt.Sprintf("[STAKER] staker.gno__CreateExternalIncentive() || pool reward balance not updated correctly(before:%d, added:%d, final:%d)", + poolRewardBalanceBefore, rewardAmount.Uint64(), poolRewardBalanceAfter)) incentives[incentiveId] = Incentive{ targetPoolPath: targetPoolPath, @@ -87,7 +93,7 @@ func CreateExternalIncentive( poolIncentives[targetPoolPath] = append(poolIncentives[targetPoolPath], incentiveId) } -func StakeToken(tokenId uint64) (string, bigint, bigint) { // poolPath, token0Amount, token1Amount +func StakeToken(tokenId uint64) (string, string, string) { // poolPath, token0Amount, token1Amount // check whether tokenId already staked or not _, exist := deposits[tokenId] require(!exist, ufmt.Sprintf("[STAKER] staker.gno__StakeToken() || tokenId(%d) already staked", tokenId)) @@ -102,8 +108,8 @@ func StakeToken(tokenId uint64) (string, bigint, bigint) { // poolPath, token0Am ) // check tokenId has liquidity or not - liquidity := pn.PositionGetPositionLiquidity(tokenId) - require(liquidity > 0, ufmt.Sprintf("[STAKER] staker.gno__StakeToken() || tokenId(%d) has no liquidity", tokenId)) + liquidity := pn.PositionGetPositionLiquidity(tokenId) // *u256.Uint + require(liquidity.Gt(u256.Zero()), ufmt.Sprintf("[STAKER] staker.gno__StakeToken() || tokenId(%d) has no liquidity", tokenId)) // check pool path from tokenid poolKey := pn.PositionGetPositionPoolKey(tokenId) @@ -119,7 +125,7 @@ func StakeToken(tokenId uint64) (string, bigint, bigint) { // poolPath, token0Am transferDeposit(tokenId, GetOrigPkgAddr()) token0Amount, token1Amount := getTokenPairBalanceFromPosition(tokenId) - return poolKey, token0Amount, token1Amount + return poolKey, token0Amount.ToString(), token1Amount.ToString() } func CollectReward(tokenId uint64) { @@ -135,49 +141,48 @@ func CollectReward(tokenId uint64) { for _, incentiveId := range poolIncentives[poolPath] { incentive := incentives[incentiveId] externalReward := rewardMathComputeExternalRewardAmount(tokenId, deposit, incentive) // external reward - externalReward = userClaimedRewardAmount(deposit.owner, tokenId, incentive.rewardToken, bigint(externalReward), true) + externalReward = userClaimedRewardAmount(deposit.owner, tokenId, incentive.rewardToken, externalReward, true) - if externalReward > 0 { + if externalReward.Gt(u256.Zero()) { // protocol fee toUser := handleRewardFee(incentive.rewardToken, externalReward, false) // then transfer rest - transferByRegisterCall(incentive.rewardToken, deposit.owner, uint64(toUser)) + transferByRegisterCall(incentive.rewardToken, deposit.owner, toUser.Uint64()) } - incentive.rewardAmount -= externalReward + incentive.rewardAmount = new(u256.Uint).Sub(incentive.rewardAmount, externalReward) incentives[incentiveId] = incentive } // default `Internal` reward internalGNS := rewardMathComputeInternalRewardAmount(tokenId, deposit) - internalGNS = userClaimedRewardAmount(deposit.owner, tokenId, consts.GNS_PATH, bigint(internalGNS), true) + internalGNS = userClaimedRewardAmount(deposit.owner, tokenId, consts.GNS_PATH, internalGNS, true) - if internalGNS > 0 { + if internalGNS.Gt(u256.Zero()) { // protocol fee toUser := handleRewardFee(consts.GNS_PATH, internalGNS, true) // then transfer rest - gns.TransferFrom(a2u(consts.INTERNAL_REWARD_ACCOUNT), a2u(deposit.owner), uint64(toUser)) + gns.TransferFrom(a2u(consts.INTERNAL_REWARD_ACCOUNT), a2u(deposit.owner), toUser.Uint64()) } - } -func UnstakeToken(tokenId uint64) (string, bigint, bigint) { +func UnstakeToken(tokenId uint64) (string, string, string) { // Claim All Rewards CollectReward(tokenId) // unstaked status deposit, exist := deposits[tokenId] require(exist, ufmt.Sprintf("[STAKER] staker.gno__UnstakeToken() || tokenId(%d) not staked", tokenId)) - deposits = deleteFromDeposits(deposits, tokenId) + delete(deposits, tokenId) // transfer NFT ownership to origin owner gnft.TransferFrom(a2u(GetOrigPkgAddr()), a2u(deposit.owner), tid(tokenId)) poolPath := pn.PositionGetPositionPoolKey(tokenId) token0Amount, token1Amount := getTokenPairBalanceFromPosition(tokenId) - return poolPath, token0Amount, token1Amount + return poolPath, token0Amount.ToString(), token1Amount.ToString() } func EndExternalIncentive(refundee std.Address, targetPoolPath, rewardToken string) { @@ -192,7 +197,7 @@ func EndExternalIncentive(refundee std.Address, targetPoolPath, rewardToken stri switch std.GetOrigCaller() { case consts.GNOSWAP_ADMIN: // admin can end incentive without refund - incentives = deleteFromIncentives(incentives, incentiveId) + delete(incentives, incentiveId) for i, v := range poolIncentives[targetPoolPath] { if v == incentiveId { poolIncentives[targetPoolPath] = append(poolIncentives[targetPoolPath][:i], poolIncentives[targetPoolPath][i+1:]...) @@ -201,11 +206,12 @@ func EndExternalIncentive(refundee std.Address, targetPoolPath, rewardToken stri case incentive.refundee: // refundee can end incentive with refund refund := incentive.rewardAmount + poolLeftExternalRewardAmount := balanceOfByRegisterCall(incentive.rewardToken, GetOrigPkgAddr()) - require(poolLeftExternalRewardAmount >= uint64(refund), ufmt.Sprintf("[STAKER] staker.gno__EndExternalIncentive() || not enough poolLeftExternalRewardAmount(%s_%d) to refund(%d)", incentive.rewardToken, poolLeftExternalRewardAmount, refund)) - transferByRegisterCall(incentive.rewardToken, incentive.refundee, uint64(refund)) + require(poolLeftExternalRewardAmount >= refund.Uint64(), ufmt.Sprintf("[STAKER] staker.gno__EndExternalIncentive() || not enough poolLeftExternalRewardAmount(%s_%d) to refund(%d)", incentive.rewardToken, poolLeftExternalRewardAmount, refund)) + transferByRegisterCall(incentive.rewardToken, incentive.refundee, refund.Uint64()) - incentives = deleteFromIncentives(incentives, incentiveId) + delete(incentives, incentiveId) for i, v := range poolIncentives[targetPoolPath] { if v == incentiveId { poolIncentives[targetPoolPath] = append(poolIncentives[targetPoolPath][:i], poolIncentives[targetPoolPath][i+1:]...) @@ -226,37 +232,7 @@ func transferDeposit(tokenId uint64, to std.Address) { gnft.TransferFrom(a2u(owner), a2u(to), tid(tokenId)) } -func deleteFromDeposits(m map[uint64]Deposit, key uint64) map[uint64]Deposit { - if _, ok := m[key]; ok { - newMap := make(map[uint64]Deposit) - for k, v := range m { - if k != key { - newMap[k] = v - } - } - - return newMap - } - - return m -} - -func deleteFromIncentives(m map[string]Incentive, key string) map[string]Incentive { - if _, ok := m[key]; ok { - newMap := make(map[string]Incentive) - for k, v := range m { - if k != key { - newMap[k] = v - } - } - - return newMap - } - - return m -} - -func getTokenPairBalanceFromPosition(tokenId uint64) (bigint, bigint) { +func getTokenPairBalanceFromPosition(tokenId uint64) (*u256.Uint, *u256.Uint) { poolKey := pn.PositionGetPositionPoolKey(tokenId) pool := pl.GetPoolFromPoolPath(poolKey) diff --git a/staker/type.gno b/staker/type.gno index 4c94051b..7c33430a 100644 --- a/staker/type.gno +++ b/staker/type.gno @@ -2,12 +2,14 @@ package staker import ( "std" + + u256 "gno.land/p/big/uint256" ) type Incentive struct { targetPoolPath string rewardToken string - rewardAmount bigint + rewardAmount *u256.Uint startTimestamp int64 endTimestamp int64 refundee std.Address diff --git a/staker/utils.gno b/staker/utils.gno index 8a01800b..fb1169e3 100644 --- a/staker/utils.gno +++ b/staker/utils.gno @@ -39,8 +39,6 @@ func tid(tokenId interface{}) grc721.TokenID { } switch tokenId.(type) { - case bigint: - return grc721.TokenID(string(tokenId.(bigint))) case string: return grc721.TokenID(tokenId.(string)) case int: From 0372d8253afb385da1c346d895924be9569fc7a9 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 7 Mar 2024 17:08:42 +0900 Subject: [PATCH 2/4] fix all testcase --- ...TEST_scenario_01_full_happy_case_test.gnoa | 48 +-- ...cenario_02_FAIL_too_small_amount_test.gnoa | 4 +- ...ario_03_FAIL_too_small_liquidity_test.gnoa | 4 +- ...ario_04_router_one_route_one_hop_test.gnoa | 14 +- ...ario_05_router_one_route_two_hop_test.gnoa | 16 +- ...uter_one_route_three_hop_println_test.gnoa | 6 +- ...e_three_hop_large_amount_println_test.gnoa | 6 +- ...sition_one_route_one_hop_println_test.gnoa | 6 +- ...uter_only_upper_position_println_test.gnoa | 4 +- ...ST_scenario_99_router_uniswap_sdk_test.gno | 245 ++++++++++++ ...scenario_99_router_uniswap_sdk_test.gnoXXX | 244 ------------ consts/consts.gno | 4 +- packages/big/uint256/uint256.gno | 50 +-- packages/big/uint256/uint256_test.gno | 15 +- packages/big/uint512/consts.gno | 5 + packages/big/uint512/uint512.gno | 86 ++-- packages/big/uint512/uint512_test.gno | 2 +- pool/_RPC_dry.gno | 18 +- pool/_TEST_pool_dryswap_and_swap_test.gno | 36 +- pool/_TEST_pool_multi_token_test.gnoa | 370 ++++++++++++++++++ pool/_TEST_pool_native_swap_test.gn_OK | 34 +- ...est.gno => _TEST_pool_single_lp_test.gnoa} | 123 +----- pool/_TEST_rpc_test.gno | 103 +++++ pool/pool.gno | 4 +- pool/position_modify.gno | 11 - pool/sqrt_price_math.gno | 150 +++---- pool/swap_math.gno | 33 +- pool/tick_bitmap.gno | 4 +- position/_TEST_position_api_test.gnoa | 2 +- ..._TEST_position_increase_decrease_test.gnoa | 32 +- position/_TEST_position_test.gno | 12 +- ...st_two_position_used_single_swap_test.gnoa | 14 +- position/liquidity_management.gno | 3 - position/position.gno | 3 - position/sqrt_price_math.gno | 138 ++++--- router/_RPC_api.gno | 27 +- ..._test.gnoa => _TEST_router_ratio_test.gno} | 56 +-- ...swap_route_1route_1hop_out_range_test.gnoa | 4 +- ...T_router_swap_route_1route_1hop_test.gnoa} | 10 +- ..._route_1route_2hop_native_in_out_test.gnoa | 29 +- ..._route_1route_3hop_native_middle_test.gnoa | 12 +- ...ST_router_swap_route_2route_2hop_test.gnoa | 8 +- 42 files changed, 1183 insertions(+), 812 deletions(-) create mode 100644 _test/_TEST_scenario_99_router_uniswap_sdk_test.gno delete mode 100644 _test/_TEST_scenario_99_router_uniswap_sdk_test.gnoXXX create mode 100644 packages/big/uint512/consts.gno create mode 100644 pool/_TEST_pool_multi_token_test.gnoa rename pool/{_TEST_pool_single_lp_test.gno => _TEST_pool_single_lp_test.gnoa} (72%) create mode 100644 pool/_TEST_rpc_test.gno rename router/{_TEST_router_ratio_test.gnoa => _TEST_router_ratio_test.gno} (64%) rename router/{_TEST_router_swap_route_1route_1hop_test.gno => _TEST_router_swap_route_1route_1hop_test.gnoa} (95%) diff --git a/_test/_TEST_scenario_01_full_happy_case_test.gnoa b/_test/_TEST_scenario_01_full_happy_case_test.gnoa index 869a5eef..9cd49ac0 100644 --- a/_test/_TEST_scenario_01_full_happy_case_test.gnoa +++ b/_test/_TEST_scenario_01_full_happy_case_test.gnoa @@ -103,7 +103,7 @@ func TestPositionMintBarBazInRange(t *testing.T) { shouldEQ(t, tokenId, 1) shouldEQ(t, liquidity, "4473213900") - shouldEQ(t, amount0, "499941") + shouldEQ(t, amount0, "499942") shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) @@ -161,7 +161,7 @@ func TestPositionMintBarBazUpperRange(t *testing.T) { shouldEQ(t, tokenId, 3) shouldEQ(t, liquidity, "470937834") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "0") std.TestSkipHeights(3) @@ -189,7 +189,7 @@ func TestPositionMintBazFooInRange(t *testing.T) { shouldEQ(t, tokenId, 4) shouldEQ(t, liquidity, "3163542978") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "999700") std.TestSkipHeights(3) @@ -226,7 +226,7 @@ func TestPositionMintFooGnotInRange(t *testing.T) { shouldEQ(t, tokenId, 5) shouldEQ(t, liquidity, "45848241") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "499941") std.TestSkipHeights(4) @@ -264,7 +264,7 @@ func TestPositionMintGnsGnotInRange(t *testing.T) { shouldEQ(t, tokenId, 6) shouldEQ(t, liquidity, "205051662") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(4) @@ -319,12 +319,12 @@ func TestApproveGNS(t *testing.T) { func TestStakerCollectInternalReward(t *testing.T) { std.TestSetOrigCaller(lp01) - shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90000001) + shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90000000) shouldEQ(t, obl.BalanceOf(a2u(lp01)), 0) sr.CollectReward(6) - shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90163351) + shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90163350) shouldEQ(t, obl.BalanceOf(a2u(lp01)), 0) std.TestSkipHeights(1) @@ -333,12 +333,12 @@ func TestStakerCollectInternalReward(t *testing.T) { func TestStakerCollectExternalReward(t *testing.T) { std.TestSetOrigCaller(lp01) - shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90163351) + shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90163350) shouldEQ(t, obl.BalanceOf(a2u(lp01)), 0) sr.CollectReward(1) - shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90163351) + shouldEQ(t, gns.BalanceOf(a2u(lp01)), 90163350) shouldEQ(t, obl.BalanceOf(a2u(lp01)), 21) std.TestSkipHeights(1) @@ -427,9 +427,9 @@ func TestRouterSwapRouteBarBazExactOut(t *testing.T) { "100", // quoteArr "100000", // tokenAmountLimit ) - shouldEQ(t, swapResult, "5000") + shouldEQ(t, swapResult, "5001") - shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99895000) + shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99894999) shouldEQ(t, baz.BalanceOf(a2u(tr01)), 102096686) std.TestSkipHeights(2) @@ -442,7 +442,7 @@ func TestRouterSwapRouteBarBazFooWgnotExactIn(t *testing.T) { bar.Approve(a2u(consts.POOL_ADDR), 100000) wugnot.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) - shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99895000) + shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99894999) shouldEQ(t, wugnot.BalanceOf(a2u(tr01)), 0) swapResult := rr.SwapRoute( @@ -456,7 +456,7 @@ func TestRouterSwapRouteBarBazFooWgnotExactIn(t *testing.T) { ) shouldEQ(t, swapResult, "9965") - shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99795000) + shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99794999) shouldEQ(t, wugnot.BalanceOf(a2u(tr01)), 9965) std.TestSkipHeights(2) @@ -479,7 +479,7 @@ func TestRouterSwapRouteWgnotFooBazBarExactIn(t *testing.T) { bar.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) shouldEQ(t, wugnot.BalanceOf(a2u(tr01)), 109965) - shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99795000) + shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99794999) swapResult := rr.SwapRoute( consts.WRAPPED_WUGNOT, // inputToken @@ -490,10 +490,10 @@ func TestRouterSwapRouteWgnotFooBazBarExactIn(t *testing.T) { "100", // quoteArr "300000", // tokenAmountLimit ) - shouldEQ(t, swapResult, "9958") + shouldEQ(t, swapResult, "9984") - shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99894789) - shouldEQ(t, wugnot.BalanceOf(a2u(tr01)), 100007) + shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99894849) + shouldEQ(t, wugnot.BalanceOf(a2u(tr01)), 99981) std.TestSkipHeights(3) } @@ -505,7 +505,7 @@ func TestPositionCollectFeeLpTokenId_1(t *testing.T) { tokenId, amount0, amount1, poolPath := pn.CollectFee(1) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, amount0, "19") + shouldEQ(t, amount0, "17") shouldEQ(t, amount1, "198") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/baz:100") @@ -521,7 +521,7 @@ func TestPositionCollectFeeLpTokenId_4(t *testing.T) { tokenId, amount0, amount1, poolPath := pn.CollectFee(4) shouldEQ(t, tokenId, uint64(4)) - shouldEQ(t, amount0, "198") + shouldEQ(t, amount0, "197") shouldEQ(t, amount1, "20") shouldEQ(t, poolPath, "gno.land/r/demo/baz:gno.land/r/demo/foo:100") @@ -533,7 +533,7 @@ func TestPositionCollectFeeLpTokenId_5(t *testing.T) { tokenId, amount0, amount1, poolPath := pn.CollectFee(5) shouldEQ(t, tokenId, uint64(5)) - shouldEQ(t, amount0, "19") + shouldEQ(t, amount0, "18") shouldEQ(t, amount1, "0") shouldEQ(t, poolPath, "gno.land/r/demo/foo:gno.land/r/demo/wugnot:100") @@ -562,8 +562,8 @@ func TestStakerUnstake(t *testing.T) { // it will return unstaked position's poolPath, amount0, amount1 ( not reward ) poolPath, amount0, amount1 := sr.UnstakeToken(1) shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/baz:100") - shouldEQ(t, amount0, "604982") - shouldEQ(t, amount1, "7899135") + shouldEQ(t, amount0, "604922") + shouldEQ(t, amount1, "7900345") std.TestSkipHeights(1) } @@ -578,8 +578,8 @@ func TestPositionDecreaseLiquidityUnstakedPosition(t *testing.T) { ) shouldEQ(t, tokenId, uint64(1)) shouldEQ(t, liquidity, "4473213900") - shouldEQ(t, amount0, "604982") - shouldEQ(t, amount1, "7899135") + shouldEQ(t, amount0, "604922") + shouldEQ(t, amount1, "7900345") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/baz:100") std.TestSkipHeights(1) diff --git a/_test/_TEST_scenario_02_FAIL_too_small_amount_test.gnoa b/_test/_TEST_scenario_02_FAIL_too_small_amount_test.gnoa index 44f11732..9badd26c 100644 --- a/_test/_TEST_scenario_02_FAIL_too_small_amount_test.gnoa +++ b/_test/_TEST_scenario_02_FAIL_too_small_amount_test.gnoa @@ -87,7 +87,7 @@ func TestPositionMintBarBazInRange(t *testing.T) { shouldEQ(t, tokenId, 1) shouldEQ(t, liquidity, "4473213900") - shouldEQ(t, amount0, "499941") + shouldEQ(t, amount0, "499942") shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) @@ -115,7 +115,7 @@ func TestPositionMintBazFooInRange(t *testing.T) { shouldEQ(t, tokenId, 2) shouldEQ(t, liquidity, "205051662") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) diff --git a/_test/_TEST_scenario_03_FAIL_too_small_liquidity_test.gnoa b/_test/_TEST_scenario_03_FAIL_too_small_liquidity_test.gnoa index 3fa9808b..b74d076c 100644 --- a/_test/_TEST_scenario_03_FAIL_too_small_liquidity_test.gnoa +++ b/_test/_TEST_scenario_03_FAIL_too_small_liquidity_test.gnoa @@ -86,7 +86,7 @@ func TestPositionMintBarBazInRange(t *testing.T) { shouldEQ(t, tokenId, 1) shouldEQ(t, liquidity, "4473213900") - shouldEQ(t, amount0, "499941") + shouldEQ(t, amount0, "499942") shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) @@ -114,7 +114,7 @@ func TestPositionMintBazFooInRange(t *testing.T) { shouldEQ(t, tokenId, 2) shouldEQ(t, liquidity, "205051662") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) diff --git a/_test/_TEST_scenario_04_router_one_route_one_hop_test.gnoa b/_test/_TEST_scenario_04_router_one_route_one_hop_test.gnoa index cc8b1b99..0afedb64 100644 --- a/_test/_TEST_scenario_04_router_one_route_one_hop_test.gnoa +++ b/_test/_TEST_scenario_04_router_one_route_one_hop_test.gnoa @@ -98,7 +98,7 @@ func TestpnitionMintBarBazInRange(t *testing.T) { shouldEQ(t, tokenId, 1) shouldEQ(t, liquidity, "4473213900") - shouldEQ(t, amount0, "499941") + shouldEQ(t, amount0, "499942") shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) @@ -156,7 +156,7 @@ func TestpnitionMintBarBazUpperRange(t *testing.T) { shouldEQ(t, tokenId, 3) shouldEQ(t, liquidity, "470937834") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "0") std.TestSkipHeights(3) @@ -184,7 +184,7 @@ func TestpnitionMintBazFooInRange(t *testing.T) { shouldEQ(t, tokenId, 4) shouldEQ(t, liquidity, "3163542978") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "999700") std.TestSkipHeights(3) @@ -221,7 +221,7 @@ func TestpnitionMintFooGnotInRange(t *testing.T) { shouldEQ(t, tokenId, 5) shouldEQ(t, liquidity, "45848241") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "499941") std.TestSkipHeights(4) @@ -358,7 +358,7 @@ func TestRouterDrySwapRouteBarBazExactOutAfterSwap(t *testing.T) { "gno.land/r/demo/bar:gno.land/r/demo/baz:100", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, "5000") + shouldEQ(t, dryResult, "5001") std.TestSkipHeights(2) } @@ -381,9 +381,9 @@ func TestRouterSwapRouteBarBazExactOutAfterSwap(t *testing.T) { "100", // quoteArr "5001", // tokenAmountLimit (maxSpent) ) - shouldEQ(t, swapResult, "5000") + shouldEQ(t, swapResult, "5001") - shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99895000) + shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99894999) shouldEQ(t, baz.BalanceOf(a2u(tr01)), 102096686) std.TestSkipHeights(2) diff --git a/_test/_TEST_scenario_05_router_one_route_two_hop_test.gnoa b/_test/_TEST_scenario_05_router_one_route_two_hop_test.gnoa index 46b5de0b..0d48faa9 100644 --- a/_test/_TEST_scenario_05_router_one_route_two_hop_test.gnoa +++ b/_test/_TEST_scenario_05_router_one_route_two_hop_test.gnoa @@ -98,7 +98,7 @@ func TestPositionMintBarBazInRange(t *testing.T) { shouldEQ(t, tokenId, 1) shouldEQ(t, liquidity, "4473213900") - shouldEQ(t, amount0, "499941") + shouldEQ(t, amount0, "499942") shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) @@ -156,7 +156,7 @@ func TestPositionMintBarBazUpperRange(t *testing.T) { shouldEQ(t, tokenId, 3) shouldEQ(t, liquidity, "470937834") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "0") std.TestSkipHeights(3) @@ -184,7 +184,7 @@ func TestPositionMintBazFooInRange(t *testing.T) { shouldEQ(t, tokenId, 4) shouldEQ(t, liquidity, "3163542978") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "999700") std.TestSkipHeights(3) @@ -221,7 +221,7 @@ func TestPositionMintFooGnotInRange(t *testing.T) { shouldEQ(t, tokenId, 5) shouldEQ(t, liquidity, "45848241") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "499941") std.TestSkipHeights(4) @@ -348,7 +348,7 @@ func TestRouterDrySwapRouteBarFooExactOutAfterSwap(t *testing.T) { "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, "50056") + shouldEQ(t, dryResult, "50057") std.TestSkipHeights(2) } @@ -369,11 +369,11 @@ func TestRouterSwapRouteBarFooExactOutAfterSwap(t *testing.T) { "EXACT_OUT", // swapType "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr "100", // quoteArr - "50056", // maxSpent + "50057", // maxSpent ) - shouldEQ(t, swapResult, "50056") + shouldEQ(t, swapResult, "50057") - shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99849944) + shouldEQ(t, bar.BalanceOf(a2u(tr01)), 99849943) shouldEQ(t, foo.BalanceOf(a2u(tr01)), 100299414) std.TestSkipHeights(2) diff --git a/_test/_TEST_scenario_06_router_one_route_three_hop_println_test.gnoa b/_test/_TEST_scenario_06_router_one_route_three_hop_println_test.gnoa index bf6c5958..28c66bf5 100644 --- a/_test/_TEST_scenario_06_router_one_route_three_hop_println_test.gnoa +++ b/_test/_TEST_scenario_06_router_one_route_three_hop_println_test.gnoa @@ -92,7 +92,7 @@ func TestPositionMintBarBazInRange(t *testing.T) { shouldEQ(t, tokenId, 1) shouldEQ(t, liquidity, "4473213900") - shouldEQ(t, amount0, "499941") + shouldEQ(t, amount0, "499942") shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) @@ -120,7 +120,7 @@ func TestPositionMintBazFooInRange(t *testing.T) { shouldEQ(t, tokenId, 2) shouldEQ(t, liquidity, "3163542978") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "999700") std.TestSkipHeights(3) @@ -148,7 +148,7 @@ func TestPositionMintFooQuxInRange(t *testing.T) { shouldEQ(t, tokenId, 3) shouldEQ(t, liquidity, "2237166073") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "499941") std.TestSkipHeights(3) diff --git a/_test/_TEST_scenario_07_FAIL_router_one_route_three_hop_large_amount_println_test.gnoa b/_test/_TEST_scenario_07_FAIL_router_one_route_three_hop_large_amount_println_test.gnoa index 0de0b4a4..714ce595 100644 --- a/_test/_TEST_scenario_07_FAIL_router_one_route_three_hop_large_amount_println_test.gnoa +++ b/_test/_TEST_scenario_07_FAIL_router_one_route_three_hop_large_amount_println_test.gnoa @@ -93,7 +93,7 @@ func TestPositionMintBarBazInRange(t *testing.T) { shouldEQ(t, tokenId, 1) shouldEQ(t, liquidity, "4473213900") - shouldEQ(t, amount0, "499941") + shouldEQ(t, amount0, "499942") shouldEQ(t, amoutn1, "9999999") std.TestSkipHeights(3) @@ -121,7 +121,7 @@ func TestPositionMintBazFooInRange(t *testing.T) { shouldEQ(t, tokenId, 2) shouldEQ(t, liquidity, "3163542978") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "999700") std.TestSkipHeights(3) @@ -149,7 +149,7 @@ func TestPositionMintFooQuxInRange(t *testing.T) { shouldEQ(t, tokenId, 3) shouldEQ(t, liquidity, "2237166073") - shouldEQ(t, amount0, "9999999") + shouldEQ(t, amount0, "10000000") shouldEQ(t, amoutn1, "499941") std.TestSkipHeights(3) diff --git a/_test/_TEST_scenario_08_router_two_position_one_route_one_hop_println_test.gnoa b/_test/_TEST_scenario_08_router_two_position_one_route_one_hop_println_test.gnoa index 5b1b2a8c..6ddac26f 100644 --- a/_test/_TEST_scenario_08_router_two_position_one_route_one_hop_println_test.gnoa +++ b/_test/_TEST_scenario_08_router_two_position_one_route_one_hop_println_test.gnoa @@ -77,7 +77,7 @@ func TestPositionMintBarBazInRange(t *testing.T) { ) shouldEQ(t, tokenId, 1) shouldEQ(t, liquidity, "447321") - shouldEQ(t, amount0, "49") + shouldEQ(t, amount0, "50") shouldEQ(t, amoutn1, "999") std.TestSkipHeights(3) @@ -104,8 +104,8 @@ func TestPositionMintBarBazInRangeMore(t *testing.T) { ) shouldEQ(t, tokenId, 2) shouldEQ(t, liquidity, "447321") - shouldEQ(t, amount0, "49") - shouldEQ(t, amoutn1, "999") + shouldEQ(t, amount0, "50") + shouldEQ(t, amoutn1, "1000") std.TestSkipHeights(3) diff --git a/_test/_TEST_scenario_98_router_only_upper_position_println_test.gnoa b/_test/_TEST_scenario_98_router_only_upper_position_println_test.gnoa index 881d9d27..4baf4578 100644 --- a/_test/_TEST_scenario_98_router_only_upper_position_println_test.gnoa +++ b/_test/_TEST_scenario_98_router_only_upper_position_println_test.gnoa @@ -107,9 +107,9 @@ func TestPositionMintBarBazUpperRange(t *testing.T) { "0", // amount1Min max_timeout, // deadline ) - // shouldEQ(t, tokenId, "2")) + // shouldEQ(t, tokenId, "2") shouldEQ(t, liquidity, "24723") - shouldEQ(t, amount0, "999") + shouldEQ(t, amount0, "1000") shouldEQ(t, amoutn1, "0") poolBar := bar.BalanceOf(a2u(consts.POOL_ADDR)) diff --git a/_test/_TEST_scenario_99_router_uniswap_sdk_test.gno b/_test/_TEST_scenario_99_router_uniswap_sdk_test.gno new file mode 100644 index 00000000..f75a75f5 --- /dev/null +++ b/_test/_TEST_scenario_99_router_uniswap_sdk_test.gno @@ -0,0 +1,245 @@ +/* +UNISWAP TEST REF + - https://github.com/Uniswap/v3-core/blob/main/test/shared/fixtures.ts + - https://github.com/Uniswap/v3-core/blob/main/test/UniswapV3Router.spec.ts + - https://github.com/Uniswap/router-sdk/blob/main/src/swapRouter.test.ts +*/ +package swap_scenario + +import ( + "std" + "testing" + + "gno.land/p/demo/testutils" + + "gno.land/r/demo/consts" + + pl "gno.land/r/demo/pool" + pn "gno.land/r/demo/position" + rr "gno.land/r/demo/router" + + "gno.land/r/demo/bar" + "gno.land/r/demo/baz" + "gno.land/r/demo/foo" + + "gno.land/r/demo/gns" +) + +var ( + lp01 = testutils.TestAddress("lp01") + tr01 = testutils.TestAddress("tr01") + + // vars from Uniswap TEST + feeAmount uint32 = 3000 + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L24 + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/shared/utilities.ts#L23 + + tickSpacing = 60 + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L25 + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/shared/utilities.ts#L29 + + minTick int32 = -887272 + maxTick int32 = 887272 + // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/shared/utilities.ts#L10-L11 +) + +func TestPoolInitByAdmin(t *testing.T) { + std.TestSetOrigCaller(gsa) + pl.InitManual() + + std.TestSkipHeights(1) +} + +func TestPoolCreatePools(t *testing.T) { + std.TestSetPrevAddr(test1) + gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*2) + + // bar-baz + pl.CreatePool(barPath, bazPath, 100, "79228162514264337593543950337") // tick 0 ≈ 1:1 + + // baz-foo + pl.CreatePool(bazPath, fooPath, 100, "79228162514264337593543950337") // tick 0 ≈ 1:1 + + std.TestSkipHeights(4) +} + +func TestFaucetLP01(t *testing.T) { + std.TestSetOrigCaller(lp01) + + shouldEQ(t, bar.BalanceOf(a2u(lp01)), 0) + shouldEQ(t, baz.BalanceOf(a2u(lp01)), 0) + shouldEQ(t, foo.BalanceOf(a2u(lp01)), 0) + + bar.Faucet(lp01) + baz.Faucet(lp01) + foo.Faucet(lp01) + + shouldEQ(t, bar.BalanceOf(a2u(lp01)), 100000000) + shouldEQ(t, baz.BalanceOf(a2u(lp01)), 100000000) + shouldEQ(t, foo.BalanceOf(a2u(lp01)), 100000000) + std.TestSkipHeights(5) +} + +// https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L83C16-L83C16 +func TestPositionMintBarBazInRange(t *testing.T) { + std.TestSetOrigCaller(lp01) + + // approve bar, baz to pool ( position.Mint() calls pool.Mint() ≈ so approve to pool ) + bar.Approve(a2u(consts.POOL_ADDR), 10000000) + baz.Approve(a2u(consts.POOL_ADDR), 10000000) + + tokenId, liquidity, amount0, amoutn1 := pn.Mint( + barPath, // token0 + bazPath, // token1 + 100, // fee + minTick, // tickLower + maxTick, // tickUpper + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min + max_timeout, // deadline + ) + + shouldEQ(t, tokenId, 1) + shouldEQ(t, liquidity, "10000000") + shouldEQ(t, amount0, "10000000") + shouldEQ(t, amoutn1, "9999999") + + std.TestSkipHeights(3) +} + +// https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L84 +func TestPositionMintBazFooInRange(t *testing.T) { + std.TestSetOrigCaller(lp01) + + // approve bar, baz to pool ( position.Mint() calls pool.Mint() ≈ so approve to pool ) + baz.Approve(a2u(consts.POOL_ADDR), 10000000) + foo.Approve(a2u(consts.POOL_ADDR), 10000000) + + tokenId, liquidity, amount0, amoutn1 := pn.Mint( + bazPath, // token0 + fooPath, // token1 + 100, // fee + minTick, // tickLower + maxTick, // tickUpper + "10000000", // amount0Desired + "10000000", // amount1Desired + "0", // amount0Min + "0", // amount1Min + max_timeout, // deadline + ) + + shouldEQ(t, tokenId, 2) + shouldEQ(t, liquidity, "10000000") + shouldEQ(t, amount0, "10000000") + shouldEQ(t, amoutn1, "9999999") + + std.TestSkipHeights(3) +} + +func TestFaucetTR01(t *testing.T) { + std.TestSetOrigCaller(tr01) + + shouldEQ(t, bar.BalanceOf(a2u(tr01)), 0) + + bar.Faucet(tr01) + + shouldEQ(t, bar.BalanceOf(a2u(tr01)), 100000000) + + std.TestSkipHeights(5) +} + +func TestRouterDrySwapRouteBarFooExactIn(t *testing.T) { + std.TestSetOrigCaller(tr01) + + dryResult := rr.DrySwapRoute( + barPath, // inputToken + fooPath, // outputToken + "100000", // amountSpecified + "EXACT_IN", // swapType + "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr + "100", // quoteArr + ) + shouldEQ(t, dryResult, "98019") + std.TestSkipHeights(2) +} + +func TestRouterSwapRouteBarFooExactIn(t *testing.T) { + std.TestSetOrigCaller(tr01) + + // approve bar to pool + bar.Approve(a2u(consts.POOL_ADDR), 100000) + foo.Approve(a2u(consts.ROUTER_ADDR), 148) // 0.15% of 98019 + + barOld := bar.BalanceOf(a2u(tr01)) + fooOld := foo.BalanceOf(a2u(tr01)) + shouldEQ(t, barOld, 100000000) + shouldEQ(t, fooOld, 0) + + swapResult := rr.SwapRoute( + barPath, // inputToken + fooPath, // outputToken + "100000", // amountSpecified + "EXACT_IN", // swapType + "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr + "100", // quoteArr + "1", // tokenAmountLimit (minRecv) + ) + shouldEQ(t, swapResult, "97872") + + barNew := bar.BalanceOf(a2u(tr01)) + fooNew := foo.BalanceOf(a2u(tr01)) + + shouldEQ(t, barOld-barNew, 100000) + shouldEQ(t, fooNew-fooOld, 97872) + + std.TestSkipHeights(2) +} + +func TestRouterDrySwapRouteBarFooExactOutAfterSwap(t *testing.T) { + std.TestSetOrigCaller(tr01) + + dryResult := rr.DrySwapRoute( + barPath, // inputToken + fooPath, // outputToken + "100000", // amountSpecified + "EXACT_OUT", // swapType + "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr + "100", // quoteArr + ) + shouldEQ(t, dryResult, "106228") + std.TestSkipHeights(2) +} + +func TestRouterSwapRouteBarFooExactOutAfterSwap(t *testing.T) { + std.TestSetOrigCaller(tr01) + + // approve bar to pool + bar.Approve(a2u(consts.POOL_ADDR), 106228) + foo.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) + + barOld := bar.BalanceOf(a2u(tr01)) + fooOld := foo.BalanceOf(a2u(tr01)) + shouldEQ(t, barOld, 99900000) + shouldEQ(t, fooOld, 97872) + + swapResult := rr.SwapRoute( + barPath, // inputToken + fooPath, // outputToken + "100000", // amountSpecified + "EXACT_OUT", // swapType + "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr + "100", // quoteArr + "123456", // tokenAmountLimit (maxSpent) + ) + shouldEQ(t, swapResult, "106228") + + barNew := bar.BalanceOf(a2u(tr01)) + fooNew := foo.BalanceOf(a2u(tr01)) + + shouldEQ(t, barOld-barNew, 106228) + shouldEQ(t, fooNew-fooOld, 99850) + + std.TestSkipHeights(2) +} diff --git a/_test/_TEST_scenario_99_router_uniswap_sdk_test.gnoXXX b/_test/_TEST_scenario_99_router_uniswap_sdk_test.gnoXXX deleted file mode 100644 index 8d9b5718..00000000 --- a/_test/_TEST_scenario_99_router_uniswap_sdk_test.gnoXXX +++ /dev/null @@ -1,244 +0,0 @@ -/* -UNISWAP TEST REF - - https://github.com/Uniswap/v3-core/blob/main/test/shared/fixtures.ts - - https://github.com/Uniswap/v3-core/blob/main/test/UniswapV3Router.spec.ts - - https://github.com/Uniswap/router-sdk/blob/main/src/swapRouter.test.ts -*/ -package swap_scenario - -import ( - "std" - "testing" - - "gno.land/p/demo/testutils" - - "gno.land/r/demo/consts" - - pl "gno.land/r/demo/pool" - pn "gno.land/r/demo/position" - - "gno.land/r/demo/bar" - "gno.land/r/demo/baz" - "gno.land/r/demo/foo" - - "gno.land/r/demo/gns" -) - -var ( - lp01 = testutils.TestAddress("lp01") - tr01 = testutils.TestAddress("tr01") - - // vars from Uniswap TEST - feeAmount uint32 = 3000 - // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L24 - // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/shared/utilities.ts#L23 - - tickSpacing = 60 - // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L25 - // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/shared/utilities.ts#L29 - - minTick int32 = -887272 - maxTick int32 = 887272 - // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/shared/utilities.ts#L10-L11 -) - -func TestPoolInitByAdmin(t *testing.T) { - std.TestSetOrigCaller(gsa) - pl.InitManual() - - std.TestSkipHeights(1) -} - -func TestPoolCreatePools(t *testing.T) { - std.TestSetPrevAddr(test1) - gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*2) - - // bar-baz - pl.CreatePool(barPath, bazPath, 100, "79228162514264337593543950337") // tick 0 ≈ 1:1 - - // baz-foo - // pl.CreatePool(bazPath, fooPath, 100, "79228162514264337593543950337") // tick 0 ≈ 1:1 - - std.TestSkipHeights(4) -} - -func TestFaucetLP01(t *testing.T) { - std.TestSetOrigCaller(lp01) - - shouldEQ(t, bar.BalanceOf(a2u(lp01)), 0) - shouldEQ(t, baz.BalanceOf(a2u(lp01)), 0) - shouldEQ(t, foo.BalanceOf(a2u(lp01)), 0) - - bar.Faucet(lp01) - baz.Faucet(lp01) - foo.Faucet(lp01) - - shouldEQ(t, bar.BalanceOf(a2u(lp01)), 100000000) - shouldEQ(t, baz.BalanceOf(a2u(lp01)), 100000000) - shouldEQ(t, foo.BalanceOf(a2u(lp01)), 100000000) - std.TestSkipHeights(5) -} - -// https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L83C16-L83C16 -func TestPositionMintBarBazInRange(t *testing.T) { - std.TestSetOrigCaller(lp01) - - // approve bar, baz to pool ( position.Mint() calls pool.Mint() ≈ so approve to pool ) - bar.Approve(a2u(consts.POOL_ADDR), 10000000) - baz.Approve(a2u(consts.POOL_ADDR), 10000000) - - tokenId, liquidity, amount0, amoutn1 := pn.Mint( - barPath, // token0 - bazPath, // token1 - 100, // fee - minTick, // tickLower - maxTick, // tickUpper - "10000000", // amount0Desired - "10000000", // amount1Desired - "0", // amount0Min - "0", // amount1Min - max_timeout, // deadline - ) - - shouldEQ(t, tokenId, 1) - shouldEQ(t, liquidity, "10000000") - shouldEQ(t, amount0, "9999999") - shouldEQ(t, amoutn1, "9999999") - - std.TestSkipHeights(3) -} - -// // https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/test/UniswapV3Router.spec.ts#L84 -// func TestPositionMintBazFooInRange(t *testing.T) { -// std.TestSetOrigCaller(lp01) - -// // approve bar, baz to pool ( position.Mint() calls pool.Mint() ≈ so approve to pool ) -// baz.Approve(a2u(consts.POOL_ADDR), 10000000) -// foo.Approve(a2u(consts.POOL_ADDR), 10000000) - -// tokenId, liquidity, amount0, amoutn1 := pn.Mint( -// bazPath, // token0 -// fooPath, // token1 -// 100, // fee -// minTick, // tickLower -// maxTick, // tickUpper -// "10000000", // amount0Desired -// "10000000", // amount1Desired -// "0", // amount0Min -// "0", // amount1Min -// max_timeout, // deadline -// ) - -// shouldEQ(t, tokenId, 2) -// shouldEQ(t, liquidity, "10000000") -// shouldEQ(t, amount0, "9999999") -// shouldEQ(t, amoutn1, "9999999") - -// std.TestSkipHeights(3) -// } - -// func TestFaucetTR01(t *testing.T) { -// std.TestSetOrigCaller(tr01) - -// shouldEQ(t, bar.BalanceOf(a2u(tr01)), 0) - -// bar.Faucet(tr01) - -// shouldEQ(t, bar.BalanceOf(a2u(tr01)), 100000000) - -// std.TestSkipHeights(5) -// } - -// func TestRouterDrySwapRouteBarFooExactIn(t *testing.T) { -// std.TestSetOrigCaller(tr01) - -// dryResult := rr.DrySwapRoute( -// barPath, // inputToken -// fooPath, // outputToken -// "100000", // amountSpecified -// "EXACT_IN", // swapType -// "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr -// "100", // quoteArr -// ) -// shouldEQ(t, dryResult, "98019") -// std.TestSkipHeights(2) -// } - -// func TestRouterSwapRouteBarFooExactIn(t *testing.T) { -// std.TestSetOrigCaller(tr01) - -// // approve bar to pool -// bar.Approve(a2u(consts.POOL_ADDR), 100000) -// foo.Approve(a2u(consts.ROUTER_ADDR), 148) // 0.15% of 98019 - -// barOld := bar.BalanceOf(a2u(tr01)) -// fooOld := foo.BalanceOf(a2u(tr01)) -// shouldEQ(t, barOld, 100000000) -// shouldEQ(t, fooOld, 0) - -// swapResult := rr.SwapRoute( -// barPath, // inputToken -// fooPath, // outputToken -// "100000", // amountSpecified -// "EXACT_IN", // swapType -// "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr -// "100", // quoteArr -// "1", // tokenAmountLimit (minRecv) -// ) -// shouldEQ(t, swapResult, "97872") - -// barNew := bar.BalanceOf(a2u(tr01)) -// fooNew := foo.BalanceOf(a2u(tr01)) - -// shouldEQ(t, barOld-barNew, 100000) -// shouldEQ(t, fooNew-fooOld, 97872) - -// std.TestSkipHeights(2) -// } - -// func TestRouterDrySwapRouteBarFooExactOutAfterSwap(t *testing.T) { -// std.TestSetOrigCaller(tr01) - -// dryResult := rr.DrySwapRoute( -// barPath, // inputToken -// fooPath, // outputToken -// "100000", // amountSpecified -// "EXACT_OUT", // swapType -// "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr -// "100", // quoteArr -// ) -// shouldEQ(t, dryResult, "106226") -// std.TestSkipHeights(2) -// } - -// func TestRouterSwapRouteBarFooExactOutAfterSwap(t *testing.T) { -// std.TestSetOrigCaller(tr01) - -// // approve bar to pool -// bar.Approve(a2u(consts.POOL_ADDR), 106226) -// foo.Approve(a2u(consts.ROUTER_ADDR), consts.UINT64_MAX) - -// barOld := bar.BalanceOf(a2u(tr01)) -// fooOld := foo.BalanceOf(a2u(tr01)) -// shouldEQ(t, barOld, 99900000) -// shouldEQ(t, fooOld, 97872) - -// swapResult := rr.SwapRoute( -// barPath, // inputToken -// fooPath, // outputToken -// "100000", // amountSpecified -// "EXACT_OUT", // swapType -// "gno.land/r/demo/bar:gno.land/r/demo/baz:100*POOL*gno.land/r/demo/baz:gno.land/r/demo/foo:100", // strRouteArr -// "100", // quoteArr -// "123456", // tokenAmountLimit (maxSpent) -// ) -// shouldEQ(t, swapResult, "106226") - -// barNew := bar.BalanceOf(a2u(tr01)) -// fooNew := foo.BalanceOf(a2u(tr01)) - -// shouldEQ(t, barOld-barNew, 106226) -// shouldEQ(t, fooNew-fooOld, 99849) - -// std.TestSkipHeights(2) -// } diff --git a/consts/consts.gno b/consts/consts.gno index 3b1eb7fa..ff6ab49f 100644 --- a/consts/consts.gno +++ b/consts/consts.gno @@ -6,7 +6,7 @@ import ( // MOST LIKELY FIXED, BUT CHANGABLE VIA GOVERNANCE var ( - PROTOCOL_FEE_ROUTER = 15 // 0.15% + PROTOCOL_FEE_ROUTER uint64 = 15 // 0.15% ) // GNOSWAP SERVICE @@ -14,7 +14,7 @@ const ( GNOSWAP_ADMIN std.Address = "g12l9splsyngcgefrwa52x5a7scc29e9v086m6p4" // GSA, r3v4_xxx: CHANGE WHEN DEPLOYING TO OFFICIAL NETWORK FEE_COLLECTOR std.Address = "g12l9splsyngcgefrwa52x5a7scc29e9v086m6p4" // SAME AS GSA FOR NOW, r3v4_xxx: CHANGE WHEN DEPLOYING TO OFFICIAL NETWORK - INTERNAL_REWARD_ACCOUNT std.Address = "g1paqttvcjcluuya9n9twyw7yacv54mt7ld3gvzm" // IRA, r3v4_xxx: CHANGE WHEN DEPLOYING TO OFFICIAL NETWORK + INTERNAL_REWARD_ACCOUNT std.Address = "g1paqttvcjcluuya9n9twyw7yacv54mt7ld3gvzm" // IRA for GNS, r3v4_xxx: CHANGE WHEN DEPLOYING TO OFFICIAL NETWORK POOL_CREATION_FEE uint64 = 500_000_000 ) diff --git a/packages/big/uint256/uint256.gno b/packages/big/uint256/uint256.gno index 08daf9f3..9fa63f64 100644 --- a/packages/big/uint256/uint256.gno +++ b/packages/big/uint256/uint256.gno @@ -28,15 +28,6 @@ type Uint struct { arr [4]uint64 } -// func (x *Uint) Int() *Int { -// // panic if x > MaxInt64 -// if x.arr[3] > 0x7fffffffffffffff { -// panic("U256 Int overflow") -// } - -// return &Int{v: *x} -// } - // NewUint returns a new initialized Uint. func NewUint(val uint64) *Uint { z := &Uint{arr: [4]uint64{val, 0, 0, 0}} @@ -78,6 +69,11 @@ func (z *Uint) Clear() *Uint { return z } +// Neg returns -x mod 2**256. +func (z *Uint) Neg(x *Uint) *Uint { + return z.Sub(new(Uint), x) +} + // SetAllOne sets all the bits of z to 1 func (z *Uint) SetAllOne() *Uint { z.arr[3], z.arr[2], z.arr[1], z.arr[0] = MaxUint64, MaxUint64, MaxUint64, MaxUint64 @@ -166,13 +162,6 @@ func (z *Uint) SetOne() *Uint { return z } -// func (z *Uint) AddInt(x *Uint, y *Int) *Uint { -// if y.IsNeg() { -// return z.Sub(x, y.Abs()) -// } -// return z.Add(x, y.Uint()) -// } - // Add sets z to the sum x+y func (z *Uint) Add(x, y *Uint) *Uint { var carry uint64 @@ -180,11 +169,6 @@ func (z *Uint) Add(x, y *Uint) *Uint { z.arr[1], carry = Add64(x.arr[1], y.arr[1], carry) z.arr[2], carry = Add64(x.arr[2], y.arr[2], carry) z.arr[3], _ = Add64(x.arr[3], y.arr[3], carry) - // Different from the original implementation! - // We panic on overflow - if carry != 0 { - panic("U256 Add overflow") - } return z } @@ -229,24 +213,6 @@ func (z *Uint) Sub(x, y *Uint) *Uint { z.arr[1], carry = Sub64(x.arr[1], y.arr[1], carry) z.arr[2], carry = Sub64(x.arr[2], y.arr[2], carry) z.arr[3], _ = Sub64(x.arr[3], y.arr[3], carry) - - // Different from the original implementation! - // We panic on underflow - // r3v4 -> mconcat : why do we panic? - if carry != 0 { - panic("U256 Sub underflow") - } - return z -} - -// Sub sets z to the difference x-y -func (z *Uint) UnsafeSub(x, y *Uint) *Uint { - var carry uint64 - z.arr[0], carry = Sub64(x.arr[0], y.arr[0], 0) - z.arr[1], carry = Sub64(x.arr[1], y.arr[1], carry) - z.arr[2], carry = Sub64(x.arr[2], y.arr[2], carry) - z.arr[3], _ = Sub64(x.arr[3], y.arr[3], carry) - return z } @@ -272,7 +238,6 @@ func (z *Uint) Mul(x, y *Uint) *Uint { res3 = res3 + x.arr[1]*y.arr[2] + carry res.arr[3] = res3 + x.arr[0]*y.arr[3] - return z.Set(&res) } @@ -303,10 +268,9 @@ func (z *Uint) MulMod(x, y, m *Uint) *Uint { pl Uint ph Uint ) - // copy(pl[:], p[:4]) - // copy(ph[:], p[4:]) pl = Uint{arr: [4]uint64{p[0], p[1], p[2], p[3]}} + ph = Uint{arr: [4]uint64{p[4], p[5], p[6], p[7]}} // If the multiplication is within 256 bits use Mod(). if ph.IsZero() { @@ -1008,7 +972,7 @@ func (z *Uint) fromDecimal(bs string) error { z.SetUint64(num) } else { base := NewUint(num) - z.Add(z, base.Mul(base, mult)) + z.UnsafeAdd(z, base.Mul(base, mult)) } // Chop off another 19 characters if remaining > 19 { diff --git a/packages/big/uint256/uint256_test.gno b/packages/big/uint256/uint256_test.gno index 5c56abd5..16dc0b64 100644 --- a/packages/big/uint256/uint256_test.gno +++ b/packages/big/uint256/uint256_test.gno @@ -5,14 +5,13 @@ import ( ) func TestFuncs(t *testing.T) { - x := NewUint(0) - y := NewUint(1) + x := UnsafeFromDecimal("79188548433007205424747178") + y := UnsafeFromDecimal("130406999485845074795897568971") - // println(x.Dec()) + z := new(Uint).Add(x, y) + println("z:", z.ToString()) // 130486188034278082001322316149 - var m256 bigint = 115792089237316195423570985008687907853269984665640564039457584007913129639935 - - z := FromBigint(m256) - - println(z.Dec()) + if z.ToString() != "130486188034278082001322316149" { + t.Error("Expected 130486188034278082001322316149, got ", z.ToString()) + } } diff --git a/packages/big/uint512/consts.gno b/packages/big/uint512/consts.gno new file mode 100644 index 00000000..48eb1edb --- /dev/null +++ b/packages/big/uint512/consts.gno @@ -0,0 +1,5 @@ +package uint512 + +const ( + MAX_UINT256 = "115792089237316195423570985008687907853269984665640564039457584007913129639935" +) diff --git a/packages/big/uint512/uint512.gno b/packages/big/uint512/uint512.gno index 38ce69c9..f7913820 100644 --- a/packages/big/uint512/uint512.gno +++ b/packages/big/uint512/uint512.gno @@ -10,7 +10,7 @@ func fullMul( x *u256.Uint, y *u256.Uint, ) (*u256.Uint, *u256.Uint) { // l, h - mm := new(u256.Uint).MulMod(x, y, u256.UnsafeFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935")) + mm := new(u256.Uint).MulMod(x, y, u256.UnsafeFromDecimal(MAX_UINT256)) l := new(u256.Uint).Mul(x, y) h := new(u256.Uint).Sub(mm, l) @@ -32,49 +32,24 @@ func fullDiv( negD := i256.Zero().Neg(posD) intPow2 := i256.Zero().And(posD, negD) - d = new(u256.Uint).Div(d, intPow2.Abs()) l = new(u256.Uint).Div(l, intPow2.Abs()) - // l += h * ((-pow2) / pow2 + 1); - _negPow2 := new(u256.Uint).Sub(u256.UnsafeFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935"), intPow2.Abs()) - _negPow2 = new(u256.Uint).Add(_negPow2, u256.One()) - - value1 := new(u256.Uint).Div(_negPow2, intPow2.Abs()) // (-pow2) / pow2 - // println("value1:", value1.ToString()) + _negPow2 := new(u256.Uint).Neg(intPow2.Abs()) + value1 := new(u256.Uint).Div(_negPow2, intPow2.Abs()) // (-pow2) / pow2 value2 := new(u256.Uint).UnsafeAdd(value1, u256.One()) // (-pow2) / pow2 + 1) - // println("value2:", value2.ToString()) - - // _intH := i256.FromUint256(h) - value3 := new(u256.Uint).Mul(h, value2) // h * ((-pow2) / pow2 + 1); + value3 := new(u256.Uint).Mul(h, value2) // h * ((-pow2) / pow2 + 1); l = new(u256.Uint).UnsafeAdd(l, value3) r := u256.One() - - // r *= 2 - d * r; [ x8 ] - // value11 := new(u256.Uint).UnsafeSub(u256.NewUint(2), d) // 2 - d - // value12 := new(u256.Uint).Mul(value11, r) // 2 - d * r - // r = new(u256.Uint).Mul(r, value12) // r *= 2 - d * r; - - // d * r - // 2 - ( d * r ) - for i := 0; i < 8; i++ { - value1 := new(u256.Uint).Mul(d, r) // d * r - value2 := new(u256.Uint).UnsafeSub(u256.NewUint(2), value1) // 2 - ( d * r ) - r = new(u256.Uint).Mul(r, value2) // r *= 2 - d * r; - + value1 := new(u256.Uint).Mul(d, r) // d * r + value2 := new(u256.Uint).Sub(u256.NewUint(2), value1) // 2 - ( d * r ) + r = new(u256.Uint).Mul(r, value2) // r *= 2 - d * r; } - - println("l:", l.ToString()) - println("r:", r.ToString()) - res := new(u256.Uint).Mul(l, r) - println("res:", res.ToString()) return res - // return new(u256.Uint).Mul(l, r) - } func MulDiv( @@ -101,31 +76,46 @@ func MulDiv( return fullDiv(l, h, d) } -func DivRoundingUp( +func MulDivRoundingUp( x *u256.Uint, y *u256.Uint, + d *u256.Uint, ) *u256.Uint { - div := new(u256.Uint).Div(x, y) + result := MulDiv(x, y, d) - mod := new(u256.Uint).Mod(x, y) - gt := u256.Zero() - if mod.Gt(u256.Zero()) { - gt = mod - } else { - gt = u256.Zero() - } + // _mm := new(u256.Uint).MulMod(x, y, d) + // if _mm.Gt(u256.Zero()) { + // if result.Lt(u256.UnsafeFromDecimal(MAX_UINT256)) { + // result = new(u256.Uint).Add(result, u256.One()) + // } + // } - return new(u256.Uint).Add(div, gt) + return result } -// HELPERs -func mulmod( +func DivRoundingUp( x *u256.Uint, y *u256.Uint, - z *u256.Uint, ) *u256.Uint { - mul := new(u256.Uint).Mul(x, y) - mod := new(u256.Uint).Mod(mul, z) + div := new(u256.Uint).Div(x, y) + + mod := new(u256.Uint).Mod(x, y) + return new(u256.Uint).Add(div, gt(mod, u256.Zero())) +} - return mod +// HELPERs +func lt(x, y *u256.Uint) *u256.Uint { + if x.Lt(y) { + return u256.One() + } else { + return u256.Zero() + } +} + +func gt(x, y *u256.Uint) *u256.Uint { + if x.Gt(y) { + return u256.One() + } else { + return u256.Zero() + } } diff --git a/packages/big/uint512/uint512_test.gno b/packages/big/uint512/uint512_test.gno index b261c048..af8a0e66 100644 --- a/packages/big/uint512/uint512_test.gno +++ b/packages/big/uint512/uint512_test.gno @@ -30,7 +30,7 @@ func TestFunc2(t *testing.T) { sqrtA := u256.UnsafeFromDecimal("79228162514264337593543950337") z := MulDiv(x, y, sqrtB) - println("num1 * num2 / sqrtB:", z.ToString()) + // println("num1 * num2 / sqrtB:", z.ToString()) r := DivRoundingUp(z, sqrtA) println("num1 * num2 / sqrtB / sqrtA:", r.ToString()) diff --git a/pool/_RPC_dry.gno b/pool/_RPC_dry.gno index 0594f054..8bf9b954 100644 --- a/pool/_RPC_dry.gno +++ b/pool/_RPC_dry.gno @@ -95,9 +95,13 @@ func DrySwap( liquidity: cache.liquidityStart, } } + // println("state.tick:", state.tick) + // println("IN state.sqrtPriceX96:", state.sqrtPriceX96.ToString()) + // println("state.sqrtPriceX96:", state.sqrtPriceX96.ToString()) // continue swapping as long as we haven't used the entire input/output and haven't reached the price limit for !(state.amountSpecifiedRemaining.IsZero()) && !(state.sqrtPriceX96.Eq(sqrtPriceLimitX96)) { + // println("state.amountSpecifiedRemaining:", state.amountSpecifiedRemaining.ToString()) var step StepComputations step.sqrtPriceStartX96 = state.sqrtPriceX96 @@ -127,6 +131,11 @@ func DrySwap( sqrtRatioTargetX96 = step.sqrtPriceNextX96 } + // println("state.sqrtPriceX96:", state.sqrtPriceX96.ToString()) + // println("sqrtRatioTargetX96:", sqrtRatioTargetX96.ToString()) + // println("state.liquidity:", state.liquidity.ToString()) + // println("state.amountSpecifiedRemaining:", state.amountSpecifiedRemaining.ToString()) + // println("pool.fee:", pool.fee) state.sqrtPriceX96, step.amountIn, step.amountOut, step.feeAmount = swapMathComputeSwapStep( state.sqrtPriceX96, sqrtRatioTargetX96, @@ -134,6 +143,13 @@ func DrySwap( state.amountSpecifiedRemaining, uint64(pool.fee), ) + if step.amountIn.ToString() == "271" { + // println("> state.sqrtPriceX96:", state.sqrtPriceX96.ToString()) + // println("step.amountIn:", step.amountIn.ToString()) + // println("step.amountOut:", step.amountOut.ToString()) + // println("step.feeAmount:", step.feeAmount.ToString()) + // panic("FIX") + } amountInWithFee := i256.FromUint256(new(u256.Uint).Add(step.amountIn, step.feeAmount)) if exactInput { @@ -224,7 +240,7 @@ func DrySwap( } // JUST NOT ENOUGH BALANCE - if amount0.IsZero() && amount1.IsZero() { + if amount0.IsZero() || amount1.IsZero() { return "0", "0", false } diff --git a/pool/_TEST_pool_dryswap_and_swap_test.gno b/pool/_TEST_pool_dryswap_and_swap_test.gno index 827aea8c..7aaaf5ed 100644 --- a/pool/_TEST_pool_dryswap_and_swap_test.gno +++ b/pool/_TEST_pool_dryswap_and_swap_test.gno @@ -43,8 +43,8 @@ func TestDrySwap_ZeroForOneTrue_AmountSpecified_Positive_16000(t *testing.T) { // not enough mint == swap will fail std.TestSetPrevAddr(test1) - foo.Approve(a2u(consts.POOL_ADDR), uint64(0)) - bar.Approve(a2u(consts.POOL_ADDR), uint64(0)) + foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) std.TestSetPrevRealm(consts.POSITION_PATH) std.TestSetOrigCaller(test1) @@ -53,8 +53,6 @@ func TestDrySwap_ZeroForOneTrue_AmountSpecified_Positive_16000(t *testing.T) { shouldEQ(t, ok, false) std.TestSetPrevAddr(test1) - foo.Approve(a2u(consts.POOL_ADDR), 2958014649) - bar.Approve(a2u(consts.POOL_ADDR), 8040315471) std.TestSetPrevRealm(consts.POSITION_PATH) std.TestSetOrigCaller(test1) @@ -75,23 +73,23 @@ func TestDrySwap_ZeroForOneTrue_AmountSpecified_Positive_16000(t *testing.T) { shouldEQ(t, poolOut, "-5883") } -// func TestDrySwap_ZeroForOneTrue_AmountSpecified_Negative_16000(t *testing.T) { -// // zeroForOne true -// // amountSpecified -16000 +func TestDrySwap_ZeroForOneTrue_AmountSpecified_Negative_16000(t *testing.T) { + // zeroForOne true + // amountSpecified -16000 -// poolIn, poolOut, _ := DrySwap( -// fooPath, // fooPath -// barPath, // barPath -// fee500, // fee500 -// "_", // recipient -// true, // zeroForOne -// "-16000", // amountSpecified -// consts.MIN_PRICE, // sqrtPriceLimitX96 -// ) + poolIn, poolOut, _ := DrySwap( + fooPath, // fooPath + barPath, // barPath + fee500, // fee500 + "_", // recipient + true, // zeroForOne + "-16000", // amountSpecified + consts.MIN_PRICE, // sqrtPriceLimitX96 + ) -// shouldEQ(t, poolIn, "43511") -// shouldEQ(t, poolOut, "-16000") -// } + shouldEQ(t, poolIn, "43512") // r3v4_xxx: ROUNDING ERROR + shouldEQ(t, poolOut, "-16000") +} // func TestDrySwap_ZeroForOneFalse_AmountSpecified_Positive_16000(t *testing.T) { // // zeroForOne false diff --git a/pool/_TEST_pool_multi_token_test.gnoa b/pool/_TEST_pool_multi_token_test.gnoa new file mode 100644 index 00000000..7670578e --- /dev/null +++ b/pool/_TEST_pool_multi_token_test.gnoa @@ -0,0 +1,370 @@ +package pool + +import ( + "std" + "strconv" + "testing" + + "gno.land/r/demo/consts" + + "gno.land/r/demo/bar" + "gno.land/r/demo/baz" + "gno.land/r/demo/foo" + + "gno.land/r/demo/gns" + + u256 "gno.land/p/big/uint256" +) + +var ( + test_tickLower = int32(9000) + test_tickUpper = int32(11000) + test_liquidityExpectStr = "100000000" + test_liquidityExpect256 = u256.NewUint(100_000_000) +) + +// 1. Init Pool +func TestInit(t *testing.T) { + std.TestSetPrevAddr(gsa) + InitManual() +} + +// 2. Create Foo:Bar Pool +func TestCreateFooBarPool(t *testing.T) { + std.TestSetPrevAddr(test1) + gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) + + CreatePool(fooPath, barPath, fee500, "130621891405341611593710811006") + shouldEQ(t, len(pools), 1) +} + +// 3. Create Bar:Baz Pool +func TestCreateBarBazPool(t *testing.T) { + std.TestSetPrevAddr(test1) + gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) + + CreatePool(barPath, bazPath, fee500, "130621891405341611593710811006") + shouldEQ(t, len(pools), 2) +} + +// 4. Mint Foo:Bar Liquidity by test1 +func TestMintFooBarLiquidity(t *testing.T) { + std.TestSetPrevAddr(test1) + foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + + std.TestSetPrevRealm(consts.POSITION_PATH) + std.TestSetOrigCaller(test1) + amount0, amount1 := Mint( + fooPath, + barPath, + fee500, + consts.POSITION_ADDR, + -test_tickUpper, + -test_tickLower, + test_liquidityExpectStr, + ) + shouldEQ(t, amount0, "8040316") + shouldEQ(t, amount1, "2958014") +} + +// 5. Mint Bar:Baz Liquidity by test1 +func TestMintBarBazLiquidity(t *testing.T) { + std.TestSetPrevAddr(test1) + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + baz.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + + std.TestSetPrevRealm(consts.POSITION_PATH) + std.TestSetOrigCaller(test1) + amount0, amount1 := Mint( + barPath, + bazPath, + fee500, + consts.POSITION_ADDR, + test_tickLower, + test_tickUpper, + test_liquidityExpectStr, + ) + shouldEQ(t, amount0, "2958015") + shouldEQ(t, amount1, "8040315") +} + +// 6. Swap Foo:Bar Foo > Bar by test1 +func TestSwapFooBarFooToBar(t *testing.T) { + oldTest1Bar := balanceOfByRegisterCall(barPath, test1) + oldTest1Foo := balanceOfByRegisterCall(fooPath, test1) + + oldPoolBar := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) + oldPoolFoo := balanceOfByRegisterCall(fooPath, consts.POOL_ADDR) + + std.TestSetPrevAddr(test1) + bar.Approve(a2u(consts.POOL_ADDR), 16000) + + std.TestSetPrevRealm(consts.ROUTER_PATH) + std.TestSetOrigCaller(test1) + poolIn, poolOut := Swap( + barPath, + fooPath, + fee500, + test1, + true, + "16000", + consts.MIN_PRICE, + std.GetOrigCaller(), + ) + shouldEQ(t, poolIn, "16000") + shouldEQ(t, poolOut, "-5882") + + newTest1Bar := balanceOfByRegisterCall(barPath, test1) + newTest1Foo := balanceOfByRegisterCall(fooPath, test1) + + newPoolBar := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) + newPoolFoo := balanceOfByRegisterCall(fooPath, consts.POOL_ADDR) + + shouldEQ(t, oldTest1Bar-newTest1Bar, 16000) + shouldEQ(t, newTest1Foo-oldTest1Foo, 5882) + + shouldEQ(t, newPoolBar-oldPoolBar, 16000) + shouldEQ(t, oldPoolFoo-newPoolFoo, 5882) +} + +// 7. Swap Bar:Baz Bar > Baz by test1 +func TestSwapBarBazBarToBaz(t *testing.T) { + oldTest1Token0Balance := balanceOfByRegisterCall(barPath, test1) + oldtest1BazBalance := balanceOfByRegisterCall(bazPath, test1) + oldPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) + oldPoolBazBalance := balanceOfByRegisterCall(bazPath, consts.POOL_ADDR) + + std.TestSetPrevAddr(test1) + bar.Approve(a2u(consts.POOL_ADDR), 16000) + + std.TestSetPrevRealm(consts.ROUTER_PATH) + std.TestSetOrigCaller(test1) + poolIn, poolOut := Swap( + barPath, + bazPath, + fee500, + test1, + true, + "16000", + consts.MIN_PRICE, + std.GetOrigCaller(), + ) + shouldEQ(t, poolIn, "16000") + shouldEQ(t, poolOut, "-43457") + + newTest1Token0Balance := balanceOfByRegisterCall(barPath, test1) + newtest1BazBalance := balanceOfByRegisterCall(bazPath, test1) + newPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) + newPoolBazBalance := balanceOfByRegisterCall(bazPath, consts.POOL_ADDR) + + shouldEQ(t, oldTest1Token0Balance-newTest1Token0Balance, 16000) + shouldEQ(t, newtest1BazBalance-oldtest1BazBalance, 43457) + shouldEQ(t, newPoolToken0Balance-oldPoolToken0Balance, 16000) + shouldEQ(t, oldPoolBazBalance-newPoolBazBalance, 43457) +} + +// 8. Collect Foo:Bar Fees by test1 +func TestCollectFooBarFees(t *testing.T) { + std.TestSetPrevRealm(consts.POSITION_PATH) + std.TestSetOrigCaller(test1) + + oldTest1Token1Balance := balanceOfByRegisterCall(fooPath, test1) + oldTest1Token0Balance := balanceOfByRegisterCall(barPath, test1) + oldPoolToken1Balance := balanceOfByRegisterCall(fooPath, consts.POOL_ADDR) + oldPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) + + // burn 0 to collect swap fees + Burn(fooPath, barPath, fee500, -test_tickUpper, -test_tickLower, "0") + + c0, c1 := Collect( + fooPath, + barPath, + fee500, + test1, + -test_tickUpper, + -test_tickLower, + "100000", + "100000", + ) + + shouldNEQ(t, c0, "0") // swap was foo > bar, so only foo has fees + shouldEQ(t, c1, "0") // swap was foo > bar, so bar has no fees + + newTest1Token1Balance := balanceOfByRegisterCall(fooPath, test1) + newTest1Token0Balance := balanceOfByRegisterCall(barPath, test1) + newPoolToken1Balance := balanceOfByRegisterCall(fooPath, consts.POOL_ADDR) + newPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) + + shouldEQ(t, newTest1Token1Balance-oldTest1Token1Balance, c1) + shouldEQ(t, newTest1Token0Balance-oldTest1Token0Balance, strToUint64(c0)) + shouldEQ(t, oldPoolToken1Balance-newPoolToken1Balance, c1) + shouldEQ(t, oldPoolToken0Balance-newPoolToken0Balance, strToUint64(c0)) +} + +// 9. Collect Bar:Baz Fees by test1 +func TestCollectBarBazFees(t *testing.T) { + std.TestSetPrevRealm(consts.POSITION_PATH) + std.TestSetOrigCaller(test1) + + oldTest1Token0Balance := balanceOfByRegisterCall(barPath, test1) + oldtest1BazBalance := balanceOfByRegisterCall(bazPath, test1) + oldPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) + oldPoolBazBalance := balanceOfByRegisterCall(bazPath, consts.POOL_ADDR) + + // burn 0 to collect swap fees + Burn(barPath, bazPath, fee500, test_tickLower, test_tickUpper, "0") + + c0, c1 := Collect( + barPath, + bazPath, + fee500, + test1, + test_tickLower, + test_tickUpper, + "100000", + "100000", + ) + + shouldNEQ(t, c0, "0") // swap was foo > bar, so only foo has fees + shouldEQ(t, c1, "0") // swap was foo > bar, so bar has no fees + + newTest1Token0Balance := balanceOfByRegisterCall(barPath, test1) + newtest1BazBalance := balanceOfByRegisterCall(bazPath, test1) + newPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) + newPoolBazBalance := balanceOfByRegisterCall(bazPath, consts.POOL_ADDR) + + shouldEQ(t, newTest1Token0Balance-oldTest1Token0Balance, strToUint64(c0)) + shouldEQ(t, newtest1BazBalance-oldtest1BazBalance, c1) + shouldEQ(t, oldPoolToken0Balance-newPoolToken0Balance, strToUint64(c0)) + shouldEQ(t, oldPoolBazBalance-newPoolBazBalance, c1) +} + +// 10. Burn Foo:Bar Liquidity by test1 +func TestBurnFooBarLiquidity(t *testing.T) { + std.TestSetOrigCaller(test1) + std.TestSetPrevRealm(consts.POSITION_PATH) + + pool := GetPool(fooPath, barPath, fee500) + poolOldLiquidity := pool.PoolGetLiquidity() + + b0, b1 := Burn( + fooPath, + barPath, + fee500, + -test_tickUpper, + -test_tickLower, + test_liquidityExpectStr, + ) + + shouldNEQ(t, b0, "0") + shouldNEQ(t, b1, "0") + + poolNewLiquidity := pool.PoolGetLiquidity() + + shouldEQ(t, true, new(u256.Uint).Sub(poolOldLiquidity, poolNewLiquidity).Eq(test_liquidityExpect256)) +} + +// 11. Burn Bar:Baz Liquidity by test1 +func TestBurnBarBazLiquidity(t *testing.T) { + std.TestSetOrigCaller(test1) + std.TestSetPrevRealm(consts.POSITION_PATH) + + pool := GetPool(barPath, bazPath, fee500) + poolOldLiquidity := pool.PoolGetLiquidity() + + b0, b1 := Burn( + barPath, + bazPath, + fee500, + test_tickLower, + test_tickUpper, + test_liquidityExpectStr, + ) + + shouldNEQ(t, b0, "0") + shouldNEQ(t, b1, "0") + + poolNewLiquidity := pool.PoolGetLiquidity() + + // shouldEQ(t, poolOldLiquidity-poolNewLiquidity, test_liquidityExpect256) +} + +// 12. Collect Foo:Bar burned Liquidity by test1 +func TestCollectFooBarLiquidity(t *testing.T) { + std.TestSetOrigCaller(test1) + std.TestSetPrevRealm(consts.POSITION_PATH) + + oldTest1Token1Balance := balanceOfByRegisterCall(fooPath, test1) + oldTest1Token0Balance := balanceOfByRegisterCall(barPath, test1) + oldPoolToken1Balance := balanceOfByRegisterCall(fooPath, consts.POOL_ADDR) + oldPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) + + c0, c1 := Collect( + fooPath, + barPath, + fee500, + test1, + -test_tickUpper, + -test_tickLower, + "100000", + "100000", + ) + + shouldNEQ(t, c0, "0") + shouldNEQ(t, c1, "0") + + newTest1Token1Balance := balanceOfByRegisterCall(fooPath, test1) + newTest1Token0Balance := balanceOfByRegisterCall(barPath, test1) + newPoolToken1Balance := balanceOfByRegisterCall(fooPath, consts.POOL_ADDR) + newPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) + + shouldEQ(t, newTest1Token1Balance-oldTest1Token1Balance, strToUint64(c0)) + shouldEQ(t, newTest1Token0Balance-oldTest1Token0Balance, strToUint64(c1)) + shouldEQ(t, oldPoolToken1Balance-newPoolToken1Balance, strToUint64(c0)) + shouldEQ(t, oldPoolToken0Balance-newPoolToken0Balance, strToUint64(c1)) +} + +// 13. Collect Bar:Baz burned Liquidity by test1 +func TestCollectBarBazLiquidity(t *testing.T) { + std.TestSetOrigCaller(test1) + std.TestSetPrevRealm(consts.POSITION_PATH) + + oldTest1Token0Balance := balanceOfByRegisterCall(barPath, test1) + oldtest1BazBalance := balanceOfByRegisterCall(bazPath, test1) + oldPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) + oldPoolBazBalance := balanceOfByRegisterCall(bazPath, consts.POOL_ADDR) + + c0, c1 := Collect( + barPath, + bazPath, + fee500, + test1, + test_tickLower, + test_tickUpper, + "100000", + "100000", + ) + + shouldNEQ(t, c0, "0") + shouldNEQ(t, c1, "0") + + newTest1Token0Balance := balanceOfByRegisterCall(barPath, test1) + newtest1BazBalance := balanceOfByRegisterCall(bazPath, test1) + newPoolToken0Balance := balanceOfByRegisterCall(barPath, consts.POOL_ADDR) + newPoolBazBalance := balanceOfByRegisterCall(bazPath, consts.POOL_ADDR) + + shouldEQ(t, newTest1Token0Balance-oldTest1Token0Balance, strToUint64(c0)) + shouldEQ(t, newtest1BazBalance-oldtest1BazBalance, strToUint64(c1)) + shouldEQ(t, oldPoolToken0Balance-newPoolToken0Balance, strToUint64(c0)) + shouldEQ(t, oldPoolBazBalance-newPoolBazBalance, strToUint64(c1)) +} + +// UTILs // +func strToUint64(s string) uint64 { + i, err := strconv.Atoi(s) + if err != nil { + panic("strToUint64") + } + return uint64(i) +} diff --git a/pool/_TEST_pool_native_swap_test.gn_OK b/pool/_TEST_pool_native_swap_test.gn_OK index 2ab3c71c..62a7e40c 100644 --- a/pool/_TEST_pool_native_swap_test.gn_OK +++ b/pool/_TEST_pool_native_swap_test.gn_OK @@ -36,19 +36,19 @@ func TestMint(t *testing.T) { // prepare ugnot testBanker := std.GetBanker(std.BankerTypeRealmIssue) - testBanker.IssueCoin(test1, "ugnot", 804_031) + testBanker.IssueCoin(test1, "ugnot", 804_032) // simulate transfer & decrase - std.TestSetOrigSend(std.Coins{{"ugnot", 804_031}}, nil) - testBanker.RemoveCoin(std.GetOrigCaller(), "ugnot", 804_031) + std.TestSetOrigSend(std.Coins{{"ugnot", 804_032}}, nil) + testBanker.RemoveCoin(std.GetOrigCaller(), "ugnot", 804_032) // Deposit(wrap) std.TestSetPrevAddr(test1) wugnot.Deposit() std.TestSetPrevAddr(test1) - foo.Approve(a2u(consts.POOL_ADDR), 295801) - wugnot.Approve(a2u(consts.POOL_ADDR), 804031) + foo.Approve(a2u(consts.POOL_ADDR), 295802) + wugnot.Approve(a2u(consts.POOL_ADDR), 804032) // Mint std.TestSetPrevRealm(consts.POSITION_PATH) @@ -62,7 +62,7 @@ func TestMint(t *testing.T) { "10000000", ) - shouldEQ(t, amount0, "295801") + shouldEQ(t, amount0, "295802") shouldEQ(t, amount1, "804031") } @@ -71,8 +71,8 @@ func TestSwapBuyNative(t *testing.T) { test1OldT0Bal := balanceOfByRegisterCall(pool.token0Path, test1) test1OldT1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - shouldEQ(t, test1OldT0Bal, 499999999704199) // foo - shouldEQ(t, test1OldT1Bal, "0") // wugnot + shouldEQ(t, test1OldT0Bal, 499999999704198) // foo + shouldEQ(t, test1OldT1Bal, 1) // wugnot std.TestSetPrevAddr(test1) foo.Approve(a2u(consts.POOL_ADDR), 10000) @@ -94,8 +94,8 @@ func TestSwapBuyNative(t *testing.T) { test1NewT0Bal := balanceOfByRegisterCall(pool.token0Path, test1) test1NewT1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - shouldEQ(t, test1NewT0Bal, 499999999694199) // - 10_000 // user sells 10_000 - shouldEQ(t, test1NewT1Bal, 27123) // gets WGNOT + shouldEQ(t, test1NewT0Bal, 499999999694198) // - 10_000 // user sells 10_000 + shouldEQ(t, test1NewT1Bal, 27124) // gets WGNOT } func TestSwapSellNative(t *testing.T) { @@ -103,11 +103,11 @@ func TestSwapSellNative(t *testing.T) { test1OldT0Bal := balanceOfByRegisterCall(pool.token0Path, test1) test1OldT1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - shouldEQ(t, test1OldT0Bal, 499999999694199) - shouldEQ(t, test1OldT1Bal, 27123) + shouldEQ(t, test1OldT0Bal, 499999999694198) // foo + shouldEQ(t, test1OldT1Bal, 27124) // wugnot std.TestSetPrevAddr(test1) - wugnot.Approve(a2u(consts.POOL_ADDR), 10000) + wugnot.Approve(a2u(consts.POOL_ADDR), 27123) std.TestSetPrevRealm(consts.ROUTER_PATH) std.TestSetOrigCaller(test1) @@ -121,11 +121,11 @@ func TestSwapSellNative(t *testing.T) { consts.MAX_PRICE, std.GetOrigCaller(), ) - shouldEQ(t, amount0, "-3687") - shouldEQ(t, amount1, "10000") + shouldEQ(t, amount0, "-3687") // pool sent + shouldEQ(t, amount1, "10000") // pool recv test1NewT0Bal := balanceOfByRegisterCall(pool.token0Path, test1) test1NewT1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - shouldEQ(t, test1NewT0Bal, 499999999697886) // foo - shouldEQ(t, test1NewT1Bal, 17123) // wugnot + shouldEQ(t, test1NewT0Bal, 499999999697885) // foo + shouldEQ(t, test1NewT1Bal, 17124) // wugnot } diff --git a/pool/_TEST_pool_single_lp_test.gno b/pool/_TEST_pool_single_lp_test.gnoa similarity index 72% rename from pool/_TEST_pool_single_lp_test.gno rename to pool/_TEST_pool_single_lp_test.gnoa index 10ba3639..8cf09626 100644 --- a/pool/_TEST_pool_single_lp_test.gno +++ b/pool/_TEST_pool_single_lp_test.gnoa @@ -1,24 +1,18 @@ package pool import ( -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - "std" - "testing" - -======== ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno "encoding/gjson" "std" "strconv" "testing" + "gno.land/r/demo/bar" + "gno.land/r/demo/foo" + "gno.land/r/demo/gns" + "gno.land/r/demo/consts" -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - "gno.land/p/demo/u256" -======== u256 "gno.land/p/big/uint256" ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno ) var ( @@ -33,37 +27,24 @@ var ( // 1. Init & Create Pool using Factory Contract by Gnoswap Admin func TestInitCreatePool(t *testing.T) { - std.TestSetOrigCaller(test1) + std.TestSetPrevAddr(gsa) InitManual() -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - std.TestSetOrigCaller(test1) - CreatePool(barPath, fooPath, fee500, 130621891405341611593710811006) - - // sqrtPrice - // 130621891405341611593710811006 // tick = 10000 - shouldPanic(t, func() { CreatePool(barPath, fooPath, 500, 130621891405341611593710811006) }) -======== std.TestSetPrevAddr(test1) gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) CreatePool(barPath, fooPath, fee500, "130621891405341611593710811006") // x2.7 ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno } // 2. Mint by test1 func TestMint(t *testing.T) { -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK -======== std.TestSetPrevAddr(test1) bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno std.TestSetPrevRealm(consts.POSITION_PATH) std.TestSetOrigCaller(test1) - - Mint( + amount0, amount1 := Mint( fooPath, barPath, fee500, @@ -72,19 +53,12 @@ func TestMint(t *testing.T) { test_tickUpper, test_liquidityExpectStr, ) -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - - pool := GetPool(barPath, fooPath, fee500) - test_liquidity := pool.PoolGetLiquidity() - shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect)), true) -======== - shouldEQ(t, amount0, "29") + shouldEQ(t, amount0, "30") shouldEQ(t, amount1, "80") pool := GetPool(barPath, fooPath, fee500) test_liquidity := pool.PoolGetLiquidity() shouldEQ(t, test_liquidity.Dec(), test_liquidityExpectStr) ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) @@ -103,11 +77,7 @@ func TestMint(t *testing.T) { shouldEQ(t, m82, m102) test_liquidity = pool.PoolGetLiquidity() -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*10)), true) -======== shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(10)))) ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno // tickLower > currentTick == don't add to current liquidity Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower2, test_tickUpper2, test_liquidityExpectStr) @@ -133,26 +103,8 @@ func TestMint(t *testing.T) { Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpectStr) test_liquidity = pool.PoolGetLiquidity() -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*10)), true) - - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, test_liquidityExpect) - - test_liquidity = pool.PoolGetLiquidity() - shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*20)), true) -======== shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(20)))) ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno } // 3. Burn by test1 @@ -167,43 +119,23 @@ func TestBurn(t *testing.T) { pool := GetPool(barPath, fooPath, fee500) test_liquidity := pool.PoolGetLiquidity() -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*18)), true) -======== shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(18)))) ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(8)).ToString()) test_liquidity = pool.PoolGetLiquidity() -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*10)), true) -======== shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(10)))) ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, "1") test_liquidity = pool.PoolGetLiquidity() -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - shouldEQ(t, test_liquidity.Eq(u256.FromBigint(9999)), true) -======== shouldEQ(t, test_liquidity.ToString(), "9999") ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, "999") test_liquidity = pool.PoolGetLiquidity() -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - shouldEQ(t, test_liquidity.Eq(u256.FromBigint(test_liquidityExpect*9)), true) -======== shouldEQ(t, true, test_liquidity.Eq(new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(9)))) ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(9)).ToString()) test_liquidity = pool.PoolGetLiquidity() -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - shouldEQ(t, test_liquidity.IsZero(), true) -======== shouldEQ(t, test_liquidity.ToString(), "0") ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno } // 4. Collect @@ -217,11 +149,7 @@ func TestCollect(t *testing.T) { // pool should have zero liquidity pool := GetPool(barPath, fooPath, fee500) test_liquidity := pool.PoolGetLiquidity() -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - shouldEQ(t, test_liquidity.IsZero(), true) -======== shouldEQ(t, test_liquidity.ToString(), "0") ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno Mint(barPath, fooPath, fee500, consts.POSITION_ADDR, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) Burn(barPath, fooPath, fee500, test_tickLower, test_tickUpper, new(u256.Uint).Mul(test_liquidityExpect256, u256.NewUint(15)).ToString()) @@ -262,11 +190,7 @@ func TestCollect(t *testing.T) { func TestSwap(t *testing.T) { pool := GetPool(barPath, fooPath, fee500) test_liquidity := pool.PoolGetLiquidity() -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - shouldEQ(t, test_liquidity.IsZero(), true) -======== shouldEQ(t, test_liquidity.ToString(), "0") ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno std.TestSetPrevRealm(consts.POSITION_PATH) std.TestSetOrigCaller(test1) @@ -384,11 +308,11 @@ func TestSwap(t *testing.T) { // 6. SetFeeProtocol by Gnoswap Admin func TestSetFeeProtocol(t *testing.T) { // non admin call - std.TestSetOrigCaller(test1) + std.TestSetOrigCaller(gsa) shouldPanic(t, func() { SetFeeProtocol(2, 2) }) // admin call - std.TestSetOrigCaller(test1) + std.TestSetOrigCaller(gsa) SetFeeProtocol(6, 8) for _, pool := range pools { @@ -398,8 +322,7 @@ func TestSetFeeProtocol(t *testing.T) { // 7. CollectProtocol by Gnoswap Admin func TestCollectProtocol(t *testing.T) { - std.TestSetOrigCaller(test1) - + std.TestSetOrigCaller(gsa) SetFeeProtocol(6, 8) pool := GetPool(barPath, fooPath, fee500) test_slot0 := pool.PoolGetSlot0() @@ -416,13 +339,8 @@ func TestCollectProtocol(t *testing.T) { test1OldToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) test1OldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - std.TestSetPrevAddr(test1) - amount0, amount1 := CollectProtocol(barPath, fooPath, fee500, test1, u256.NewUint(100000), u256.NewUint(100000)) -======== std.TestSetPrevAddr(gsa) amount0, amount1 := CollectProtocol(barPath, fooPath, fee500, test1, "100000", "100000") ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno test1NewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) test1NewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) @@ -430,27 +348,11 @@ func TestCollectProtocol(t *testing.T) { _token0Diff := test1NewToken0Bal - test1OldToken0Bal _token1Diff := test1NewToken1Bal - test1OldToken1Bal -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - { - std.TestSetPrevRealm(consts.ROUTER_PATH) - std.TestSetOrigCaller(test1) - Swap(barPath, fooPath, fee500, test1, false, 200000, consts.MAX_SQRT_RATIO-1, std.GetOrigCaller()) // swap token0 -> token1 => fee only in token0 - - test1OldToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) - test1OldToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) - - std.TestSetPrevAddr(test1) - amount0, amount1 := CollectProtocol(barPath, fooPath, fee500, test1, u256.NewUint(100000), u256.NewUint(100000)) - - test1NewToken0Bal := balanceOfByRegisterCall(pool.token0Path, test1) - test1NewToken1Bal := balanceOfByRegisterCall(pool.token1Path, test1) -======== token0DiffStr := strconv.Itoa(int(_token0Diff)) token1DiffStr := strconv.Itoa(int(_token1Diff)) shouldEQ(t, token0DiffStr, amount0) shouldEQ(t, token1DiffStr, amount1) ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno } } @@ -459,13 +361,8 @@ func TestApiGetPools(t *testing.T) { gpls := ApiGetPools() jsonStr := gjson.Parse(gpls) -<<<<<<<< HEAD:pool/_TEST_pool_single_lp_test.gno_OK - shouldEQ(t, jsonStr.Get("stat.height").Int(), GetHeight()) - shouldEQ(t, jsonStr.Get("stat.timestamp").Int(), GetTimestamp()) -======== // shouldEQ(t, jsonStr.Get("stat.height").Int(), std.GetHeight()) // shouldEQ(t, jsonStr.Get("stat.timestamp").Int(), time.Now().Unix()) ->>>>>>>> 486effd (feat: uint256, int256 instead of bigint):pool/_TEST_pool_single_lp_test.gno // shouldEQ(t, len(jsonStr.Get("response").Array()), 1) } diff --git a/pool/_TEST_rpc_test.gno b/pool/_TEST_rpc_test.gno new file mode 100644 index 00000000..32180faf --- /dev/null +++ b/pool/_TEST_rpc_test.gno @@ -0,0 +1,103 @@ +package pool + +import ( + "std" + "testing" + + "encoding/gjson" + + "gno.land/r/demo/consts" + + "gno.land/r/demo/bar" + "gno.land/r/demo/baz" + "gno.land/r/demo/foo" + "gno.land/r/demo/gns" +) + +var ( + test_tickLower = int32(9000) + test_tickUpper = int32(11000) + test_liquidityExpectStr = "100000000" +) + +// 1. Init Pool +func TestInit(t *testing.T) { + std.TestSetPrevAddr(gsa) + InitManual() + std.TestSkipHeights(1) +} + +// 2. Create Foo:Bar Pool +func TestCreateFooBarPool(t *testing.T) { + std.TestSetPrevAddr(test1) + gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) + std.TestSkipHeights(1) + + CreatePool(fooPath, barPath, fee500, "130621891405341611593710811006") // tick 10000 + shouldEQ(t, len(pools), 1) + std.TestSkipHeights(1) +} + +// 3. Create Bar:Baz Pool +func TestCreateBarBazPool(t *testing.T) { + std.TestSetPrevAddr(test1) + gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE) + std.TestSkipHeights(1) + + CreatePool(barPath, bazPath, fee500, "130621891405341611593710811006") // tick 10000 + shouldEQ(t, len(pools), 2) + std.TestSkipHeights(1) +} + +// 4. Mint Foo:Bar Liquidity by test1 +func TestMintFooBarLiquidity(t *testing.T) { + std.TestSetPrevAddr(test1) + foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + std.TestSkipHeights(2) + + std.TestSetPrevRealm(consts.POSITION_PATH) + std.TestSetOrigCaller(test1) + amount0, amount1 := Mint( + barPath, + fooPath, + fee500, + consts.POSITION_ADDR, + -11000, // -11000 + -9000, // -9000 + test_liquidityExpectStr, + ) + shouldEQ(t, amount0, "8040316") + shouldEQ(t, amount1, "2958014") + std.TestSkipHeights(1) +} + +// 5. Mint Bar:Baz Liquidity by test1 +func TestMintBarBazLiquidity(t *testing.T) { + std.TestSetPrevAddr(test1) + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + baz.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + std.TestSkipHeights(2) + + std.TestSetPrevRealm(consts.POSITION_PATH) + std.TestSetOrigCaller(test1) + amount0, amount1 := Mint( + barPath, + bazPath, + fee500, + consts.POSITION_ADDR, + test_tickLower, + test_tickUpper, + test_liquidityExpectStr, + ) + shouldEQ(t, amount0, "2958015") + shouldEQ(t, amount1, "8040315") + std.TestSkipHeights(1) +} + +// API TESTS +func TestApiGetPools(t *testing.T) { + jsonStr := ApiGetPools() + jsonArr := gjson.Parse(jsonStr).Get("response").Array() + shouldEQ(t, len(jsonArr), 2) +} diff --git a/pool/pool.gno b/pool/pool.gno index caf0539c..1af9de82 100644 --- a/pool/pool.gno +++ b/pool/pool.gno @@ -40,9 +40,6 @@ func Mint( i256.FromUint256(liquidityAmount), // liquidityDelta }, ) - println("amount0:", amount0.ToString()) - println("amount1:", amount1.ToString()) - panic("FIX 0 3") if amount0.Gt(i256.Zero()) { balance0Before := balanceOfByRegisterCall(pool.token0Path, GetOrigPkgAddr()) @@ -502,6 +499,7 @@ func Swap( } require(pool.balances.token0.Gte(u256.Zero()), ufmt.Sprintf("[POOL] pool.gno__Swap() || pool.balances.token0(%d) >= 0", pool.balances.token0)) } + pool.slot0.unlocked = true return amount0.ToString(), amount1.ToString() } diff --git a/pool/position_modify.gno b/pool/position_modify.gno index 69023ec4..eebdb482 100644 --- a/pool/position_modify.gno +++ b/pool/position_modify.gno @@ -24,32 +24,21 @@ func (pool *Pool) modifyPosition(params ModifyPositionParams) (PositionInfo, *i2 params.liquidityDelta, ) } else if pool.slot0.tick < params.tickUpper { - println("HERE") liquidityBefore := pool.liquidity - println("tickUpper:", params.tickUpper) - println("common.TickMathGetSqrtRatioAtTick(params.tickUpper):", common.TickMathGetSqrtRatioAtTick(params.tickUpper).ToString()) - println() - println("tickLower:", params.tickLower) - println("common.TickMathGetSqrtRatioAtTick(params.tickLower):", common.TickMathGetSqrtRatioAtTick(params.tickLower).ToString()) - println() - amount0 = sqrtPriceMathGetAmount0Delta( pool.slot0.sqrtPriceX96, common.TickMathGetSqrtRatioAtTick(params.tickUpper), params.liquidityDelta, ) - println("amount0:", amount0.ToString()) amount1 = sqrtPriceMathGetAmount1Delta( common.TickMathGetSqrtRatioAtTick(params.tickLower), pool.slot0.sqrtPriceX96, params.liquidityDelta, ) - println("amount1:", amount1.ToString()) pool.liquidity = liquidityMathAddDelta(liquidityBefore, params.liquidityDelta) - panic("FIX 0 666") } else { amount1 = sqrtPriceMathGetAmount1Delta( diff --git a/pool/sqrt_price_math.gno b/pool/sqrt_price_math.gno index 599c00ac..3607a2e7 100644 --- a/pool/sqrt_price_math.gno +++ b/pool/sqrt_price_math.gno @@ -5,7 +5,7 @@ import ( i256 "gno.land/p/big/int256" u256 "gno.land/p/big/uint256" - _ "gno.land/p/big/uint512" + u512 "gno.land/p/big/uint512" ) func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( @@ -17,31 +17,42 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( if amount.IsZero() { return sqrtPX96 } + // println("|| sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp:", add) numerator1 := new(u256.Uint).Lsh(liquidity, 96) - product := new(u256.Uint).Mul(amount, sqrtPX96) + // println("numerator1:", numerator1.ToString()) if add { - denominator := new(u256.Uint).Add(numerator1, product) + product := new(u256.Uint).Mul(amount, sqrtPX96) + if new(u256.Uint).Div(product, amount).Eq(sqrtPX96) { + denominator := new(u256.Uint).Add(numerator1, product) - if denominator.IsZero() { - panic("pool_sqrt price math #1") + if denominator.Gte(numerator1) { + return u512.MulDivRoundingUp(numerator1, sqrtPX96, denominator) + } } - res := new(u256.Uint).Mul(numerator1, sqrtPX96) - res = res.Div(res, denominator) - return res - } + _value1 := new(u256.Uint).Div(numerator1, sqrtPX96) + _value2 := new(u256.Uint).Add(_value1, amount) + return u512.DivRoundingUp(numerator1, _value2) + } else { + product := new(u256.Uint).Mul(amount, sqrtPX96) + // println("product:", product.ToString()) - denominator := new(u256.Uint).Sub(numerator1, product) + cond1 := new(u256.Uint).Div(product, amount).Eq(sqrtPX96) + cond2 := numerator1.Gt(product) - if !(denominator.Gt(u256.Zero())) { - panic("pool_sqrt price math #2") - } + if !(cond1 && cond2) { + panic("pool_sqrt price math #1") + } + denominator := new(u256.Uint).Sub(numerator1, product) + // println("denominator:", denominator.ToString()) - _tmp := new(u256.Uint).Div(numerator1, sqrtPX96) - _tmp = _tmp.Add(_tmp, amount) - return new(u256.Uint).Div(numerator1, _tmp) + zxc := u512.MulDivRoundingUp(numerator1, sqrtPX96, denominator) + return zxc + // return new(u256.Uint).Sub(zxc, u256.One()) + // return u512.MulDivRoundingUp(numerator1, sqrtPX96, denominator) + } } func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown( @@ -51,31 +62,37 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown( add bool, ) *u256.Uint { // uint160 quotient := u256.Zero() - if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { - quotient = quotient.Lsh(amount, 96) - quotient = quotient.Div(quotient, liquidity) - } else { - _tmp := new(u256.Uint).Div(u256.UnsafeFromDecimal(consts.Q96), liquidity) - quotient = new(u256.Uint).Mul(amount, _tmp) - } - - // quotient mutst be positive when amount and liquidity are positive + // println("sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown", add) if add { - result := new(u256.Uint).Add(sqrtPX96, quotient) + if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { + quotient = new(u256.Uint).Lsh(amount, 96) + quotient = new(u256.Uint).Div(quotient, liquidity) + } else { + quotient = u512.MulDiv(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) + } - if !(result.Gte(sqrtPX96)) { - panic("pool_sqrt price math #3") + quotient = new(u256.Uint).Sub(quotient, u256.One()) + return new(u256.Uint).Add(sqrtPX96, quotient) + } else { + // println("FF") + if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { + value1 := new(u256.Uint).Lsh(amount, 96) + quotient = u512.DivRoundingUp(value1, liquidity) + // println("q1:", quotient.ToString()) + } else { + quotient = u512.MulDivRoundingUp(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) + // println("q2:", quotient.ToString()) } + // println("sqrtPX96:", sqrtPX96.ToString()) - return result - } + if !(sqrtPX96.Gt(quotient)) { + panic("pool_sqrt price math #2") + } - result := new(u256.Uint).Sub(sqrtPX96, quotient) - if !(result.Gte(u256.Zero())) { - panic("pool_sqrt price math #4") + // roundDown + quotient = new(u256.Uint).Sub(quotient, u256.One()) + return new(u256.Uint).Sub(sqrtPX96, quotient) } - - return result } func sqrtPriceMathGetNextSqrtPriceFromInput( @@ -85,12 +102,9 @@ func sqrtPriceMathGetNextSqrtPriceFromInput( zeroForOne bool, // bool ) *u256.Uint { // uint160 if zeroForOne { - amount0Result := sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true) - return amount0Result + return sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true) } - - amount1Result := sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true) - return amount1Result + return sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true) } func sqrtPriceMathGetNextSqrtPriceFromOutput( @@ -99,64 +113,58 @@ func sqrtPriceMathGetNextSqrtPriceFromOutput( amountOut *u256.Uint, // uint256 zeroForOne bool, // bool ) *u256.Uint { // uint160 + // println("sqrtPriceMathGetNextSqrtPriceFromOutput:", zeroForOne) if zeroForOne { - amount1Result := sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) - return amount1Result + return sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) } - amount0Result := sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false) - return amount0Result + return sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false) } func sqrtPriceMathGetAmount0DeltaHelper( sqrtRatioAX96 *u256.Uint, // uint160 sqrtRatioBX96 *u256.Uint, // uint160 liquidity *u256.Uint, // uint160 + roundUp bool, ) *u256.Uint { // uint256 if sqrtRatioAX96.Gt(sqrtRatioBX96) { sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96 } numerator1 := new(u256.Uint).Lsh(liquidity, 96) - println("numerator1:", numerator1.ToString()) numerator2 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - println("numerator2:", numerator2.ToString()) - - // res := new(u256.Uint).Mul(numerator1, numerator2) - // res = res.Div(res, sqrtRatioBX96) - // res = res.Div(res, sqrtRatioAX96) - value1 := new(u256.Uint).Mul(numerator1, numerator2) - println("value1:", value1.ToString()) - { - ov1, c := new(u256.Uint).MulOverflow(numerator1, numerator2) - println("ov1:", ov1.ToString(), "c:", c) + if !(sqrtRatioAX96.Gt(u256.Zero())) { + panic("pool_sqrt price math #3") } - value2 := new(u256.Uint).Div(value1, sqrtRatioBX96) - println("value2:", value2.ToString()) - - res := new(u256.Uint).Div(value2, sqrtRatioAX96) - println("res:", res.ToString()) + if roundUp { + value1 := u512.MulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96) + return u512.DivRoundingUp(value1, sqrtRatioAX96) + } else { + value1 := u512.MulDiv(numerator1, numerator2, sqrtRatioBX96) + return new(u256.Uint).Div(value1, sqrtRatioAX96) + } - panic("Q") - return res } func sqrtPriceMathGetAmount1DeltaHelper( sqrtRatioAX96 *u256.Uint, // uint160 sqrtRatioBX96 *u256.Uint, // uint160 liquidity *u256.Uint, // uint160 + roundUp bool, ) *u256.Uint { // uint256 if sqrtRatioAX96.Gt(sqrtRatioBX96) { sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96 } - _tmp := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - res := new(u256.Uint).Mul(liquidity, _tmp) - res = res.Div(res, u256.UnsafeFromDecimal(consts.Q96)) - - return res + if roundUp { + value1 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) + return u512.MulDivRoundingUp(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) + } else { + value1 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) + return u512.MulDiv(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) + } } func sqrtPriceMathGetAmount0Delta( @@ -166,11 +174,11 @@ func sqrtPriceMathGetAmount0Delta( ) *i256.Int { // int256 if liquidity.IsNeg() { - u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), false) i := i256.FromUint256(u) return i256.Zero().Neg(i) } - u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true) return i256.FromUint256(u) } @@ -180,11 +188,11 @@ func sqrtPriceMathGetAmount1Delta( liquidity *i256.Int, // int128 ) *i256.Int { // int256 if liquidity.IsNeg() { - u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), false) i := i256.FromUint256(u) return i256.Zero().Neg(i) } - u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true) return i256.FromUint256(u) } diff --git a/pool/swap_math.gno b/pool/swap_math.gno index 61b7ec8a..d3120fad 100644 --- a/pool/swap_math.gno +++ b/pool/swap_math.gno @@ -18,6 +18,10 @@ func swapMathComputeSwapStep( // NEGATIVE == EXACT_OUT => Estimated AmountIn exactIn := !(amountRemaining.IsNeg()) // amountRemaining >= 0 + // println() + // println("exactIn", exactIn) // f + // println("isToken1Expensive", isToken1Expensive) // t + if exactIn { amountRemainingLessFee := u256.Zero() @@ -25,11 +29,10 @@ func swapMathComputeSwapStep( _amountRemaining := amountRemaining.Abs() amountRemainingLessFee = amountRemainingLessFee.Mul(_amountRemaining, u256.NewUint(1000000-feePips)) amountRemainingLessFee = amountRemainingLessFee.Div(amountRemainingLessFee, u256.NewUint(1000000)) - if isToken1Expensive { - amountIn = sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity) + amountIn = sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, true) } else { - amountIn = sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity) + amountIn = sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, true) } if amountRemainingLessFee.Gte(amountIn) { @@ -44,20 +47,31 @@ func swapMathComputeSwapStep( } } else { if isToken1Expensive { - amountOut = sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity) + // println(1) + amountOut = sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, false) } else { - amountOut = sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity) + // println(2) + amountOut = sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, false) } if amountRemaining.Abs().Gte(amountOut) { + // println(3) sqrtRatioNextX96 = sqrtRatioTargetX96 } else { + // println(4) + // println("sqrtRatioCurrentX96:", sqrtRatioCurrentX96.ToString()) + // println("liquidity:", liquidity.ToString()) + // println("amountRemaining.Abs():", amountRemaining.Abs().ToString()) + // println("isToken1Expensive:", isToken1Expensive) + // println("<< SQRT") sqrtRatioNextX96 = sqrtPriceMathGetNextSqrtPriceFromOutput( sqrtRatioCurrentX96, liquidity, amountRemaining.Abs(), isToken1Expensive, ) + // println("sqrtRatioNextX96:", sqrtRatioNextX96.ToString()) + // panic("F") } } @@ -67,25 +81,25 @@ func swapMathComputeSwapStep( if max && exactIn { amountIn = amountIn } else { - amountIn = sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity) + amountIn = sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, true) } if max && !exactIn { amountOut = amountOut } else { - amountOut = sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity) + amountOut = sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, false) } } else { if max && exactIn { amountIn = amountIn } else { - amountIn = sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioCurrentX96, sqrtRatioNextX96, liquidity) + amountIn = sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioCurrentX96, sqrtRatioNextX96, liquidity, true) } if max && !exactIn { amountOut = amountOut } else { - amountOut = sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioCurrentX96, sqrtRatioNextX96, liquidity) + amountOut = sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioCurrentX96, sqrtRatioNextX96, liquidity, false) } } @@ -103,5 +117,6 @@ func swapMathComputeSwapStep( if !exactIn && !(amountOut.IsZero()) { amountOut = amountOut.Add(amountOut, u256.NewUint(1)) } + // println() return sqrtRatioNextX96, amountIn, amountOut, feeAmount } diff --git a/pool/tick_bitmap.gno b/pool/tick_bitmap.gno index 44f19f9e..24343c93 100644 --- a/pool/tick_bitmap.gno +++ b/pool/tick_bitmap.gno @@ -53,7 +53,7 @@ func (pool *Pool) tickBitmapNextInitializedTickWithInOneWord( shift1LeftByBitPos := new(u256.Uint).Lsh(u256.NewUint(1), uint(bitPos)) mask := shift1LeftByBitPos.Clone() - mask = new(u256.Uint).UnsafeSub(mask, u256.NewUint(1)) + mask = new(u256.Uint).Sub(mask, u256.NewUint(1)) mask = new(u256.Uint).Add(mask, shift1LeftByBitPos.Clone()) // masked := pool.tickBitmaps[wordPos] & mask @@ -75,7 +75,7 @@ func (pool *Pool) tickBitmapNextInitializedTickWithInOneWord( shift1LeftByBitPos := new(u256.Uint).Lsh(u256.NewUint(1), uint(bitPos)) _mask := shift1LeftByBitPos.Clone() - _mask = new(u256.Uint).UnsafeSub(_mask, u256.NewUint(1)) + _mask = new(u256.Uint).Sub(_mask, u256.NewUint(1)) mask := bigintBitwiseNotForUint256BitmapIndexing(_mask) pool.tickBitmaps[wordPos] = pool.tickBitmaps[wordPos].NilToZero() diff --git a/position/_TEST_position_api_test.gnoa b/position/_TEST_position_api_test.gnoa index 8e067836..626fb040 100644 --- a/position/_TEST_position_api_test.gnoa +++ b/position/_TEST_position_api_test.gnoa @@ -62,7 +62,7 @@ func TestCollectFeeAfterSwap(t *testing.T) { std.TestSetOrigCaller(test1) tokneId, fee0, fee1, fromPath := CollectFee(1) shouldEQ(t, tokneId, uint64(1)) - shouldEQ(t, fee0, "61") + shouldEQ(t, fee0, "60") shouldEQ(t, fee1, "0") shouldEQ(t, fromPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } diff --git a/position/_TEST_position_increase_decrease_test.gnoa b/position/_TEST_position_increase_decrease_test.gnoa index 42a84e62..b103498e 100644 --- a/position/_TEST_position_increase_decrease_test.gnoa +++ b/position/_TEST_position_increase_decrease_test.gnoa @@ -27,8 +27,8 @@ func TestPoolInitCreatePool(t *testing.T) { func TestMintPosition(t *testing.T) { std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), 18394891) - foo.Approve(a2u(consts.POOL_ADDR), 49999999) + bar.Approve(a2u(consts.POOL_ADDR), 18394892) + foo.Approve(a2u(consts.POOL_ADDR), 50000000) tokenId, liquidity, amount0, amount1 := Mint( barPath, @@ -44,14 +44,14 @@ func TestMintPosition(t *testing.T) { ) shouldEQ(t, tokenId, 1) shouldEQ(t, getNextId(), 2) - shouldEQ(t, amount0, "18394891") + shouldEQ(t, amount0, "18394892") shouldEQ(t, amount1, "49999999") } func TestIncreaseLiquidity(t *testing.T) { std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), 3678978) - foo.Approve(a2u(consts.POOL_ADDR), 9999999) + bar.Approve(a2u(consts.POOL_ADDR), 3678979) + foo.Approve(a2u(consts.POOL_ADDR), 10000000) pool := getPoolFromLpTokenId(uint64(1)) oldLiquidity := pool.PoolGetLiquidity() @@ -64,7 +64,7 @@ func TestIncreaseLiquidity(t *testing.T) { "0", // amount1Min max_timeout, // deadline ) - shouldEQ(t, m0, "3678978") + shouldEQ(t, m0, "3678979") shouldEQ(t, m1, "9999999") newLiquidity := pool.PoolGetLiquidity() @@ -108,7 +108,7 @@ func TestCollectFeeAfterSwap(t *testing.T) { tokenId, fee0, fee1, poolPath := CollectFee(1) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, fee0, "611") // this is input token + shouldEQ(t, fee0, "610") // this is input token shouldEQ(t, fee1, "0") // this it output token shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } @@ -147,12 +147,12 @@ func TestSwap2(t *testing.T) { std.TestSetOrigCaller(test1) oldFee0, oldFee1 := unclaimedFee(uint64(1)) - shouldEQ(t, oldFee0.ToString(), "499") + shouldEQ(t, oldFee0.ToString(), "498") shouldEQ(t, oldFee1.ToString(), "0") tokenId, fee0, fee1, poolPath := CollectFee(1) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, fee0, "495") // 499 -> 495 ≈ cause of protocol fee + shouldEQ(t, fee0, "494") // decreased cause of fee shouldEQ(t, fee1, "0") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } @@ -171,12 +171,12 @@ func TestDecreaseLiquidity(t *testing.T) { max_timeout, // deadline ) - // newLiquidity := getPoolFromLpTokenId(uint64(1)).PoolGetLiquidity() - // shouldLT(t, oldLiquidity, newLiquidity) + newLiquidity := getPoolFromLpTokenId(uint64(1)).PoolGetLiquidity() + shouldEQ(t, true, newLiquidity.Lt(oldLiquidity)) - // // check fee left - // tokenId, fee0, fee1, poolPath := CollectFee(1) - // shouldEQ(t, tokenId, uint64(1)) - // shouldEQ(t, fee0, "0") - // shouldEQ(t, fee1, "0") + // check fee left + tokenId, fee0, fee1, poolPath := CollectFee(1) + shouldEQ(t, tokenId, uint64(1)) + shouldEQ(t, fee0, "0") + shouldEQ(t, fee1, "0") } diff --git a/position/_TEST_position_test.gno b/position/_TEST_position_test.gno index 464d7515..21c29125 100644 --- a/position/_TEST_position_test.gno +++ b/position/_TEST_position_test.gno @@ -28,8 +28,8 @@ func TestPoolInitCreatePool(t *testing.T) { func TestMintPosition01InRange(t *testing.T) { std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), 18394891) - foo.Approve(a2u(consts.POOL_ADDR), 49999999) + bar.Approve(a2u(consts.POOL_ADDR), 18394892) + foo.Approve(a2u(consts.POOL_ADDR), 50000000) tokenId, liquidity, amount0, amount1 := Mint( barPath, @@ -45,14 +45,14 @@ func TestMintPosition01InRange(t *testing.T) { ) shouldEQ(t, tokenId, 1) shouldEQ(t, getNextId(), 2) - shouldEQ(t, amount0, "18394891") + shouldEQ(t, amount0, "18394892") shouldEQ(t, amount1, "49999999") } func TestMintPosition02LowerRange(t *testing.T) { std.TestSetPrevAddr(test1) bar.Approve(a2u(consts.POOL_ADDR), 0) - foo.Approve(a2u(consts.POOL_ADDR), 49999999) + foo.Approve(a2u(consts.POOL_ADDR), 50000000) tokenId, liquidity, amount0, amount1 := Mint( barPath, @@ -74,7 +74,7 @@ func TestMintPosition02LowerRange(t *testing.T) { func TestMintPosition03UpperRange(t *testing.T) { std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), 49999999) + bar.Approve(a2u(consts.POOL_ADDR), 50000000) foo.Approve(a2u(consts.POOL_ADDR), 0) tokenId, liquidity, amount0, amount1 := Mint( @@ -91,7 +91,7 @@ func TestMintPosition03UpperRange(t *testing.T) { ) shouldEQ(t, tokenId, 3) shouldEQ(t, getNextId(), 4) - shouldEQ(t, amount0, "49999999") + shouldEQ(t, amount0, "50000000") shouldEQ(t, amount1, "0") } diff --git a/position/_TEST_position_test_two_position_used_single_swap_test.gnoa b/position/_TEST_position_test_two_position_used_single_swap_test.gnoa index 41659dec..00693c37 100644 --- a/position/_TEST_position_test_two_position_used_single_swap_test.gnoa +++ b/position/_TEST_position_test_two_position_used_single_swap_test.gnoa @@ -25,8 +25,8 @@ func TestPoolInitCreatePool(t *testing.T) { func TestMintPosition01WideInRange(t *testing.T) { std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), 18394891) - foo.Approve(a2u(consts.POOL_ADDR), 49999999) + bar.Approve(a2u(consts.POOL_ADDR), 18394892) + foo.Approve(a2u(consts.POOL_ADDR), 50000000) tokenId, liquidity, amount0, amount1 := Mint( barPath, @@ -43,14 +43,14 @@ func TestMintPosition01WideInRange(t *testing.T) { shouldEQ(t, tokenId, 1) shouldEQ(t, getNextId(), 2) shouldEQ(t, liquidity, "318704392") - shouldEQ(t, amount0, "18394891") + shouldEQ(t, amount0, "18394892") shouldEQ(t, amount1, "49999999") } func TestMintPositionTightInRange(t *testing.T) { std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), 18394891) - foo.Approve(a2u(consts.POOL_ADDR), 49999999) + bar.Approve(a2u(consts.POOL_ADDR), 18394892) + foo.Approve(a2u(consts.POOL_ADDR), 50000000) tokenId, liquidity, amount0, amount1 := Mint( barPath, @@ -67,7 +67,7 @@ func TestMintPositionTightInRange(t *testing.T) { shouldEQ(t, tokenId, 2) shouldEQ(t, getNextId(), 3) shouldEQ(t, liquidity, "1228379121") - shouldEQ(t, amount0, "18394891") + shouldEQ(t, amount0, "18394892") shouldEQ(t, amount1, "49999999") } @@ -122,7 +122,7 @@ func TestCollectFeeAfterSwapPos1(t *testing.T) { func TestCollectFeeAfterSwapPos2(t *testing.T) { tokenId, fee0, fee1, poolPath := CollectFee(2) shouldEQ(t, tokenId, uint64(2)) - shouldEQ(t, fee0, "486") + shouldEQ(t, fee0, "485") shouldEQ(t, fee1, "0") shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500") } diff --git a/position/liquidity_management.gno b/position/liquidity_management.gno index 9d7818c5..4cf29d51 100644 --- a/position/liquidity_management.gno +++ b/position/liquidity_management.gno @@ -36,9 +36,6 @@ func addLiquidity(params AddLiquidityParams) (*u256.Uint, *u256.Uint, *u256.Uint params.tickUpper, // tickUpper int32 liquidity.ToString(), // _liquidityAmount string(uint128) ) - println("amount0:", amount0) - println("amount1:", amount1) - panic("FIX 0 2") amount0Uint, err := u256.FromDecimal(amount0) if err != nil { diff --git a/position/position.gno b/position/position.gno index 7f877d71..4c8205ea 100644 --- a/position/position.gno +++ b/position/position.gno @@ -85,9 +85,6 @@ func mint(params MintParams) (uint64, string, string, string) { amount1Min: params.amount1Min, }, ) - println("amount0", amount0.ToString()) - println("amount1", amount1.ToString()) - panic("FIX 0") tokenId := nextId nextId++ // nextId = nextId + 1 diff --git a/position/sqrt_price_math.gno b/position/sqrt_price_math.gno index 1e63f055..f6716d35 100644 --- a/position/sqrt_price_math.gno +++ b/position/sqrt_price_math.gno @@ -5,6 +5,7 @@ import ( i256 "gno.land/p/big/int256" u256 "gno.land/p/big/uint256" + u512 "gno.land/p/big/uint512" ) func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( @@ -16,31 +17,42 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( if amount.IsZero() { return sqrtPX96 } + // println("|| sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp:", add) numerator1 := new(u256.Uint).Lsh(liquidity, 96) - product := new(u256.Uint).Mul(amount, sqrtPX96) + // println("numerator1:", numerator1.ToString()) if add { - denominator := new(u256.Uint).Add(numerator1, product) + product := new(u256.Uint).Mul(amount, sqrtPX96) + if new(u256.Uint).Div(product, amount).Eq(sqrtPX96) { + denominator := new(u256.Uint).Add(numerator1, product) - if denominator.IsZero() { - panic("position_sqrt price math #1") + if denominator.Gte(numerator1) { + return u512.MulDivRoundingUp(numerator1, sqrtPX96, denominator) + } } - res := new(u256.Uint).Mul(numerator1, sqrtPX96) - res = res.Div(res, denominator) - return res - } + _value1 := new(u256.Uint).Div(numerator1, sqrtPX96) + _value2 := new(u256.Uint).Add(_value1, amount) + return u512.DivRoundingUp(numerator1, _value2) + } else { + product := new(u256.Uint).Mul(amount, sqrtPX96) + // println("product:", product.ToString()) - denominator := new(u256.Uint).Sub(numerator1, product) + cond1 := new(u256.Uint).Div(product, amount).Eq(sqrtPX96) + cond2 := numerator1.Gt(product) - if !(denominator.Gt(u256.Zero())) { - panic("position_sqrt price math #2") - } + if !(cond1 && cond2) { + panic("position_sqrt price math #1") + } + denominator := new(u256.Uint).Sub(numerator1, product) + // println("denominator:", denominator.ToString()) - _tmp := new(u256.Uint).Div(numerator1, sqrtPX96) - _tmp = _tmp.Add(_tmp, amount) - return new(u256.Uint).Div(numerator1, _tmp) + zxc := u512.MulDivRoundingUp(numerator1, sqrtPX96, denominator) + return zxc + // return new(u256.Uint).Sub(zxc, u256.One()) + // return u512.MulDivRoundingUp(numerator1, sqrtPX96, denominator) + } } func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown( @@ -50,31 +62,37 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown( add bool, ) *u256.Uint { // uint160 quotient := u256.Zero() - if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { - quotient = quotient.Lsh(amount, 96) - quotient = quotient.Div(quotient, liquidity) - } else { - _tmp := new(u256.Uint).Div(u256.UnsafeFromDecimal(consts.Q96), liquidity) - quotient = new(u256.Uint).Mul(amount, _tmp) - } - - // quotient mutst be positive when amount and liquidity are positive + // println("sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown", add) if add { - result := new(u256.Uint).Add(sqrtPX96, quotient) + if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { + quotient = new(u256.Uint).Lsh(amount, 96) + quotient = new(u256.Uint).Div(quotient, liquidity) + } else { + quotient = u512.MulDiv(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) + } - if !(result.Gte(sqrtPX96)) { - panic("position_sqrt price math #3") + quotient = new(u256.Uint).Sub(quotient, u256.One()) + return new(u256.Uint).Add(sqrtPX96, quotient) + } else { + // println("FF") + if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { + value1 := new(u256.Uint).Lsh(amount, 96) + quotient = u512.DivRoundingUp(value1, liquidity) + // println("q1:", quotient.ToString()) + } else { + quotient = u512.MulDivRoundingUp(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) + // println("q2:", quotient.ToString()) } + // println("sqrtPX96:", sqrtPX96.ToString()) - return result - } + if !(sqrtPX96.Gt(quotient)) { + panic("position_sqrt price math #2") + } - result := new(u256.Uint).Sub(sqrtPX96, quotient) - if !(result.Gte(u256.Zero())) { - panic("position_sqrt price math #4") + // roundDown + quotient = new(u256.Uint).Sub(quotient, u256.One()) + return new(u256.Uint).Sub(sqrtPX96, quotient) } - - return result } func sqrtPriceMathGetNextSqrtPriceFromInput( @@ -84,12 +102,9 @@ func sqrtPriceMathGetNextSqrtPriceFromInput( zeroForOne bool, // bool ) *u256.Uint { // uint160 if zeroForOne { - amount0Result := sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true) - return amount0Result + return sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true) } - - amount1Result := sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true) - return amount1Result + return sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true) } func sqrtPriceMathGetNextSqrtPriceFromOutput( @@ -98,19 +113,19 @@ func sqrtPriceMathGetNextSqrtPriceFromOutput( amountOut *u256.Uint, // uint256 zeroForOne bool, // bool ) *u256.Uint { // uint160 + // println("sqrtPriceMathGetNextSqrtPriceFromOutput:", zeroForOne) if zeroForOne { - amount1Result := sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) - return amount1Result + return sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) } - amount0Result := sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false) - return amount0Result + return sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false) } func sqrtPriceMathGetAmount0DeltaHelper( sqrtRatioAX96 *u256.Uint, // uint160 sqrtRatioBX96 *u256.Uint, // uint160 liquidity *u256.Uint, // uint160 + roundUp bool, ) *u256.Uint { // uint256 if sqrtRatioAX96.Gt(sqrtRatioBX96) { sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96 @@ -119,27 +134,37 @@ func sqrtPriceMathGetAmount0DeltaHelper( numerator1 := new(u256.Uint).Lsh(liquidity, 96) numerator2 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - res := new(u256.Uint).Mul(numerator1, numerator2) - res = res.Div(res, sqrtRatioBX96) - res = res.Div(res, sqrtRatioAX96) + if !(sqrtRatioAX96.Gt(u256.Zero())) { + panic("position_sqrt price math #3") + } + + if roundUp { + value1 := u512.MulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96) + return u512.DivRoundingUp(value1, sqrtRatioAX96) + } else { + value1 := u512.MulDiv(numerator1, numerator2, sqrtRatioBX96) + return new(u256.Uint).Div(value1, sqrtRatioAX96) + } - return res } func sqrtPriceMathGetAmount1DeltaHelper( sqrtRatioAX96 *u256.Uint, // uint160 sqrtRatioBX96 *u256.Uint, // uint160 liquidity *u256.Uint, // uint160 + roundUp bool, ) *u256.Uint { // uint256 if sqrtRatioAX96.Gt(sqrtRatioBX96) { sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96 } - _tmp := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - res := new(u256.Uint).Mul(liquidity, _tmp) - res = res.Div(res, u256.UnsafeFromDecimal(consts.Q96)) - - return res + if roundUp { + value1 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) + return u512.MulDivRoundingUp(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) + } else { + value1 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) + return u512.MulDiv(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) + } } func sqrtPriceMathGetAmount0Delta( @@ -147,12 +172,13 @@ func sqrtPriceMathGetAmount0Delta( sqrtRatioBX96 *u256.Uint, // uint160 liquidity *i256.Int, // int128 ) *i256.Int { // int256 + if liquidity.IsNeg() { - u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), false) i := i256.FromUint256(u) return i256.Zero().Neg(i) } - u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true) return i256.FromUint256(u) } @@ -162,11 +188,11 @@ func sqrtPriceMathGetAmount1Delta( liquidity *i256.Int, // int128 ) *i256.Int { // int256 if liquidity.IsNeg() { - u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), false) i := i256.FromUint256(u) return i256.Zero().Neg(i) } - u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs()) + u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true) return i256.FromUint256(u) } diff --git a/router/_RPC_api.gno b/router/_RPC_api.gno index b50d2276..3a5cbf46 100644 --- a/router/_RPC_api.gno +++ b/router/_RPC_api.gno @@ -71,7 +71,7 @@ func findRatios(maxHops int) []TokenRatio { } else { numRoutes := uint64(len(routes)) - var _tokenRatioX96 *u256.Uint + _tokenRatioX96 := u256.Zero() for _, route := range routes { numHops := uint64(len(route.route)) @@ -87,7 +87,6 @@ func findRatios(maxHops int) []TokenRatio { } avgPriceX96 := new(u256.Uint).Div(_tokenRatioX96, u256.NewUint(numRoutes)) tokenRatio[token] = avgPriceX96 - } } // LOOP FIN @@ -113,36 +112,36 @@ func calculateTokenRatio(currentToken string, routes []PoolWithMeta, proceed int if token1Path == currentToken { poolSqrtPriceX96 := pool.PoolGetSlot0SqrtPriceX96() - priceX96 *= poolSqrtPriceX96 * poolSqrtPriceX96 + sqrtX96 := new(u256.Uint).Mul(poolSqrtPriceX96, poolSqrtPriceX96) + priceX96 = new(u256.Uint).Mul(priceX96, sqrtX96) currentToken = token0Path } else if token0Path == currentToken { poolTick := pool.PoolGetSlot0Tick() oppositeTick := -poolTick oppositeSqrtPriceX96 := common.TickMathGetSqrtRatioAtTick(oppositeTick) - currentPriceX96 *= oppositeSqrtPriceX96.Bigint() * oppositeSqrtPriceX96.Bigint() - currentToken = poolToken0 + oppSqrtX96 := new(u256.Uint).Mul(oppositeSqrtPriceX96, oppositeSqrtPriceX96) + priceX96 = new(u256.Uint).Mul(priceX96, oppSqrtX96) + currentToken = token1Path } else { // wrong condition - // panic("[ROUTER] _RPC_api.gno__calculateTokenRatio() || wrong condition") + panic("[ROUTER] _RPC_api.gno__calculateTokenRatio() || wrong condition") return u256.Zero() - } proceed += 1 - if proceed == len(routes) { // numHops - for { // remove as much X96 as possible - tempPriceX96 := priceX96 - priceX96 = new(u256.Uint).Div(priceX96, u256.UnsafeFromDecimal(consts.Q96)) + for { // remove as much X96 as possible + tempPriceX96 := priceX96.Clone() + priceX96 = new(u256.Uint).Div(priceX96, u256.UnsafeFromDecimal(consts.Q96)) - if priceX96.Lt(u256.UnsafeFromDecimal(consts.MIN_PRICE)) { + if priceX96.Lt(u256.UnsafeFromDecimal(consts.MIN_PRICE)) { + if proceed == len(routes) { return tempPriceX96 } + return calculateTokenRatio(currentToken, routes, proceed, priceX96) } } - - return calculateTokenRatio(currentToken, routes, proceed, priceX96) } func getTokenList() []string { diff --git a/router/_TEST_router_ratio_test.gnoa b/router/_TEST_router_ratio_test.gno similarity index 64% rename from router/_TEST_router_ratio_test.gnoa rename to router/_TEST_router_ratio_test.gno index cd4abfcc..3d38dee8 100644 --- a/router/_TEST_router_ratio_test.gnoa +++ b/router/_TEST_router_ratio_test.gno @@ -28,9 +28,9 @@ func TestPoolCreatePool(t *testing.T) { gns.Approve(a2u(consts.POOL_ADDR), consts.POOL_CREATION_FEE*(3+4+3)) // 1 HOPS - pl.CreatePool(barPath, consts.WRAPPED_WUGNOT, fee100, common.TickMathGetSqrtRatioAtTick(10_000)) - pl.CreatePool(barPath, consts.WRAPPED_WUGNOT, fee500, common.TickMathGetSqrtRatioAtTick(20_000)) - pl.CreatePool(barPath, consts.WRAPPED_WUGNOT, fee3000, common.TickMathGetSqrtRatioAtTick(60_000)) // NOT USED BY SMALL LIQ + pl.CreatePool(barPath, consts.WRAPPED_WUGNOT, fee100, common.TickMathGetSqrtRatioAtTick(10_000).ToString()) + pl.CreatePool(barPath, consts.WRAPPED_WUGNOT, fee500, common.TickMathGetSqrtRatioAtTick(20_000).ToString()) + pl.CreatePool(barPath, consts.WRAPPED_WUGNOT, fee3000, common.TickMathGetSqrtRatioAtTick(60_000).ToString()) // NOT USED BY SMALL LIQ // -10_000 0.367897 // -20_000 0.135348 // 0.367897 + 0.135348 = 0.503245 @@ -38,20 +38,20 @@ func TestPoolCreatePool(t *testing.T) { // 1 WGNOT = 0.2516225 BAR // 2 HOPS - pl.CreatePool(consts.WRAPPED_WUGNOT, quxPath, fee100, common.TickMathGetSqrtRatioAtTick(0)) // 1:1 - pl.CreatePool(quxPath, fooPath, fee100, common.TickMathGetSqrtRatioAtTick(50_000)) - pl.CreatePool(quxPath, fooPath, fee500, common.TickMathGetSqrtRatioAtTick(60_000)) - pl.CreatePool(quxPath, fooPath, fee3000, common.TickMathGetSqrtRatioAtTick(100_000)) // NOT USED BY SMALL LIQ + pl.CreatePool(consts.WRAPPED_WUGNOT, quxPath, fee100, common.TickMathGetSqrtRatioAtTick(0).ToString()) // 1:1 + pl.CreatePool(quxPath, fooPath, fee100, common.TickMathGetSqrtRatioAtTick(50_000).ToString()) + pl.CreatePool(quxPath, fooPath, fee500, common.TickMathGetSqrtRatioAtTick(60_000).ToString()) + pl.CreatePool(quxPath, fooPath, fee3000, common.TickMathGetSqrtRatioAtTick(100_000).ToString()) // NOT USED BY SMALL LIQ // 50_000 148.376062 // 60_000 403.307791 // 148.376062 + 403.307791 = 551.683853 // 551.683853 / 2 = 275.8419265 - // 1 WGNOT = 275.8419265 BAR + // 1 WGNOT = 275.8419265 FOO // 3 HOPS - pl.CreatePool(consts.WRAPPED_WUGNOT, bazPath, fee100, common.TickMathGetSqrtRatioAtTick(6932)) // 1:2 - pl.CreatePool(bazPath, oblPath, fee100, common.TickMathGetSqrtRatioAtTick(6932)) // 1:2 - pl.CreatePool(oblPath, consts.GNS_PATH, fee100, common.TickMathGetSqrtRatioAtTick(6932)) // 1:2 + pl.CreatePool(consts.WRAPPED_WUGNOT, bazPath, fee100, common.TickMathGetSqrtRatioAtTick(6932).ToString()) // 1:2 + pl.CreatePool(bazPath, oblPath, fee100, common.TickMathGetSqrtRatioAtTick(6932).ToString()) // 1:2 + pl.CreatePool(oblPath, consts.GNS_PATH, fee100, common.TickMathGetSqrtRatioAtTick(6932).ToString()) // 1:2 // 1 GNOT = 8 GNS } @@ -68,20 +68,20 @@ func TestPositionMint(t *testing.T) { std.TestSetPrevAddr(test1) wugnot.Deposit() - bar.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) - wugnot.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) - qux.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) - foo.Approve(a2u(consts.POOL_ADDR), uint64(consts.MAX_UINT64)) + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + wugnot.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + qux.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + foo.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) - pn.Mint(barPath, consts.WRAPPED_WUGNOT, fee100, 8000, 12000, 100_000_000, 100_000_000, 0, 0, max_timeout) - pn.Mint(barPath, consts.WRAPPED_WUGNOT, fee500, 18000, 22000, 80_000_000, 80_000_000, 0, 0, max_timeout) - pn.Mint(barPath, consts.WRAPPED_WUGNOT, fee3000, 58020, 62040, 10_000_000, 10_000_000, 0, 0, max_timeout) + pn.Mint(barPath, consts.WRAPPED_WUGNOT, fee100, 8000, 12000, "100000000", "100000000", "0", "0", max_timeout) + pn.Mint(barPath, consts.WRAPPED_WUGNOT, fee500, 18000, 22000, "80000000", "80000000", "0", "0", max_timeout) + pn.Mint(barPath, consts.WRAPPED_WUGNOT, fee3000, 58020, 62040, "10000000", "10000000", "0", "0", max_timeout) - pn.Mint(quxPath, fooPath, fee100, 48000, 52000, 100_000_000, 100_000_000, 0, 0, max_timeout) - pn.Mint(quxPath, fooPath, fee500, 58000, 62000, 80_000_000, 80_000_000, 0, 0, max_timeout) - pn.Mint(quxPath, fooPath, fee3000, 98040, 10020, 10_000_000, 10_000_000, 0, 0, max_timeout) + pn.Mint(quxPath, fooPath, fee100, 48000, 52000, "100000000", "100000000", "0", "0", max_timeout) + pn.Mint(quxPath, fooPath, fee500, 58000, 62000, "80000000", "80000000", "0", "0", max_timeout) + pn.Mint(quxPath, fooPath, fee3000, 98040, 10020, "100000", "100000", "0", "0", max_timeout) - // pn.Mint(fooPath, consts.GNS_PATH, fee100, 48000, 52000, 100_000_000, 100_000_000, 0, 0, max_timeout) + // pn.Mint(fooPath, consts.GNS_PATH, fee100, 48000, 52000, "100000000", "100000000","0", "0" max_timeout) } func TestApiGetRatiosFromBase(t *testing.T) { @@ -96,10 +96,10 @@ func TestApiGetRatiosFromBase(t *testing.T) { {"token":"gno.land/r/demo/wugnot","ratio":79228162514264337593543950336} {"token":"gno.land/r/demo/bar","ratio":19935653721785907863909200771} {"token":"gno.land/r/demo/qux","ratio":79228162514264337593543950338} - {"token":"gno.land/r/demo/foo","ratio":21854449020437189859372345675086} + {"token":"gno.land/r/demo/foo","ratio":21827358772679825007021358318119} {"token":"gno.land/r/demo/baz","ratio":158459202898910110285447649633} - {"token":"gno.land/r/demo/obl","ratio":316924161643118367991168631863} - {"token":"gno.land/r/demo/gns","ratio":633859835185907382391729498087} + {"token":"gno.land/r/demo/obl","ratio":316918405797820220570895299266} + {"token":"gno.land/r/demo/gns","ratio":633836811595640441141790598532} */ shouldEQ(t, responseArr[0].Get("token").String(), "gno.land/r/demo/wugnot") @@ -112,14 +112,14 @@ func TestApiGetRatiosFromBase(t *testing.T) { shouldEQ(t, responseArr[2].Get("ratio").String(), "79228162514264337593543950338") shouldEQ(t, responseArr[3].Get("token").String(), "gno.land/r/demo/foo") - shouldEQ(t, responseArr[3].Get("ratio").String(), "21854449020437189859372345675086") + shouldEQ(t, responseArr[3].Get("ratio").String(), "21827358772679825007021358318119") shouldEQ(t, responseArr[4].Get("token").String(), "gno.land/r/demo/baz") shouldEQ(t, responseArr[4].Get("ratio").String(), "158459202898910110285447649633") shouldEQ(t, responseArr[5].Get("token").String(), "gno.land/r/demo/obl") - shouldEQ(t, responseArr[5].Get("ratio").String(), "316924161643118367991168631863") + shouldEQ(t, responseArr[5].Get("ratio").String(), "316918405797820220570895299266") shouldEQ(t, responseArr[6].Get("token").String(), "gno.land/r/demo/gns") - shouldEQ(t, responseArr[6].Get("ratio").String(), "633859835185907382391729498087") + shouldEQ(t, responseArr[6].Get("ratio").String(), "633836811595640441141790598532") } diff --git a/router/_TEST_router_swap_route_1route_1hop_out_range_test.gnoa b/router/_TEST_router_swap_route_1route_1hop_out_range_test.gnoa index 4d2313e8..0412410b 100644 --- a/router/_TEST_router_swap_route_1route_1hop_out_range_test.gnoa +++ b/router/_TEST_router_swap_route_1route_1hop_out_range_test.gnoa @@ -41,8 +41,8 @@ func TestPositionMint(t *testing.T) { tokenId, liquidity, amount0, amount1 := pn.Mint(barPath, bazPath, fee500, int32(12000), int32(15000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(1)) // shouldEQ(t, liquidity, "1308151") - shouldEQ(t, amount0, "99999") // ONLY BAR - shouldEQ(t, amount1, "0") // NO BAZ + shouldEQ(t, amount0, "100000") // ONLY BAR + shouldEQ(t, amount1, "0") // NO BAZ } func TestDrySwapRouteBarBazExactIn(t *testing.T) { diff --git a/router/_TEST_router_swap_route_1route_1hop_test.gno b/router/_TEST_router_swap_route_1route_1hop_test.gnoa similarity index 95% rename from router/_TEST_router_swap_route_1route_1hop_test.gno rename to router/_TEST_router_swap_route_1route_1hop_test.gnoa index 70d174f9..d1e541f6 100644 --- a/router/_TEST_router_swap_route_1route_1hop_test.gno +++ b/router/_TEST_router_swap_route_1route_1hop_test.gnoa @@ -34,13 +34,13 @@ func TestCreatePool(t *testing.T) { func TestPositionMint(t *testing.T) { // bar_baz_500 by test1 std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), 36789) - baz.Approve(a2u(consts.POOL_ADDR), 99999) + bar.Approve(a2u(consts.POOL_ADDR), 36790) + baz.Approve(a2u(consts.POOL_ADDR), 100000) // Mint tokenId, liquidity, amount0, amount1 := pn.Mint(barPath, bazPath, fee500, int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, amount0, "36789") + shouldEQ(t, amount0, "36790") shouldEQ(t, amount1, "99999") } @@ -89,7 +89,7 @@ func TestDrySwapRouteBarBazExactOut(t *testing.T) { "100", // quoteArr ) - shouldEQ(t, dryResult, "369") + shouldEQ(t, dryResult, "370") } func TestSwapRouteBarBazExactOut(t *testing.T) { @@ -108,7 +108,7 @@ func TestSwapRouteBarBazExactOut(t *testing.T) { "370", // tokenAmountLimit ) - shouldEQ(t, swapResult, "369") + shouldEQ(t, swapResult, "370") } func TestDrySwapRouteBazBarExactIn(t *testing.T) { diff --git a/router/_TEST_router_swap_route_1route_2hop_native_in_out_test.gnoa b/router/_TEST_router_swap_route_1route_2hop_native_in_out_test.gnoa index 4e8daaec..2ea68e92 100644 --- a/router/_TEST_router_swap_route_1route_2hop_native_in_out_test.gnoa +++ b/router/_TEST_router_swap_route_1route_2hop_native_in_out_test.gnoa @@ -38,23 +38,22 @@ func TestCreatePool(t *testing.T) { func TestPositionMintBarBaz(t *testing.T) { std.TestSetPrevAddr(test1) - bar.Approve(a2u(consts.POOL_ADDR), 36789) - baz.Approve(a2u(consts.POOL_ADDR), 99999) - + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + baz.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) tokenId, liquidity, amount0, amount1 := pn.Mint(barPath, bazPath, fee500, int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, amount0, "36789") // bar + shouldEQ(t, amount0, "36790") // bar shouldEQ(t, amount1, "99999") // baz } func TestPositionMintBazQux(t *testing.T) { std.TestSetPrevAddr(test1) - baz.Approve(a2u(consts.POOL_ADDR), 36789) - qux.Approve(a2u(consts.POOL_ADDR), 99999) + baz.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + qux.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) tokenId, liquidity, amount0, amount1 := pn.Mint(bazPath, quxPath, fee500, int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(2)) - shouldEQ(t, amount0, "36789") + shouldEQ(t, amount0, "36790") shouldEQ(t, amount1, "99999") } @@ -63,21 +62,21 @@ func TestPositionMintQuxGnot(t *testing.T) { std.TestSetPrevAddr(test1) // send - std.TestIssueCoins(test1, std.Coins{{"ugnot", 999999}}) - std.TestSetOrigSend(std.Coins{{"ugnot", 999999}}, nil) + std.TestIssueCoins(test1, std.Coins{{"ugnot", 1000009}}) + std.TestSetOrigSend(std.Coins{{"ugnot", 1000009}}, nil) testBanker := std.GetBanker(std.BankerTypeRealmIssue) - testBanker.RemoveCoin(std.GetOrigCaller(), "ugnot", 999999) + testBanker.RemoveCoin(std.GetOrigCaller(), "ugnot", 1000009) // Deposit(wrap) std.TestSetPrevAddr(test1) wugnot.Deposit() - qux.Approve(a2u(consts.POOL_ADDR), 36789) - wugnot.Approve(a2u(consts.POOL_ADDR), 99999) + qux.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + wugnot.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) tokenId, liquidity, amount0, amount1 := pn.Mint(quxPath, consts.WRAPPED_WUGNOT, fee500, int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(3)) - shouldEQ(t, amount0, "36789") + shouldEQ(t, amount0, "36790") shouldEQ(t, amount1, "99999") } @@ -106,7 +105,7 @@ func TestDrySwapRouteBarGnotExactOut(t *testing.T) { "gno.land/r/demo/bar:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/qux:500*POOL*gno.land/r/demo/qux:gno.land/r/demo/wugnot:500", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, "1011") + shouldEQ(t, dryResult, "1012") } func TestDrySwapRouteGnotBarExactIn(t *testing.T) { @@ -134,5 +133,5 @@ func TestDrySwapRouteGnotBarExactOut(t *testing.T) { "gno.land/r/demo/wugnot:gno.land/r/demo/qux:500*POOL*gno.land/r/demo/qux:gno.land/r/demo/baz:500*POOL*gno.land/r/demo/baz:gno.land/r/demo/bar:500", // strRouteArr "100", // quoteArr ) - shouldEQ(t, dryResult, "1986") + shouldEQ(t, dryResult, "2003") } diff --git a/router/_TEST_router_swap_route_1route_3hop_native_middle_test.gnoa b/router/_TEST_router_swap_route_1route_3hop_native_middle_test.gnoa index 230d105f..41106a58 100644 --- a/router/_TEST_router_swap_route_1route_3hop_native_middle_test.gnoa +++ b/router/_TEST_router_swap_route_1route_3hop_native_middle_test.gnoa @@ -46,13 +46,13 @@ func TestPositionMintGnsGnot(t *testing.T) { std.TestSetPrevAddr(test1) wugnot.Deposit() - gns.Approve(a2u(consts.POOL_ADDR), 36789) - wugnot.Approve(a2u(consts.POOL_ADDR), 99999) + gns.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + wugnot.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) tokenId, liquidity, amount0, amount1 := pn.Mint(consts.GNS_PATH, consts.WRAPPED_WUGNOT, fee100, int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(1)) - shouldEQ(t, amount0, "36789") // 36789 - shouldEQ(t, amount1, "99999") // 99999 + shouldEQ(t, amount0, "36790") + shouldEQ(t, amount1, "99999") } func TestPositionMintGnotBar(t *testing.T) { @@ -73,8 +73,8 @@ func TestPositionMintGnotBar(t *testing.T) { tokenId, liquidity, amount0, amount1 := pn.Mint(consts.WRAPPED_WUGNOT, barPath, fee100, int32(9000), int32(11000), "100000", "100000", "0", "0", max_timeout) shouldEQ(t, tokenId, uint64(2)) - shouldEQ(t, amount0, "99999") // 99999 - shouldEQ(t, amount1, "36789") // 36789 + shouldEQ(t, amount0, "100000") // 100000 + shouldEQ(t, amount1, "36789") // 36789 } func TestDrySwapRouteGnsBarExactIn(t *testing.T) { diff --git a/router/_TEST_router_swap_route_2route_2hop_test.gnoa b/router/_TEST_router_swap_route_2route_2hop_test.gnoa index 83ba26bb..fd5a236b 100644 --- a/router/_TEST_router_swap_route_2route_2hop_test.gnoa +++ b/router/_TEST_router_swap_route_2route_2hop_test.gnoa @@ -92,7 +92,7 @@ func TestDrySwapRouteBarQuxExactOut(t *testing.T) { "50,50", // quoteArr ) - shouldEQ(t, dryResult, "136") + shouldEQ(t, dryResult, "138") } func TestSwapRouteBarQuxExactOut(t *testing.T) { @@ -108,7 +108,7 @@ func TestSwapRouteBarQuxExactOut(t *testing.T) { "99999", // tokenAmountLimit ) - shouldEQ(t, swapResult, "136") + shouldEQ(t, swapResult, "138") } func TestDrySwapRouteQuxBarExactIn(t *testing.T) { @@ -154,7 +154,7 @@ func TestDrySwapRouteQuxBarExactOut(t *testing.T) { "30,70", // quoteArr ) - shouldEQ(t, dryResult, "7285") + shouldEQ(t, dryResult, "7336") } func TestwapRouteQuxBarExactOut(t *testing.T) { @@ -173,5 +173,5 @@ func TestwapRouteQuxBarExactOut(t *testing.T) { "99999", // tokenAmountLimit ) - shouldEQ(t, swapResult, "7278") + shouldEQ(t, swapResult, "7350") } From bb45f7aedd294bcecad34638d4627c7b9dbb5598 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 7 Mar 2024 17:34:38 +0900 Subject: [PATCH 3/4] feat: u256*u256 in u256 package chore: remove comments --- ...sition_one_route_one_hop_println_test.gnoa | 2 +- packages/big/{uint512 => uint256}/consts.gno | 2 +- .../uint256/uint256_overflow_calculation.gno | 98 ++++++++++++++ packages/big/uint256/uint256_test.gno | 1 - packages/big/uint512/uint512.gno | 121 ------------------ packages/big/uint512/uint512_test.gno | 37 ------ pool/_RPC_dry.gno | 16 --- pool/_TEST_pool_dryswap_and_swap_test.gno | 2 +- pool/sqrt_price_math.gno | 36 ++---- pool/swap_math.gno | 15 --- position/sqrt_price_math.gno | 36 ++---- 11 files changed, 123 insertions(+), 243 deletions(-) rename packages/big/{uint512 => uint256}/consts.gno (86%) create mode 100644 packages/big/uint256/uint256_overflow_calculation.gno delete mode 100644 packages/big/uint512/uint512.gno delete mode 100644 packages/big/uint512/uint512_test.gno diff --git a/_test/_TEST_scenario_08_router_two_position_one_route_one_hop_println_test.gnoa b/_test/_TEST_scenario_08_router_two_position_one_route_one_hop_println_test.gnoa index 6ddac26f..706f1e2e 100644 --- a/_test/_TEST_scenario_08_router_two_position_one_route_one_hop_println_test.gnoa +++ b/_test/_TEST_scenario_08_router_two_position_one_route_one_hop_println_test.gnoa @@ -105,7 +105,7 @@ func TestPositionMintBarBazInRangeMore(t *testing.T) { shouldEQ(t, tokenId, 2) shouldEQ(t, liquidity, "447321") shouldEQ(t, amount0, "50") - shouldEQ(t, amoutn1, "1000") + shouldEQ(t, amoutn1, "999") std.TestSkipHeights(3) diff --git a/packages/big/uint512/consts.gno b/packages/big/uint256/consts.gno similarity index 86% rename from packages/big/uint512/consts.gno rename to packages/big/uint256/consts.gno index 48eb1edb..2de43d58 100644 --- a/packages/big/uint512/consts.gno +++ b/packages/big/uint256/consts.gno @@ -1,4 +1,4 @@ -package uint512 +package uint256 const ( MAX_UINT256 = "115792089237316195423570985008687907853269984665640564039457584007913129639935" diff --git a/packages/big/uint256/uint256_overflow_calculation.gno b/packages/big/uint256/uint256_overflow_calculation.gno new file mode 100644 index 00000000..88879c3e --- /dev/null +++ b/packages/big/uint256/uint256_overflow_calculation.gno @@ -0,0 +1,98 @@ +// REF: https://github.com/Uniswap/solidity-lib/blob/master/contracts/libraries/FullMath.sol +package uint256 + +func fullMul( + x Uint, + y Uint, +) (Uint, Uint) { // l, h + mm := new(*Uint).MulMod(x, y, UnsafeFromDecimal(MAX_UINT256)) + + l := new(Uint).Mul(x, y) + h := new(Uint).Sub(mm, l) + + if mm.Lt(l) { + h = new(Uint).Sub(h, One()) + } + + return l, h +} + +func fullDiv( + l Uint, + h Uint, + d Uint, +) Uint { + // uint256 pow2 = d & -d; + // d + _negD := new(Uint).Neg(d) + pow2 := new(Uint).And(d, _negD) + d = new(Uint).Div(d, pow2) + l = new(Uint).Div(l, pow2) + + _negPow2 := new(Uint).Neg(pow2) + + value1 := new(Uint).Div(_negPow2, pow2) // (-pow2) / pow2 + value2 := new(Uint).UnsafeAdd(value1, One()) // (-pow2) / pow2 + 1) + value3 := new(Uint).Mul(h, value2) // h * ((-pow2) / pow2 + 1); + l = new(Uint).UnsafeAdd(l, value3) + + r := One() + for i := 0; i < 8; i++ { + value1 := new(Uint).Mul(d, r) // d * r + value2 := new(Uint).Sub(NewUint(2), value1) // 2 - ( d * r ) + r = new(Uint).Mul(r, value2) // r *= 2 - d * r; + } + res := new(Uint).Mul(l, r) + return res +} + +func MulDiv( + x Uint, + y Uint, + d Uint, +) Uint { + l, h := fullMul(x, y) + mm := new(Uint).MulMod(x, y, d) + + if mm.Gt(l) { + h = new(Uint).Sub(h, One()) + } + l = new(Uint).Sub(l, mm) + + if h.IsZero() { + return new(Uint).Div(l, d) + } + + if !(h.Lt(d)) { + panic("FULLDIV_OVERFLOW") + } + + return fullDiv(l, h, d) +} + +func DivRoundingUp( + x Uint, + y Uint, +) Uint { + div := new(Uint).Div(x, y) + + mod := new(Uint).Mod(x, y) + return new(Uint).Add(div, gt(mod, Zero())) +} + +// HELPERs +func lt(x, y Uint) Uint { + if x.Lt(y) { + return One() + } else { + return Zero() + } +} + +func gt(x, y Uint) Uint { + if x.Gt(y) { + return One() + } else { + return Zero() + } +} diff --git a/packages/big/uint256/uint256_test.gno b/packages/big/uint256/uint256_test.gno index 16dc0b64..4f72747e 100644 --- a/packages/big/uint256/uint256_test.gno +++ b/packages/big/uint256/uint256_test.gno @@ -9,7 +9,6 @@ func TestFuncs(t *testing.T) { y := UnsafeFromDecimal("130406999485845074795897568971") z := new(Uint).Add(x, y) - println("z:", z.ToString()) // 130486188034278082001322316149 if z.ToString() != "130486188034278082001322316149" { t.Error("Expected 130486188034278082001322316149, got ", z.ToString()) diff --git a/packages/big/uint512/uint512.gno b/packages/big/uint512/uint512.gno deleted file mode 100644 index f7913820..00000000 --- a/packages/big/uint512/uint512.gno +++ /dev/null @@ -1,121 +0,0 @@ -// REF: https://github.com/Uniswap/solidity-lib/blob/master/contracts/libraries/FullMath.sol -package uint512 - -import ( - i256 "gno.land/p/big/int256" - u256 "gno.land/p/big/uint256" -) - -func fullMul( - x *u256.Uint, - y *u256.Uint, -) (*u256.Uint, *u256.Uint) { // l, h - mm := new(u256.Uint).MulMod(x, y, u256.UnsafeFromDecimal(MAX_UINT256)) - - l := new(u256.Uint).Mul(x, y) - h := new(u256.Uint).Sub(mm, l) - - if mm.Lt(l) { - h = new(u256.Uint).Sub(h, u256.One()) - } - - return l, h -} - -func fullDiv( - l *u256.Uint, - h *u256.Uint, - d *u256.Uint, -) *u256.Uint { - // uint256 pow2 = d & -d; - posD := i256.FromUint256(d) - negD := i256.Zero().Neg(posD) - - intPow2 := i256.Zero().And(posD, negD) - d = new(u256.Uint).Div(d, intPow2.Abs()) - l = new(u256.Uint).Div(l, intPow2.Abs()) - - _negPow2 := new(u256.Uint).Neg(intPow2.Abs()) - - value1 := new(u256.Uint).Div(_negPow2, intPow2.Abs()) // (-pow2) / pow2 - value2 := new(u256.Uint).UnsafeAdd(value1, u256.One()) // (-pow2) / pow2 + 1) - value3 := new(u256.Uint).Mul(h, value2) // h * ((-pow2) / pow2 + 1); - l = new(u256.Uint).UnsafeAdd(l, value3) - - r := u256.One() - for i := 0; i < 8; i++ { - value1 := new(u256.Uint).Mul(d, r) // d * r - value2 := new(u256.Uint).Sub(u256.NewUint(2), value1) // 2 - ( d * r ) - r = new(u256.Uint).Mul(r, value2) // r *= 2 - d * r; - } - res := new(u256.Uint).Mul(l, r) - return res -} - -func MulDiv( - x *u256.Uint, - y *u256.Uint, - d *u256.Uint, -) *u256.Uint { - l, h := fullMul(x, y) - mm := new(u256.Uint).MulMod(x, y, d) - - if mm.Gt(l) { - h = new(u256.Uint).Sub(h, u256.One()) - } - l = new(u256.Uint).Sub(l, mm) - - if h.IsZero() { - return new(u256.Uint).Div(l, d) - } - - if !(h.Lt(d)) { - panic("FULLDIV_OVERFLOW") - } - - return fullDiv(l, h, d) -} - -func MulDivRoundingUp( - x *u256.Uint, - y *u256.Uint, - d *u256.Uint, -) *u256.Uint { - result := MulDiv(x, y, d) - - // _mm := new(u256.Uint).MulMod(x, y, d) - // if _mm.Gt(u256.Zero()) { - // if result.Lt(u256.UnsafeFromDecimal(MAX_UINT256)) { - // result = new(u256.Uint).Add(result, u256.One()) - // } - // } - - return result -} - -func DivRoundingUp( - x *u256.Uint, - y *u256.Uint, -) *u256.Uint { - div := new(u256.Uint).Div(x, y) - - mod := new(u256.Uint).Mod(x, y) - return new(u256.Uint).Add(div, gt(mod, u256.Zero())) -} - -// HELPERs -func lt(x, y *u256.Uint) *u256.Uint { - if x.Lt(y) { - return u256.One() - } else { - return u256.Zero() - } -} - -func gt(x, y *u256.Uint) *u256.Uint { - if x.Gt(y) { - return u256.One() - } else { - return u256.Zero() - } -} diff --git a/packages/big/uint512/uint512_test.gno b/packages/big/uint512/uint512_test.gno deleted file mode 100644 index af8a0e66..00000000 --- a/packages/big/uint512/uint512_test.gno +++ /dev/null @@ -1,37 +0,0 @@ -package uint512 - -import ( - i256 "gno.land/p/big/int256" - u256 "gno.land/p/big/uint256" - - "testing" -) - -func init() { - var _1 = i256.Zero() - var _2 = u256.Zero() -} - -// func TestFunc(*testing.T) { -// x := u256.UnsafeFromDecimal("792281625142643375935439503360000000") -// y := u256.UnsafeFromDecimal("1461446703485210103208044889689724484785180020005") -// d := u256.One() - -// z := MulDiv(x, y, d) -// println(z.ToString()) -// } - -func TestFunc2(t *testing.T) { - x := u256.UnsafeFromDecimal("792281625142643375935439503360000000") // num1 - y := u256.UnsafeFromDecimal("1461446703485210103208044889689724484785180020005") // num2 - // d := u256.One() - - sqrtB := u256.UnsafeFromDecimal("1461446703485210103287273052203988822378723970342") - sqrtA := u256.UnsafeFromDecimal("79228162514264337593543950337") - - z := MulDiv(x, y, sqrtB) - // println("num1 * num2 / sqrtB:", z.ToString()) - - r := DivRoundingUp(z, sqrtA) - println("num1 * num2 / sqrtB / sqrtA:", r.ToString()) -} diff --git a/pool/_RPC_dry.gno b/pool/_RPC_dry.gno index 8bf9b954..46c74306 100644 --- a/pool/_RPC_dry.gno +++ b/pool/_RPC_dry.gno @@ -95,13 +95,9 @@ func DrySwap( liquidity: cache.liquidityStart, } } - // println("state.tick:", state.tick) - // println("IN state.sqrtPriceX96:", state.sqrtPriceX96.ToString()) - // println("state.sqrtPriceX96:", state.sqrtPriceX96.ToString()) // continue swapping as long as we haven't used the entire input/output and haven't reached the price limit for !(state.amountSpecifiedRemaining.IsZero()) && !(state.sqrtPriceX96.Eq(sqrtPriceLimitX96)) { - // println("state.amountSpecifiedRemaining:", state.amountSpecifiedRemaining.ToString()) var step StepComputations step.sqrtPriceStartX96 = state.sqrtPriceX96 @@ -131,11 +127,6 @@ func DrySwap( sqrtRatioTargetX96 = step.sqrtPriceNextX96 } - // println("state.sqrtPriceX96:", state.sqrtPriceX96.ToString()) - // println("sqrtRatioTargetX96:", sqrtRatioTargetX96.ToString()) - // println("state.liquidity:", state.liquidity.ToString()) - // println("state.amountSpecifiedRemaining:", state.amountSpecifiedRemaining.ToString()) - // println("pool.fee:", pool.fee) state.sqrtPriceX96, step.amountIn, step.amountOut, step.feeAmount = swapMathComputeSwapStep( state.sqrtPriceX96, sqrtRatioTargetX96, @@ -143,13 +134,6 @@ func DrySwap( state.amountSpecifiedRemaining, uint64(pool.fee), ) - if step.amountIn.ToString() == "271" { - // println("> state.sqrtPriceX96:", state.sqrtPriceX96.ToString()) - // println("step.amountIn:", step.amountIn.ToString()) - // println("step.amountOut:", step.amountOut.ToString()) - // println("step.feeAmount:", step.feeAmount.ToString()) - // panic("FIX") - } amountInWithFee := i256.FromUint256(new(u256.Uint).Add(step.amountIn, step.feeAmount)) if exactInput { diff --git a/pool/_TEST_pool_dryswap_and_swap_test.gno b/pool/_TEST_pool_dryswap_and_swap_test.gno index 7aaaf5ed..f7b6af10 100644 --- a/pool/_TEST_pool_dryswap_and_swap_test.gno +++ b/pool/_TEST_pool_dryswap_and_swap_test.gno @@ -87,7 +87,7 @@ func TestDrySwap_ZeroForOneTrue_AmountSpecified_Negative_16000(t *testing.T) { consts.MIN_PRICE, // sqrtPriceLimitX96 ) - shouldEQ(t, poolIn, "43512") // r3v4_xxx: ROUNDING ERROR + shouldEQ(t, poolIn, "43512") shouldEQ(t, poolOut, "-16000") } diff --git a/pool/sqrt_price_math.gno b/pool/sqrt_price_math.gno index 3607a2e7..b0181e2b 100644 --- a/pool/sqrt_price_math.gno +++ b/pool/sqrt_price_math.gno @@ -5,7 +5,6 @@ import ( i256 "gno.land/p/big/int256" u256 "gno.land/p/big/uint256" - u512 "gno.land/p/big/uint512" ) func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( @@ -17,10 +16,8 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( if amount.IsZero() { return sqrtPX96 } - // println("|| sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp:", add) numerator1 := new(u256.Uint).Lsh(liquidity, 96) - // println("numerator1:", numerator1.ToString()) if add { product := new(u256.Uint).Mul(amount, sqrtPX96) @@ -28,16 +25,15 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( denominator := new(u256.Uint).Add(numerator1, product) if denominator.Gte(numerator1) { - return u512.MulDivRoundingUp(numerator1, sqrtPX96, denominator) + return u256.MulDiv(numerator1, sqrtPX96, denominator) } } _value1 := new(u256.Uint).Div(numerator1, sqrtPX96) _value2 := new(u256.Uint).Add(_value1, amount) - return u512.DivRoundingUp(numerator1, _value2) + return u256.DivRoundingUp(numerator1, _value2) } else { product := new(u256.Uint).Mul(amount, sqrtPX96) - // println("product:", product.ToString()) cond1 := new(u256.Uint).Div(product, amount).Eq(sqrtPX96) cond2 := numerator1.Gt(product) @@ -46,12 +42,8 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( panic("pool_sqrt price math #1") } denominator := new(u256.Uint).Sub(numerator1, product) - // println("denominator:", denominator.ToString()) - zxc := u512.MulDivRoundingUp(numerator1, sqrtPX96, denominator) - return zxc - // return new(u256.Uint).Sub(zxc, u256.One()) - // return u512.MulDivRoundingUp(numerator1, sqrtPX96, denominator) + return u256.MulDiv(numerator1, sqrtPX96, denominator) } } @@ -62,28 +54,23 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown( add bool, ) *u256.Uint { // uint160 quotient := u256.Zero() - // println("sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown", add) if add { if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { quotient = new(u256.Uint).Lsh(amount, 96) quotient = new(u256.Uint).Div(quotient, liquidity) } else { - quotient = u512.MulDiv(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) + quotient = u256.MulDiv(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) } quotient = new(u256.Uint).Sub(quotient, u256.One()) return new(u256.Uint).Add(sqrtPX96, quotient) } else { - // println("FF") if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { value1 := new(u256.Uint).Lsh(amount, 96) - quotient = u512.DivRoundingUp(value1, liquidity) - // println("q1:", quotient.ToString()) + quotient = u256.DivRoundingUp(value1, liquidity) } else { - quotient = u512.MulDivRoundingUp(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) - // println("q2:", quotient.ToString()) + quotient = u256.MulDiv(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) } - // println("sqrtPX96:", sqrtPX96.ToString()) if !(sqrtPX96.Gt(quotient)) { panic("pool_sqrt price math #2") @@ -113,7 +100,6 @@ func sqrtPriceMathGetNextSqrtPriceFromOutput( amountOut *u256.Uint, // uint256 zeroForOne bool, // bool ) *u256.Uint { // uint160 - // println("sqrtPriceMathGetNextSqrtPriceFromOutput:", zeroForOne) if zeroForOne { return sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) } @@ -139,10 +125,10 @@ func sqrtPriceMathGetAmount0DeltaHelper( } if roundUp { - value1 := u512.MulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96) - return u512.DivRoundingUp(value1, sqrtRatioAX96) + value1 := u256.MulDiv(numerator1, numerator2, sqrtRatioBX96) + return u256.DivRoundingUp(value1, sqrtRatioAX96) } else { - value1 := u512.MulDiv(numerator1, numerator2, sqrtRatioBX96) + value1 := u256.MulDiv(numerator1, numerator2, sqrtRatioBX96) return new(u256.Uint).Div(value1, sqrtRatioAX96) } @@ -160,10 +146,10 @@ func sqrtPriceMathGetAmount1DeltaHelper( if roundUp { value1 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - return u512.MulDivRoundingUp(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) + return u256.MulDiv(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) } else { value1 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - return u512.MulDiv(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) + return u256.MulDiv(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) } } diff --git a/pool/swap_math.gno b/pool/swap_math.gno index d3120fad..4ea025a9 100644 --- a/pool/swap_math.gno +++ b/pool/swap_math.gno @@ -18,10 +18,6 @@ func swapMathComputeSwapStep( // NEGATIVE == EXACT_OUT => Estimated AmountIn exactIn := !(amountRemaining.IsNeg()) // amountRemaining >= 0 - // println() - // println("exactIn", exactIn) // f - // println("isToken1Expensive", isToken1Expensive) // t - if exactIn { amountRemainingLessFee := u256.Zero() @@ -47,30 +43,20 @@ func swapMathComputeSwapStep( } } else { if isToken1Expensive { - // println(1) amountOut = sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, false) } else { - // println(2) amountOut = sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, false) } if amountRemaining.Abs().Gte(amountOut) { - // println(3) sqrtRatioNextX96 = sqrtRatioTargetX96 } else { - // println(4) - // println("sqrtRatioCurrentX96:", sqrtRatioCurrentX96.ToString()) - // println("liquidity:", liquidity.ToString()) - // println("amountRemaining.Abs():", amountRemaining.Abs().ToString()) - // println("isToken1Expensive:", isToken1Expensive) - // println("<< SQRT") sqrtRatioNextX96 = sqrtPriceMathGetNextSqrtPriceFromOutput( sqrtRatioCurrentX96, liquidity, amountRemaining.Abs(), isToken1Expensive, ) - // println("sqrtRatioNextX96:", sqrtRatioNextX96.ToString()) // panic("F") } } @@ -117,6 +103,5 @@ func swapMathComputeSwapStep( if !exactIn && !(amountOut.IsZero()) { amountOut = amountOut.Add(amountOut, u256.NewUint(1)) } - // println() return sqrtRatioNextX96, amountIn, amountOut, feeAmount } diff --git a/position/sqrt_price_math.gno b/position/sqrt_price_math.gno index f6716d35..12a0e682 100644 --- a/position/sqrt_price_math.gno +++ b/position/sqrt_price_math.gno @@ -5,7 +5,6 @@ import ( i256 "gno.land/p/big/int256" u256 "gno.land/p/big/uint256" - u512 "gno.land/p/big/uint512" ) func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( @@ -17,10 +16,8 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( if amount.IsZero() { return sqrtPX96 } - // println("|| sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp:", add) numerator1 := new(u256.Uint).Lsh(liquidity, 96) - // println("numerator1:", numerator1.ToString()) if add { product := new(u256.Uint).Mul(amount, sqrtPX96) @@ -28,16 +25,15 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( denominator := new(u256.Uint).Add(numerator1, product) if denominator.Gte(numerator1) { - return u512.MulDivRoundingUp(numerator1, sqrtPX96, denominator) + return u256.MulDiv(numerator1, sqrtPX96, denominator) } } _value1 := new(u256.Uint).Div(numerator1, sqrtPX96) _value2 := new(u256.Uint).Add(_value1, amount) - return u512.DivRoundingUp(numerator1, _value2) + return u256.DivRoundingUp(numerator1, _value2) } else { product := new(u256.Uint).Mul(amount, sqrtPX96) - // println("product:", product.ToString()) cond1 := new(u256.Uint).Div(product, amount).Eq(sqrtPX96) cond2 := numerator1.Gt(product) @@ -46,12 +42,8 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp( panic("position_sqrt price math #1") } denominator := new(u256.Uint).Sub(numerator1, product) - // println("denominator:", denominator.ToString()) - zxc := u512.MulDivRoundingUp(numerator1, sqrtPX96, denominator) - return zxc - // return new(u256.Uint).Sub(zxc, u256.One()) - // return u512.MulDivRoundingUp(numerator1, sqrtPX96, denominator) + return u256.MulDiv(numerator1, sqrtPX96, denominator) } } @@ -62,28 +54,23 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown( add bool, ) *u256.Uint { // uint160 quotient := u256.Zero() - // println("sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown", add) if add { if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { quotient = new(u256.Uint).Lsh(amount, 96) quotient = new(u256.Uint).Div(quotient, liquidity) } else { - quotient = u512.MulDiv(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) + quotient = u256.MulDiv(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) } quotient = new(u256.Uint).Sub(quotient, u256.One()) return new(u256.Uint).Add(sqrtPX96, quotient) } else { - // println("FF") if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { value1 := new(u256.Uint).Lsh(amount, 96) - quotient = u512.DivRoundingUp(value1, liquidity) - // println("q1:", quotient.ToString()) + quotient = u256.DivRoundingUp(value1, liquidity) } else { - quotient = u512.MulDivRoundingUp(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) - // println("q2:", quotient.ToString()) + quotient = u256.MulDiv(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) } - // println("sqrtPX96:", sqrtPX96.ToString()) if !(sqrtPX96.Gt(quotient)) { panic("position_sqrt price math #2") @@ -113,7 +100,6 @@ func sqrtPriceMathGetNextSqrtPriceFromOutput( amountOut *u256.Uint, // uint256 zeroForOne bool, // bool ) *u256.Uint { // uint160 - // println("sqrtPriceMathGetNextSqrtPriceFromOutput:", zeroForOne) if zeroForOne { return sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) } @@ -139,10 +125,10 @@ func sqrtPriceMathGetAmount0DeltaHelper( } if roundUp { - value1 := u512.MulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96) - return u512.DivRoundingUp(value1, sqrtRatioAX96) + value1 := u256.MulDiv(numerator1, numerator2, sqrtRatioBX96) + return u256.DivRoundingUp(value1, sqrtRatioAX96) } else { - value1 := u512.MulDiv(numerator1, numerator2, sqrtRatioBX96) + value1 := u256.MulDiv(numerator1, numerator2, sqrtRatioBX96) return new(u256.Uint).Div(value1, sqrtRatioAX96) } @@ -160,10 +146,10 @@ func sqrtPriceMathGetAmount1DeltaHelper( if roundUp { value1 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - return u512.MulDivRoundingUp(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) + return u256.MulDiv(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) } else { value1 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - return u512.MulDiv(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) + return u256.MulDiv(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) } } From 51439a5b097e6c523cb8a77b1a792b7f7aacb863 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 7 Mar 2024 17:39:16 +0900 Subject: [PATCH 4/4] chore: remove Unsafe* --- packages/big/int256/int256.gno | 2 +- packages/big/uint256/uint256.gno | 26 ++----- .../uint256/uint256_overflow_calculation.gno | 42 ++++++------ packages/big/uint256/uint256_test.gno | 5 +- packages/common/liquidity_amounts.gno | 6 +- packages/common/tick_math.gno | 68 +++++++++---------- pool/_RPC_dry.gno | 6 +- pool/bit_math.gno | 14 ++-- pool/pool.gno | 6 +- pool/position.gno | 4 +- pool/sqrt_price_math.gno | 12 ++-- pool/tick.gno | 2 +- pool/tick_bitmap.gno | 2 +- position/_RPC_api.gno | 4 +- position/position.gno | 16 ++--- position/sqrt_price_math.gno | 12 ++-- router/_RPC_api.gno | 6 +- router/swap_inner.gno | 8 +-- staker/reward_math.gno | 8 +-- 19 files changed, 118 insertions(+), 131 deletions(-) diff --git a/packages/big/int256/int256.gno b/packages/big/int256/int256.gno index 5ee9ac72..a1028b70 100644 --- a/packages/big/int256/int256.gno +++ b/packages/big/int256/int256.gno @@ -76,7 +76,7 @@ func FromDecimal(s string) (*Int, error) { return new(Int).SetString(s) } -func UnsafeFromDecimal(s string) *Int { +func MustFromDecimal(s string) *Int { z, err := FromDecimal(s) if err != nil { panic(err) diff --git a/packages/big/uint256/uint256.gno b/packages/big/uint256/uint256.gno index 9fa63f64..d78ac6aa 100644 --- a/packages/big/uint256/uint256.gno +++ b/packages/big/uint256/uint256.gno @@ -172,20 +172,6 @@ func (z *Uint) Add(x, y *Uint) *Uint { return z } -func (z *Uint) UnsafeAdd(x, y *Uint) *Uint { - var carry uint64 - z.arr[0], carry = Add64(x.arr[0], y.arr[0], 0) - z.arr[1], carry = Add64(x.arr[1], y.arr[1], carry) - z.arr[2], carry = Add64(x.arr[2], y.arr[2], carry) - z.arr[3], _ = Add64(x.arr[3], y.arr[3], carry) - // Different from the original implementation! - // // We panic on overflow - // if carry != 0 { - // panic("U256 Add overflow") - // } - return z -} - // AddOverflow sets z to the sum x+y, and returns z and whether overflow occurred func (z *Uint) AddOverflow(x, y *Uint) (*Uint, bool) { var carry uint64 @@ -850,13 +836,13 @@ func FromDecimal(decimal string) (*Uint, error) { return &z, nil } -// UnsafeFromDecimal is a convenience-constructor to create an Uint from a -// decimal (base 10) string. Numbers larger than 256 bits are not accepted. -// panic if the input is invalid -func UnsafeFromDecimal(decimal string) *Uint { +// MustFromDecimal is a convenience-constructor to create an Int from a +// decimal (base 10) string. +// Returns a new Int and panics if any error occurred. +func MustFromDecimal(decimal string) *Uint { var z Uint if err := z.SetFromDecimal(decimal); err != nil { - panic("UNSAFE FROM DECIMAL") + panic(err) } return &z } @@ -972,7 +958,7 @@ func (z *Uint) fromDecimal(bs string) error { z.SetUint64(num) } else { base := NewUint(num) - z.UnsafeAdd(z, base.Mul(base, mult)) + z.Add(z, base.Mul(base, mult)) } // Chop off another 19 characters if remaining > 19 { diff --git a/packages/big/uint256/uint256_overflow_calculation.gno b/packages/big/uint256/uint256_overflow_calculation.gno index 88879c3e..9cceba98 100644 --- a/packages/big/uint256/uint256_overflow_calculation.gno +++ b/packages/big/uint256/uint256_overflow_calculation.gno @@ -2,10 +2,10 @@ package uint256 func fullMul( - x Uint, - y Uint, -) (Uint, Uint) { // l, h - mm := new(*Uint).MulMod(x, y, UnsafeFromDecimal(MAX_UINT256)) + x *Uint, + y *Uint, +) (*Uint, *Uint) { // l, h + mm := new(Uint).MulMod(x, y, MustFromDecimal(MAX_UINT256)) l := new(Uint).Mul(x, y) h := new(Uint).Sub(mm, l) @@ -18,10 +18,10 @@ func fullMul( } func fullDiv( - l Uint, - h Uint, - d Uint, -) Uint { + l *Uint, + h *Uint, + d *Uint, +) *Uint { // uint256 pow2 = d & -d; // d _negD := new(Uint).Neg(d) @@ -31,10 +31,10 @@ func fullDiv( _negPow2 := new(Uint).Neg(pow2) - value1 := new(Uint).Div(_negPow2, pow2) // (-pow2) / pow2 - value2 := new(Uint).UnsafeAdd(value1, One()) // (-pow2) / pow2 + 1) - value3 := new(Uint).Mul(h, value2) // h * ((-pow2) / pow2 + 1); - l = new(Uint).UnsafeAdd(l, value3) + value1 := new(Uint).Div(_negPow2, pow2) // (-pow2) / pow2 + value2 := new(Uint).Add(value1, One()) // (-pow2) / pow2 + 1) + value3 := new(Uint).Mul(h, value2) // h * ((-pow2) / pow2 + 1); + l = new(Uint).Add(l, value3) r := One() for i := 0; i < 8; i++ { @@ -47,10 +47,10 @@ func fullDiv( } func MulDiv( - x Uint, - y Uint, - d Uint, -) Uint { + x *Uint, + y *Uint, + d *Uint, +) *Uint { l, h := fullMul(x, y) mm := new(Uint).MulMod(x, y, d) @@ -71,9 +71,9 @@ func MulDiv( } func DivRoundingUp( - x Uint, - y Uint, -) Uint { + x *Uint, + y *Uint, +) *Uint { div := new(Uint).Div(x, y) mod := new(Uint).Mod(x, y) @@ -81,7 +81,7 @@ func DivRoundingUp( } // HELPERs -func lt(x, y Uint) Uint { +func lt(x, y *Uint) *Uint { if x.Lt(y) { return One() } else { @@ -89,7 +89,7 @@ func lt(x, y Uint) Uint { } } -func gt(x, y Uint) Uint { +func gt(x, y *Uint) *Uint { if x.Gt(y) { return One() } else { diff --git a/packages/big/uint256/uint256_test.gno b/packages/big/uint256/uint256_test.gno index 4f72747e..2bba72a9 100644 --- a/packages/big/uint256/uint256_test.gno +++ b/packages/big/uint256/uint256_test.gno @@ -5,10 +5,11 @@ import ( ) func TestFuncs(t *testing.T) { - x := UnsafeFromDecimal("79188548433007205424747178") - y := UnsafeFromDecimal("130406999485845074795897568971") + x := MustFromDecimal("79188548433007205424747178") + y := MustFromDecimal("130406999485845074795897568971") z := new(Uint).Add(x, y) + println("z:", z.ToString()) // 130486188034278082001322316149 if z.ToString() != "130486188034278082001322316149" { t.Error("Expected 130486188034278082001322316149, got ", z.ToString()) diff --git a/packages/common/liquidity_amounts.gno b/packages/common/liquidity_amounts.gno index d0be00d3..90a3a4c5 100644 --- a/packages/common/liquidity_amounts.gno +++ b/packages/common/liquidity_amounts.gno @@ -21,7 +21,7 @@ func toAscendingOrder(a, b *u256.Uint) (*u256.Uint, *u256.Uint) { func calcIntermediateValue(sqrtRatioAX96, sqrtRatioBX96 *u256.Uint) *u256.Uint { res := new(u256.Uint).Mul(sqrtRatioAX96, sqrtRatioBX96) - res = res.Div(res, u256.UnsafeFromDecimal(consts.Q96)) + res = res.Div(res, u256.MustFromDecimal(consts.Q96)) return res } @@ -42,7 +42,7 @@ func computeLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1 *u256.Uint sqrtRatioAX96, sqrtRatioBX96 = toAscendingOrder(sqrtRatioAX96, sqrtRatioBX96) diff := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - res := new(u256.Uint).Mul(amount1, u256.UnsafeFromDecimal(consts.Q96)) + res := new(u256.Uint).Mul(amount1, u256.MustFromDecimal(consts.Q96)) res = res.Div(res, diff) return res } @@ -91,7 +91,7 @@ func computeAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity *u256.Ui diff := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) res := new(u256.Uint).Mul(liquidity, diff) - res = res.Div(res, u256.UnsafeFromDecimal(consts.Q96)) + res = res.Div(res, u256.MustFromDecimal(consts.Q96)) return res } diff --git a/packages/common/tick_math.gno b/packages/common/tick_math.gno index b6cb0e8c..65bb9918 100644 --- a/packages/common/tick_math.gno +++ b/packages/common/tick_math.gno @@ -6,46 +6,46 @@ import ( ) var tickRatioMap = map[int32]*u256.Uint{ - 0x1: u256.UnsafeFromDecimal("340265354078544963557816517032075149313"), // 0xfffcb933bd6fad37aa2d162d1a594001, - 0x2: u256.UnsafeFromDecimal("340248342086729790484326174814286782778"), // 0xfff97272373d413259a46990580e213a, - 0x4: u256.UnsafeFromDecimal("340214320654664324051920982716015181260"), // 0xfff2e50f5f656932ef12357cf3c7fdcc, - 0x8: u256.UnsafeFromDecimal("340146287995602323631171512101879684304"), // 0xffe5caca7e10e4e61c3624eaa0941cd0, - 0x10: u256.UnsafeFromDecimal("340010263488231146823593991679159461444"), // 0xffcb9843d60f6159c9db58835c926644, - 0x20: u256.UnsafeFromDecimal("339738377640345403697157401104375502016"), // 0xff973b41fa98c081472e6896dfb254c0, - 0x40: u256.UnsafeFromDecimal("339195258003219555707034227454543997025"), // 0xff2ea16466c96a3843ec78b326b52861, - 0x80: u256.UnsafeFromDecimal("338111622100601834656805679988414885971"), // 0xfe5dee046a99a2a811c461f1969c3053, - 0x100: u256.UnsafeFromDecimal("335954724994790223023589805789778977700"), // 0xfcbe86c7900a88aedcffc83b479aa3a4, - 0x200: u256.UnsafeFromDecimal("331682121138379247127172139078559817300"), // 0xf987a7253ac413176f2b074cf7815e54, - 0x400: u256.UnsafeFromDecimal("323299236684853023288211250268160618739"), // 0xf3392b0822b70005940c7a398e4b70f3, - 0x800: u256.UnsafeFromDecimal("307163716377032989948697243942600083929"), // 0xe7159475a2c29b7443b29c7fa6e889d9, - 0x1000: u256.UnsafeFromDecimal("277268403626896220162999269216087595045"), // 0xd097f3bdfd2022b8845ad8f792aa5825, - 0x2000: u256.UnsafeFromDecimal("225923453940442621947126027127485391333"), // 0xa9f746462d870fdf8a65dc1f90e061e5, - 0x4000: u256.UnsafeFromDecimal("149997214084966997727330242082538205943"), // 0x70d869a156d2a1b890bb3df62baf32f7, - 0x8000: u256.UnsafeFromDecimal("66119101136024775622716233608466517926"), // 0x31be135f97d08fd981231505542fcfa6, - 0x10000: u256.UnsafeFromDecimal("12847376061809297530290974190478138313"), // 0x9aa508b5b7a84e1c677de54f3e99bc9, - 0x20000: u256.UnsafeFromDecimal("485053260817066172746253684029974020"), // 0x5d6af8dedb81196699c329225ee604, - 0x40000: u256.UnsafeFromDecimal("691415978906521570653435304214168"), // 0x2216e584f5fa1ea926041bedfe98, - 0x80000: u256.UnsafeFromDecimal("1404880482679654955896180642"), // 0x48a170391f7dc42444e8fa2, + 0x1: u256.MustFromDecimal("340265354078544963557816517032075149313"), // 0xfffcb933bd6fad37aa2d162d1a594001, + 0x2: u256.MustFromDecimal("340248342086729790484326174814286782778"), // 0xfff97272373d413259a46990580e213a, + 0x4: u256.MustFromDecimal("340214320654664324051920982716015181260"), // 0xfff2e50f5f656932ef12357cf3c7fdcc, + 0x8: u256.MustFromDecimal("340146287995602323631171512101879684304"), // 0xffe5caca7e10e4e61c3624eaa0941cd0, + 0x10: u256.MustFromDecimal("340010263488231146823593991679159461444"), // 0xffcb9843d60f6159c9db58835c926644, + 0x20: u256.MustFromDecimal("339738377640345403697157401104375502016"), // 0xff973b41fa98c081472e6896dfb254c0, + 0x40: u256.MustFromDecimal("339195258003219555707034227454543997025"), // 0xff2ea16466c96a3843ec78b326b52861, + 0x80: u256.MustFromDecimal("338111622100601834656805679988414885971"), // 0xfe5dee046a99a2a811c461f1969c3053, + 0x100: u256.MustFromDecimal("335954724994790223023589805789778977700"), // 0xfcbe86c7900a88aedcffc83b479aa3a4, + 0x200: u256.MustFromDecimal("331682121138379247127172139078559817300"), // 0xf987a7253ac413176f2b074cf7815e54, + 0x400: u256.MustFromDecimal("323299236684853023288211250268160618739"), // 0xf3392b0822b70005940c7a398e4b70f3, + 0x800: u256.MustFromDecimal("307163716377032989948697243942600083929"), // 0xe7159475a2c29b7443b29c7fa6e889d9, + 0x1000: u256.MustFromDecimal("277268403626896220162999269216087595045"), // 0xd097f3bdfd2022b8845ad8f792aa5825, + 0x2000: u256.MustFromDecimal("225923453940442621947126027127485391333"), // 0xa9f746462d870fdf8a65dc1f90e061e5, + 0x4000: u256.MustFromDecimal("149997214084966997727330242082538205943"), // 0x70d869a156d2a1b890bb3df62baf32f7, + 0x8000: u256.MustFromDecimal("66119101136024775622716233608466517926"), // 0x31be135f97d08fd981231505542fcfa6, + 0x10000: u256.MustFromDecimal("12847376061809297530290974190478138313"), // 0x9aa508b5b7a84e1c677de54f3e99bc9, + 0x20000: u256.MustFromDecimal("485053260817066172746253684029974020"), // 0x5d6af8dedb81196699c329225ee604, + 0x40000: u256.MustFromDecimal("691415978906521570653435304214168"), // 0x2216e584f5fa1ea926041bedfe98, + 0x80000: u256.MustFromDecimal("1404880482679654955896180642"), // 0x48a170391f7dc42444e8fa2, } var binaryLogConsts = [8]*u256.Uint{ - u256.UnsafeFromDecimal("0"), // 0x0, - u256.UnsafeFromDecimal("3"), // 0x3, - u256.UnsafeFromDecimal("15"), // 0xF, - u256.UnsafeFromDecimal("255"), // 0xFF, - u256.UnsafeFromDecimal("65535"), // 0xFFFF, - u256.UnsafeFromDecimal("4294967295"), // 0xFFFFFFFF, - u256.UnsafeFromDecimal("18446744073709551615"), // 0xFFFFFFFFFFFFFFFF, - u256.UnsafeFromDecimal("340282366920938463463374607431768211455"), // 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, + u256.MustFromDecimal("0"), // 0x0, + u256.MustFromDecimal("3"), // 0x3, + u256.MustFromDecimal("15"), // 0xF, + u256.MustFromDecimal("255"), // 0xFF, + u256.MustFromDecimal("65535"), // 0xFFFF, + u256.MustFromDecimal("4294967295"), // 0xFFFFFFFF, + u256.MustFromDecimal("18446744073709551615"), // 0xFFFFFFFFFFFFFFFF, + u256.MustFromDecimal("340282366920938463463374607431768211455"), // 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, } var ( - shift1By32Left = u256.UnsafeFromDecimal("4294967296") // (1 << 32) + shift1By32Left = u256.MustFromDecimal("4294967296") // (1 << 32) ) func TickMathGetSqrtRatioAtTick(tick int32) *u256.Uint { // uint160 sqrtPriceX96 absTick := abs(tick) - ratio := u256.UnsafeFromDecimal("340282366920938463463374607431768211456") // consts.Q128 + ratio := u256.MustFromDecimal("340282366920938463463374607431768211456") // consts.Q128 for mask, value := range tickRatioMap { if absTick&mask != 0 { @@ -56,7 +56,7 @@ func TickMathGetSqrtRatioAtTick(tick int32) *u256.Uint { // uint160 sqrtPriceX96 } if tick > 0 { - _maxUint256 := u256.UnsafeFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935") // consts.MAX_UINT256 + _maxUint256 := u256.MustFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935") // consts.MAX_UINT256 _tmp := new(u256.Uint).Div(_maxUint256, ratio) ratio = _tmp.Clone() } @@ -160,17 +160,17 @@ func calculateLog2(msb, ratio *u256.Uint) *i256.Int { func getTickValue(log2 *i256.Int, sqrtPriceX96 *u256.Uint) int32 { // ref: https://github.com/Uniswap/v3-core/issues/500 // 2^64 / log2 (√1.0001) = 255738958999603826347141 - log_sqrt10001 := i256.Zero().Mul(log2, i256.UnsafeFromDecimal("255738958999603826347141")) + log_sqrt10001 := i256.Zero().Mul(log2, i256.MustFromDecimal("255738958999603826347141")) // ref: https://ethereum.stackexchange.com/questions/113844/how-does-uniswap-v3s-logarithm-library-tickmath-sol-work/113912#113912 // 0.010000497 x 2^128 = 3402992956809132418596140100660247210 - tickLow256 := i256.Zero().Sub(log_sqrt10001, i256.UnsafeFromDecimal("3402992956809132418596140100660247210")) + tickLow256 := i256.Zero().Sub(log_sqrt10001, i256.MustFromDecimal("3402992956809132418596140100660247210")) tickLow256 = tickLow256.Rsh(tickLow256, 128) tickLow := int32(tickLow256.Int64()) // ref: https://ethereum.stackexchange.com/questions/113844/how-does-uniswap-v3s-logarithm-library-tickmath-sol-work/113912#113912 // 0.856 x 2^128 = 291339464771989622907027621153398088495 - tickHi256 := i256.Zero().Add(log_sqrt10001, i256.UnsafeFromDecimal("291339464771989622907027621153398088495")) + tickHi256 := i256.Zero().Add(log_sqrt10001, i256.MustFromDecimal("291339464771989622907027621153398088495")) tickHi256 = tickHi256.Rsh(tickHi256, 128) tickHi := int32(tickHi256.Int64()) diff --git a/pool/_RPC_dry.gno b/pool/_RPC_dry.gno index 46c74306..c393a6f6 100644 --- a/pool/_RPC_dry.gno +++ b/pool/_RPC_dry.gno @@ -39,7 +39,7 @@ func DrySwap( slot0Start := pool.slot0 if zeroForOne { - min_sqrt_ratio := u256.UnsafeFromDecimal(consts.MIN_SQRT_RATIO) + min_sqrt_ratio := u256.MustFromDecimal(consts.MIN_SQRT_RATIO) cond1 := sqrtPriceLimitX96.Lt(slot0Start.sqrtPriceX96) cond2 := sqrtPriceLimitX96.Gt(min_sqrt_ratio) @@ -47,7 +47,7 @@ func DrySwap( return "0", "0", false } } else { - max_sqrt_ratio := u256.UnsafeFromDecimal(consts.MAX_SQRT_RATIO) + max_sqrt_ratio := u256.MustFromDecimal(consts.MAX_SQRT_RATIO) cond1 := sqrtPriceLimitX96.Gt(slot0Start.sqrtPriceX96) cond2 := sqrtPriceLimitX96.Lt(max_sqrt_ratio) @@ -153,7 +153,7 @@ func DrySwap( // update global fee tracker if state.liquidity.Gt(u256.Zero()) { - _q128 := u256.UnsafeFromDecimal(consts.Q128) + _q128 := u256.MustFromDecimal(consts.Q128) value1 := new(u256.Uint).Mul(step.feeAmount, _q128) value2 := new(u256.Uint).Div(value1, state.liquidity) diff --git a/pool/bit_math.gno b/pool/bit_math.gno index ceaeced1..95e8f112 100644 --- a/pool/bit_math.gno +++ b/pool/bit_math.gno @@ -13,8 +13,8 @@ type bitShift struct { func bitMathMostSignificantBit(x *u256.Uint) uint8 { shifts := []bitShift{ - {u256.UnsafeFromDecimal(consts.Q128), 128}, // 2^128 - {u256.UnsafeFromDecimal(consts.Q64), 64}, // 2^64 + {u256.MustFromDecimal(consts.Q128), 128}, // 2^128 + {u256.MustFromDecimal(consts.Q64), 64}, // 2^64 {u256.NewUint(0x100000000), 32}, {u256.NewUint(0x10000), 16}, {u256.NewUint(0x100), 8}, @@ -36,11 +36,11 @@ func bitMathMostSignificantBit(x *u256.Uint) uint8 { func bitMathLeastSignificantBit(x *u256.Uint) uint8 { shifts := []bitShift{ - {u256.UnsafeFromDecimal(consts.MAX_UINT128), 128}, - {u256.UnsafeFromDecimal(consts.MAX_UINT64), 64}, - {u256.UnsafeFromDecimal(consts.MAX_UINT32), 32}, - {u256.UnsafeFromDecimal(consts.MAX_UINT16), 16}, - {u256.UnsafeFromDecimal(consts.MAX_UINT8), 8}, + {u256.MustFromDecimal(consts.MAX_UINT128), 128}, + {u256.MustFromDecimal(consts.MAX_UINT64), 64}, + {u256.MustFromDecimal(consts.MAX_UINT32), 32}, + {u256.MustFromDecimal(consts.MAX_UINT16), 16}, + {u256.MustFromDecimal(consts.MAX_UINT8), 8}, {u256.NewUint(0xf), 4}, {u256.NewUint(0x3), 2}, {u256.NewUint(0x1), 1}, diff --git a/pool/pool.gno b/pool/pool.gno index 1af9de82..194a1b9b 100644 --- a/pool/pool.gno +++ b/pool/pool.gno @@ -219,7 +219,7 @@ func Swap( var feeGrowthGlobalX128 *u256.Uint if zeroForOne { - min_sqrt_ratio := u256.UnsafeFromDecimal(consts.MIN_SQRT_RATIO) + min_sqrt_ratio := u256.MustFromDecimal(consts.MIN_SQRT_RATIO) cond1 := sqrtPriceLimitX96.Lt(slot0Start.sqrtPriceX96) cond2 := sqrtPriceLimitX96.Gt(min_sqrt_ratio) require(cond1 && cond2, ufmt.Sprintf("[POOL] pool.gno__Swap() || sqrtPriceLimitX96(%s) < slot0Start.sqrtPriceX96(%s) && sqrtPriceLimitX96(%s) > consts.MIN_SQRT_RATIO(%s)", sqrtPriceLimitX96.ToString(), slot0Start.sqrtPriceX96.ToString(), sqrtPriceLimitX96.ToString(), consts.MIN_SQRT_RATIO)) @@ -227,7 +227,7 @@ func Swap( feeProtocol = slot0Start.feeProtocol % 16 feeGrowthGlobalX128 = pool.feeGrowthGlobal0X128.Clone() } else { - max_sqrt_ratio := u256.UnsafeFromDecimal(consts.MAX_SQRT_RATIO) + max_sqrt_ratio := u256.MustFromDecimal(consts.MAX_SQRT_RATIO) cond1 := sqrtPriceLimitX96.Gt(slot0Start.sqrtPriceX96) cond2 := sqrtPriceLimitX96.Lt(max_sqrt_ratio) require(cond1 && cond2, ufmt.Sprintf("[POOL] pool.gno__Swap() || sqrtPriceLimitX96(%s) > slot0Start.sqrtPriceX96(%s) && sqrtPriceLimitX96(%s) < consts.MAX_SQRT_RATIO(%s)", sqrtPriceLimitX96.ToString(), slot0Start.sqrtPriceX96.ToString(), sqrtPriceLimitX96.ToString(), consts.MAX_SQRT_RATIO)) @@ -333,7 +333,7 @@ func Swap( // update global fee tracker if state.liquidity.Gt(u256.Zero()) { - _q128 := u256.UnsafeFromDecimal(consts.Q128) + _q128 := u256.MustFromDecimal(consts.Q128) value1 := new(u256.Uint).Mul(step.feeAmount, _q128) value2 := new(u256.Uint).Div(value1, state.liquidity) diff --git a/pool/position.gno b/pool/position.gno index e17454b5..4c0b9338 100644 --- a/pool/position.gno +++ b/pool/position.gno @@ -69,11 +69,11 @@ func positionUpdate( tokensOwed0 := new(u256.Uint).Sub(feeGrowthInside0X128, self.feeGrowthInside0LastX128) tokensOwed0 = tokensOwed0.Mul(tokensOwed0, self.liquidity) - tokensOwed0 = tokensOwed0.Div(tokensOwed0, u256.UnsafeFromDecimal(consts.Q128)) + tokensOwed0 = tokensOwed0.Div(tokensOwed0, u256.MustFromDecimal(consts.Q128)) tokensOwed1 := new(u256.Uint).Sub(feeGrowthInside1X128, self.feeGrowthInside1LastX128) tokensOwed1 = tokensOwed1.Mul(tokensOwed1, self.liquidity) - tokensOwed1 = tokensOwed1.Div(tokensOwed1, u256.UnsafeFromDecimal(consts.Q128)) + tokensOwed1 = tokensOwed1.Div(tokensOwed1, u256.MustFromDecimal(consts.Q128)) if !(liquidityDelta.IsZero()) { self.liquidity = liquidityNext diff --git a/pool/sqrt_price_math.gno b/pool/sqrt_price_math.gno index b0181e2b..d5bf3005 100644 --- a/pool/sqrt_price_math.gno +++ b/pool/sqrt_price_math.gno @@ -55,21 +55,21 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown( ) *u256.Uint { // uint160 quotient := u256.Zero() if add { - if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { + if amount.Lte(u256.MustFromDecimal(consts.MAX_UINT160)) { quotient = new(u256.Uint).Lsh(amount, 96) quotient = new(u256.Uint).Div(quotient, liquidity) } else { - quotient = u256.MulDiv(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) + quotient = u256.MulDiv(amount, u256.MustFromDecimal(consts.Q96), liquidity) } quotient = new(u256.Uint).Sub(quotient, u256.One()) return new(u256.Uint).Add(sqrtPX96, quotient) } else { - if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { + if amount.Lte(u256.MustFromDecimal(consts.MAX_UINT160)) { value1 := new(u256.Uint).Lsh(amount, 96) quotient = u256.DivRoundingUp(value1, liquidity) } else { - quotient = u256.MulDiv(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) + quotient = u256.MulDiv(amount, u256.MustFromDecimal(consts.Q96), liquidity) } if !(sqrtPX96.Gt(quotient)) { @@ -146,10 +146,10 @@ func sqrtPriceMathGetAmount1DeltaHelper( if roundUp { value1 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - return u256.MulDiv(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) + return u256.MulDiv(liquidity, value1, u256.MustFromDecimal(consts.Q96)) } else { value1 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - return u256.MulDiv(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) + return u256.MulDiv(liquidity, value1, u256.MustFromDecimal(consts.Q96)) } } diff --git a/pool/tick.gno b/pool/tick.gno index 8cfe7f16..64b10bcc 100644 --- a/pool/tick.gno +++ b/pool/tick.gno @@ -15,7 +15,7 @@ func tickTickSpacingToMaxLiquidityPerTick(tickSpacing int32) *u256.Uint { // requireUnsigned(consts.MAX_UINT128/numTicks, ufmt.Sprintf("[POOL] tick.gno__tickTickSpacingToMaxLiquidityPerTick() || consts.MAX_UINT128(%d) / numTicks(%d) >= 0(%d)", consts.MAX_UINT128, numTicks, consts.MAX_UINT128/numTicks)) // return consts.MAX_UINT128 / numTicks - _maxUint128 := u256.UnsafeFromDecimal(consts.MAX_UINT128) + _maxUint128 := u256.MustFromDecimal(consts.MAX_UINT128) return new(u256.Uint).Div(_maxUint128, u256.NewUint(numTicks)) } diff --git a/pool/tick_bitmap.gno b/pool/tick_bitmap.gno index 24343c93..40606c38 100644 --- a/pool/tick_bitmap.gno +++ b/pool/tick_bitmap.gno @@ -96,7 +96,7 @@ func bigintBitwiseNotForUint256BitmapIndexing(x *u256.Uint) *u256.Uint { // REF: https://stackoverflow.com/a/77071037 // Create a mask with all bits set to 1 - mask := u256.UnsafeFromDecimal(consts.MAX_UINT256) + mask := u256.MustFromDecimal(consts.MAX_UINT256) mask = new(u256.Uint).Sub(mask, u256.NewUint(1)) // XOR with mask to perform bitwise NOT diff --git a/position/_RPC_api.gno b/position/_RPC_api.gno index c8caac11..30c19ca0 100644 --- a/position/_RPC_api.gno +++ b/position/_RPC_api.gno @@ -162,11 +162,11 @@ func unclaimedFee(tokenId uint64) (*u256.Uint, *u256.Uint) { value01 := new(u256.Uint).Sub(feeGrowthInside0X128, feeGrowthInside0LastX128) value02 := new(u256.Uint).Mul(liquidity, value01) - unclaimedFee0 := new(u256.Uint).Div(value02, u256.UnsafeFromDecimal(consts.Q128)) + unclaimedFee0 := new(u256.Uint).Div(value02, u256.MustFromDecimal(consts.Q128)) value11 := new(u256.Uint).Sub(feeGrowthInside1X128, feeGrowthInside1LastX128) value12 := new(u256.Uint).Mul(liquidity, value11) - unclaimedFee1 := new(u256.Uint).Div(value12, u256.UnsafeFromDecimal(consts.Q128)) + unclaimedFee1 := new(u256.Uint).Div(value12, u256.MustFromDecimal(consts.Q128)) return unclaimedFee0, unclaimedFee1 } diff --git a/position/position.gno b/position/position.gno index 4c8205ea..4e9b2c29 100644 --- a/position/position.gno +++ b/position/position.gno @@ -181,7 +181,7 @@ func increaseLiquidity(params IncreaseLiquidityParams) (uint64, string, string, // position.tokensOwed0 += (feeGrowthInside0LastX128 - position.feeGrowthInside0LastX128) * position.liquidity / consts.Q128 value1 := new(u256.Uint).Sub(feeGrowthInside0LastX128.Clone(), position.feeGrowthInside0LastX128.Clone()) value2 := new(u256.Uint).Mul(value1, position.liquidity) - value3 := new(u256.Uint).Div(value2, u256.UnsafeFromDecimal(consts.Q128)) + value3 := new(u256.Uint).Div(value2, u256.MustFromDecimal(consts.Q128)) position.tokensOwed0 = new(u256.Uint).Add(position.tokensOwed0, value3) } @@ -189,7 +189,7 @@ func increaseLiquidity(params IncreaseLiquidityParams) (uint64, string, string, // position.tokensOwed1 += (feeGrowthInside1LastX128 - position.feeGrowthInside1LastX128) * position.liquidity / consts.Q128 value1 := new(u256.Uint).Sub(feeGrowthInside1LastX128.Clone(), position.feeGrowthInside1LastX128.Clone()) value2 := new(u256.Uint).Mul(value1, position.liquidity) - value3 := new(u256.Uint).Div(value2, u256.UnsafeFromDecimal(consts.Q128)) + value3 := new(u256.Uint).Div(value2, u256.MustFromDecimal(consts.Q128)) position.tokensOwed1 = new(u256.Uint).Add(position.tokensOwed1, value3) } @@ -282,7 +282,7 @@ func decreaseLiquidity(params DecreaseLiquidityParams) (uint64, string, string, { value1 := new(u256.Uint).Sub(feeGrowthInside0LastX128, position.feeGrowthInside0LastX128) value2 := new(u256.Uint).Mul(value1, position.liquidity) - value3 := new(u256.Uint).Div(value2, u256.UnsafeFromDecimal(consts.Q128)) + value3 := new(u256.Uint).Div(value2, u256.MustFromDecimal(consts.Q128)) value4 := new(u256.Uint).Add(burnedAmount0, value3) position.tokensOwed0 = new(u256.Uint).Add(position.tokensOwed0, value4) @@ -291,7 +291,7 @@ func decreaseLiquidity(params DecreaseLiquidityParams) (uint64, string, string, { value1 := new(u256.Uint).Sub(feeGrowthInside1LastX128, position.feeGrowthInside1LastX128) value2 := new(u256.Uint).Mul(value1, position.liquidity) - value3 := new(u256.Uint).Div(value2, u256.UnsafeFromDecimal(consts.Q128)) + value3 := new(u256.Uint).Div(value2, u256.MustFromDecimal(consts.Q128)) value4 := new(u256.Uint).Add(burnedAmount1, value3) position.tokensOwed1 = new(u256.Uint).Add(position.tokensOwed1, value4) @@ -302,14 +302,14 @@ func decreaseLiquidity(params DecreaseLiquidityParams) (uint64, string, string, if feeGrowthInside0LastX128.IsZero() { position.feeGrowthInside0LastX128 = u256.Zero() } else { - _cloneFromDecimal := u256.UnsafeFromDecimal(feeGrowthInside0LastX128.ToString()) + _cloneFromDecimal := u256.MustFromDecimal(feeGrowthInside0LastX128.ToString()) position.feeGrowthInside0LastX128 = _cloneFromDecimal } if feeGrowthInside1LastX128.IsZero() { position.feeGrowthInside1LastX128 = u256.Zero() } else { - _cloneFromDecimal := u256.UnsafeFromDecimal(feeGrowthInside1LastX128.ToString()) + _cloneFromDecimal := u256.MustFromDecimal(feeGrowthInside1LastX128.ToString()) position.feeGrowthInside1LastX128 = _cloneFromDecimal } @@ -377,14 +377,14 @@ func CollectFee(tokenId uint64) (uint64, string, string, string) { // tokenId, t { value1 := new(u256.Uint).Sub(feeGrowthInside0LastX128, position.feeGrowthInside0LastX128) value2 := new(u256.Uint).Mul(value1, position.liquidity) - value3 := new(u256.Uint).Div(value2, u256.UnsafeFromDecimal(consts.Q128)) + value3 := new(u256.Uint).Div(value2, u256.MustFromDecimal(consts.Q128)) tokensOwed0 = new(u256.Uint).Add(tokensOwed0, value3) } { value1 := new(u256.Uint).Sub(feeGrowthInside1LastX128, position.feeGrowthInside1LastX128) value2 := new(u256.Uint).Mul(value1, position.liquidity) - value3 := new(u256.Uint).Div(value2, u256.UnsafeFromDecimal(consts.Q128)) + value3 := new(u256.Uint).Div(value2, u256.MustFromDecimal(consts.Q128)) tokensOwed1 = new(u256.Uint).Add(tokensOwed1, value3) } diff --git a/position/sqrt_price_math.gno b/position/sqrt_price_math.gno index 12a0e682..8ccf6415 100644 --- a/position/sqrt_price_math.gno +++ b/position/sqrt_price_math.gno @@ -55,21 +55,21 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown( ) *u256.Uint { // uint160 quotient := u256.Zero() if add { - if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { + if amount.Lte(u256.MustFromDecimal(consts.MAX_UINT160)) { quotient = new(u256.Uint).Lsh(amount, 96) quotient = new(u256.Uint).Div(quotient, liquidity) } else { - quotient = u256.MulDiv(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) + quotient = u256.MulDiv(amount, u256.MustFromDecimal(consts.Q96), liquidity) } quotient = new(u256.Uint).Sub(quotient, u256.One()) return new(u256.Uint).Add(sqrtPX96, quotient) } else { - if amount.Lte(u256.UnsafeFromDecimal(consts.MAX_UINT160)) { + if amount.Lte(u256.MustFromDecimal(consts.MAX_UINT160)) { value1 := new(u256.Uint).Lsh(amount, 96) quotient = u256.DivRoundingUp(value1, liquidity) } else { - quotient = u256.MulDiv(amount, u256.UnsafeFromDecimal(consts.Q96), liquidity) + quotient = u256.MulDiv(amount, u256.MustFromDecimal(consts.Q96), liquidity) } if !(sqrtPX96.Gt(quotient)) { @@ -146,10 +146,10 @@ func sqrtPriceMathGetAmount1DeltaHelper( if roundUp { value1 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - return u256.MulDiv(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) + return u256.MulDiv(liquidity, value1, u256.MustFromDecimal(consts.Q96)) } else { value1 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96) - return u256.MulDiv(liquidity, value1, u256.UnsafeFromDecimal(consts.Q96)) + return u256.MulDiv(liquidity, value1, u256.MustFromDecimal(consts.Q96)) } } diff --git a/router/_RPC_api.gno b/router/_RPC_api.gno index 3a5cbf46..5e09bb93 100644 --- a/router/_RPC_api.gno +++ b/router/_RPC_api.gno @@ -52,7 +52,7 @@ func ApiGetRatiosFromBase() string { func findRatios(maxHops int) []TokenRatio { var tokenRatio = make(map[string]*u256.Uint, 0) // WGNOT - tokenRatio[consts.WRAPPED_WUGNOT] = u256.UnsafeFromDecimal(consts.Q96) // ~= 1 + tokenRatio[consts.WRAPPED_WUGNOT] = u256.MustFromDecimal(consts.Q96) // ~= 1 tokens := getTokenList() @@ -133,9 +133,9 @@ func calculateTokenRatio(currentToken string, routes []PoolWithMeta, proceed int for { // remove as much X96 as possible tempPriceX96 := priceX96.Clone() - priceX96 = new(u256.Uint).Div(priceX96, u256.UnsafeFromDecimal(consts.Q96)) + priceX96 = new(u256.Uint).Div(priceX96, u256.MustFromDecimal(consts.Q96)) - if priceX96.Lt(u256.UnsafeFromDecimal(consts.MIN_PRICE)) { + if priceX96.Lt(u256.MustFromDecimal(consts.MIN_PRICE)) { if proceed == len(routes) { return tempPriceX96 } diff --git a/router/swap_inner.gno b/router/swap_inner.gno index 8a47c8cf..ebea9798 100644 --- a/router/swap_inner.gno +++ b/router/swap_inner.gno @@ -24,9 +24,9 @@ func _swap( if sqrtPriceLimitX96.IsZero() { if zeroForOne { - sqrtPriceLimitX96 = u256.UnsafeFromDecimal(consts.MIN_PRICE) + sqrtPriceLimitX96 = u256.MustFromDecimal(consts.MIN_PRICE) } else { - sqrtPriceLimitX96 = u256.UnsafeFromDecimal(consts.MAX_PRICE) + sqrtPriceLimitX96 = u256.MustFromDecimal(consts.MAX_PRICE) } } @@ -71,9 +71,9 @@ func _swapDry( if sqrtPriceLimitX96.IsZero() { if zeroForOne { - sqrtPriceLimitX96 = u256.UnsafeFromDecimal(consts.MIN_PRICE) + sqrtPriceLimitX96 = u256.MustFromDecimal(consts.MIN_PRICE) } else { - sqrtPriceLimitX96 = u256.UnsafeFromDecimal(consts.MAX_PRICE) + sqrtPriceLimitX96 = u256.MustFromDecimal(consts.MAX_PRICE) } } diff --git a/staker/reward_math.gno b/staker/reward_math.gno index a3d93256..a1013b63 100644 --- a/staker/reward_math.gno +++ b/staker/reward_math.gno @@ -50,7 +50,7 @@ func userClaimedRewardAmount(address std.Address, tokenId uint64, rewardTokenPat } func rewardMathComputeInternalRewardAmount(tokenId uint64, deposit Deposit) *u256.Uint { - _q96 := u256.UnsafeFromDecimal(consts.Q96) + _q96 := u256.MustFromDecimal(consts.Q96) // r3v4_xxx: calculate amount of `GNS` to be minted by every block // 1. get block creation time (5s for now) @@ -98,7 +98,7 @@ func rewardMathComputeInternalRewardAmount(tokenId uint64, deposit Deposit) *u25 } func rewardMathComputeExternalRewardAmount(tokenId uint64, deposit Deposit, incentive Incentive) *u256.Uint { - _q96 := u256.UnsafeFromDecimal(consts.Q96) + _q96 := u256.MustFromDecimal(consts.Q96) // 1 month reward amount incentiveDuration := incentive.endTimestamp - incentive.startTimestamp @@ -168,7 +168,7 @@ func getPoolTotalStakedLiquidity(poolPath string) *u256.Uint { } func getMyLiquidityRatio(poolPath string, tokenId uint64) *u256.Uint { - _q96 := u256.UnsafeFromDecimal(consts.Q96) + _q96 := u256.MustFromDecimal(consts.Q96) poolStakedLiquidity := getPoolTotalStakedLiquidity(poolPath) @@ -190,7 +190,7 @@ func getMyLiquidityRatio(poolPath string, tokenId uint64) *u256.Uint { // get current pool tier and reward ratio func getPoolTierAndRatio(poolPath string) (uint64, *u256.Uint) { - _q96 := u256.UnsafeFromDecimal(consts.Q96) + _q96 := u256.MustFromDecimal(consts.Q96) poolPath = poolKeyDivide(poolPath)