Skip to content

Commit

Permalink
paritally fix: CollectRewardByProjectId -- update RewardState
Browse files Browse the repository at this point in the history
  • Loading branch information
notJoon committed Jan 9, 2025
1 parent 1dd921e commit 7136488
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 62 deletions.
17 changes: 15 additions & 2 deletions launchpad/deposit.gno
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,14 @@ func processFirstDeposit(info ProjectTierInfo) (Tier, error) {
tier := info.Tier
tier.started.height = info.Height
tier.started.time = info.CurrentTime
tier.tierAmountPerBlockX96 = calcProjectTiersRewardPerBlockX96(tier)
tier.tierAmountPerBlockX128 = calcProjectTiersRewardPerBlockX128(tier)

// should be update reward state here
rewardState := NewRewardState(tier.tierAmountPerBlockX128, info.Height, info.Tier.ended.height)
rewardStates.Set(info.Project.id, info.TierStr, rewardState)

// Remove from projectTiersWithoutDeposit as it now has a deposit
delete(projectTiersWithoutDeposit, tier.id)

return tier, nil
}
Expand Down Expand Up @@ -259,7 +266,7 @@ func DepositGns(targetProjectTierId string, amount uint64) string {
"depositId", deposit.id,
"claimableHeight", strconv.FormatUint(deposit.claimableHeight, 10),
"claimableTime", strconv.FormatUint(deposit.claimableTime, 10),
"tierAmountPerBlockX96", updatedTier.tierAmountPerBlockX96.ToString(),
"tierAmountPerBlockX128", updatedTier.tierAmountPerBlockX128.ToString(),
)
}

Expand All @@ -271,6 +278,12 @@ func DepositGns(targetProjectTierId string, amount uint64) string {
project.stats.actualParticipant++
projects[projectId] = project

rewardState, err := rewardStates.Get(projectId, tierStr)
if err != nil {
panic(err)
}
rewardState.AddStake(uint64(std.GetHeight()), deposit.id, amount)

return deposit.id
}

