diff --git a/staker/reward_math.gno b/staker/reward_math.gno index 8cbadfcc9..41ea3d1d4 100644 --- a/staker/reward_math.gno +++ b/staker/reward_math.gno @@ -16,19 +16,24 @@ const ( TIMESTAMP_360DAYS = 31104000 ) -type userClaimedReward map[std.Address]map[string]bigint // address -> rewardTokenPath -> rewardTokenAmount +type userClaimedReward map[std.Address]map[uint64]map[string]bigint // address -> lpTokenId -> rewardTokenPath -> rewardTokenAmount var userClaimedRewards = make(userClaimedReward) -func userClaimedRewardAmount(address std.Address, rewardTokenPath string, rewardAmount bigint, claimeRequest bool) bigint { +func userClaimedRewardAmount(address std.Address, tokenId uint64, rewardTokenPath string, rewardAmount bigint, claimeRequest bool) bigint { userClaimed, ok := userClaimedRewards[address] // if user(address) ever claimed reward if !ok { - userClaimedRewards[address] = make(map[string]bigint) + userClaimedRewards[address] = make(map[uint64]map[string]bigint) } - claimedReward, ok := userClaimedRewards[address][rewardTokenPath] // if user(address) ever claimed rewardTokenPath + claimedPosition, ok := userClaimedRewards[address][tokenId] // if user(address) ever claimed reward from tokenId + if !ok { + userClaimedRewards[address][tokenId] = make(map[string]bigint) + } + + claimedReward, ok := userClaimedRewards[address][tokenId][rewardTokenPath] // if user(address) ever claimed rewardTokenPath if !ok { if claimeRequest { // if user is claiming rewardTokenPath - userClaimedRewards[address][rewardTokenPath] = rewardAmount // add rewardTokenPath to userClaimedRewards + userClaimedRewards[address][tokenId][rewardTokenPath] = rewardAmount // add rewardTokenPath to userClaimedRewards return rewardAmount } else { // if user is not claiming rewardTokenPath return rewardAmount @@ -39,7 +44,7 @@ func userClaimedRewardAmount(address std.Address, rewardTokenPath string, reward var claimableAmount bigint if claimeRequest { // if user is claiming rewardTokenPath claimableAmount = rewardAmount - claimedReward - userClaimedRewards[address][rewardTokenPath] += claimableAmount + userClaimedRewards[address][tokenId][rewardTokenPath] += claimableAmount return claimableAmount } else { // if user is not claiming rewardTokenPath claimableAmount = rewardAmount - claimedReward @@ -83,12 +88,12 @@ func rewardMathComputeInternalRewardAmount(tokenId uint64, deposit Deposit) bigi finalRewardQ := myWholeRewardX96 * bigint(rewardRatio) finalReward := finalRewardQ / consts.Q96 / consts.Q96 / consts.Q96 / consts.Q96 / consts.Q96 / 100 / 100 - // why do we need to divide by (Q96 ^ 5) + // divide by (Q96 ^ 5) // #1 ~ 2: used by getPoolTierAndRatio() // #3 : used by poolRewardPerBlockX96 // #4 ~ 5: used by getMyLiquidityRatio() - // why do we need to divide by (100 ^ 2) + // divide by (100 ^ 2) // #1: to convert `listTierRatio()` return value to percentage // #2: to convert `getRewardRatio()` return value to percentage @@ -105,7 +110,7 @@ func rewardMathComputeExternalRewardAmount(tokenId uint64, deposit Deposit, ince monthlyReward = incentive.rewardAmount / 3 case incentiveDuration > TIMESTAMP_90DAYS: // 1 second reward == total reward amount / reward duration - monthlyReward = incentive.rewardAmount / bigint(incentiveDuration) + monthlyReward = incentive.rewardAmount / bigint(incentiveDuration) * 2592000 // 30 days default: panic(ufmt.Sprintf("[STAKER] reward_math.gno || incentiveDuration(%d) should be at least 90 days", incentiveDuration)) } diff --git a/staker/staker.gno b/staker/staker.gno index b35cd4d85..c7df3629e 100644 --- a/staker/staker.gno +++ b/staker/staker.gno @@ -6,15 +6,13 @@ import ( "gno.land/p/demo/common" "gno.land/p/demo/ufmt" - gnft "gno.land/r/demo/gnft" // GNFT, Gnoswap NFT - gns "gno.land/r/demo/gns" // GNS, Gnoswap Share + "gno.land/r/demo/consts" - pl "gno.land/r/demo/pool" - pos "gno.land/r/demo/position" -) + "gno.land/r/demo/gnft" + "gno.land/r/demo/gns" -const ( - INTERNAL_REWARD_ACCOUNT = std.Address("g1paqttvcjcluuya9n9twyw7yacv54mt7ld3gvzm") // r3v4_xxx: CHANGE WHEN DEPLOYING TO OFFICIAL NETWORK + pl "gno.land/r/demo/pool" + pn "gno.land/r/demo/position" ) var ( @@ -106,11 +104,11 @@ func StakeToken(tokenId uint64) (string, bigint, bigint) { ) // check tokenId has liquidity or not - liquidity := pos.PositionGetPositionLiquidity(tokenId) + liquidity := pn.PositionGetPositionLiquidity(tokenId) require(liquidity > 0, ufmt.Sprintf("[STAKER] staker.gno__StakeToken() || tokenId(%d) has no liquidity", tokenId)) // check pool path from tokenid - poolKey := pos.PositionGetPositionPoolKey(tokenId) + poolKey := pn.PositionGetPositionPoolKey(tokenId) // staked status deposit := deposits[tokenId] @@ -135,13 +133,13 @@ func CollectReward( require(PrevRealmAddr() == deposit.owner, ufmt.Sprintf("[STAKER] staker.gno__CollectReward() || only owner(%s) can collect reward from tokenId(%d), PrevRealmAddr()(%s)", deposit.owner, tokenId, PrevRealmAddr())) // poolPath to collect reward - poolPath := pos.PositionGetPositionPoolKey(tokenId) + poolPath := pn.PositionGetPositionPoolKey(tokenId) // get all external reward list for this pool for _, incentiveId := range poolIncentives[poolPath] { incentive := incentives[incentiveId] externalReward := rewardMathComputeExternalRewardAmount(tokenId, deposit, incentive) // external reward - externalReward = userClaimedRewardAmount(deposit.owner, incentive.rewardToken, bigint(externalReward), true) + externalReward = userClaimedRewardAmount(deposit.owner, tokenId, incentive.rewardToken, bigint(externalReward), true) if externalReward > 0 { transferByRegisterCall(incentive.rewardToken, deposit.owner, uint64(externalReward)) @@ -153,11 +151,11 @@ func CollectReward( // default `Internal` reward internalGNS := rewardMathComputeInternalRewardAmount(tokenId, deposit) - internalGNS = userClaimedRewardAmount(deposit.owner, "gno.land/r/demo/gns", bigint(internalGNS), true) + internalGNS = userClaimedRewardAmount(deposit.owner, tokenId, consts.GNS_PATH, bigint(internalGNS), true) if internalGNS > 0 { // transfer it - gns.TransferFrom(a2u(INTERNAL_REWARD_ACCOUNT), a2u(deposit.owner), uint64(internalGNS)) + gns.TransferFrom(a2u(consts.INTERNAL_REWARD_ACCOUNT), a2u(deposit.owner), uint64(internalGNS)) } } @@ -170,13 +168,13 @@ func UnstakeToken(tokenId uint64) (string, bigint, bigint) { require(PrevRealmAddr() == deposit.owner, ufmt.Sprintf("[STAKER] staker.gno__UnstakeToken() || only owner(%s) can unstake their token(%d), PrevRealmAddr()(%s)", deposit.owner, tokenId, PrevRealmAddr())) // poolPath to unstake lp token - poolPath := pos.PositionGetPositionPoolKey(tokenId) + poolPath := pn.PositionGetPositionPoolKey(tokenId) // get all external reward list for this pool for _, incentiveId := range poolIncentives[poolPath] { incentive := incentives[incentiveId] externalReward := rewardMathComputeExternalRewardAmount(tokenId, deposit, incentive) // external reward - externalReward = userClaimedRewardAmount(deposit.owner, incentive.rewardToken, externalReward, true) + externalReward = userClaimedRewardAmount(deposit.owner, tokenId, incentive.rewardToken, externalReward, true) if externalReward > 0 { transferByRegisterCall(incentive.rewardToken, deposit.owner, uint64(externalReward)) @@ -188,10 +186,10 @@ func UnstakeToken(tokenId uint64) (string, bigint, bigint) { // default `Internal` reward internalGNS := rewardMathComputeInternalRewardAmount(tokenId, deposit) - internalGNS = userClaimedRewardAmount(deposit.owner, "gno.land/r/demo/gns", internalGNS, true) + internalGNS = userClaimedRewardAmount(deposit.owner, tokenId, consts.GNS_PATH, internalGNS, true) if internalGNS > 0 { // transfer it - gns.TransferFrom(a2u(INTERNAL_REWARD_ACCOUNT), a2u(deposit.owner), uint64(internalGNS)) + gns.TransferFrom(a2u(consts.INTERNAL_REWARD_ACCOUNT), a2u(deposit.owner), uint64(internalGNS)) } // unstaked status @@ -214,7 +212,7 @@ func EndExternalIncentive(refundee, targetPoolPath, rewardToken string) { // 1. admin can end incentive without refund // 2. refundee can end incentive with refund switch GetOrigCaller() { - case std.Address("g16kvq0mra3atvr07lkdwc2x6jqmna8a4kt0e85d"): // ADMIN + case consts.GNOSWAP_ADMIN: // r3v4_xxx: // admin can end incentive without refund incentives = deleteFromIncentives(incentives, incentiveId) for i, v := range poolIncentives[targetPoolPath] { @@ -281,18 +279,18 @@ func deleteFromIncentives(m map[string]Incentive, key string) map[string]Incenti } func getTokenPairBalanceFromPosition(tokenId uint64) (bigint, bigint) { - poolKey := pos.PositionGetPositionPoolKey(tokenId) + poolKey := pn.PositionGetPositionPoolKey(tokenId) pool := pl.GetPoolFromPoolPath(poolKey) currentX96 := pool.PoolGetSlot0SqrtPriceX96() - lowerX96 := common.TickMathGetSqrtRatioAtTick(pos.PositionGetPositionTickLower(tokenId)) - upperX96 := common.TickMathGetSqrtRatioAtTick(pos.PositionGetPositionTickUpper(tokenId)) + lowerX96 := common.TickMathGetSqrtRatioAtTick(pn.PositionGetPositionTickLower(tokenId)) + upperX96 := common.TickMathGetSqrtRatioAtTick(pn.PositionGetPositionTickUpper(tokenId)) token0Balance, token1Balance := common.LiquidityAmountsGetAmountsForLiquidity( currentX96, lowerX96, upperX96, - pos.PositionGetPositionLiquidity(tokenId), + pn.PositionGetPositionLiquidity(tokenId), ) return token0Balance, token1Balance