Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: reward ratio calculation #461

Merged
merged 88 commits into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from 67 commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
b2f1f5b
add reward ratio calculation
mconcat Jan 15, 2025
a074322
reward ratio logic works
mconcat Jan 15, 2025
9112f66
prototyping
notJoon Jan 15, 2025
6ec74b9
remove unncesary comments
notJoon Jan 15, 2025
e017660
callback: emission
notJoon Jan 15, 2025
7d74809
warmup works
mconcat Jan 15, 2025
3964119
save
notJoon Jan 15, 2025
956ba16
warmup with test works
mconcat Jan 15, 2025
33304a2
add reward ratio calculation
mconcat Jan 15, 2025
d06aff9
reward ratio logic works
mconcat Jan 15, 2025
a2862da
warmup works
mconcat Jan 15, 2025
e3a1a46
warmup with test works
mconcat Jan 15, 2025
cc9f8c6
Merge branch 'mconcat/staker-reward-optimization' of https://github.c…
onlyhyde Jan 15, 2025
451ab67
external reward WIP
mconcat Jan 15, 2025
e2e7dd6
add callbacks
mconcat Jan 16, 2025
60dfbd2
test works
mconcat Jan 16, 2025
5c8120e
Merge branch 'main' of github.com:gnoswap-labs/gnoswap into update-em…
mconcat Jan 16, 2025
bcf08c3
remove unused code
mconcat Jan 16, 2025
79ebcfb
rename
mconcat Jan 16, 2025
9008f7c
prototyping
notJoon Jan 15, 2025
5017c45
remove unncesary comments
notJoon Jan 15, 2025
286a476
callback: emission
notJoon Jan 15, 2025
4a15b6b
save
notJoon Jan 15, 2025
f41d2e0
add callbacks
mconcat Jan 16, 2025
4d5563d
test works
mconcat Jan 16, 2025
cb92d0f
remove unused code
mconcat Jan 16, 2025
7f845bc
rename
mconcat Jan 16, 2025
e9cf357
Merge branch 'update-emission' into mconcat/staker-reward-optimization
mconcat Jan 16, 2025
ee3e9ce
internal + emission working
mconcat Jan 16, 2025
c755567
Merge branch 'mconcat/staker-reward-optimization' of github.com:gnosw…
mconcat Jan 16, 2025
1b55315
fix: emission callback panic issue
onlyhyde Jan 16, 2025
b89a6b3
fix: callbackStakerEmissionChange is nil
onlyhyde Jan 16, 2025
3bd080a
emission change applied works
mconcat Jan 17, 2025
31641e1
external reward works
mconcat Jan 17, 2025
b33f24a
Merge branch 'update-emission' of github.com:gnoswap-labs/gnoswap int…
mconcat Jan 17, 2025
8bce0da
fix emission
mconcat Jan 17, 2025
48212f6
Merge branch 'update-emission' into mconcat/staker-reward-optimization
mconcat Jan 17, 2025
7e39d4c
external unclaimable works
mconcat Jan 17, 2025
ddb2e6f
test: full test
onlyhyde Jan 17, 2025
6913145
Merge branch 'mconcat/staker-reward-optimization' of https://github.c…
onlyhyde Jan 17, 2025
d5e3376
fix modifyDeposit
mconcat Jan 17, 2025
dfaf9cd
Merge branch 'mconcat/staker-reward-optimization' of github.com:gnosw…
mconcat Jan 17, 2025
67d682a
test: full test update
onlyhyde Jan 17, 2025
319c6d8
fix
mconcat Jan 17, 2025
1fbf541
Merge branch 'mconcat/staker-reward-optimization' of github.com:gnosw…
mconcat Jan 17, 2025
69f829b
fix
mconcat Jan 17, 2025
37ef883
test : test code update
onlyhyde Jan 17, 2025
4cbe214
fix : pool tier
onlyhyde Jan 18, 2025
d82c699
fix: full test // wip
r3v4s Jan 18, 2025
b564013
fix: missing init // by @mconcat
r3v4s Jan 18, 2025
a1dc39f
fix: full test // wip
r3v4s Jan 18, 2025
ff78df6
fix: nil error when pool has only external incentive
r3v4s Jan 18, 2025
41ae188
fix: external incentive is not being calculated
r3v4s Jan 18, 2025
ad07c6f
fix: full test // most of tc runs good, reward amount seems ok // wip
r3v4s Jan 18, 2025
deb3f05
fix: full test // emission reward comparing
r3v4s Jan 18, 2025
a05a1d8
fix: check amount with error range 99.99%
r3v4s Jan 18, 2025
647a3b4
fix: every test functino to check gns balance (and external reward am…
r3v4s Jan 19, 2025
1e383ab
chore: rename
r3v4s Jan 19, 2025
4a1fa8c
test(fix): __TEST_more_01
r3v4s Jan 19, 2025
8f54580
test(fix): __TEST_more_02
r3v4s Jan 19, 2025
a774334
test(fix): __TEST_more_04
r3v4s Jan 19, 2025
abb637d
test(fix): fix test cases
r3v4s Jan 19, 2025
ae007ae
fix: when collecting reward, unwrapping should be supported for ugnot…
r3v4s Jan 19, 2025
bc5c4e6
chore: rename
r3v4s Jan 19, 2025
428a4a5
update canonical env
mconcat Jan 19, 2025
27445d3
fix callback nil
mconcat Jan 19, 2025
b9a7dcb
test(fix): external gnoA
r3v4s Jan 19, 2025
3755238
test(fix): staker full test with all reward calculated
r3v4s Jan 19, 2025
2c7d84b
chore
r3v4s Jan 19, 2025
870009c
test(fix): adjust deposit amount (co-author: @mconcat)
r3v4s Jan 19, 2025
4a4b42b
test(fix): fix internal gnoA
r3v4s Jan 19, 2025
6ba7ad5
test(fix): fix test
r3v4s Jan 19, 2025
4b7ce9e
add comments, remove unused code
mconcat Jan 19, 2025
8e2fee1
Merge branch 'mconcat/staker-reward-optimization' of github.com:gnosw…
mconcat Jan 19, 2025
00c5747
test(feat): pool with internal reward + external gns
r3v4s Jan 19, 2025
da099c3
test(chore): remove duplicated scenario
r3v4s Jan 19, 2025
b1cef7c
remove unnecesary comment
notJoon Jan 19, 2025
df10589
reimplement api.gno
mconcat Jan 19, 2025
7b73e71
Merge branch 'mconcat/staker-reward-optimization' of github.com:gnosw…
mconcat Jan 19, 2025
d078082
feat: remove unused cross (co-author: @mconcat)
r3v4s Jan 19, 2025
24edb3e
fix: `ApiGetRewardTokens()` not to early return
r3v4s Jan 19, 2025
fd2a976
remove debug lines
notJoon Jan 19, 2025
eb37c0b
remove unused lines
mconcat Jan 19, 2025
46689df
resolve TODOs
mconcat Jan 19, 2025
2c56e52
readme wip
mconcat Jan 19, 2025
e93089e
readme
mconcat Jan 19, 2025
1ccf6b0
readme
mconcat Jan 19, 2025
029cec9
readme
mconcat Jan 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions _deploy/r/gnoswap/gns/errors.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import (
)

var (
errInvalidYear = errors.New("[GNOSWAP-GNS-001] invalid year")
errTooManyEmission = errors.New("[GNOSWAP-GNS-002] too many emission reward")
errInvalidYear = errors.New("[GNOSWAP-GNS-001] invalid year")
errTooManyEmission = errors.New("[GNOSWAP-GNS-002] too many emission reward")
errCallbackEmissionChangeIsNil = errors.New("[GNOSWAP-GNS-003] callback emission change is nil")
)

func addDetailToError(err error, detail string) string {
Expand Down
10 changes: 0 additions & 10 deletions _deploy/r/gnoswap/gns/gns.gno
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,6 @@ func checkErr(err error) {
// It calculates the amount of gns to mint for each halving year for block range.
// It also handles the left emission amount if the current block range includes halving year end block.
func calculateAmountToMint(fromHeight, toHeight int64) uint64 {
prevHeight := fromHeight
currentHeight := toHeight

// if toHeight is greater than emission end height, set toHeight to emission end height
endH := GetEndHeight()
if toHeight > endH {
Expand Down Expand Up @@ -259,13 +256,6 @@ func calculateAmountToMint(fromHeight, toHeight int64) uint64 {
}
}

if prevHeight == currentHeight {
addPerBlockMintUpdate(uint64(currentHeight), GetAmountPerBlockPerHalvingYear(GetHalvingYearByHeight(currentHeight)))
} else {
addPerBlockMintUpdate(uint64(prevHeight), GetAmountPerBlockPerHalvingYear(GetHalvingYearByHeight(prevHeight)))
addPerBlockMintUpdate(uint64(currentHeight), GetAmountPerBlockPerHalvingYear(GetHalvingYearByHeight(currentHeight)))
}

assertTooManyEmission(totalAmountToMint)
return totalAmountToMint
}
Expand Down
82 changes: 53 additions & 29 deletions _deploy/r/gnoswap/gns/halving.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"gno.land/p/demo/avl"
"gno.land/p/demo/json"
"gno.land/r/gnoswap/v1/common"
"gno.land/r/gnoswap/v1/consts"
)

Expand Down Expand Up @@ -62,6 +61,7 @@ type HalvingData struct {
amountPerBlock []uint64
}


func (h *HalvingData) getStartBlockHeight(year int64) int64 {
if year == 0 {
return 0
Expand Down Expand Up @@ -195,6 +195,52 @@ func (h *HalvingData) initialize(startHeight, startTimestamp int64) {
}
}

var callbackEmissionChange func(amount uint64)

func SetCallbackEmissionChange(callback func(amount uint64)) {
if callbackEmissionChange != nil {
panic("callbackEmissionChange already set")
}
callbackEmissionChange = callback
}

// endHeight MUST be smaller than the current height(we don't read future halving blocks with this function)
func GetHalvingBlocksInRange(startHeight, endHeight int64) ([]int64, []uint64) {
halvingData := GetEmissionState().getHalvingData()
halvingBlocks := []int64{}
halvingEmissions := []uint64{}
for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ {
startBlock := halvingData.getStartBlockHeight(year)
if startBlock < startHeight {
continue
}
if endHeight < startBlock {
break
}
halvingBlocks = append(halvingBlocks, startBlock)
halvingEmissions = append(halvingEmissions, halvingData.getAmountPerBlock(year))
}
return halvingBlocks, halvingEmissions
}

// height MUST be smaller than the current height(we don't read future emissions)
func GetEmission() uint64 {
halvingData := GetEmissionState().getHalvingData()
height := std.GetHeight()

for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ {
startBlock := halvingData.getStartBlockHeight(year)
endBlock := halvingData.getEndBlockHeight(year)
if startBlock <= height && height < endBlock {
return halvingData.getAmountPerBlock(year)
}
}

// haven't reached the start of the halvings
// TODO: check if returning 0 is correct
return 0
}

type EmissionState struct {
startHeight int64
startTimestamp int64
Expand Down Expand Up @@ -343,7 +389,10 @@ func setAvgBlockTimeInMs(ms int64) {
adjustedAmountPerBlock := amountLeft / uint64(blockLeft)
// update it
setAmountPerBlockPerHalvingYear(currentYear, adjustedAmountPerBlock)
addPerBlockMintUpdate(uint64(std.GetHeight()), adjustedAmountPerBlock)
if callbackEmissionChange == nil {
panic(errCallbackEmissionChangeIsNil.Error())
}
callbackEmissionChange(adjustedAmountPerBlock)

for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ {
if year < currentYear {
Expand Down Expand Up @@ -371,6 +420,8 @@ func setAvgBlockTimeInMs(ms int64) {
}

avgBlockTimeMs = ms


}

// GetAmountByHeight returns the amount of gns to mint by height
Expand Down Expand Up @@ -557,30 +608,3 @@ func getHalvingYearAndEndTimestamp(timestamp int64) (int64, int64) {

return year, startTimestamp + (consts.TIMESTAMP_YEAR * year)
}

func GetCurrentEmission() uint64 {
emission := uint64(0)
perBlockMint.ReverseIterate("", common.EncodeUint(uint64(std.GetHeight())), func(key string, value interface{}) bool {
emission = value.(uint64)
return true
})
return emission
}

func EmissionUpdates(startHeight uint64, endHeight uint64) ([]uint64, []uint64) {
heights := make([]uint64, 0)
updates := make([]uint64, 0)
println("EmissionUpdates : ", startHeight, ", ", endHeight)
perBlockMint.Iterate(common.EncodeUint(startHeight), common.EncodeUint(endHeight), func(key string, value interface{}) bool {
println("EmissionUpdates : ", key, ", ", value)
heights = append(heights, common.DecodeUint(key))
updates = append(updates, value.(uint64))
return false
})

return heights, updates
}

func addPerBlockMintUpdate(height uint64, amount uint64) {
perBlockMint.Set(common.EncodeUint(height), amount)
}
14 changes: 13 additions & 1 deletion _deploy/r/gnoswap/gns/halving_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -156,36 +156,48 @@ func TestGetHalvingInfo(t *testing.T) {

func TestSetAvgBlockTimeInMsByAdmin(t *testing.T) {
t.Run("panic if caller is not admin", func(t *testing.T) {
oldCallback := callbackEmissionChange
callbackEmissionChange = func(amount uint64) {}
uassert.PanicsWithMessage(t,
"caller(g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) has no permission",
func() {
SetAvgBlockTimeInMsByAdmin(1)
},
)
callbackEmissionChange = oldCallback
})

t.Run("success if caller is admin", func(t *testing.T) {
oldCallback := callbackEmissionChange
callbackEmissionChange = func(amount uint64) {}
std.TestSkipHeights(1)
std.TestSetRealm(adminRealm)
std.TestSetRealm(std.NewUserRealm(consts.ADMIN))
SetAvgBlockTimeInMsByAdmin(2)
uassert.Equal(t, GetAvgBlockTimeInMs(), int64(2))
callbackEmissionChange = oldCallback
})
}

func TestSetAvgBlockTimeInMs(t *testing.T) {
t.Run("panic if caller is not governance contract", func(t *testing.T) {
oldCallback := callbackEmissionChange
callbackEmissionChange = func(amount uint64) {}
uassert.PanicsWithMessage(t,
"caller(g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) has no permission",
func() {
SetAvgBlockTimeInMs(3)
},
)
callbackEmissionChange = oldCallback
})

t.Run("success if caller is governance contract", func(t *testing.T) {
oldCallback := callbackEmissionChange
callbackEmissionChange = func(amount uint64) {}
std.TestSkipHeights(3)
std.TestSetRealm(govRealm)
SetAvgBlockTimeInMs(4)
uassert.Equal(t, GetAvgBlockTimeInMs(), int64(4))
callbackEmissionChange = oldCallback
})
}
8 changes: 4 additions & 4 deletions emission/_test_helper.gno
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ func resetObject(t *testing.T) {
t.Helper()

distributionBpsPct = avl.NewTree()
distributionBpsPct.Set(strconv.Itoa(LIQUIDITY_STAKER), 7500)
distributionBpsPct.Set(strconv.Itoa(DEVOPS), 2000)
distributionBpsPct.Set(strconv.Itoa(COMMUNITY_POOL), 500)
distributionBpsPct.Set(strconv.Itoa(GOV_STAKER), 0)
distributionBpsPct.Set(strconv.Itoa(LIQUIDITY_STAKER), uint64(7500))
distributionBpsPct.Set(strconv.Itoa(DEVOPS), uint64(2000))
distributionBpsPct.Set(strconv.Itoa(COMMUNITY_POOL), uint64(500))
distributionBpsPct.Set(strconv.Itoa(GOV_STAKER), uint64(0))

distributedToStaker = 0
distributedToDevOps = 0
Expand Down
25 changes: 25 additions & 0 deletions emission/callback.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package emission

import (
"gno.land/r/gnoswap/v1/gns"
)

var callbackStakerEmissionChange func(amount uint64)

func SetCallbackStakerEmissionChange(callback func(amount uint64)) {
if callbackStakerEmissionChange != nil {
panic("callbackStakerEmissionChange already set")
}
callbackStakerEmissionChange = callback
}

// Called when per-block emission is changed from the gns side.
// It does not process non-immediate emission changes, such as halving.
func callbackEmissionChange(amount uint64) {
callbackStakerEmissionChange(calculateAmount(amount, GetDistributionBpsPct(LIQUIDITY_STAKER)))
}

func init() {
gns.SetCallbackEmissionChange(callbackEmissionChange)
}

Loading