Skip to content

Commit

Permalink
fix: delegate amount boundary test
Browse files Browse the repository at this point in the history
  • Loading branch information
onlyhyde committed Jan 7, 2025
1 parent 2f83ac9 commit 51abb02
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 27 deletions.
51 changes: 26 additions & 25 deletions gov/staker/reward_calculation.gno
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ import (
"gno.land/r/gnoswap/v1/common"
"gno.land/r/gnoswap/v1/consts"

ufmt "gno.land/p/demo/ufmt"
"gno.land/p/demo/avl"
ufmt "gno.land/p/demo/ufmt"
u256 "gno.land/p/gnoswap/uint256"

"gno.land/r/gnoswap/v1/gov/xgns"
)

var (
Expand All @@ -35,10 +33,10 @@ func currentBalance() uint64 {
}

type StakerRewardInfo struct {
StartHeight uint64 // height when staker started staking
PriceDebt *u256.Uint // price debt per xGNS stake, Q128
Amount uint64 // amount of xGNS staked
Claimed uint64 // amount of GNS reward claimed so far
StartHeight uint64 // height when staker started staking
PriceDebt *u256.Uint // price debt per xGNS stake, Q128
Amount uint64 // amount of xGNS staked
Claimed uint64 // amount of GNS reward claimed so far
}

func (self *StakerRewardInfo) Debug() string {
Expand All @@ -49,10 +47,9 @@ func (self *StakerRewardInfo) PriceDebtUint64() uint64 {
return u256.Zero().Rsh(self.PriceDebt, 128).Uint64()
}


type RewardState struct {
// CurrentBalance is sum of all the previous balances, including the reward distribution.
CurrentBalance uint64 // current balance of gov_staker, used to calculate RewardAccumulation
CurrentBalance uint64 // current balance of gov_staker, used to calculate RewardAccumulation
PriceAccumulation *u256.Uint // claimable GNS per xGNS stake, Q128
// RewardAccumulation *u256.Uint // reward accumulated so far, Q128
TotalStake uint64 // total xGNS staked
Expand All @@ -61,11 +58,11 @@ type RewardState struct {
}

func NewRewardState() *RewardState {
return &RewardState {
info: avl.NewTree(),
CurrentBalance: 0,
return &RewardState{
info: avl.NewTree(),
CurrentBalance: 0,
PriceAccumulation: u256.Zero(),
TotalStake: 0,
TotalStake: 0,
}
}

Expand Down Expand Up @@ -95,7 +92,6 @@ func (self *RewardState) PriceAccumulationUint64() uint64 {
return u256.Zero().Rsh(self.PriceAccumulation, 128).Uint64()
}


// amount MUST be less than or equal to the amount of xGNS staked
// This function does not check it
func (self *RewardState) deductReward(staker std.Address, currentBalance uint64) uint64 {
Expand Down Expand Up @@ -130,23 +126,28 @@ func (self *RewardState) finalize(currentBalance uint64) {
self.CurrentBalance = currentBalance
}

func (self *RewardState) AddStake(currentHeight uint64, staker std.Address, amount uint64, currentBalance uint64) {
if self.info.Has(staker.String()) {
panic(ufmt.Sprintf("staker %s already exists", staker.String()))
}

func (self *RewardState) AddStake(currentHeight uint64, staker std.Address, amount uint64, currentBalance uint64) {
self.finalize(currentBalance)

self.TotalStake += amount

if self.info.Has(staker.String()) {
info := self.Info(staker)
info.PriceDebt.Add(info.PriceDebt, u256.NewUint(info.Amount))
info.PriceDebt.Add(info.PriceDebt, u256.Zero().Mul(self.PriceAccumulation, u256.NewUint(amount)))
info.PriceDebt.Div(info.PriceDebt, u256.NewUint(self.TotalStake))
info.Amount += amount
self.info.Set(staker.String(), info)
return
}

info := StakerRewardInfo {
info := StakerRewardInfo{
StartHeight: currentHeight,
PriceDebt: self.PriceAccumulation.Clone(),
Amount: amount,
Claimed: 0,
PriceDebt: self.PriceAccumulation.Clone(),
Amount: amount,
Claimed: 0,
}

self.info.Set(staker.String(), info)
}

Expand All @@ -164,7 +165,7 @@ func (self *RewardState) Claim(staker std.Address, currentBalance uint64) uint64

func (self *RewardState) RemoveStake(staker std.Address, amount uint64, currentBalance uint64) uint64 {
self.finalize(currentBalance)

reward := self.deductReward(staker, currentBalance)

self.info.Remove(staker.String())
Expand Down
21 changes: 21 additions & 0 deletions gov/staker/staker.gno
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ func Delegate(to std.Address, amount uint64) {
))
}

if amount%minimumAmount != 0 {
panic(addDetailToError(
errInvalidAmount,
ufmt.Sprintf("amount must be multiple of %d", minimumAmount),
))
}

caller := std.PrevRealm().Addr()
gnsBalance := gns.BalanceOf(a2u(caller))
if gnsBalance < amount {
Expand Down Expand Up @@ -126,6 +133,13 @@ func Redelegate(from, to std.Address, amount uint64) {
))
}

if amount%minimumAmount != 0 {
panic(addDetailToError(
errInvalidAmount,
ufmt.Sprintf("amount must be multiple of %d", minimumAmount),
))
}

caller := std.PrevRealm().Addr()

delegated := xgns.BalanceOf(a2u(caller))
Expand Down Expand Up @@ -171,6 +185,13 @@ func Undelegate(from std.Address, amount uint64) {
))
}

if amount%minimumAmount != 0 {
panic(addDetailToError(
errInvalidAmount,
ufmt.Sprintf("amount must be multiple of %d", minimumAmount),
))
}

caller := std.PrevRealm().Addr()
delegated := xgns.BalanceOf(a2u(caller))

Expand Down
27 changes: 25 additions & 2 deletions gov/staker/staker_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ func TestDelegate(t *testing.T) {
{
std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH))
std.TestSkipHeights(100)
mintedGns := gns.MintGns(a2u(userRealm.Addr())) // 2M gns
println("Minted GNS:", mintedGns)
gns.MintGns(a2u(userRealm.Addr())) // 2M gns

std.TestSetRealm(userRealm)
to := makeFakeAddress("validator_1")
Expand Down Expand Up @@ -165,6 +164,30 @@ func TestDelegate(t *testing.T) {
std.TestSetOrigCaller(consts.ADMIN)
SetRunning(true)
}

{
to := makeFakeAddress("validator_2")
amount := uint64(1999_999)

defer func() {
if r := recover(); r == nil {
t.Errorf("Expected panic when delegating below minimumAmount")
}
}()
Delegate(to, amount)
}

{
to := makeFakeAddress("validator_2")
amount := uint64(2000_000)

defer func() {
if r := recover(); r == nil {
t.Errorf("Expected panic when delegating below minimumAmount")
}
}()
Delegate(to, amount)
}
}

func TestDelegate_Boundary_Values(t *testing.T) {
Expand Down

0 comments on commit 51abb02

Please sign in to comment.