Expand Down
4 changes: 2 additions & 2 deletions launchpad/json_builder.gno
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ func RefundInfoBuilder(b *json.NodeBuilder, info RefundInfo) *json.NodeBuilder {
func TierBuilder(b *json.NodeBuilder, prefix string, tier Tier) *json.NodeBuilder {
b.WriteString(prefix+"CollectWaitDuration", ufmt.Sprintf("%d", tier.collectWaitDuration))
b.WriteString(prefix+"TierAmount", ufmt.Sprintf("%d", tier.tierAmount))
if tier.tierAmountPerBlockX96 != nil {
b.WriteString(prefix+"TierAmountPerBlockX96", tier.tierAmountPerBlockX96.ToString())
if tier.tierAmountPerBlockX128 != nil {
b.WriteString(prefix+"TierAmountPerBlockX128", tier.tierAmountPerBlockX128.ToString())
}
TimeInfoBuilder(b, prefix+"Started", tier.started)
TimeInfoBuilder(b, prefix+"Ended", tier.ended)
Expand Down
4 changes: 2 additions & 2 deletions launchpad/json_builder_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func TestTierBuilder(t *testing.T) {
tier := Tier{
collectWaitDuration: 100,
tierAmount: 5000,
tierAmountPerBlockX96: amountPerBlock,
tierAmountPerBlockX128: amountPerBlock,
started: TimeInfo{height: 100, time: 1234567890},
ended: TimeInfo{height: 200, time: 1234567899},
totalDepositAmount: 1000,
Expand All @@ -68,7 +68,7 @@ func TestTierBuilder(t *testing.T) {
TierBuilder(b, "test", tier)

result := b.Node()
expected := `{"testCollectWaitDuration":"100","testTierAmount":"5000","testTierAmountPerBlockX96":"1000000","testStartedHeight":"100","testStartedTime":"1234567890","testEndedHeight":"200","testEndedTime":"1234567899","testTotalDepositAmount":"1000","testActualDepositAmount":"800","testTotalParticipant":"50","testActualParticipant":"40","testUserCollectedAmount":"300","testCalculatedAmount":"400"}`
expected := `{"testCollectWaitDuration":"100","testTierAmount":"5000","testTierAmountPerBlockX128":"1000000","testStartedHeight":"100","testStartedTime":"1234567890","testEndedHeight":"200","testEndedTime":"1234567899","testTotalDepositAmount":"1000","testActualDepositAmount":"800","testTotalParticipant":"50","testActualParticipant":"40","testUserCollectedAmount":"300","testCalculatedAmount":"400"}`

res, err := json.Marshal(result)
uassert.NoError(t, err)
Expand Down
11 changes: 9 additions & 2 deletions launchpad/launchpad.gno
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ var (
)

var (
q96 = u256.Zero()
q128 = u256.Zero()
)

const (
PAD_SEP = "*PAD*"
)

func init() {
q96 = u256.MustFromDecimal(consts.Q96)
q128 = u256.MustFromDecimal(consts.Q128)
}

// ProjectInput represents the input parameters for creating a new project
Expand Down Expand Up @@ -90,6 +90,13 @@ func createTier(projectId string, duration uint64, amount uint64, startHeight ui
},
}

// Calculate reward per block for the tier
tier.tierAmountPerBlockX128 = calcProjectTiersRewardPerBlockX128(tier)

// Initialize reward state for this tier
rewardState := NewRewardState(tier.tierAmountPerBlockX128, startHeight, endHeight)
rewardStates.Set(projectId, strconv.FormatUint(duration, 10), rewardState)

projectTiersWithoutDeposit[tierId] = true
return tier
}
Expand Down
37 changes: 22 additions & 15 deletions launchpad/reward.gno
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ func validateRewardCollection(deposit Deposit, height uint64) error {

// calculateTierRewards calculates rewards for each tier
func calculateTierRewards(tier Tier, currentHeight uint64, lastCalcHeight uint64) (*u256.Uint, uint64, error) {
if tier.tierAmountPerBlockX96 == nil {
if tier.tierAmountPerBlockX128 == nil {
return u256.Zero(), 0, nil
}

if tier.tierAmountPerBlockX96.IsZero() {
if tier.tierAmountPerBlockX128.IsZero() {
return u256.Zero(), 0, nil
}

Expand All @@ -62,10 +62,10 @@ func calculateTierRewards(tier Tier, currentHeight uint64, lastCalcHeight uint64
return u256.Zero(), 0, nil
}

rewardX96 := new(u256.Uint).Mul(tier.tierAmountPerBlockX96.NilToZero().Clone(), u256.NewUint(sinceLast))
reward := new(u256.Uint).Div(rewardX96, q96).Uint64()
rewardX128 := new(u256.Uint).Mul(tier.tierAmountPerBlockX128.NilToZero().Clone(), u256.NewUint(sinceLast))
reward := new(u256.Uint).Div(rewardX128, q128).Uint64()

return rewardX96, reward, nil
return rewardX128, reward, nil
}

/*
Expand Down Expand Up @@ -94,12 +94,14 @@ func CollectRewardByProjectId(projectId string) uint64 {

project, exists := projects[projectId]
if !exists {
println("A: return 0")
return 0
}

caller := std.PrevRealm().Addr()
depositIds, exists := depositsByUserByProject[caller][projectId]
if !exists {
println("B: return 0")
return 0
}

Expand All @@ -110,24 +112,29 @@ func CollectRewardByProjectId(projectId string) uint64 {
for _, depositId := range depositIds {
deposit, exists := deposits[depositId]
if !exists {
println("C: continue")
continue
}

rewardState, err := rewardStates.Get(deposit.projectId, deposit.tier)
if err != nil {
println("D: continue")
continue
}
reward := rewardState.Claim(depositId, height)
if reward == 0 {
println("E: continue")
continue
}

project := projects[deposit.projectId]
if project.id != projectId {
println("F: continue")
continue
}

if err := validateRewardCollection(deposit, height); err != nil {
println("G: continue")
continue
}

Expand Down Expand Up @@ -354,22 +361,22 @@ func calculateDepositReward() {
}
}
*/
// calcDepositRatioX96 calculates the deposit ratio with Q96 precision
func calcDepositRatioX96(tierAmount uint64, amount uint64) *u256.Uint {
amountX96 := new(u256.Uint).Mul(u256.NewUint(amount), q96.Clone())
amountX96x := new(u256.Uint).Mul(amountX96, u256.NewUint(1_000_000_000))
// calcDepositRatioX128 calculates the deposit ratio with Q128 precision
func calcDepositRatioX128(tierAmount uint64, amount uint64) *u256.Uint {
amountX128 := new(u256.Uint).Mul(u256.NewUint(amount), q128.Clone())
amountX128x := new(u256.Uint).Mul(amountX128, u256.NewUint(1_000_000_000))

tierAmountX96 := new(u256.Uint).Mul(u256.NewUint(tierAmount), q96.Clone())
tierAmountX128 := new(u256.Uint).Mul(u256.NewUint(tierAmount), q128.Clone())

depositRatioX96 := new(u256.Uint).Div(amountX96x, tierAmountX96)
depositRatioX96 = depositRatioX96.Mul(depositRatioX96, q96.Clone())
depositRatioX96 := new(u256.Uint).Div(amountX128x, tierAmountX128)
depositRatioX96 = depositRatioX96.Mul(depositRatioX96, q128.Clone())
depositRatioX96 = depositRatioX96.Div(depositRatioX96, u256.NewUint(1_000_000_000))

return depositRatioX96
}

// calcProjectTiersRewardPerBlockX96 calculates the reward per block with Q96 precision
func calcProjectTiersRewardPerBlockX96(tier Tier) *u256.Uint {
tierAmountX96 := new(u256.Uint).Mul(u256.NewUint(tier.tierAmount), q96)
return new(u256.Uint).Div(tierAmountX96, u256.NewUint(tier.ended.height-tier.started.height))
func calcProjectTiersRewardPerBlockX128(tier Tier) *u256.Uint {
tierAmountX128 := new(u256.Uint).Mul(u256.NewUint(tier.tierAmount), q128)
return new(u256.Uint).Div(tierAmountX128, u256.NewUint(tier.ended.height-tier.started.height))
}
47 changes: 29 additions & 18 deletions launchpad/reward_calculation.gno
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

type StakerRewardInfo struct {
StartHeight uint64 // height when staker started staking
PriceDebt *u256.Uint // price debt per xGNS stake, Q96
PriceDebt *u256.Uint // price debt per xGNS stake, Q128
Amount uint64 // amount of xGNS staked
Claimed uint64 // amount of GNS reward claimed so far
}
Expand All @@ -19,15 +19,15 @@ func (self *StakerRewardInfo) Debug() string {
}

func (self *StakerRewardInfo) PriceDebtUint64() uint64 {
return u256.Zero().Rsh(self.PriceDebt, 96).Uint64()
return u256.Zero().Rsh(self.PriceDebt, 128).Uint64()
}

type RewardState struct {
PriceAccumulation *u256.Uint // claimable Launchpad reward per xGNS stake, Q96
PriceAccumulation *u256.Uint // claimable Launchpad reward per xGNS stake, Q128
TotalStake uint64 // total xGNS staked

LastHeight uint64 // last height when reward was calculated
RewardPerBlock *u256.Uint // reward per block, = Tier.tierAmountPerBlockX96
RewardPerBlock *u256.Uint // reward per block, = Tier.tierAmountPerBlockX128
EndHeight uint64

TotalEmptyBlock uint64
Expand All @@ -46,6 +46,18 @@ func NewRewardState(rewardPerBlock *u256.Uint, startHeight uint64, endHeight uin
}
}

func (self *RewardState) PriceAccumulationUint64() uint64 {
return u256.Zero().Rsh(self.PriceAccumulation, 128).Uint64()
}

func (self *RewardState) RewardPerBlockUint64() uint64 {
return u256.Zero().Rsh(self.RewardPerBlock, 128).Uint64()
}

func (self *RewardState) Debug() string {
return ufmt.Sprintf("{ PriceAccumulation: %d, TotalStake: %d, LastHeight: %d, RewardPerBlock: %d, EndHeight: %d, info: len(%d) }", self.PriceAccumulationUint64(), self.TotalStake, self.LastHeight, self.RewardPerBlockUint64(), self.EndHeight, self.info.Size())
}

type RewardStates struct {
states *avl.Tree // projectId:tier string -> RewardState
}
Expand All @@ -63,7 +75,9 @@ func (states RewardStates) Get(projectId string, tierStr string) (*RewardState,
return statesI.(*RewardState), nil
}

/// XXXX
func (states RewardStates) Set(projectId string, tierStr string, state *RewardState) {
println("pass set")
key := projectId + ":" + tierStr
states.states.Set(key, state)
}
Expand Down Expand Up @@ -91,14 +105,6 @@ func (states RewardStates) DeleteProject(projectId string) uint64 {
return totalLeftover
}

func (self *RewardState) Debug() string {
return ufmt.Sprintf("{ PriceAccumulation: %d, TotalStake: %d, LastHeight: %d, RewardPerBlock: %d, EndHeight: %d, info: len(%d) }", self.PriceAccumulationUint64(), self.TotalStake, self.LastHeight, self.RewardPerBlockUint64(), self.EndHeight, self.info.Size())
}

func (self *RewardState) RewardPerBlockUint64() uint64 {
return u256.Zero().Rsh(self.RewardPerBlock, 96).Uint64()
}

func (self *RewardState) Info(depositId string) StakerRewardInfo {
infoI, exists := self.info.Get(depositId)
if !exists {
Expand All @@ -111,21 +117,18 @@ func (self *RewardState) CalculateReward(depositId string) uint64 {
info := self.Info(depositId)
stakerPrice := u256.Zero().Sub(self.PriceAccumulation, info.PriceDebt)
reward := stakerPrice.Mul(stakerPrice, u256.NewUint(info.Amount))
reward = reward.Rsh(reward, 96)
reward = reward.Rsh(reward,128)
return reward.Uint64() - info.Claimed
}

func (self *RewardState) PriceAccumulationUint64() uint64 {
return u256.Zero().Rsh(self.PriceAccumulation, 96).Uint64()
}

// amount MUST be less than or equal to the amount of xGNS staked
// This function does not check it
func (self *RewardState) deductReward(depositId string, currentHeight uint64) uint64 {
println("deductReward debug", self.Debug())
info := self.Info(depositId)
stakerPrice := u256.Zero().Sub(self.PriceAccumulation, info.PriceDebt)
reward := stakerPrice.Mul(stakerPrice, u256.NewUint(info.Amount))
reward = reward.Rsh(reward, 96)
reward = reward.Rsh(reward, 128)
reward64 := reward.Uint64() - info.Claimed

info.Claimed += reward64
Expand All @@ -143,10 +146,15 @@ func (self *RewardState) finalize(currentHeight uint64) {
// Not started yet
return
}
if self.LastHeight >= self.EndHeight {
// already ended
return
}
if currentHeight > self.EndHeight {
currentHeight = self.EndHeight
}

// ????? height 차이에 의한 오차 고
delta := u256.NewUint(currentHeight - self.LastHeight)
delta = delta.Mul(delta, self.RewardPerBlock)

Expand Down Expand Up @@ -187,11 +195,14 @@ func (self *RewardState) AddStake(currentHeight uint64, depositId string, amount
Claimed: 0,
}

println("addstake info", info.Debug())

self.info.Set(depositId, info)
}

func (self *RewardState) Claim(depositId string, currentHeight uint64) uint64 {
if !self.info.Has(depositId) {
println("claim debug", self.Debug())
return 0
}

Expand Down
Loading

0 comments on commit 7136488

Please sign in to comment.