From 5c66a51aac36102685d191b570ab981921477c65 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 2 Jan 2025 18:53:02 +0900 Subject: [PATCH] !fixme: processing unclaimable reward in same height --- ...eriod_internal_07_collect_rewards_test.gno | 290 ++++++++++++++++++ staker/staker.gno | 2 + 2 files changed, 292 insertions(+) create mode 100644 staker/__TEST_staker_short_warmup_period_internal_07_collect_rewards_test.gno diff --git a/staker/__TEST_staker_short_warmup_period_internal_07_collect_rewards_test.gno b/staker/__TEST_staker_short_warmup_period_internal_07_collect_rewards_test.gno new file mode 100644 index 000000000..946135039 --- /dev/null +++ b/staker/__TEST_staker_short_warmup_period_internal_07_collect_rewards_test.gno @@ -0,0 +1,290 @@ +package staker + +import ( + "math" + "std" + "testing" + + "gno.land/p/demo/uassert" + + "gno.land/r/gnoswap/v1/consts" + + en "gno.land/r/gnoswap/v1/emission" + pl "gno.land/r/gnoswap/v1/pool" + pn "gno.land/r/gnoswap/v1/position" + + "gno.land/r/gnoswap/v1/gnft" + "gno.land/r/gnoswap/v1/gns" + + "gno.land/r/onbloc/bar" + "gno.land/r/onbloc/baz" + "gno.land/r/onbloc/qux" +) + +func TestShortWarmUpInternalCollectRewards(t *testing.T) { + testInit(t) + testDoubleMint(t) + testCreatePool(t) + testMintBarQux100_1(t) + testMintBarBaz100_2(t) + testStakeToken_1(t) + testSetPoolTier(t) + testStakeToken_2(t) + testCollect1_1(t) + testCollect1_2(t) + testCollect1_3(t) + testCollect1_4(t) + testCollect2_1(t) + testCollectAll_1(t) + testCollectNow(t) + testCollectSameBlock(t) + testCollectAfterSingleBlock(t) +} + +func testInit(t *testing.T) { + t.Run("init pool tiers", func(t *testing.T) { + std.TestSetRealm(adminRealm) + + // init pool tiers + // tier 1 + deletePoolTier(t, MUST_EXISTS_IN_TIER_1) + addPoolTier(t, `gno.land/r/onbloc/bar:gno.land/r/onbloc/qux:100`, 1) + std.TestSkipHeights(1) + + // override warm-up period for testing + changeWarmup(t, 0, 150) + changeWarmup(t, 1, 300) + changeWarmup(t, 2, 900) + changeWarmup(t, 3, math.MaxInt64) + + // set unstaking fee to 0 + SetUnstakingFeeByAdmin(0) + + // set pool creation fee to 0 + pl.SetPoolCreationFeeByAdmin(0) + + // set community pool distribution to 0% (give it to devOps) + en.ChangeDistributionPctByAdmin( + 1, 7500, + 2, 2500, + 3, 0, + 4, 0, + ) + }) +} + +func testDoubleMint(t *testing.T) { + t.Run("double mint", func(t *testing.T) { + en.MintAndDistributeGns() + en.MintAndDistributeGns() + + std.TestSkipHeights(1) + }) +} + +func testCreatePool(t *testing.T) { + t.Run("create pool", func(t *testing.T) { + std.TestSetRealm(adminRealm) + + gns.Approve(a2u(consts.POOL_ADDR), pl.GetPoolCreationFee()*3) + + pl.CreatePool(barPath, quxPath, 100, "79228162514264337593543950337") + pl.CreatePool(barPath, bazPath, 3000, "79228162514264337593543950337") + + std.TestSkipHeights(1) + }) +} + +func testMintBarQux100_1(t *testing.T) { + + t.Run("mint position 01, bar:qux:100", func(t *testing.T) { + std.TestSetRealm(adminRealm) + + bar.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + qux.Approve(a2u(consts.POOL_ADDR), consts.UINT64_MAX) + + tokenId, liquidity, amount0, amount1 := pn.Mint( + barPath, // token0 + quxPath, // token1 + fee100, // fee + int32(-1000), // tickLower + int32(1000), // tickUpper + "50", // amount0Desired + "50", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, + adminAddr, + adminAddr, + ) + + uassert.Equal(t, tokenId, uint64(1)) + uassert.Equal(t, gnft.MustOwnerOf(tid(tokenId)), adminAddr) + + gpi := getPrintInfo(t) + // uassert.Equal(t, gpi, `{"height":126,"time":1234567896,"gns":{"staker":0,"devOps":8561643,"communityPool":34246574,"govStaker":0,"protocolFee":200000000,"GnoswapAdmin":99999800000000},"pool":[{"poolPath":"gno.land/r/onbloc/bar:gno.land/r/onbloc/qux:100","startTimestamp":1234567890,"tier":1,"numPoolSameTier":1,"poolReward":0,"position":[]}]}`) + + std.TestSkipHeights(1) + }) +} + +func testMintBarBaz100_2(t *testing.T) { + t.Run("mint position 02, bar:baz:3000", func(t *testing.T) { + + std.TestSetRealm(adminRealm) + + 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, // token0 + bazPath, // token1 + fee3000, // fee + int32(-1020), // tickLower + int32(1020), // tickUpper + "50", // amount0Desired + "50", // amount1Desired + "1", // amount0Min + "1", // amount1Min + max_timeout, + adminAddr, + adminAddr, + ) + + uassert.Equal(t, tokenId, uint64(2)) + uassert.Equal(t, gnft.MustOwnerOf(tid(tokenId)), adminAddr) + + std.TestSkipHeights(1) + }) +} + +func testStakeToken_1(t *testing.T) { + t.Run("stake token 01", func(t *testing.T) { + + std.TestSetRealm(adminRealm) + + gnft.Approve(consts.STAKER_ADDR, tid(1)) + StakeToken(1) + + std.TestSkipHeights(1) + }) +} + +func testSetPoolTier(t *testing.T) { + t.Run("set pool tier", func(t *testing.T) { + + std.TestSkipHeights(800) // this reward should go to bar:qux:100 + + std.TestSetRealm(adminRealm) + addPoolTier(t, "gno.land/r/onbloc/bar:gno.land/r/onbloc/baz:3000", 2) + + std.TestSkipHeights(1) + }) +} + +func testStakeToken_2(t *testing.T) { + t.Run("stake token 02", func(t *testing.T) { + + std.TestSetRealm(adminRealm) + + gnft.Approve(consts.STAKER_ADDR, tid(2)) + StakeToken(2) + + std.TestSkipHeights(1) + }) +} + +func testCollect1_1(t *testing.T) { + t.Run("collect reward for position 01, 1st time", func(t *testing.T) { + + std.TestSetRealm(adminRealm) + + CollectReward(1, false) + + std.TestSkipHeights(5) + }) +} + +func testCollect1_2(t *testing.T) { + t.Run("collect reward for position 01, 2nd time", func(t *testing.T) { + + std.TestSetRealm(adminRealm) + + CollectReward(1, false) + + std.TestSkipHeights(500) + }) +} + +func testCollect1_3(t *testing.T) { + t.Run("collect reward for position 01, 3rd time", func(t *testing.T) { + + std.TestSetRealm(adminRealm) + + CollectReward(1, false) + + std.TestSkipHeights(50) + }) +} + +func testCollect1_4(t *testing.T) { + t.Run("collect reward for position 01, 4th time", func(t *testing.T) { + + std.TestSetRealm(adminRealm) + + CollectReward(1, false) + + std.TestSkipHeights(50) + }) +} + +func testCollect2_1(t *testing.T) { + t.Run("collect reward for position 02, 1st time", func(t *testing.T) { + + std.TestSetRealm(adminRealm) + + CollectReward(2, false) + + std.TestSkipHeights(5) + }) +} + +func testCollectAll_1(t *testing.T) { + t.Run("collect reward for all positions, 1st time", func(t *testing.T) { + + std.TestSetRealm(adminRealm) + + CollectReward(1, false) + CollectReward(2, false) + + std.TestSkipHeights(5) + }) +} + +func testCollectNow(t *testing.T) { + t.Run("collect reward for position 01, now", func(t *testing.T) { + std.TestSetRealm(adminRealm) + + CollectReward(1, false) + }) +} + +func testCollectSameBlock(t *testing.T) { + t.Run("collect reward for position 01, same block", func(t *testing.T) { + std.TestSetRealm(adminRealm) + + CollectReward(1, false) + }) +} + +func testCollectAfterSingleBlock(t *testing.T) { + t.Run("collect reward for position 01, after single block", func(t *testing.T) { + std.TestSkipHeights(1) + + std.TestSetRealm(adminRealm) + + // FIXME @mconcat + // panic: slice index out of bounds: 0 (len=0) + CollectReward(1, false) + }) +} diff --git a/staker/staker.gno b/staker/staker.gno index e9d3c9edd..b02423e41 100644 --- a/staker/staker.gno +++ b/staker/staker.gno @@ -382,6 +382,8 @@ func CollectReward(tokenId uint64, unwrapResult bool) string { // internal penalty to community pool gns.Transfer(a2u(consts.COMMUNITY_POOL_ADDR), reward.InternalPenalty) + // FIXME @mconcat + // panic: slice index out of bounds: 0 (len=0) unclaimableInternal, unclaimableExternal := ProcessUnclaimableReward(deposit.targetPoolPath, uint64(std.GetHeight())) // internal unclaimable to community pool