From 1ad8968d947cd06c752fbe0fb07a9fa2a1e9deee Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 12 Dec 2024 15:49:07 +0900 Subject: [PATCH 01/17] GSW-1845 test: object reset helper --- _deploy/r/gnoswap/gns/_helper_test.gno | 40 ++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/_deploy/r/gnoswap/gns/_helper_test.gno b/_deploy/r/gnoswap/gns/_helper_test.gno index 2e976390..68dc4442 100644 --- a/_deploy/r/gnoswap/gns/_helper_test.gno +++ b/_deploy/r/gnoswap/gns/_helper_test.gno @@ -1,7 +1,9 @@ package gns import ( + "std" "testing" + "time" "gno.land/p/demo/grc/grc20" "gno.land/p/demo/ownable" @@ -9,12 +11,46 @@ import ( "gno.land/r/gnoswap/v1/consts" ) -func testResetGnsTokenObject(t *testing.T) { +func resetObject(t *testing.T) { + t.Helper() + + resetGnsTokenObject(t) + resetHalvingRelatedObject(t) + + height := std.GetHeight() + lastMintedHeight = height + startHeight = height + startTimestamp = time.Now().Unix() +} + +func resetGnsTokenObject(t *testing.T) { t.Helper() Token, privateLedger = grc20.NewToken("Gnoswap", "GNS", 6) UserTeller = Token.CallerTeller() owner = ownable.NewWithAddress(consts.ADMIN) - privateLedger.Mint(owner.Owner(), INITIAL_MINT_AMOUNT) } + +func resetHalvingRelatedObject(t *testing.T) { + t.Helper() + + for year := int64(1); year < 13; year++ { + setHalvingYearMaxAmount(year, HALVING_AMOUNTS[year-1]) + + if year == 1 { + setHalvingYearAccuAmount(year, HALVING_AMOUNTS[year-1]) + } else { + setHalvingYearAccuAmount(year, GetHalvingYearAccuAmount(year-1)+HALVING_AMOUNTS[year-1]) + } + + setHalvingYearBlock(year, startHeight+BLOCK_PER_YEAR*year) + setHalvingYearTimestamp(year, startTimestamp+(consts.TIMESTAMP_YEAR*year)) + setHalvingYearMintAmount(year, uint64(0)) + + amountPerYear := GetHalvingYearMaxAmount(year) // amount per year + amountPerDay := amountPerYear / consts.DAY_PER_YEAR // amount per day + amountPerBlock := amountPerDay / uint64(BLOCK_PER_DAY) // amount per block + setAmountPerBlockPerHalvingYear(year, uint64(amountPerBlock)) + } +} From da2fb4487ff81ccf53df4487a381c55f6603204e Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 12 Dec 2024 15:50:31 +0900 Subject: [PATCH 02/17] GSW-1845 refactor: repalce map to avl with each variable's getter/setter --- _deploy/r/gnoswap/gns/halving.gno | 251 +++++++++++++++++++----------- 1 file changed, 160 insertions(+), 91 deletions(-) diff --git a/_deploy/r/gnoswap/gns/halving.gno b/_deploy/r/gnoswap/gns/halving.gno index 934a34bd..18525f5d 100644 --- a/_deploy/r/gnoswap/gns/halving.gno +++ b/_deploy/r/gnoswap/gns/halving.gno @@ -2,8 +2,11 @@ package gns import ( "std" + "strconv" "time" + "gno.land/p/demo/avl" + "gno.land/p/demo/seqid" "gno.land/p/demo/ufmt" "gno.land/r/gnoswap/v1/common" @@ -22,6 +25,22 @@ import ( (365 days) 1 year = 31536000 block */ +const HALVING_AMOUNTS = []uint64{ + // MAX_EMISSION_AMOUNT = 225000000000000 + 18_750_000_000_000 * 12, // Year 1: 225000000000000 + 18_750_000_000_000 * 12, // Year 2: 225000000000000 + 9_375_000_000_000 * 12, // Year 3: 112500000000000 + 9_375_000_000_000 * 12, // Year 4: 112500000000000 + 4_687_500_000_000 * 12, // Year 5: 56250000000000 + 4_687_500_000_000 * 12, // Year 6: 56250000000000 + 2_343_750_000_000 * 12, // Year 7: 28125000000000 + 2_343_750_000_000 * 12, // Year 8: 28125000000000 + 1_171_875_000_000 * 12, // Year 9: 14062500000000 + 1_171_875_000_000 * 12, // Year 10: 14062500000000 + 1_171_875_000_000 * 12, // Year 11: 14062500000000 + 1_171_875_000_000 * 12, // Year 12: 14062500000000 +} + var ( BLOCK_PER_YEAR = consts.TIMESTAMP_YEAR / consts.BLOCK_GENERATION_INTERVAL BLOCK_PER_DAY = consts.TIMESTAMP_DAY / consts.BLOCK_GENERATION_INTERVAL @@ -30,66 +49,40 @@ var ( ) var ( - initialized bool startHeight int64 startTimestamp int64 ) -var halvingYearBlock = make(map[int64]int64) // year => block -var halvingYearTimestamp = make(map[int64]int64) // year => timestamp - -var halvingYearAmount = make(map[int64]uint64) // year => mintAmount -var halvingYearMintAmount = make(map[int64]uint64) // year => (actual) mintAmount -var halvingYearAccuAmount = make(map[int64]uint64) // year => accuAmount -func init() { - // yearly mint amount - halvingYearAmount[1] = 18_750_000_000_000 * 12 // 225000000000000 - halvingYearAmount[2] = 18_750_000_000_000 * 12 // 225000000000000 - halvingYearAmount[3] = 9_375_000_000_000 * 12 // 112500000000000 - halvingYearAmount[4] = 9_375_000_000_000 * 12 // 112500000000000 - halvingYearAmount[5] = 4_687_500_000_000 * 12 // 56250000000000 - halvingYearAmount[6] = 4_687_500_000_000 * 12 // 56250000000000 - halvingYearAmount[7] = 2_343_750_000_000 * 12 // 28125000000000 - halvingYearAmount[8] = 2_343_750_000_000 * 12 // 28125000000000 - halvingYearAmount[9] = 1_171_875_000_000 * 12 // 14062500000000 - halvingYearAmount[10] = 1_171_875_000_000 * 12 // 14062500000000 - halvingYearAmount[11] = 1_171_875_000_000 * 12 // 14062500000000 - halvingYearAmount[12] = 1_171_875_000_000 * 12 // 14062500000000 - - // yearly accumulated mint amount - halvingYearAccuAmount[1] = halvingYearAmount[1] - halvingYearAccuAmount[2] = halvingYearAccuAmount[1] + halvingYearAmount[2] - halvingYearAccuAmount[3] = halvingYearAccuAmount[2] + halvingYearAmount[3] - halvingYearAccuAmount[4] = halvingYearAccuAmount[3] + halvingYearAmount[4] - halvingYearAccuAmount[5] = halvingYearAccuAmount[4] + halvingYearAmount[5] - halvingYearAccuAmount[6] = halvingYearAccuAmount[5] + halvingYearAmount[6] - halvingYearAccuAmount[7] = halvingYearAccuAmount[6] + halvingYearAmount[7] - halvingYearAccuAmount[8] = halvingYearAccuAmount[7] + halvingYearAmount[8] - halvingYearAccuAmount[9] = halvingYearAccuAmount[8] + halvingYearAmount[9] - halvingYearAccuAmount[10] = halvingYearAccuAmount[9] + halvingYearAmount[10] - halvingYearAccuAmount[11] = halvingYearAccuAmount[10] + halvingYearAmount[11] - halvingYearAccuAmount[12] = halvingYearAccuAmount[11] + halvingYearAmount[12] -} - -var amountPerBlockPerHalvingYear = make(map[int64]uint64) // year => reward per block +var ( + halvingYearBlock = avl.NewTree() // year -> last block height + halvingYearTimestamp = avl.NewTree() // year -> timestamp + halvingYearMaxAmount = avl.NewTree() // year -> (maximum) mintAmount + halvingYearMintAmount = avl.NewTree() // year -> (actual) mintAmount + halvingYearAccuAmount = avl.NewTree() // year -> accuAmount + amountPerBlockPerHalvingYear = avl.NewTree() // year -> amount per block +) func init() { - height := std.GetHeight() - - startHeight = height + startHeight = std.GetHeight() startTimestamp = time.Now().Unix() - initialized = true + for year := int64(1); year < 13; year++ { + setHalvingYearMaxAmount(year, HALVING_AMOUNTS[year-1]) - for i := int64(1); i < 13; i++ { - halvingYearBlock[i] = height + BLOCK_PER_YEAR*i - halvingYearTimestamp[i] = startTimestamp + (consts.TIMESTAMP_YEAR * i) + if year == 1 { + setHalvingYearAccuAmount(year, HALVING_AMOUNTS[year-1]) + } else { + setHalvingYearAccuAmount(year, GetHalvingYearAccuAmount(year-1)+HALVING_AMOUNTS[year-1]) + } + + setHalvingYearBlock(year, startHeight+BLOCK_PER_YEAR*year) + setHalvingYearTimestamp(year, startTimestamp+(consts.TIMESTAMP_YEAR*year)) + setHalvingYearMintAmount(year, uint64(0)) - amountPerYear := halvingYearAmount[i] // amount per year + amountPerYear := GetHalvingYearMaxAmount(year) // amount per year amountPerDay := amountPerYear / consts.DAY_PER_YEAR // amount per day amountPerBlock := amountPerDay / uint64(BLOCK_PER_DAY) // amount per block - - amountPerBlockPerHalvingYear[i] = uint64(amountPerBlock) + setAmountPerBlockPerHalvingYear(year, uint64(amountPerBlock)) } } @@ -143,7 +136,7 @@ func setAvgBlockTimeInMs(ms int64) { // which year current time is in now := time.Now().Unix() height := std.GetHeight() - year, endTimestamp := GetHalvingYearByTimestamp(now) + year, endTimestamp := getHalvingYearAndEndTimestamp(now) // how much time left to next halving timeLeft := endTimestamp - now @@ -151,56 +144,38 @@ func setAvgBlockTimeInMs(ms int64) { // how many block left to next halving timeLeftMs := timeLeft * consts.SECOND_IN_MILLISECOND blockLeft := timeLeftMs / avgBlockTimeMs - // how many reward left to next halving minted := MintedEmissionAmount() - amountLeft := halvingYearAccuAmount[year] - minted + amountLeft := GetHalvingYearAccuAmount(year) - minted // how much reward per block adjustedAmountPerBlock := amountLeft / uint64(blockLeft) // update it - amountPerBlockPerHalvingYear[year] = adjustedAmountPerBlock + setAmountPerBlockPerHalvingYear(year, adjustedAmountPerBlock) - // adjust halving block - for keyYear, _ := range halvingYearBlock { - yearEnd := halvingYearTimestamp[keyYear] + for year := int64(1); year < 13; year++ { + yearEndTimestamp := GetHalvingYearTimestamp(year) - if now >= yearEnd { + if now >= yearEndTimestamp { continue } - diff := yearEnd - now + diff := yearEndTimestamp - now numBlock := diff * consts.SECOND_IN_MILLISECOND / avgBlockTimeMs - halvingYearBlock[keyYear] = height + numBlock + setHalvingYearBlock(year, height+numBlock) } } -func GetHalvingYearAmount(year int64) uint64 { - return halvingYearAmount[year] -} - -func GetHalvingYearMintAmount(year int64) uint64 { - return halvingYearMintAmount[year] -} - -func SetHalvingYearMintAmount(year int64, amount uint64) { - halvingYearMintAmount[year] = amount -} - func GetAmountByHeight(height int64) uint64 { halvingYear := GetHalvingYearByHeight(height) - - return amountPerBlockPerHalvingYear[halvingYear] -} - -func GetAmountByYear(year int64) uint64 { - return amountPerBlockPerHalvingYear[year] + return GetAmountPerBlockPerHalvingYear(halvingYear) } +// GetHalvingYearByHeight returns the halving year by height func GetHalvingYearByHeight(height int64) int64 { - // determine which halving year block is in - for year, block := range halvingYearBlock { + for year := int64(1); year < 13; year++ { + block := GetHalvingYearBlock(year) if height <= block { return year } @@ -209,19 +184,25 @@ func GetHalvingYearByHeight(height int64) int64 { return 0 } -func GetHalvingYearByTimestamp(timestamp int64) (int64, int64) { - // determine which halving tier block is in - for tier, ts := range halvingYearTimestamp { - if timestamp <= ts { - return tier, ts +func getHalvingYearAndEndTimestamp(timestamp int64) (int64, int64) { + timestamp -= startTimestamp + + divValue := timestamp / consts.TIMESTAMP_YEAR + modValue := timestamp % consts.TIMESTAMP_YEAR + + if modValue == 0 { + if divValue > 12 { + return 0, 0 } + + return divValue, startTimestamp + (consts.TIMESTAMP_YEAR * divValue) } - return 0, 0 -} + if divValue+1 > 12 { + return 0, 0 + } -func GetHalvingYearBlock(year int64) int64 { - return halvingYearBlock[year] + return divValue + 1, startTimestamp + (consts.TIMESTAMP_YEAR * (divValue + 1)) } func GetHalvingInfo() string { @@ -229,13 +210,18 @@ func GetHalvingInfo() string { now := time.Now().Unix() halvings := make([]*json.Node, 0) - for year, block := range halvingYearBlock { + // for year, block := range halvingYearBlock { + halvingYearBlock.Iterate("", "", func(yearStr string, value interface{}) bool { + yearInt, _ := strconv.ParseInt(yearStr, 10, 64) + block := value.(int64) halvings = append(halvings, json.ObjectNode("", map[string]*json.Node{ - "year": json.NumberNode("year", float64(year)), + "year": json.StringNode("year", yearStr), "block": json.NumberNode("block", float64(block)), - "amount": json.NumberNode("amount", float64(amountPerBlockPerHalvingYear[year])), + "amount": json.NumberNode("amount", float64(GetAmountPerBlockPerHalvingYear(yearInt))), })) - } + + return true + }) node := json.ObjectNode("", map[string]*json.Node{ "height": json.NumberNode("height", float64(height)), @@ -268,3 +254,86 @@ func callType() string { return "INDIRECT" } + +func GetHalvingYearBlock(year int64) int64 { + iBlock, exist := halvingYearBlock.Get(strconv.FormatInt(year, 10)) + if !exist { + panic(ufmt.Sprintf("halving.gno__GetHalvingYearBlock() || year(%d) not found", year)) + } + + return iBlock.(int64) +} + +func setHalvingYearBlock(year int64, block int64) { + halvingYearBlock.Set(strconv.FormatInt(year, 10), block) + +} + +func GetHalvingYearTimestamp(year int64) int64 { + iTimestamp, exist := halvingYearTimestamp.Get(strconv.FormatInt(year, 10)) + if !exist { + panic(ufmt.Sprintf("halving.gno__GetHalvingYearTimestamp() || year(%d) not found", year)) + } + + return iTimestamp.(int64) +} + +func setHalvingYearTimestamp(year int64, timestamp int64) { + halvingYearTimestamp.Set(strconv.FormatInt(year, 10), timestamp) +} + +func GetHalvingYearMaxAmount(year int64) uint64 { + iAmount, exist := halvingYearMaxAmount.Get(strconv.FormatInt(year, 10)) + if !exist { + panic(ufmt.Sprintf("halving.gno__GetHalvingYearMaxAmount() || year(%d) not found", year)) + } + + return iAmount.(uint64) +} + +func setHalvingYearMaxAmount(year int64, amount uint64) { + halvingYearMaxAmount.Set(strconv.FormatInt(year, 10), amount) +} + +func GetHalvingYearMintAmount(year int64) uint64 { + iAmount, exist := halvingYearMintAmount.Get(strconv.FormatInt(year, 10)) + if !exist { + panic(ufmt.Sprintf("halving.gno__GetHalvingYearMintAmount() || year(%d) not found", year)) + } + + return iAmount.(uint64) +} + +func setHalvingYearMintAmount(year int64, amount uint64) { + halvingYearMintAmount.Set(strconv.FormatInt(year, 10), amount) +} + +func GetHalvingYearAccuAmount(year int64) uint64 { + iAmount, exist := halvingYearAccuAmount.Get(strconv.FormatInt(year, 10)) + if !exist { + panic(ufmt.Sprintf("halving.gno__GetHalvingYearAccuAmount() || year(%d) not found", year)) + } + + return iAmount.(uint64) +} + +func setHalvingYearAccuAmount(year int64, amount uint64) { + halvingYearAccuAmount.Set(strconv.FormatInt(year, 10), amount) +} + +func GetAmountPerBlockPerHalvingYear(year int64) uint64 { + iAmount, exist := amountPerBlockPerHalvingYear.Get(strconv.FormatInt(year, 10)) + if !exist { + panic(ufmt.Sprintf("halving.gno__GetAmountPerBlockPerHalvingYear() || year(%d) not found", year)) + } + + return iAmount.(uint64) +} + +func setAmountPerBlockPerHalvingYear(year int64, amount uint64) { + amountPerBlockPerHalvingYear.Set(strconv.FormatInt(year, 10), amount) +} + +func getSeqID(num int64) string { + return seqid.ID(uint64(num)).Binary() +} From c0ba829a44808e664429c78f5d4dc2b30afe4596 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 12 Dec 2024 15:50:59 +0900 Subject: [PATCH 03/17] GSW-1845 chore : use getter/setter, remove unused functions --- _deploy/r/gnoswap/gns/gns.gno | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_deploy/r/gnoswap/gns/gns.gno b/_deploy/r/gnoswap/gns/gns.gno index d4c3a682..6435c9f5 100644 --- a/_deploy/r/gnoswap/gns/gns.gno +++ b/_deploy/r/gnoswap/gns/gns.gno @@ -160,7 +160,7 @@ func calculateAmountToMint(fromHeight, toHeight int64) uint64 { blocks := uint64(mintUntilHeight-fromHeight) + 1 // amount of gns to mint for each block for current year - singleBlockAmount := GetAmountByHeight(yearEndHeight) + singleBlockAmount := GetAmountPerBlockPerHalvingYear(i) // amount of gns to mint for current year yearAmountToMint := singleBlockAmount * blocks @@ -190,7 +190,7 @@ func isLastBlockOfHalvingYear(height int64) bool { // handleLeftEmissionAmount handles the left emission amount for a halving year. // It calculates the left emission amount by subtracting the halving year mint amount from the halving year amount. func handleLeftEmissionAmount(year int64, amount uint64) uint64 { - return GetHalvingYearAmount(year) - GetHalvingYearMintAmount(year) - amount + return GetHalvingYearMaxAmount(year) - GetHalvingYearMintAmount(year) - amount } // skipIfSameHeight returns true if the current block height is the same as the last minted height. From a914cd3e7a561e0e7222258a91abaa0233f36a56 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 12 Dec 2024 15:55:07 +0900 Subject: [PATCH 04/17] GSW-1845 test: update testcases --- _deploy/r/gnoswap/gns/halving_test.gno | 562 ++++++++++++++++++ _deploy/r/gnoswap/gns/tests/halving_test.gnoA | 224 ------- 2 files changed, 562 insertions(+), 224 deletions(-) create mode 100644 _deploy/r/gnoswap/gns/halving_test.gno delete mode 100644 _deploy/r/gnoswap/gns/tests/halving_test.gnoA diff --git a/_deploy/r/gnoswap/gns/halving_test.gno b/_deploy/r/gnoswap/gns/halving_test.gno new file mode 100644 index 00000000..31f48b01 --- /dev/null +++ b/_deploy/r/gnoswap/gns/halving_test.gno @@ -0,0 +1,562 @@ +package gns + +import ( + "std" + "testing" + + "gno.land/p/demo/testutils" + "gno.land/p/demo/uassert" + + "gno.land/r/gnoswap/v1/consts" +) + +func TestGetHalvingYearByHeight(t *testing.T) { + tests := []struct { + name string + height int64 + want int64 + }{ + { + name: "year 1, begin", + height: startHeight + 1, + want: 1, + }, + { + name: "year 1, middle", + height: startHeight + BLOCK_PER_YEAR/2, + want: 1, + }, + { + name: "year 1, end", + height: startHeight + BLOCK_PER_YEAR*1, + want: 1, + }, + + { + name: "year 2, begin", + height: startHeight + BLOCK_PER_YEAR*1 + 1, + want: 2, + }, + { + name: "year 2, middle", + height: startHeight + BLOCK_PER_YEAR*2 - 1, + want: 2, + }, + { + name: "year 2, end", + height: startHeight + BLOCK_PER_YEAR*2, + want: 2, + }, + + { + name: "year 3, begin", + height: startHeight + BLOCK_PER_YEAR*2 + 1, + want: 3, + }, + { + name: "year 3, middle", + height: startHeight + BLOCK_PER_YEAR*3 - 1, + want: 3, + }, + { + name: "year 3, end", + height: startHeight + BLOCK_PER_YEAR*3, + want: 3, + }, + + { + name: "year 4, begin", + height: startHeight + BLOCK_PER_YEAR*3 + 1, + want: 4, + }, + { + name: "year 4, middle", + height: startHeight + BLOCK_PER_YEAR*4 - 1, + want: 4, + }, + { + name: "year 4, end", + height: startHeight + BLOCK_PER_YEAR*4, + want: 4, + }, + + { + name: "year 5, begin", + height: startHeight + BLOCK_PER_YEAR*4 + 1, + want: 5, + }, + { + name: "year 5, middle", + height: startHeight + BLOCK_PER_YEAR*5 - 1, + want: 5, + }, + { + name: "year 5, end", + height: startHeight + BLOCK_PER_YEAR*5, + want: 5, + }, + + {name: "year 6, begin", height: startHeight + BLOCK_PER_YEAR*5 + 1, want: 6}, + { + name: "year 6, middle", + height: startHeight + BLOCK_PER_YEAR*6 - 1, + want: 6, + }, + { + name: "year 6, end", + height: startHeight + BLOCK_PER_YEAR*6, + want: 6, + }, + + { + name: "year 7, begin", + height: startHeight + BLOCK_PER_YEAR*6 + 1, + want: 7, + }, + { + name: "year 7, middle", + height: startHeight + BLOCK_PER_YEAR*7 - 1, + want: 7, + }, + { + name: "year 7, end", + height: startHeight + BLOCK_PER_YEAR*7, + want: 7, + }, + + { + name: "year 8, begin", + height: startHeight + BLOCK_PER_YEAR*7 + 1, + want: 8, + }, + { + name: "year 8, middle", + height: startHeight + BLOCK_PER_YEAR*8 - 1, + want: 8, + }, + { + name: "year 8, end", + height: startHeight + BLOCK_PER_YEAR*8, + want: 8, + }, + + { + name: "year 9, begin", + height: startHeight + BLOCK_PER_YEAR*8 + 1, + want: 9, + }, + { + name: "year 9, middle", + height: startHeight + BLOCK_PER_YEAR*9 - 1, + want: 9, + }, + { + name: "year 9, end", + height: startHeight + BLOCK_PER_YEAR*9, + want: 9, + }, + + { + name: "year 10, begin", + height: startHeight + BLOCK_PER_YEAR*9 + 1, + want: 10, + }, + { + name: "year 10, middle", + height: startHeight + BLOCK_PER_YEAR*10 - 1, + want: 10, + }, + { + name: "year 10, end", + height: startHeight + BLOCK_PER_YEAR*10, + want: 10, + }, + + { + name: "year 11, begin", + height: startHeight + BLOCK_PER_YEAR*10 + 1, + want: 11, + }, + { + name: "year 11, middle", + height: startHeight + BLOCK_PER_YEAR*11 - 1, + want: 11, + }, + { + name: "year 11, end", + height: startHeight + BLOCK_PER_YEAR*11, + want: 11, + }, + + { + name: "year 12, begin", + height: startHeight + BLOCK_PER_YEAR*11 + 1, + want: 12, + }, + { + name: "year 12, middle", + height: startHeight + BLOCK_PER_YEAR*12 - 1, + want: 12, + }, + { + name: "year 12, end", + height: startHeight + BLOCK_PER_YEAR*12, + want: 12, + }, + + { + name: "after year 12", + height: startHeight + BLOCK_PER_YEAR*12 + 1, + want: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + uassert.Equal(t, tt.want, GetHalvingYearByHeight(tt.height)) + }) + } +} + +func TestGetHalvingYearAndEndTimestamp(t *testing.T) { + tests := []struct { + name string + timestamp int64 + wantYear int64 + wantEndTimestamp int64 + }{ + { + name: "year 1, begin", + timestamp: startTimestamp + 1, + wantYear: 1, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR, + }, + { + name: "year 1, middle", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR/2, + wantYear: 1, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR, + }, + { + name: "year 1, end", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*1, + wantYear: 1, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR, + }, + + { + name: "year 2, begin", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*1 + 1, + wantYear: 2, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*2, + }, + + { + name: "year 2, middle", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*2 - 1, + wantYear: 2, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*2, + }, + + { + name: "year 2, end", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*2, + wantYear: 2, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*2, + }, + + { + name: "year 3, begin", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*2 + 1, + wantYear: 3, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*3, + }, + + { + name: "year 3, middle", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*3 - 1, + wantYear: 3, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*3, + }, + + { + name: "year 3, end", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*3, + wantYear: 3, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*3, + }, + + { + name: "year 4, begin", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*3 + 1, + wantYear: 4, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*4, + }, + + { + name: "year 4, middle", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*4 - 1, + wantYear: 4, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*4, + }, + + { + name: "year 4, end", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*4, + wantYear: 4, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*4, + }, + + { + name: "year 5, begin", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*4 + 1, + wantYear: 5, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*5, + }, + + { + name: "year 5, middle", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*5 - 1, + wantYear: 5, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*5, + }, + + { + name: "year 5, end", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*5, + wantYear: 5, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*5, + }, + + { + name: "year 6, begin", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*5 + 1, + wantYear: 6, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*6, + }, + + { + name: "year 6, middle", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*6 - 1, + wantYear: 6, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*6, + }, + + { + name: "year 6, end", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*6, + wantYear: 6, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*6, + }, + + { + name: "year 7, begin", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*6 + 1, + wantYear: 7, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*7, + }, + + { + name: "year 7, middle", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*7 - 1, + wantYear: 7, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*7, + }, + + { + name: "year 7, end", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*7, + wantYear: 7, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*7, + }, + + { + name: "year 8, begin", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*7 + 1, + wantYear: 8, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*8, + }, + + { + name: "year 8, middle", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*8 - 1, + wantYear: 8, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*8, + }, + + { + name: "year 8, end", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*8, + wantYear: 8, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*8, + }, + + { + name: "year 9, begin", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*8 + 1, + wantYear: 9, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*9, + }, + + { + name: "year 9, middle", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*9 - 1, + wantYear: 9, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*9, + }, + + { + name: "year 9, end", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*9, + wantYear: 9, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*9, + }, + + { + name: "year 10, begin", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*9 + 1, + wantYear: 10, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*10, + }, + + { + name: "year 10, middle", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*10 - 1, + wantYear: 10, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*10, + }, + + { + name: "year 10, end", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*10, + wantYear: 10, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*10, + }, + + { + name: "year 11, begin", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*10 + 1, + wantYear: 11, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*11, + }, + + { + name: "year 11, middle", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*11 - 1, + wantYear: 11, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*11, + }, + + { + name: "year 11, end", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*11, + wantYear: 11, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*11, + }, + + { + name: "year 12, begin", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*11 + 1, + wantYear: 12, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*12, + }, + + { + name: "year 12, middle", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*12 - 1, + wantYear: 12, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*12, + }, + + { + name: "year 12, end", + timestamp: startTimestamp + consts.TIMESTAMP_YEAR*12, + wantYear: 12, + wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*12, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotYear, gotEndTimestamp := getHalvingYearAndEndTimestamp(tt.timestamp) + uassert.Equal(t, tt.wantYear, gotYear) + uassert.Equal(t, tt.wantEndTimestamp, gotEndTimestamp) + }) + } +} + +func TestSetAvgBlockTimeInMs(t *testing.T) { + // reset state + resetObject(t) + + var ( + user01Addr = testutils.TestAddress("user01Addr") + user01Realm = std.NewUserRealm(user01Addr) + ) + + t.Run("skip 50 blocks", func(t *testing.T) { + std.TestSkipHeights(50) + uassert.Equal(t, int64(173), std.GetHeight()) + + std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) + mintedAmount := Mint(a2u(user01Addr)) + uassert.Equal(t, mintedAmount, uint64(14269406*50)) + uassert.Equal(t, MintedEmissionAmount(), uint64(713470300)) + }) + + t.Run("set avg block time in ms", func(t *testing.T) { + std.TestSetRealm(std.NewUserRealm(consts.ADMIN)) + setAvgBlockTimeInMs(2500) + + // for block time 2.5s + // amount per block is 17836757 + std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) + std.TestSkipHeights(1) + mintedAmount := Mint(a2u(user01Addr)) + uassert.Equal(t, mintedAmount, uint64(17836757)) + uassert.Equal(t, MintedEmissionAmount(), uint64(713470300+17836757)) // 731307057 + }) + + t.Run("reach almost first halving", func(t *testing.T) { + // current height = 174 + // next halving = 12614533 + // 12614533 - 174 = 12614359 + + std.TestSkipHeights(12614358) + std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) + Mint(a2u(user01Addr)) + + uassert.Equal(t, MintedEmissionAmount(), uint64(224999969664063)) + // 224999969664063 - 731307057 = 224999238357006 + // 224999238357006 / 12614358 = 17836757 + }) + + t.Run("reach exact first halving", func(t *testing.T) { + std.TestSkipHeights(1) + uassert.Equal(t, std.GetHeight(), int64(12614533)) + + std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) + Mint(a2u(user01Addr)) + + // minted all amount for first halving year + uassert.Equal(t, MintedEmissionAmount(), uint64(225000000000000)) + + year := GetHalvingYearByHeight(std.GetHeight()) + uassert.Equal(t, int64(1), year) // year 1 ends + + }) + + t.Run("start second halving", func(t *testing.T) { + std.TestSkipHeights(1) + + year := GetHalvingYearByHeight(std.GetHeight()) + uassert.Equal(t, int64(2), year) // year 2 starts + + year2AmountPerBlock := GetAmountPerBlockPerHalvingYear(2) + uassert.Equal(t, uint64(14269406), year2AmountPerBlock) + + std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) + Mint(a2u(user01Addr)) + uassert.Equal(t, MintedEmissionAmount(), uint64(225000000000000+14269406)) + }) +} diff --git a/_deploy/r/gnoswap/gns/tests/halving_test.gnoA b/_deploy/r/gnoswap/gns/tests/halving_test.gnoA deleted file mode 100644 index 57b6d5ee..00000000 --- a/_deploy/r/gnoswap/gns/tests/halving_test.gnoA +++ /dev/null @@ -1,224 +0,0 @@ -package gns - -import ( - "std" - "testing" - - "gno.land/p/demo/uassert" - - "gno.land/r/gnoswap/v1/consts" -) - -func TestPreCalculatedData(t *testing.T) { - uassert.Equal(t, uint64(900_000_000_000_000), amountToEmission) - - sumAmount := uint64(0) - for _, amountYearly := range halvingYearAmount { - sumAmount += uint64(amountYearly) - } - uassert.Equal(t, amountToEmission, sumAmount) -} - -func TestGetHalvingYearByHeight(t *testing.T) { - height := std.GetHeight() - - t.Run("year 1", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+1), int64(1)) - uassert.Equal(t, GetHalvingYearByHeight(height+15768000), int64(1)) - }) - - t.Run("year 2", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+15768000+1), int64(2)) - uassert.Equal(t, GetHalvingYearByHeight(height+31536000), int64(2)) - }) - - t.Run("year 3", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+31536000+1), int64(3)) - uassert.Equal(t, GetHalvingYearByHeight(height+47304000), int64(3)) - }) - - t.Run("year 4", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+47304000+1), int64(4)) - uassert.Equal(t, GetHalvingYearByHeight(height+63072000), int64(4)) - }) - - t.Run("year 5", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+63072000+1), int64(5)) - uassert.Equal(t, GetHalvingYearByHeight(height+78840000), int64(5)) - }) - - t.Run("year 6", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+78840000+1), int64(6)) - uassert.Equal(t, GetHalvingYearByHeight(height+94608000), int64(6)) - }) - - t.Run("year 7", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+94608000+1), int64(7)) - uassert.Equal(t, GetHalvingYearByHeight(height+110376000), int64(7)) - }) - - t.Run("year 8", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+110376000+1), int64(8)) - uassert.Equal(t, GetHalvingYearByHeight(height+126144000), int64(8)) - }) - - t.Run("year 9", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+126144000+1), int64(9)) - uassert.Equal(t, GetHalvingYearByHeight(height+141912000), int64(9)) - }) - - t.Run("year 10", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+141912000+1), int64(10)) - uassert.Equal(t, GetHalvingYearByHeight(height+157680000), int64(10)) - }) - - t.Run("year 11", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+157680000+1), int64(11)) - uassert.Equal(t, GetHalvingYearByHeight(height+173448000), int64(11)) - }) - - t.Run("year 12", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+173448000+1), int64(12)) - uassert.Equal(t, GetHalvingYearByHeight(height+189216000), int64(12)) - }) - - t.Run("emission end", func(t *testing.T) { - uassert.Equal(t, GetHalvingYearByHeight(height+189216000+1), int64(0)) - }) -} - -func TestGetAmountByHeight(t *testing.T) { - height1Year := int64(15768000) - - t.Run("year 1", func(t *testing.T) { - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(14_269_406)) - std.TestSkipHeights(height1Year) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(14_269_406)) - }) - - t.Run("year 2", func(t *testing.T) { - std.TestSkipHeights(1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(14_269_406)) - std.TestSkipHeights(height1Year - 1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(14_269_406)) - }) - - t.Run("year 3", func(t *testing.T) { - std.TestSkipHeights(1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(7_134_703)) - std.TestSkipHeights(height1Year - 1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(7_134_703)) - }) - - t.Run("year 4", func(t *testing.T) { - std.TestSkipHeights(1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(7_134_703)) - std.TestSkipHeights(height1Year - 1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(7_134_703)) - }) - - t.Run("year 5", func(t *testing.T) { - std.TestSkipHeights(1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(3_567_351)) - std.TestSkipHeights(height1Year - 1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(3_567_351)) - }) - - t.Run("year 6", func(t *testing.T) { - std.TestSkipHeights(1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(3_567_351)) - std.TestSkipHeights(height1Year - 1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(3_567_351)) - }) - - t.Run("year 7", func(t *testing.T) { - std.TestSkipHeights(1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(1_783_675)) - std.TestSkipHeights(height1Year - 1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(1_783_675)) - }) - - t.Run("year 8", func(t *testing.T) { - std.TestSkipHeights(1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(1_783_675)) - std.TestSkipHeights(height1Year - 1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(1_783_675)) - }) - - t.Run("year 9", func(t *testing.T) { - std.TestSkipHeights(1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(891_837)) - std.TestSkipHeights(height1Year - 1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(891_837)) - }) - - t.Run("year 10", func(t *testing.T) { - std.TestSkipHeights(1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(891_837)) - std.TestSkipHeights(height1Year - 1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(891_837)) - }) - - t.Run("year 11", func(t *testing.T) { - std.TestSkipHeights(1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(891_837)) - std.TestSkipHeights(height1Year - 1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(891_837)) - }) - - t.Run("year 12", func(t *testing.T) { - std.TestSkipHeights(1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(891_837)) - std.TestSkipHeights(height1Year - 1) - uassert.Equal(t, GetAmountByHeight(std.GetHeight()), uint64(891_837)) - }) -} - -func TestSetAvgBlockTimeInMsByAdmin(t *testing.T) { - t.Run("panic if not admin", func(t *testing.T) { - uassert.PanicsWithMessage(t, - `[GNOSWAP-GNS-001] caller has no permission || gns.gno__SetAvgBlockTimeInMsByAdmin() || only admin(g17290cwvmrapvp869xfnhhawa8sm9edpufzat7d) can call this function, called from g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm`, - func() { - SetAvgBlockTimeInMsByAdmin(1000) - }) - }) - - t.Run("success if admin", func(t *testing.T) { - uassert.Equal(t, GetAvgBlockTimeInMs(), int64(2000)) - - std.TestSetRealm(std.NewUserRealm(consts.ADMIN)) - SetAvgBlockTimeInMsByAdmin(1000) - - uassert.Equal(t, GetAvgBlockTimeInMs(), int64(1000)) - }) -} - -func TestSetAvgBlockTimeInMs(t *testing.T) { - t.Run("panic if not governance", func(t *testing.T) { - uassert.PanicsWithMessage(t, - `[GNOSWAP-GNS-001] caller has no permission || gns.gno__SetAvgBlockTimeInMs() || only governance contract(g17s8w2ve7k85fwfnrk59lmlhthkjdted8whvqxd) can call this function, called from g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm`, func() { - SetAvgBlockTimeInMs(1000) - }) - }) - - t.Run("success if governance", func(t *testing.T) { - std.TestSetRealm(std.NewCodeRealm(consts.GOV_GOVERNANCE_PATH)) - SetAvgBlockTimeInMs(2000) - - uassert.Equal(t, GetAvgBlockTimeInMs(), int64(2000)) - }) -} - -func TestDataFor2000msBlockTime(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(consts.ADMIN)) - SetAvgBlockTimeInMsByAdmin(2000) - ghi := GetHalvingInfo() - uassert.Equal(t, `{"height":123,"timestamp":1234567890,"avgBlockTimeMs":2000,"halvings":[{"year":1,"block":15768123,"amount":14269406},{"year":2,"block":31536123,"amount":14269406},{"year":3,"block":47304123,"amount":7134703},{"year":4,"block":63072123,"amount":7134703},{"year":5,"block":78840123,"amount":3567351},{"year":6,"block":94608123,"amount":3567351},{"year":7,"block":110376123,"amount":1783675},{"year":8,"block":126144123,"amount":1783675},{"year":9,"block":141912123,"amount":891837},{"year":10,"block":157680123,"amount":891837},{"year":11,"block":173448123,"amount":891837},{"year":12,"block":189216123,"amount":891837}]}`, ghi) -} - -func TestDataFor3000msBlockTime(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(consts.ADMIN)) - SetAvgBlockTimeInMsByAdmin(3000) - ghi := GetHalvingInfo() - uassert.Equal(t, `{"height":123,"timestamp":1234567890,"avgBlockTimeMs":3000,"halvings":[{"year":1,"block":10512123,"amount":21404109},{"year":2,"block":21024123,"amount":14269406},{"year":3,"block":31536123,"amount":7134703},{"year":4,"block":42048123,"amount":7134703},{"year":5,"block":52560123,"amount":3567351},{"year":6,"block":63072123,"amount":3567351},{"year":7,"block":73584123,"amount":1783675},{"year":8,"block":84096123,"amount":1783675},{"year":9,"block":94608123,"amount":891837},{"year":10,"block":105120123,"amount":891837},{"year":11,"block":115632123,"amount":891837},{"year":12,"block":126144123,"amount":891837}]}`, ghi) -} From 6fc1b11c563798b6966a8cc4315e522240e17a54 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 12 Dec 2024 15:55:33 +0900 Subject: [PATCH 05/17] GSW-1845 chore: use getter/setter for avl data --- _deploy/r/gnoswap/gns/gns_test.gno | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/_deploy/r/gnoswap/gns/gns_test.gno b/_deploy/r/gnoswap/gns/gns_test.gno index c7657f9b..74a15fe3 100644 --- a/_deploy/r/gnoswap/gns/gns_test.gno +++ b/_deploy/r/gnoswap/gns/gns_test.gno @@ -41,7 +41,7 @@ func TestIsLastBlockOfHalvingYear(t *testing.T) { want bool }{ name: fmt.Sprintf("last block of halving year %d", i), - height: halvingYearBlock[i], + height: GetHalvingYearBlock(i), want: true, }) @@ -51,7 +51,7 @@ func TestIsLastBlockOfHalvingYear(t *testing.T) { want bool }{ name: fmt.Sprintf("not last block of halving year %d", i), - height: halvingYearBlock[i] - 1, + height: GetHalvingYearBlock(i) - 1, want: false, }) } @@ -81,7 +81,7 @@ func TestHandleLeftEmissionAmount(t *testing.T) { name: fmt.Sprintf("handle left emission amount for year %d, non minted", i), year: i, amount: 0, - want: halvingYearAmount[i], + want: GetHalvingYearMaxAmount(i), }) tests = append(tests, struct { @@ -93,7 +93,7 @@ func TestHandleLeftEmissionAmount(t *testing.T) { name: fmt.Sprintf("handle left emission amount for year %d, minted", i), year: i, amount: uint64(123456), - want: halvingYearAmount[i] - uint64(123456), + want: GetHalvingYearMaxAmount(i) - uint64(123456), }) } } From 40689cb96880904777b9aab1dc8e3ff538af5313 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Fri, 13 Dec 2024 15:19:29 +0900 Subject: [PATCH 06/17] GSW-1845 fix: typo --- _deploy/r/gnoswap/gns/gns_test.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_deploy/r/gnoswap/gns/gns_test.gno b/_deploy/r/gnoswap/gns/gns_test.gno index 74a15fe3..68d6a648 100644 --- a/_deploy/r/gnoswap/gns/gns_test.gno +++ b/_deploy/r/gnoswap/gns/gns_test.gno @@ -237,7 +237,7 @@ func TestGrc20Methods(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - testResetGnsTokenObject(t) + resetGnsTokenObject(t) if tt.shouldPanic { uassert.PanicsWithMessage(t, tt.panicMsg, tt.fn) From 7b1de0b5dab8c07012a03bb9f18c51f59bf80a31 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Fri, 13 Dec 2024 15:19:35 +0900 Subject: [PATCH 07/17] GSW-1845 chore --- _deploy/r/gnoswap/gns/halving.gno | 118 +++++++++++++----------------- 1 file changed, 49 insertions(+), 69 deletions(-) diff --git a/_deploy/r/gnoswap/gns/halving.gno b/_deploy/r/gnoswap/gns/halving.gno index 18525f5d..4e6d7b21 100644 --- a/_deploy/r/gnoswap/gns/halving.gno +++ b/_deploy/r/gnoswap/gns/halving.gno @@ -6,7 +6,6 @@ import ( "time" "gno.land/p/demo/avl" - "gno.land/p/demo/seqid" "gno.land/p/demo/ufmt" "gno.land/r/gnoswap/v1/common" @@ -25,21 +24,25 @@ import ( (365 days) 1 year = 31536000 block */ -const HALVING_AMOUNTS = []uint64{ - // MAX_EMISSION_AMOUNT = 225000000000000 - 18_750_000_000_000 * 12, // Year 1: 225000000000000 - 18_750_000_000_000 * 12, // Year 2: 225000000000000 - 9_375_000_000_000 * 12, // Year 3: 112500000000000 - 9_375_000_000_000 * 12, // Year 4: 112500000000000 - 4_687_500_000_000 * 12, // Year 5: 56250000000000 - 4_687_500_000_000 * 12, // Year 6: 56250000000000 - 2_343_750_000_000 * 12, // Year 7: 28125000000000 - 2_343_750_000_000 * 12, // Year 8: 28125000000000 - 1_171_875_000_000 * 12, // Year 9: 14062500000000 - 1_171_875_000_000 * 12, // Year 10: 14062500000000 - 1_171_875_000_000 * 12, // Year 11: 14062500000000 - 1_171_875_000_000 * 12, // Year 12: 14062500000000 -} +const ( + MONTH_PER_YEAR = uint64(12) + HALVING_AMOUNTS = []uint64{ + 18_750_000_000_000 * 12, // Year 1: 225000000000000 + 18_750_000_000_000 * 12, // Year 2: 225000000000000 + 9_375_000_000_000 * 12, // Year 3: 112500000000000 + 9_375_000_000_000 * 12, // Year 4: 112500000000000 + 4_687_500_000_000 * 12, // Year 5: 56250000000000 + 4_687_500_000_000 * 12, // Year 6: 56250000000000 + 2_343_750_000_000 * 12, // Year 7: 28125000000000 + 2_343_750_000_000 * 12, // Year 8: 28125000000000 + 1_171_875_000_000 * 12, // Year 9: 14062500000000 + 1_171_875_000_000 * 12, // Year 10: 14062500000000 + 1_171_875_000_000 * 12, // Year 11: 14062500000000 + 1_171_875_000_000 * 12, // Year 12: 14062500000000 + } + + MAX_HALVING_YEAR = int64(12) +) var ( BLOCK_PER_YEAR = consts.TIMESTAMP_YEAR / consts.BLOCK_GENERATION_INTERVAL @@ -167,6 +170,7 @@ func setAvgBlockTimeInMs(ms int64) { } } +// GetAmountByHeight returns the amount of gns to mint by height func GetAmountByHeight(height int64) uint64 { halvingYear := GetHalvingYearByHeight(height) return GetAmountPerBlockPerHalvingYear(halvingYear) @@ -184,6 +188,8 @@ func GetHalvingYearByHeight(height int64) int64 { return 0 } +// getHalvingYearAndEndTimestamp returns the halving year and end timestamp of the given timestamp +// if the timestamp is not in any halving year, it returns 0, 0 func getHalvingYearAndEndTimestamp(timestamp int64) (int64, int64) { timestamp -= startTimestamp @@ -205,56 +211,6 @@ func getHalvingYearAndEndTimestamp(timestamp int64) (int64, int64) { return divValue + 1, startTimestamp + (consts.TIMESTAMP_YEAR * (divValue + 1)) } -func GetHalvingInfo() string { - height := std.GetHeight() - now := time.Now().Unix() - - halvings := make([]*json.Node, 0) - // for year, block := range halvingYearBlock { - halvingYearBlock.Iterate("", "", func(yearStr string, value interface{}) bool { - yearInt, _ := strconv.ParseInt(yearStr, 10, 64) - block := value.(int64) - halvings = append(halvings, json.ObjectNode("", map[string]*json.Node{ - "year": json.StringNode("year", yearStr), - "block": json.NumberNode("block", float64(block)), - "amount": json.NumberNode("amount", float64(GetAmountPerBlockPerHalvingYear(yearInt))), - })) - - return true - }) - - node := json.ObjectNode("", map[string]*json.Node{ - "height": json.NumberNode("height", float64(height)), - "timestamp": json.NumberNode("timestamp", float64(now)), - "avgBlockTimeMs": json.NumberNode("avgBlockTimeMs", float64(avgBlockTimeMs)), - "halvings": json.ArrayNode("", halvings), - }) - - b, err := json.Marshal(node) - if err != nil { - panic(err.Error()) - } - - return string(b) -} - -func getYearlyBlockForTimestampMs(ms int64) int64 { - yearMs := consts.TIMESTAMP_YEAR * consts.SECOND_IN_MILLISECOND // how much millisecond in a year - return int64(yearMs) / ms // how many block in a year -} - -func prevRealm() string { - return std.PrevRealm().PkgPath() -} - -func callType() string { - if prevRealm() == "" { - return "DIRECT" - } - - return "INDIRECT" -} - func GetHalvingYearBlock(year int64) int64 { iBlock, exist := halvingYearBlock.Get(strconv.FormatInt(year, 10)) if !exist { @@ -266,7 +222,6 @@ func GetHalvingYearBlock(year int64) int64 { func setHalvingYearBlock(year int64, block int64) { halvingYearBlock.Set(strconv.FormatInt(year, 10), block) - } func GetHalvingYearTimestamp(year int64) int64 { @@ -334,6 +289,31 @@ func setAmountPerBlockPerHalvingYear(year int64, amount uint64) { amountPerBlockPerHalvingYear.Set(strconv.FormatInt(year, 10), amount) } -func getSeqID(num int64) string { - return seqid.ID(uint64(num)).Binary() +func GetHalvingInfo() string { + height := std.GetHeight() + now := time.Now().Unix() + + halvings := make([]*json.Node, 0) + + for year := int64(1); year <= MAX_HALVING_YEAR; year++ { + halvings = append(halvings, json.ObjectNode("", map[string]*json.Node{ + "year": json.StringNode("year", strconv.FormatInt(year, 10)), + "block": json.NumberNode("block", float64(GetHalvingYearBlock(year))), + "amount": json.NumberNode("amount", float64(GetAmountPerBlockPerHalvingYear(year))), + })) + } + + node := json.ObjectNode("", map[string]*json.Node{ + "height": json.NumberNode("height", float64(height)), + "timestamp": json.NumberNode("timestamp", float64(now)), + "avgBlockTimeMs": json.NumberNode("avgBlockTimeMs", float64(avgBlockTimeMs)), + "halvings": json.ArrayNode("", halvings), + }) + + b, err := json.Marshal(node) + if err != nil { + panic(err.Error()) + } + + return string(b) } From 483ca6b24f1a8829093a3b0ae13c46b3c33659db Mon Sep 17 00:00:00 2001 From: n3wbie Date: Fri, 13 Dec 2024 15:20:24 +0900 Subject: [PATCH 08/17] GSW-1845 test: halving_test --- _deploy/r/gnoswap/gns/halving_test.gno | 638 +++++-------------------- 1 file changed, 112 insertions(+), 526 deletions(-) diff --git a/_deploy/r/gnoswap/gns/halving_test.gno b/_deploy/r/gnoswap/gns/halving_test.gno index 31f48b01..2ed4a01d 100644 --- a/_deploy/r/gnoswap/gns/halving_test.gno +++ b/_deploy/r/gnoswap/gns/halving_test.gno @@ -4,559 +4,145 @@ import ( "std" "testing" - "gno.land/p/demo/testutils" + "gno.land/p/demo/json" + "gno.land/p/demo/uassert" "gno.land/r/gnoswap/v1/consts" ) -func TestGetHalvingYearByHeight(t *testing.T) { - tests := []struct { - name string - height int64 - want int64 - }{ - { - name: "year 1, begin", - height: startHeight + 1, - want: 1, - }, - { - name: "year 1, middle", - height: startHeight + BLOCK_PER_YEAR/2, - want: 1, - }, - { - name: "year 1, end", - height: startHeight + BLOCK_PER_YEAR*1, - want: 1, - }, - - { - name: "year 2, begin", - height: startHeight + BLOCK_PER_YEAR*1 + 1, - want: 2, - }, - { - name: "year 2, middle", - height: startHeight + BLOCK_PER_YEAR*2 - 1, - want: 2, - }, - { - name: "year 2, end", - height: startHeight + BLOCK_PER_YEAR*2, - want: 2, - }, - - { - name: "year 3, begin", - height: startHeight + BLOCK_PER_YEAR*2 + 1, - want: 3, - }, - { - name: "year 3, middle", - height: startHeight + BLOCK_PER_YEAR*3 - 1, - want: 3, - }, - { - name: "year 3, end", - height: startHeight + BLOCK_PER_YEAR*3, - want: 3, - }, - - { - name: "year 4, begin", - height: startHeight + BLOCK_PER_YEAR*3 + 1, - want: 4, - }, - { - name: "year 4, middle", - height: startHeight + BLOCK_PER_YEAR*4 - 1, - want: 4, - }, - { - name: "year 4, end", - height: startHeight + BLOCK_PER_YEAR*4, - want: 4, - }, - - { - name: "year 5, begin", - height: startHeight + BLOCK_PER_YEAR*4 + 1, - want: 5, - }, - { - name: "year 5, middle", - height: startHeight + BLOCK_PER_YEAR*5 - 1, - want: 5, - }, - { - name: "year 5, end", - height: startHeight + BLOCK_PER_YEAR*5, - want: 5, - }, +var ( + govRealm = std.NewCodeRealm(consts.GOV_GOVERNANCE_PATH) +) - {name: "year 6, begin", height: startHeight + BLOCK_PER_YEAR*5 + 1, want: 6}, - { - name: "year 6, middle", - height: startHeight + BLOCK_PER_YEAR*6 - 1, - want: 6, - }, - { - name: "year 6, end", - height: startHeight + BLOCK_PER_YEAR*6, - want: 6, - }, +var LAST_BLOCK_OF_YEAR = []int64{ + 0, + startHeight + BLOCK_PER_YEAR*1, + startHeight + BLOCK_PER_YEAR*2, + startHeight + BLOCK_PER_YEAR*3, + startHeight + BLOCK_PER_YEAR*4, + startHeight + BLOCK_PER_YEAR*5, + startHeight + BLOCK_PER_YEAR*6, + startHeight + BLOCK_PER_YEAR*7, + startHeight + BLOCK_PER_YEAR*8, + startHeight + BLOCK_PER_YEAR*9, + startHeight + BLOCK_PER_YEAR*10, + startHeight + BLOCK_PER_YEAR*11, + startHeight + BLOCK_PER_YEAR*12, +} - { - name: "year 7, begin", - height: startHeight + BLOCK_PER_YEAR*6 + 1, - want: 7, - }, - { - name: "year 7, middle", - height: startHeight + BLOCK_PER_YEAR*7 - 1, - want: 7, - }, - { - name: "year 7, end", - height: startHeight + BLOCK_PER_YEAR*7, - want: 7, - }, +var LAST_TIMESTAMP_OF_YEAR = []int64{ + 0, + startTimestamp + consts.TIMESTAMP_YEAR*1, + startTimestamp + consts.TIMESTAMP_YEAR*2, + startTimestamp + consts.TIMESTAMP_YEAR*3, + startTimestamp + consts.TIMESTAMP_YEAR*4, + startTimestamp + consts.TIMESTAMP_YEAR*5, + startTimestamp + consts.TIMESTAMP_YEAR*6, + startTimestamp + consts.TIMESTAMP_YEAR*7, + startTimestamp + consts.TIMESTAMP_YEAR*8, + startTimestamp + consts.TIMESTAMP_YEAR*9, + startTimestamp + consts.TIMESTAMP_YEAR*10, + startTimestamp + consts.TIMESTAMP_YEAR*11, + startTimestamp + consts.TIMESTAMP_YEAR*12, +} - { - name: "year 8, begin", - height: startHeight + BLOCK_PER_YEAR*7 + 1, - want: 8, - }, - { - name: "year 8, middle", - height: startHeight + BLOCK_PER_YEAR*8 - 1, - want: 8, - }, - { - name: "year 8, end", - height: startHeight + BLOCK_PER_YEAR*8, - want: 8, - }, +func TestSetAvgBlockTimeInMsByAdmin(t *testing.T) { + t.Run("panic if caller is not admin", func(t *testing.T) { + uassert.PanicsWithMessage(t, + "caller(g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) has no permission", + func() { + SetAvgBlockTimeInMsByAdmin(1) + }, + ) + }) - { - name: "year 9, begin", - height: startHeight + BLOCK_PER_YEAR*8 + 1, - want: 9, - }, - { - name: "year 9, middle", - height: startHeight + BLOCK_PER_YEAR*9 - 1, - want: 9, - }, - { - name: "year 9, end", - height: startHeight + BLOCK_PER_YEAR*9, - want: 9, - }, + t.Run("success if caller is admin", func(t *testing.T) { + std.TestSkipHeights(1) + std.TestSetRealm(adminRealm) + SetAvgBlockTimeInMsByAdmin(2) + uassert.Equal(t, GetAvgBlockTimeInMs(), int64(2)) + }) +} - { - name: "year 10, begin", - height: startHeight + BLOCK_PER_YEAR*9 + 1, - want: 10, - }, - { - name: "year 10, middle", - height: startHeight + BLOCK_PER_YEAR*10 - 1, - want: 10, - }, - { - name: "year 10, end", - height: startHeight + BLOCK_PER_YEAR*10, - want: 10, - }, +func TestSetAvgBlockTimeInMs(t *testing.T) { + t.Run("panic if caller is not governance contract", func(t *testing.T) { + uassert.PanicsWithMessage(t, + "caller(g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) has no permission", + func() { + SetAvgBlockTimeInMs(3) + }, + ) + }) - { - name: "year 11, begin", - height: startHeight + BLOCK_PER_YEAR*10 + 1, - want: 11, - }, - { - name: "year 11, middle", - height: startHeight + BLOCK_PER_YEAR*11 - 1, - want: 11, - }, - { - name: "year 11, end", - height: startHeight + BLOCK_PER_YEAR*11, - want: 11, - }, + t.Run("success if caller is governance contract", func(t *testing.T) { + std.TestSkipHeights(3) + std.TestSetRealm(govRealm) + SetAvgBlockTimeInMs(4) + uassert.Equal(t, GetAvgBlockTimeInMs(), int64(4)) + }) - { - name: "year 12, begin", - height: startHeight + BLOCK_PER_YEAR*11 + 1, - want: 12, - }, - { - name: "year 12, middle", - height: startHeight + BLOCK_PER_YEAR*12 - 1, - want: 12, - }, - { - name: "year 12, end", - height: startHeight + BLOCK_PER_YEAR*12, - want: 12, - }, + // reset to default for further test + setAvgBlockTimeInMs(consts.SECOND_IN_MILLISECOND * consts.BLOCK_GENERATION_INTERVAL) +} - { - name: "after year 12", - height: startHeight + BLOCK_PER_YEAR*12 + 1, - want: 0, - }, +func TestGetAmountByHeight(t *testing.T) { + for year := int64(1); year <= MAX_HALVING_YEAR; year++ { + lastBlockOfYear := LAST_BLOCK_OF_YEAR[year] + uassert.Equal(t, GetAmountPerBlockPerHalvingYear(year), GetAmountByHeight(lastBlockOfYear)) } +} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - uassert.Equal(t, tt.want, GetHalvingYearByHeight(tt.height)) - }) +func TestGetHalvingYearByHeight(t *testing.T) { + for year := int64(1); year <= MAX_HALVING_YEAR; year++ { + lastBlockOfYear := LAST_BLOCK_OF_YEAR[year] + uassert.Equal(t, year, GetHalvingYearByHeight(lastBlockOfYear)) } } func TestGetHalvingYearAndEndTimestamp(t *testing.T) { - tests := []struct { - name string - timestamp int64 - wantYear int64 - wantEndTimestamp int64 - }{ - { - name: "year 1, begin", - timestamp: startTimestamp + 1, - wantYear: 1, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR, - }, - { - name: "year 1, middle", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR/2, - wantYear: 1, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR, - }, - { - name: "year 1, end", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*1, - wantYear: 1, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR, - }, - - { - name: "year 2, begin", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*1 + 1, - wantYear: 2, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*2, - }, - - { - name: "year 2, middle", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*2 - 1, - wantYear: 2, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*2, - }, - - { - name: "year 2, end", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*2, - wantYear: 2, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*2, - }, - - { - name: "year 3, begin", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*2 + 1, - wantYear: 3, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*3, - }, - - { - name: "year 3, middle", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*3 - 1, - wantYear: 3, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*3, - }, - - { - name: "year 3, end", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*3, - wantYear: 3, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*3, - }, - - { - name: "year 4, begin", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*3 + 1, - wantYear: 4, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*4, - }, - - { - name: "year 4, middle", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*4 - 1, - wantYear: 4, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*4, - }, - - { - name: "year 4, end", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*4, - wantYear: 4, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*4, - }, - - { - name: "year 5, begin", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*4 + 1, - wantYear: 5, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*5, - }, - - { - name: "year 5, middle", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*5 - 1, - wantYear: 5, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*5, - }, - - { - name: "year 5, end", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*5, - wantYear: 5, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*5, - }, - - { - name: "year 6, begin", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*5 + 1, - wantYear: 6, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*6, - }, - - { - name: "year 6, middle", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*6 - 1, - wantYear: 6, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*6, - }, - - { - name: "year 6, end", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*6, - wantYear: 6, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*6, - }, - - { - name: "year 7, begin", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*6 + 1, - wantYear: 7, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*7, - }, - - { - name: "year 7, middle", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*7 - 1, - wantYear: 7, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*7, - }, - - { - name: "year 7, end", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*7, - wantYear: 7, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*7, - }, - - { - name: "year 8, begin", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*7 + 1, - wantYear: 8, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*8, - }, - - { - name: "year 8, middle", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*8 - 1, - wantYear: 8, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*8, - }, - - { - name: "year 8, end", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*8, - wantYear: 8, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*8, - }, - - { - name: "year 9, begin", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*8 + 1, - wantYear: 9, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*9, - }, - - { - name: "year 9, middle", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*9 - 1, - wantYear: 9, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*9, - }, - - { - name: "year 9, end", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*9, - wantYear: 9, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*9, - }, - - { - name: "year 10, begin", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*9 + 1, - wantYear: 10, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*10, - }, - - { - name: "year 10, middle", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*10 - 1, - wantYear: 10, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*10, - }, - - { - name: "year 10, end", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*10, - wantYear: 10, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*10, - }, - - { - name: "year 11, begin", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*10 + 1, - wantYear: 11, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*11, - }, - - { - name: "year 11, middle", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*11 - 1, - wantYear: 11, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*11, - }, - - { - name: "year 11, end", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*11, - wantYear: 11, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*11, - }, - - { - name: "year 12, begin", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*11 + 1, - wantYear: 12, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*12, - }, - - { - name: "year 12, middle", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*12 - 1, - wantYear: 12, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*12, - }, - - { - name: "year 12, end", - timestamp: startTimestamp + consts.TIMESTAMP_YEAR*12, - wantYear: 12, - wantEndTimestamp: startTimestamp + consts.TIMESTAMP_YEAR*12, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotYear, gotEndTimestamp := getHalvingYearAndEndTimestamp(tt.timestamp) - uassert.Equal(t, tt.wantYear, gotYear) - uassert.Equal(t, tt.wantEndTimestamp, gotEndTimestamp) - }) + for year := int64(1); year <= MAX_HALVING_YEAR; year++ { + lastTimestampOfYear := LAST_TIMESTAMP_OF_YEAR[year] + gotYear, gotEndTimestamp := getHalvingYearAndEndTimestamp(lastTimestampOfYear) + uassert.Equal(t, year, gotYear) + uassert.Equal(t, LAST_TIMESTAMP_OF_YEAR[year], gotEndTimestamp) } } -func TestSetAvgBlockTimeInMs(t *testing.T) { - // reset state - resetObject(t) - - var ( - user01Addr = testutils.TestAddress("user01Addr") - user01Realm = std.NewUserRealm(user01Addr) - ) - - t.Run("skip 50 blocks", func(t *testing.T) { - std.TestSkipHeights(50) - uassert.Equal(t, int64(173), std.GetHeight()) - - std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - mintedAmount := Mint(a2u(user01Addr)) - uassert.Equal(t, mintedAmount, uint64(14269406*50)) - uassert.Equal(t, MintedEmissionAmount(), uint64(713470300)) - }) - - t.Run("set avg block time in ms", func(t *testing.T) { - std.TestSetRealm(std.NewUserRealm(consts.ADMIN)) - setAvgBlockTimeInMs(2500) - - // for block time 2.5s - // amount per block is 17836757 - std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - std.TestSkipHeights(1) - mintedAmount := Mint(a2u(user01Addr)) - uassert.Equal(t, mintedAmount, uint64(17836757)) - uassert.Equal(t, MintedEmissionAmount(), uint64(713470300+17836757)) // 731307057 - }) - - t.Run("reach almost first halving", func(t *testing.T) { - // current height = 174 - // next halving = 12614533 - // 12614533 - 174 = 12614359 - - std.TestSkipHeights(12614358) - std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - Mint(a2u(user01Addr)) - - uassert.Equal(t, MintedEmissionAmount(), uint64(224999969664063)) - // 224999969664063 - 731307057 = 224999238357006 - // 224999238357006 / 12614358 = 17836757 - }) - - t.Run("reach exact first halving", func(t *testing.T) { - std.TestSkipHeights(1) - uassert.Equal(t, std.GetHeight(), int64(12614533)) - - std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - Mint(a2u(user01Addr)) +func TestHalvingYearBlock(t *testing.T) { + setHalvingYearBlock(1, 100) + uassert.Equal(t, GetHalvingYearBlock(1), int64(100)) +} - // minted all amount for first halving year - uassert.Equal(t, MintedEmissionAmount(), uint64(225000000000000)) +func TestHalvingYearTimestamp(t *testing.T) { + setHalvingYearTimestamp(2, 200) + uassert.Equal(t, GetHalvingYearTimestamp(2), int64(200)) +} - year := GetHalvingYearByHeight(std.GetHeight()) - uassert.Equal(t, int64(1), year) // year 1 ends +func TestHalvingYearMaxAmount(t *testing.T) { + setHalvingYearMaxAmount(3, 300) + uassert.Equal(t, GetHalvingYearMaxAmount(3), uint64(300)) +} - }) +func TestHalvingYearMintAmount(t *testing.T) { + setHalvingYearMintAmount(4, 400) + uassert.Equal(t, GetHalvingYearMintAmount(4), uint64(400)) +} - t.Run("start second halving", func(t *testing.T) { - std.TestSkipHeights(1) +func TestHalvingYearAccuAmount(t *testing.T) { + setHalvingYearAccuAmount(5, 500) + uassert.Equal(t, GetHalvingYearAccuAmount(5), uint64(500)) +} - year := GetHalvingYearByHeight(std.GetHeight()) - uassert.Equal(t, int64(2), year) // year 2 starts +func TestAmountPerBlockPerHalvingYear(t *testing.T) { + setAmountPerBlockPerHalvingYear(6, 600) + uassert.Equal(t, GetAmountPerBlockPerHalvingYear(6), uint64(600)) +} - year2AmountPerBlock := GetAmountPerBlockPerHalvingYear(2) - uassert.Equal(t, uint64(14269406), year2AmountPerBlock) +func TestGetHalvingInfo(t *testing.T) { + jsonStr, err := json.Unmarshal([]byte(GetHalvingInfo())) + uassert.NoError(t, err) - std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - Mint(a2u(user01Addr)) - uassert.Equal(t, MintedEmissionAmount(), uint64(225000000000000+14269406)) - }) + halving := jsonStr.MustKey("halvings").MustArray() + uassert.Equal(t, len(halving), 12) } From a7703c4727d2a350cde4b7e6dd5ee40ccd10aad6 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Fri, 13 Dec 2024 15:30:12 +0900 Subject: [PATCH 09/17] GSW-1845 fix: old function names used in test --- _deploy/r/gnoswap/gns/tests/z1_filetest.gno | 23 +++++++++---------- _deploy/r/gnoswap/gns/tests/z2_filetest.gno | 25 +++++++++------------ _deploy/r/gnoswap/gns/tests/z3_filetest.gno | 25 +++++++++------------ 3 files changed, 32 insertions(+), 41 deletions(-) diff --git a/_deploy/r/gnoswap/gns/tests/z1_filetest.gno b/_deploy/r/gnoswap/gns/tests/z1_filetest.gno index 553efdfb..674fd31b 100644 --- a/_deploy/r/gnoswap/gns/tests/z1_filetest.gno +++ b/_deploy/r/gnoswap/gns/tests/z1_filetest.gno @@ -22,9 +22,6 @@ var ( user01Realm = std.NewUserRealm(user01Addr) ) -func init() { -} - func main() { skip50Blocks() blockTime2500ms() @@ -38,8 +35,8 @@ func skip50Blocks() { uassert.Equal(t, std.GetHeight(), int64(173)) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) // 14269406 * 50 = 713470300 - uassert.Equal(t, uint64(713470300), gns.TotalMinted()) + gns.MintGns(a2u(user01Addr)) // 14269406 * 50 = 713470300 + uassert.Equal(t, uint64(713470300), gns.MintedEmissionAmount()) } func blockTime2500ms() { @@ -51,8 +48,8 @@ func blockTime2500ms() { // amount per block is 17836757 std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) // 17836757 - uassert.Equal(t, uint64(713470300+17836757), gns.TotalMinted()) // 731307057 + gns.MintGns(a2u(user01Addr)) // 17836757 + uassert.Equal(t, uint64(713470300+17836757), gns.MintedEmissionAmount()) // 731307057 } func reachAlmostFirstHalving() { @@ -62,9 +59,9 @@ func reachAlmostFirstHalving() { std.TestSkipHeights(12614358) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) + gns.MintGns(a2u(user01Addr)) - uassert.Equal(t, uint64(224999969664063), gns.TotalMinted()) + uassert.Equal(t, uint64(224999969664063), gns.MintedEmissionAmount()) // 224999969664063 - 731307057 = 224999238357006 // 224999238357006 / 12614358 = 17836757 } @@ -72,10 +69,10 @@ func reachAlmostFirstHalving() { func reachExactFirstHalving() { std.TestSkipHeights(1) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) + gns.MintGns(a2u(user01Addr)) // minted all amount for first halving year - uassert.Equal(t, uint64(225000000000000), gns.TotalMinted()) + uassert.Equal(t, uint64(225000000000000), gns.MintedEmissionAmount()) year := gns.GetHalvingYearByHeight(std.GetHeight()) uassert.Equal(t, int64(1), year) @@ -91,8 +88,8 @@ func startSecondHalving() { uassert.Equal(t, uint64(14269406), amount) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) - uassert.Equal(t, uint64(225000000000000+14269406), gns.TotalMinted()) + gns.MintGns(a2u(user01Addr)) + uassert.Equal(t, uint64(225000000000000+14269406), gns.MintedEmissionAmount()) } func a2u(addr std.Address) pusers.AddressOrName { diff --git a/_deploy/r/gnoswap/gns/tests/z2_filetest.gno b/_deploy/r/gnoswap/gns/tests/z2_filetest.gno index 3bcbd458..31b612bc 100644 --- a/_deploy/r/gnoswap/gns/tests/z2_filetest.gno +++ b/_deploy/r/gnoswap/gns/tests/z2_filetest.gno @@ -22,9 +22,6 @@ var ( user01Realm = std.NewUserRealm(user01Addr) ) -func init() { -} - func main() { skip50Blocks() blockTime4000ms() @@ -38,8 +35,8 @@ func skip50Blocks() { uassert.Equal(t, std.GetHeight(), int64(173)) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) // 14269406 * 50 = 713470300 - uassert.Equal(t, uint64(713470300), gns.TotalMinted()) + gns.MintGns(a2u(user01Addr)) // 14269406 * 50 = 713470300 + uassert.Equal(t, uint64(713470300), gns.MintedEmissionAmount()) } func blockTime4000ms() { @@ -51,10 +48,10 @@ func blockTime4000ms() { // amount per block is 28538812 std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) // 28538812 - uassert.Equal(t, uint64(713470300+28538812), gns.TotalMinted()) // 742009112 + gns.MintGns(a2u(user01Addr)) // 28538812 + uassert.Equal(t, uint64(713470300+28538812), gns.MintedEmissionAmount()) // 742009112 - firstYearAmountPerBlock := gns.GetAmountByYear(1) + firstYearAmountPerBlock := gns.GetAmountPerBlockPerHalvingYear(1) uassert.Equal(t, uint64(28538812), firstYearAmountPerBlock) uassert.Equal(t, int64(7884148), gns.GetHalvingYearBlock(1)) // FORMULA @@ -79,10 +76,10 @@ func reachFirstHalving() { std.TestSkipHeights(7883974) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) + gns.MintGns(a2u(user01Addr)) // minted all amount for first halving year - uassert.Equal(t, uint64(225000000000000), gns.TotalMinted()) + uassert.Equal(t, uint64(225000000000000), gns.MintedEmissionAmount()) year := gns.GetHalvingYearByHeight(std.GetHeight()) uassert.Equal(t, int64(1), year) @@ -98,8 +95,8 @@ func startSecondHalving() { uassert.Equal(t, uint64(14269406), amount) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) - uassert.Equal(t, uint64(225000000000000+14269406), gns.TotalMinted()) + gns.MintGns(a2u(user01Addr)) + uassert.Equal(t, uint64(225000000000000+14269406), gns.MintedEmissionAmount()) } func reachSecondHalving() { @@ -109,10 +106,10 @@ func reachSecondHalving() { std.TestSkipHeights(7883999) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) + gns.MintGns(a2u(user01Addr)) // minted all amount until second halving - uassert.Equal(t, uint64(225000000000000*2), gns.TotalMinted()) + uassert.Equal(t, uint64(225000000000000*2), gns.MintedEmissionAmount()) } func a2u(addr std.Address) pusers.AddressOrName { diff --git a/_deploy/r/gnoswap/gns/tests/z3_filetest.gno b/_deploy/r/gnoswap/gns/tests/z3_filetest.gno index b1ab87d1..cba84223 100644 --- a/_deploy/r/gnoswap/gns/tests/z3_filetest.gno +++ b/_deploy/r/gnoswap/gns/tests/z3_filetest.gno @@ -22,9 +22,6 @@ var ( user01Realm = std.NewUserRealm(user01Addr) ) -func init() { -} - func main() { skip50Blocks() blockTime4000ms() // 4s @@ -39,8 +36,8 @@ func skip50Blocks() { uassert.Equal(t, std.GetHeight(), int64(173)) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) // 14269406 * 50 = 713470300 - uassert.Equal(t, uint64(713470300), gns.TotalMinted()) + gns.MintGns(a2u(user01Addr)) // 14269406 * 50 = 713470300 + uassert.Equal(t, uint64(713470300), gns.MintedEmissionAmount()) } func blockTime4000ms() { @@ -52,10 +49,10 @@ func blockTime4000ms() { // amount per block is 28538812 std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) // 28538812 - uassert.Equal(t, uint64(713470300+28538812), gns.TotalMinted()) // 742009112 + gns.MintGns(a2u(user01Addr)) // 28538812 + uassert.Equal(t, uint64(713470300+28538812), gns.MintedEmissionAmount()) // 742009112 - firstYearAmountPerBlock := gns.GetAmountByYear(1) + firstYearAmountPerBlock := gns.GetAmountPerBlockPerHalvingYear(1) uassert.Equal(t, uint64(28538812), firstYearAmountPerBlock) uassert.Equal(t, int64(7884148), gns.GetHalvingYearBlock(1)) // FORMULA @@ -81,10 +78,10 @@ func reachAboutHalfOfFirstHalving() { std.TestSkipHeights(3941987) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) + gns.MintGns(a2u(user01Addr)) // minted about 50% amount for first halving year - uassert.Equal(t, uint64(112500367908556), gns.TotalMinted()) + uassert.Equal(t, uint64(112500367908556), gns.MintedEmissionAmount()) year := gns.GetHalvingYearByHeight(std.GetHeight()) uassert.Equal(t, int64(1), year) @@ -103,10 +100,10 @@ func reachFirstHalving() { std.TestSkipHeights(7883973) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) + gns.MintGns(a2u(user01Addr)) // minted all amount for first halving year - uassert.Equal(t, uint64(225000000000000), gns.TotalMinted()) + uassert.Equal(t, uint64(225000000000000), gns.MintedEmissionAmount()) // we're at the end of first halving year year := gns.GetHalvingYearByHeight(std.GetHeight()) @@ -123,8 +120,8 @@ func startSecondHalving() { uassert.Equal(t, uint64(14269406), amount) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) - uassert.Equal(t, uint64(225000000000000+14269406), gns.TotalMinted()) + gns.MintGns(a2u(user01Addr)) + uassert.Equal(t, uint64(225000000000000+14269406), gns.MintedEmissionAmount()) } func a2u(addr std.Address) pusers.AddressOrName { From b21f75e544ae0764d474bf4cf53bf80cfd80635e Mon Sep 17 00:00:00 2001 From: n3wbie Date: Mon, 16 Dec 2024 19:46:49 +0900 Subject: [PATCH 10/17] GSW-1845 refactor: use array if possible rather than avl --- _deploy/r/gnoswap/gns/halving.gno | 148 ++++++++++++------------- _deploy/r/gnoswap/gns/halving_test.gno | 67 +++++++---- 2 files changed, 119 insertions(+), 96 deletions(-) diff --git a/_deploy/r/gnoswap/gns/halving.gno b/_deploy/r/gnoswap/gns/halving.gno index 4e6d7b21..226e9509 100644 --- a/_deploy/r/gnoswap/gns/halving.gno +++ b/_deploy/r/gnoswap/gns/halving.gno @@ -5,7 +5,6 @@ import ( "strconv" "time" - "gno.land/p/demo/avl" "gno.land/p/demo/ufmt" "gno.land/r/gnoswap/v1/common" @@ -25,8 +24,10 @@ import ( */ const ( - MONTH_PER_YEAR = uint64(12) - HALVING_AMOUNTS = []uint64{ + HALVING_START_YEAR = int64(1) + HALVING_END_YEAR = int64(12) + + HALVING_AMOUNTS_PER_YEAR = []uint64{ 18_750_000_000_000 * 12, // Year 1: 225000000000000 18_750_000_000_000 * 12, // Year 2: 225000000000000 9_375_000_000_000 * 12, // Year 3: 112500000000000 @@ -40,8 +41,6 @@ const ( 1_171_875_000_000 * 12, // Year 11: 14062500000000 1_171_875_000_000 * 12, // Year 12: 14062500000000 } - - MAX_HALVING_YEAR = int64(12) ) var ( @@ -54,32 +53,36 @@ var ( var ( startHeight int64 startTimestamp int64 + + endHeight int64 // (approximately) after 12 years, block height which gns emission will be ended + endTimestamp int64 // (exactly) after 12 years, timestamp which gns emission will be ended ) var ( - halvingYearBlock = avl.NewTree() // year -> last block height - halvingYearTimestamp = avl.NewTree() // year -> timestamp - halvingYearMaxAmount = avl.NewTree() // year -> (maximum) mintAmount - halvingYearMintAmount = avl.NewTree() // year -> (actual) mintAmount - halvingYearAccuAmount = avl.NewTree() // year -> accuAmount - amountPerBlockPerHalvingYear = avl.NewTree() // year -> amount per block + halvingYearBlock = make([]int64, HALVING_END_YEAR) // start block of each halving year + halvingYearTimestamp = make([]int64, HALVING_END_YEAR) // start timestamp of each halving year + + halvingYearMaxAmount = make([]uint64, HALVING_END_YEAR) + halvingYearMintAmount = make([]uint64, HALVING_END_YEAR) + halvingYearAccuAmount = make([]uint64, HALVING_END_YEAR) + amountPerBlockPerHalvingYear = make([]uint64, HALVING_END_YEAR) ) func init() { startHeight = std.GetHeight() startTimestamp = time.Now().Unix() - for year := int64(1); year < 13; year++ { - setHalvingYearMaxAmount(year, HALVING_AMOUNTS[year-1]) + for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { + setHalvingYearMaxAmount(year, HALVING_AMOUNTS_PER_YEAR[year-1]) if year == 1 { - setHalvingYearAccuAmount(year, HALVING_AMOUNTS[year-1]) + setHalvingYearAccuAmount(year, HALVING_AMOUNTS_PER_YEAR[year-1]) } else { - setHalvingYearAccuAmount(year, GetHalvingYearAccuAmount(year-1)+HALVING_AMOUNTS[year-1]) + setHalvingYearAccuAmount(year, GetHalvingYearAccuAmount(year-1)+HALVING_AMOUNTS_PER_YEAR[year-1]) } - setHalvingYearBlock(year, startHeight+BLOCK_PER_YEAR*year) - setHalvingYearTimestamp(year, startTimestamp+(consts.TIMESTAMP_YEAR*year)) + setHalvingYearBlock(year, startHeight+BLOCK_PER_YEAR*(year-1)) + setHalvingYearTimestamp(year, startTimestamp+(consts.TIMESTAMP_YEAR*year-1)) setHalvingYearMintAmount(year, uint64(0)) amountPerYear := GetHalvingYearMaxAmount(year) // amount per year @@ -87,6 +90,9 @@ func init() { amountPerBlock := amountPerDay / uint64(BLOCK_PER_DAY) // amount per block setAmountPerBlockPerHalvingYear(year, uint64(amountPerBlock)) } + + setEndHeight(startHeight + BLOCK_PER_YEAR*HALVING_END_YEAR) + setEndTimestamp(startTimestamp + consts.TIMESTAMP_YEAR*HALVING_END_YEAR) } func GetAvgBlockTimeInMs() int64 { @@ -172,13 +178,21 @@ func setAvgBlockTimeInMs(ms int64) { // GetAmountByHeight returns the amount of gns to mint by height func GetAmountByHeight(height int64) uint64 { + if isEmissionEnded(height) { + return 0 + } + halvingYear := GetHalvingYearByHeight(height) return GetAmountPerBlockPerHalvingYear(halvingYear) } // GetHalvingYearByHeight returns the halving year by height func GetHalvingYearByHeight(height int64) int64 { - for year := int64(1); year < 13; year++ { + if isEmissionEnded(height) { + return 0 + } + + for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { block := GetHalvingYearBlock(year) if height <= block { return year @@ -191,102 +205,80 @@ func GetHalvingYearByHeight(height int64) int64 { // getHalvingYearAndEndTimestamp returns the halving year and end timestamp of the given timestamp // if the timestamp is not in any halving year, it returns 0, 0 func getHalvingYearAndEndTimestamp(timestamp int64) (int64, int64) { - timestamp -= startTimestamp - - divValue := timestamp / consts.TIMESTAMP_YEAR - modValue := timestamp % consts.TIMESTAMP_YEAR - - if modValue == 0 { - if divValue > 12 { - return 0, 0 - } - - return divValue, startTimestamp + (consts.TIMESTAMP_YEAR * divValue) - } - - if divValue+1 > 12 { + if timestamp > endTimestamp { // after 12 years return 0, 0 } - return divValue + 1, startTimestamp + (consts.TIMESTAMP_YEAR * (divValue + 1)) + timestamp -= startTimestamp + + year := timestamp / consts.TIMESTAMP_YEAR + year += 1 // since we subtract startTimestamp at line 215, we need to add 1 to get the correct year + + return year, startTimestamp + (consts.TIMESTAMP_YEAR * year) } func GetHalvingYearBlock(year int64) int64 { - iBlock, exist := halvingYearBlock.Get(strconv.FormatInt(year, 10)) - if !exist { - panic(ufmt.Sprintf("halving.gno__GetHalvingYearBlock() || year(%d) not found", year)) - } - - return iBlock.(int64) + return halvingYearBlock[year-1] } func setHalvingYearBlock(year int64, block int64) { - halvingYearBlock.Set(strconv.FormatInt(year, 10), block) + halvingYearBlock[year-1] = block } func GetHalvingYearTimestamp(year int64) int64 { - iTimestamp, exist := halvingYearTimestamp.Get(strconv.FormatInt(year, 10)) - if !exist { - panic(ufmt.Sprintf("halving.gno__GetHalvingYearTimestamp() || year(%d) not found", year)) - } - - return iTimestamp.(int64) + return halvingYearTimestamp[year-1] } func setHalvingYearTimestamp(year int64, timestamp int64) { - halvingYearTimestamp.Set(strconv.FormatInt(year, 10), timestamp) + halvingYearTimestamp[year-1] = timestamp } func GetHalvingYearMaxAmount(year int64) uint64 { - iAmount, exist := halvingYearMaxAmount.Get(strconv.FormatInt(year, 10)) - if !exist { - panic(ufmt.Sprintf("halving.gno__GetHalvingYearMaxAmount() || year(%d) not found", year)) - } - - return iAmount.(uint64) + return halvingYearMaxAmount[year-1] } func setHalvingYearMaxAmount(year int64, amount uint64) { - halvingYearMaxAmount.Set(strconv.FormatInt(year, 10), amount) + halvingYearMaxAmount[year-1] = amount } func GetHalvingYearMintAmount(year int64) uint64 { - iAmount, exist := halvingYearMintAmount.Get(strconv.FormatInt(year, 10)) - if !exist { - panic(ufmt.Sprintf("halving.gno__GetHalvingYearMintAmount() || year(%d) not found", year)) - } - - return iAmount.(uint64) + return halvingYearMintAmount[year-1] } func setHalvingYearMintAmount(year int64, amount uint64) { - halvingYearMintAmount.Set(strconv.FormatInt(year, 10), amount) + halvingYearMintAmount[year-1] = amount } func GetHalvingYearAccuAmount(year int64) uint64 { - iAmount, exist := halvingYearAccuAmount.Get(strconv.FormatInt(year, 10)) - if !exist { - panic(ufmt.Sprintf("halving.gno__GetHalvingYearAccuAmount() || year(%d) not found", year)) - } - - return iAmount.(uint64) + return halvingYearAccuAmount[year-1] } func setHalvingYearAccuAmount(year int64, amount uint64) { - halvingYearAccuAmount.Set(strconv.FormatInt(year, 10), amount) + halvingYearAccuAmount[year-1] = amount } func GetAmountPerBlockPerHalvingYear(year int64) uint64 { - iAmount, exist := amountPerBlockPerHalvingYear.Get(strconv.FormatInt(year, 10)) - if !exist { - panic(ufmt.Sprintf("halving.gno__GetAmountPerBlockPerHalvingYear() || year(%d) not found", year)) - } - - return iAmount.(uint64) + return amountPerBlockPerHalvingYear[year-1] } func setAmountPerBlockPerHalvingYear(year int64, amount uint64) { - amountPerBlockPerHalvingYear.Set(strconv.FormatInt(year, 10), amount) + amountPerBlockPerHalvingYear[year-1] = amount +} + +func GetEndHeight() int64 { + return endHeight +} + +func setEndHeight(height int64) { + endHeight = height +} + +func GetEndTimestamp() int64 { + return endTimestamp +} + +func setEndTimestamp(timestamp int64) { + endTimestamp = timestamp } func GetHalvingInfo() string { @@ -295,7 +287,7 @@ func GetHalvingInfo() string { halvings := make([]*json.Node, 0) - for year := int64(1); year <= MAX_HALVING_YEAR; year++ { + for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { halvings = append(halvings, json.ObjectNode("", map[string]*json.Node{ "year": json.StringNode("year", strconv.FormatInt(year, 10)), "block": json.NumberNode("block", float64(GetHalvingYearBlock(year))), @@ -317,3 +309,7 @@ func GetHalvingInfo() string { return string(b) } + +func isEmissionEnded(height int64) bool { + return height > endHeight +} diff --git a/_deploy/r/gnoswap/gns/halving_test.gno b/_deploy/r/gnoswap/gns/halving_test.gno index 2ed4a01d..233a941b 100644 --- a/_deploy/r/gnoswap/gns/halving_test.gno +++ b/_deploy/r/gnoswap/gns/halving_test.gno @@ -5,18 +5,18 @@ import ( "testing" "gno.land/p/demo/json" - "gno.land/p/demo/uassert" "gno.land/r/gnoswap/v1/consts" ) var ( - govRealm = std.NewCodeRealm(consts.GOV_GOVERNANCE_PATH) + govRealm = std.NewCodeRealm(consts.GOV_GOVERNANCE_PATH) + adminRealm = std.NewUserRealm(consts.ADMIN) ) -var LAST_BLOCK_OF_YEAR = []int64{ - 0, +var FIRST_BLOCK_OF_YEAR = []int64{ + startHeight, startHeight + BLOCK_PER_YEAR*1, startHeight + BLOCK_PER_YEAR*2, startHeight + BLOCK_PER_YEAR*3, @@ -28,11 +28,24 @@ var LAST_BLOCK_OF_YEAR = []int64{ startHeight + BLOCK_PER_YEAR*9, startHeight + BLOCK_PER_YEAR*10, startHeight + BLOCK_PER_YEAR*11, - startHeight + BLOCK_PER_YEAR*12, } -var LAST_TIMESTAMP_OF_YEAR = []int64{ - 0, +var FIRST_TIMESTAMP_OF_YEAR = []int64{ + startTimestamp, + startTimestamp + consts.TIMESTAMP_YEAR*1, + startTimestamp + consts.TIMESTAMP_YEAR*2, + startTimestamp + consts.TIMESTAMP_YEAR*3, + startTimestamp + consts.TIMESTAMP_YEAR*4, + startTimestamp + consts.TIMESTAMP_YEAR*5, + startTimestamp + consts.TIMESTAMP_YEAR*6, + startTimestamp + consts.TIMESTAMP_YEAR*7, + startTimestamp + consts.TIMESTAMP_YEAR*8, + startTimestamp + consts.TIMESTAMP_YEAR*9, + startTimestamp + consts.TIMESTAMP_YEAR*10, + startTimestamp + consts.TIMESTAMP_YEAR*11, +} + +var END_TIMESTAMP_OF_YEAR = []int64{ startTimestamp + consts.TIMESTAMP_YEAR*1, startTimestamp + consts.TIMESTAMP_YEAR*2, startTimestamp + consts.TIMESTAMP_YEAR*3, @@ -87,26 +100,40 @@ func TestSetAvgBlockTimeInMs(t *testing.T) { } func TestGetAmountByHeight(t *testing.T) { - for year := int64(1); year <= MAX_HALVING_YEAR; year++ { - lastBlockOfYear := LAST_BLOCK_OF_YEAR[year] - uassert.Equal(t, GetAmountPerBlockPerHalvingYear(year), GetAmountByHeight(lastBlockOfYear)) + for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { + firstBlockOfYear := FIRST_BLOCK_OF_YEAR[year-1] + uassert.Equal(t, GetAmountPerBlockPerHalvingYear(year), GetAmountByHeight(firstBlockOfYear)) } } func TestGetHalvingYearByHeight(t *testing.T) { - for year := int64(1); year <= MAX_HALVING_YEAR; year++ { - lastBlockOfYear := LAST_BLOCK_OF_YEAR[year] - uassert.Equal(t, year, GetHalvingYearByHeight(lastBlockOfYear)) - } + t.Run("during halving years", func(t *testing.T) { + for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { + firstBlockOfYear := FIRST_BLOCK_OF_YEAR[year-1] + uassert.Equal(t, year, GetHalvingYearByHeight(firstBlockOfYear)) + } + }) + + t.Run("no year after 12 years", func(t *testing.T) { + uassert.Equal(t, int64(0), GetHalvingYearByHeight(GetEndHeight()+1)) + }) } func TestGetHalvingYearAndEndTimestamp(t *testing.T) { - for year := int64(1); year <= MAX_HALVING_YEAR; year++ { - lastTimestampOfYear := LAST_TIMESTAMP_OF_YEAR[year] - gotYear, gotEndTimestamp := getHalvingYearAndEndTimestamp(lastTimestampOfYear) - uassert.Equal(t, year, gotYear) - uassert.Equal(t, LAST_TIMESTAMP_OF_YEAR[year], gotEndTimestamp) - } + t.Run("bit of extra timestamp for each year", func(t *testing.T) { + for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { + firstTimestampOfYear := FIRST_TIMESTAMP_OF_YEAR[year-1] + gotYear, gotEndTimestamp := getHalvingYearAndEndTimestamp(firstTimestampOfYear + 5) // after 5s + uassert.Equal(t, year, gotYear) + uassert.Equal(t, gotEndTimestamp, END_TIMESTAMP_OF_YEAR[year-1]) + } + }) + + t.Run("after 12 years", func(t *testing.T) { + year, endTimestamp := getHalvingYearAndEndTimestamp(GetEndTimestamp() + 1) + uassert.Equal(t, int64(0), year) + uassert.Equal(t, int64(0), endTimestamp) + }) } func TestHalvingYearBlock(t *testing.T) { From 3240e82ab70d91dd5355429affd238957ede25dd Mon Sep 17 00:00:00 2001 From: n3wbie Date: Mon, 16 Dec 2024 19:57:22 +0900 Subject: [PATCH 11/17] GSW-1845 feat: skip minting gns block - if emission is ended --- _deploy/r/gnoswap/gns/_helper_test.gno | 6 +++--- _deploy/r/gnoswap/gns/gns.gno | 23 ++++++++++------------- _deploy/r/gnoswap/gns/gns_test.gno | 10 ++++++++++ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/_deploy/r/gnoswap/gns/_helper_test.gno b/_deploy/r/gnoswap/gns/_helper_test.gno index 68dc4442..8c3d0006 100644 --- a/_deploy/r/gnoswap/gns/_helper_test.gno +++ b/_deploy/r/gnoswap/gns/_helper_test.gno @@ -36,12 +36,12 @@ func resetHalvingRelatedObject(t *testing.T) { t.Helper() for year := int64(1); year < 13; year++ { - setHalvingYearMaxAmount(year, HALVING_AMOUNTS[year-1]) + setHalvingYearMaxAmount(year, HALVING_AMOUNTS_PER_YEAR[year-1]) if year == 1 { - setHalvingYearAccuAmount(year, HALVING_AMOUNTS[year-1]) + setHalvingYearAccuAmount(year, HALVING_AMOUNTS_PER_YEAR[year-1]) } else { - setHalvingYearAccuAmount(year, GetHalvingYearAccuAmount(year-1)+HALVING_AMOUNTS[year-1]) + setHalvingYearAccuAmount(year, GetHalvingYearAccuAmount(year-1)+HALVING_AMOUNTS_PER_YEAR[year-1]) } setHalvingYearBlock(year, startHeight+BLOCK_PER_YEAR*year) diff --git a/_deploy/r/gnoswap/gns/gns.gno b/_deploy/r/gnoswap/gns/gns.gno index 6435c9f5..2143c4eb 100644 --- a/_deploy/r/gnoswap/gns/gns.gno +++ b/_deploy/r/gnoswap/gns/gns.gno @@ -54,8 +54,10 @@ func MintGns(address pusers.AddressOrName) uint64 { lastMintedHeight := GetLastMintedHeight() currentHeight := std.GetHeight() - // skip minting process if gns for current block is already minted - if skipIfSameHeight(lastMintedHeight, currentHeight) { + // skip minting process if following conditions are met + // - if gns for current block is already minted + // - if emission has ended + if skipIfSameHeight(lastMintedHeight, currentHeight) || skipIfEmissionEnded(currentHeight) { return 0 } @@ -146,10 +148,6 @@ func calculateAmountToMint(fromHeight, toHeight int64) uint64 { fromYear := GetHalvingYearByHeight(fromHeight) toYear := GetHalvingYearByHeight(toHeight) - if isEmissionEnded(fromYear) || isEmissionEnded(toYear) { - return 0 - } - totalAmountToMint := uint64(0) for i := fromYear; i <= toYear; i++ { @@ -170,7 +168,7 @@ func calculateAmountToMint(fromHeight, toHeight int64) uint64 { yearAmountToMint += handleLeftEmissionAmount(i, yearAmountToMint) } totalAmountToMint += yearAmountToMint - SetHalvingYearMintAmount(i, GetHalvingYearMintAmount(i)+yearAmountToMint) + setHalvingYearMintAmount(i, GetHalvingYearMintAmount(i)+yearAmountToMint) // update fromHeight for next year (if necessary) fromHeight = mintUntilHeight + 1 @@ -199,14 +197,13 @@ func skipIfSameHeight(lastMintedHeight, currentHeight int64) bool { return lastMintedHeight == currentHeight } -// isEmissionEnded returns true if the emission is ended. -// It returns false if the emission is not ended. -func isEmissionEnded(year int64) bool { - if 1 <= year && year <= 12 { - return false +// skipIfEmissionEnded returns true if the emission has ended. +func skipIfEmissionEnded(height int64) bool { + if isEmissionEnded(height) { + return true } - return true + return false } // Getter diff --git a/_deploy/r/gnoswap/gns/gns_test.gno b/_deploy/r/gnoswap/gns/gns_test.gno index 68d6a648..870d507e 100644 --- a/_deploy/r/gnoswap/gns/gns_test.gno +++ b/_deploy/r/gnoswap/gns/gns_test.gno @@ -108,6 +108,16 @@ func TestSkipIfSameHeight(t *testing.T) { }) } +func TestSkipIfEmissionEnded(t *testing.T) { + t.Run("should skip if emission has ended", func(t *testing.T) { + uassert.True(t, skipIfEmissionEnded(GetEndHeight()+1)) + }) + + t.Run("should not skip if emission has not ended", func(t *testing.T) { + uassert.False(t, skipIfEmissionEnded(std.GetHeight())) + }) +} + func TestGetterSetter(t *testing.T) { t.Run("last minted height", func(t *testing.T) { value := int64(1234) From f6c7b5482c597c7fd9f3ef4623f30cf7f2662ecc Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 19 Dec 2024 17:02:02 +0900 Subject: [PATCH 12/17] GSW-1845 refactor: declare type first, then initialize value --- _deploy/r/gnoswap/gns/gns.gno | 57 +++++++++++++++++-------------- _deploy/r/gnoswap/gns/halving.gno | 6 ++-- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/_deploy/r/gnoswap/gns/gns.gno b/_deploy/r/gnoswap/gns/gns.gno index 2143c4eb..44e7a70c 100644 --- a/_deploy/r/gnoswap/gns/gns.gno +++ b/_deploy/r/gnoswap/gns/gns.gno @@ -22,32 +22,32 @@ const ( ) var ( - lastMintedHeight = std.GetHeight() -) + owner *ownable.Ownable -var ( - // Initial amount set to 900_000_000_000_000 (MAXIMUM_SUPPLY - INITIAL_MINT_AMOUNT). - // leftEmissionAmount will decrease as tokens are minted. - leftEmissionAmount = MAX_EMISSION_AMOUNT - mintedEmissionAmount = uint64(0) -) + Token *grc20.Token + privateLedger *grc20.PrivateLedger + UserTeller grc20.Teller -var ( - Token, privateLedger = grc20.NewToken("Gnoswap", "GNS", 6) - UserTeller = Token.CallerTeller() - owner = ownable.NewWithAddress(consts.ADMIN) + leftEmissionAmount uint64 + mintedEmissionAmount uint64 + lastMintedHeight int64 ) func init() { + owner = ownable.NewWithAddress(consts.ADMIN) + + Token, privateLedger = grc20.NewToken("Gnoswap", "GNS", 6) + UserTeller = Token.CallerTeller() + privateLedger.Mint(owner.Owner(), INITIAL_MINT_AMOUNT) getter := func() *grc20.Token { return Token } grc20reg.Register(getter, "") -} -// MintedEmissionAmount returns the amount of GNS that has been minted by the emission contract. -// It does not include initial minted amount. -func MintedEmissionAmount() uint64 { - return TotalSupply() - INITIAL_MINT_AMOUNT + // Initial amount set to 900_000_000_000_000 (MAXIMUM_SUPPLY - INITIAL_MINT_AMOUNT). + // leftEmissionAmount will decrease as tokens are minted. + leftEmissionAmount = MAX_EMISSION_AMOUNT + + lastMintedHeight = std.GetHeight() } func MintGns(address pusers.AddressOrName) uint64 { @@ -56,8 +56,12 @@ func MintGns(address pusers.AddressOrName) uint64 { // skip minting process if following conditions are met // - if gns for current block is already minted - // - if emission has ended - if skipIfSameHeight(lastMintedHeight, currentHeight) || skipIfEmissionEnded(currentHeight) { + // - if last minted height is last block to mint ( 12 years passed ) + + // WIP + // if lastMintedHeight == currentHeight || + // } + if skipIfSameHeight(lastMintedHeight, currentHeight) || skipIfEmissionEnded(lastMintedHeight+1) { return 0 } @@ -66,16 +70,17 @@ func MintGns(address pusers.AddressOrName) uint64 { // calculate gns amount to mint, and the mint to the target address amountToMint := calculateAmountToMint(lastMintedHeight+1, currentHeight) - err := privateLedger.Mint(users.Resolve(address), amountToMint) - if err != nil { - panic(err.Error()) - } // update setLastMintedHeight(currentHeight) setMintedEmissionAmount(GetMintedEmissionAmount() + amountToMint) setLeftEmissionAmount(GetLeftEmissionAmount() - amountToMint) + err := privateLedger.Mint(users.Resolve(address), amountToMint) + if err != nil { + panic(err.Error()) + } + return amountToMint } @@ -206,20 +211,22 @@ func skipIfEmissionEnded(height int64) bool { return false } -// Getter +// GetLastMintedHeight returns the last block height that gns was minted. func GetLastMintedHeight() int64 { return lastMintedHeight } +// GetLeftEmissionAmount returns the amount of GNS can be minted. func GetLeftEmissionAmount() uint64 { return leftEmissionAmount } +// GetMintedEmissionAmount returns the amount of GNS that has been minted by the emission contract. +// It does not include initial minted amount. func GetMintedEmissionAmount() uint64 { return mintedEmissionAmount } -// Setter func setLastMintedHeight(height int64) { lastMintedHeight = height } diff --git a/_deploy/r/gnoswap/gns/halving.gno b/_deploy/r/gnoswap/gns/halving.gno index 226e9509..a1b5e800 100644 --- a/_deploy/r/gnoswap/gns/halving.gno +++ b/_deploy/r/gnoswap/gns/halving.gno @@ -27,7 +27,7 @@ const ( HALVING_START_YEAR = int64(1) HALVING_END_YEAR = int64(12) - HALVING_AMOUNTS_PER_YEAR = []uint64{ + HALVING_AMOUNTS_PER_YEAR = [12]uint64{ 18_750_000_000_000 * 12, // Year 1: 225000000000000 18_750_000_000_000 * 12, // Year 2: 225000000000000 9_375_000_000_000 * 12, // Year 3: 112500000000000 @@ -154,7 +154,7 @@ func setAvgBlockTimeInMs(ms int64) { timeLeftMs := timeLeft * consts.SECOND_IN_MILLISECOND blockLeft := timeLeftMs / avgBlockTimeMs // how many reward left to next halving - minted := MintedEmissionAmount() + minted := GetMintedEmissionAmount() amountLeft := GetHalvingYearAccuAmount(year) - minted // how much reward per block @@ -163,7 +163,7 @@ func setAvgBlockTimeInMs(ms int64) { // update it setAmountPerBlockPerHalvingYear(year, adjustedAmountPerBlock) - for year := int64(1); year < 13; year++ { + for year := int64(1); year < HALVING_END_YEAR+1; year++ { yearEndTimestamp := GetHalvingYearTimestamp(year) if now >= yearEndTimestamp { From ed5164815fa5e29193f97e5e04f867ec216bb021 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 19 Dec 2024 19:14:11 +0900 Subject: [PATCH 13/17] GSW-1845 refactor: if block range for emission includes emission end height, mint until end height --- _deploy/r/gnoswap/gns/gns.gno | 14 ++++---- _deploy/r/gnoswap/gns/halving.gno | 59 +++++++++++++++---------------- 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/_deploy/r/gnoswap/gns/gns.gno b/_deploy/r/gnoswap/gns/gns.gno index 44e7a70c..43c5bf80 100644 --- a/_deploy/r/gnoswap/gns/gns.gno +++ b/_deploy/r/gnoswap/gns/gns.gno @@ -56,12 +56,8 @@ func MintGns(address pusers.AddressOrName) uint64 { // skip minting process if following conditions are met // - if gns for current block is already minted - // - if last minted height is last block to mint ( 12 years passed ) - - // WIP - // if lastMintedHeight == currentHeight || - // } - if skipIfSameHeight(lastMintedHeight, currentHeight) || skipIfEmissionEnded(lastMintedHeight+1) { + // - if last minted height is same as last height to mint ( 12 years passed ) + if lastMintedHeight == currentHeight || lastMintedHeight == GetEndHeight() { return 0 } @@ -144,13 +140,15 @@ func checkErr(err error) { } } -// helper functions - // calculateAmountToMint calculates the amount of gns to mint // 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 { fromYear := GetHalvingYearByHeight(fromHeight) + + if toHeight > GetEndHeight() { + toHeight = GetEndHeight() + } toYear := GetHalvingYearByHeight(toHeight) totalAmountToMint := uint64(0) diff --git a/_deploy/r/gnoswap/gns/halving.gno b/_deploy/r/gnoswap/gns/halving.gno index a1b5e800..88a3c8df 100644 --- a/_deploy/r/gnoswap/gns/halving.gno +++ b/_deploy/r/gnoswap/gns/halving.gno @@ -54,8 +54,9 @@ var ( startHeight int64 startTimestamp int64 - endHeight int64 // (approximately) after 12 years, block height which gns emission will be ended - endTimestamp int64 // (exactly) after 12 years, timestamp which gns emission will be ended + // (exactly) after 12 years, timestamp which gns emission will be ended + // can not be changed + endTimestamp int64 ) var ( @@ -82,7 +83,7 @@ func init() { } setHalvingYearBlock(year, startHeight+BLOCK_PER_YEAR*(year-1)) - setHalvingYearTimestamp(year, startTimestamp+(consts.TIMESTAMP_YEAR*year-1)) + setHalvingYearTimestamp(year, startTimestamp+(consts.TIMESTAMP_YEAR*(year-1))) setHalvingYearMintAmount(year, uint64(0)) amountPerYear := GetHalvingYearMaxAmount(year) // amount per year @@ -91,7 +92,6 @@ func init() { setAmountPerBlockPerHalvingYear(year, uint64(amountPerBlock)) } - setEndHeight(startHeight + BLOCK_PER_YEAR*HALVING_END_YEAR) setEndTimestamp(startTimestamp + consts.TIMESTAMP_YEAR*HALVING_END_YEAR) } @@ -139,41 +139,40 @@ func SetAvgBlockTimeInMs(ms int64) { func setAvgBlockTimeInMs(ms int64) { common.IsHalted() - // set it - avgBlockTimeMs = ms - - // which year current time is in now := time.Now().Unix() height := std.GetHeight() - year, endTimestamp := getHalvingYearAndEndTimestamp(now) - // how much time left to next halving - timeLeft := endTimestamp - now + // get the halving year and end timestamp of current time + currentYear, endTimestamp := getHalvingYearAndEndTimestamp(now) - // how many block left to next halving + // how much time left for current halving year + timeLeft := endTimestamp - now timeLeftMs := timeLeft * consts.SECOND_IN_MILLISECOND - blockLeft := timeLeftMs / avgBlockTimeMs - // how many reward left to next halving - minted := GetMintedEmissionAmount() - amountLeft := GetHalvingYearAccuAmount(year) - minted - // how much reward per block - adjustedAmountPerBlock := amountLeft / uint64(blockLeft) + // how many block left for current halving year + blockLeft := timeLeftMs / ms - // update it - setAmountPerBlockPerHalvingYear(year, adjustedAmountPerBlock) + // how many reward left for current halving year + minted := GetMintedEmissionAmount() + amountLeft := GetHalvingYearAccuAmount(currentYear) - minted - for year := int64(1); year < HALVING_END_YEAR+1; year++ { - yearEndTimestamp := GetHalvingYearTimestamp(year) + // how much reward should be minted per block for current halving year + adjustedAmountPerBlock := amountLeft / uint64(blockLeft) + setAmountPerBlockPerHalvingYear(currentYear, adjustedAmountPerBlock) - if now >= yearEndTimestamp { + for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { + if year < currentYear { + // pass past halving years continue } - diff := yearEndTimestamp - now - numBlock := diff * consts.SECOND_IN_MILLISECOND / avgBlockTimeMs + yearEndTimestamp := GetHalvingYearTimestamp(year) + consts.TIMESTAMP_YEAR + timeLeftForYear := yearEndTimestamp - now + numBlock := (timeLeftForYear * consts.SECOND_IN_MILLISECOND) / ms setHalvingYearBlock(year, height+numBlock) } + + avgBlockTimeMs = ms } // GetAmountByHeight returns the amount of gns to mint by height @@ -266,11 +265,9 @@ func setAmountPerBlockPerHalvingYear(year int64, amount uint64) { } func GetEndHeight() int64 { - return endHeight -} - -func setEndHeight(height int64) { - endHeight = height + // last block of last halving year(12) is last block of emission + // later than this block, no more gns will be minted + return GetHalvingYearBlock(HALVING_END_YEAR) } func GetEndTimestamp() int64 { @@ -311,5 +308,5 @@ func GetHalvingInfo() string { } func isEmissionEnded(height int64) bool { - return height > endHeight + return height > GetEndHeight() } From bbed8629a6b984270d20bb6175498d2542207c16 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 19 Dec 2024 19:54:28 +0900 Subject: [PATCH 14/17] GSW-1845 refactor: assert too many emission amount --- _deploy/r/gnoswap/gns/errors.gno | 3 +- _deploy/r/gnoswap/gns/gns.gno | 39 +++++-- _deploy/r/gnoswap/gns/gns_test.gno | 10 +- _deploy/r/gnoswap/gns/halving_test.gno | 101 +++++++++--------- .../tests/gns_calculate_and_mint_test.gnoA | 37 ++++--- .../minted_and_left_emission_amount_test.gnoA | 25 +++-- _deploy/r/gnoswap/gns/tests/z1_filetest.gno | 42 +++++--- _deploy/r/gnoswap/gns/tests/z2_filetest.gno | 53 ++++----- _deploy/r/gnoswap/gns/tests/z3_filetest.gno | 54 +++------- _deploy/r/gnoswap/gns/tests/z4_filetest.gno | 93 ++++++++++++++++ 10 files changed, 292 insertions(+), 165 deletions(-) create mode 100644 _deploy/r/gnoswap/gns/tests/z4_filetest.gno diff --git a/_deploy/r/gnoswap/gns/errors.gno b/_deploy/r/gnoswap/gns/errors.gno index 55eb28cd..2f4480fd 100644 --- a/_deploy/r/gnoswap/gns/errors.gno +++ b/_deploy/r/gnoswap/gns/errors.gno @@ -7,7 +7,8 @@ import ( ) var ( - errNoPermission = errors.New("[GNOSWAP-GNS-001] caller has no permission") + errNoPermission = errors.New("[GNOSWAP-GNS-001] caller has no permission") + errTooManyEmission = errors.New("[GNOSWAP-GNS-002] too many emission reward") ) func addDetailToError(err error, detail string) string { diff --git a/_deploy/r/gnoswap/gns/gns.gno b/_deploy/r/gnoswap/gns/gns.gno index 43c5bf80..f647460a 100644 --- a/_deploy/r/gnoswap/gns/gns.gno +++ b/_deploy/r/gnoswap/gns/gns.gno @@ -31,6 +31,8 @@ var ( leftEmissionAmount uint64 mintedEmissionAmount uint64 lastMintedHeight int64 + + burnAmount uint64 ) func init() { @@ -56,15 +58,15 @@ func MintGns(address pusers.AddressOrName) uint64 { // skip minting process if following conditions are met // - if gns for current block is already minted - // - if last minted height is same as last height to mint ( 12 years passed ) - if lastMintedHeight == currentHeight || lastMintedHeight == GetEndHeight() { + // - if last minted height is same or later than emission end height + if lastMintedHeight == currentHeight || lastMintedHeight >= GetEndHeight() { return 0 } assertShouldNotBeHalted() assertCallerIsEmission() - // calculate gns amount to mint, and the mint to the target address + // calculate gns amount to mint amountToMint := calculateAmountToMint(lastMintedHeight+1, currentHeight) // update @@ -84,6 +86,8 @@ func Burn(from pusers.AddressOrName, amount uint64) { owner.AssertCallerIsOwner() fromAddr := users.Resolve(from) checkErr(privateLedger.Burn(fromAddr, amount)) + + burnAmount += amount } func TotalSupply() uint64 { @@ -153,37 +157,38 @@ func calculateAmountToMint(fromHeight, toHeight int64) uint64 { totalAmountToMint := uint64(0) - for i := fromYear; i <= toYear; i++ { - yearEndHeight := GetHalvingYearBlock(i) + for year := fromYear; year <= toYear; year++ { + yearEndHeight := GetHalvingYearEndBlock(year) mintUntilHeight := i64Min(yearEndHeight, toHeight) // how many blocks to calculate blocks := uint64(mintUntilHeight-fromHeight) + 1 // amount of gns to mint for each block for current year - singleBlockAmount := GetAmountPerBlockPerHalvingYear(i) + singleBlockAmount := GetAmountPerBlockPerHalvingYear(year) // amount of gns to mint for current year yearAmountToMint := singleBlockAmount * blocks // if last block of halving year, handle left emission amount if isLastBlockOfHalvingYear(mintUntilHeight) { - yearAmountToMint += handleLeftEmissionAmount(i, yearAmountToMint) + yearAmountToMint += handleLeftEmissionAmount(year, yearAmountToMint) } totalAmountToMint += yearAmountToMint - setHalvingYearMintAmount(i, GetHalvingYearMintAmount(i)+yearAmountToMint) + setHalvingYearMintAmount(year, GetHalvingYearMintAmount(year)+yearAmountToMint) // update fromHeight for next year (if necessary) fromHeight = mintUntilHeight + 1 } + assertTooManyEmission(totalAmountToMint) return totalAmountToMint } // isLastBlockOfHalvingYear returns true if the current block is the last block of a halving year. func isLastBlockOfHalvingYear(height int64) bool { year := GetHalvingYearByHeight(height) - lastBlock := GetHalvingYearBlock(year) + lastBlock := GetHalvingYearEndBlock(year) return height == lastBlock } @@ -219,6 +224,11 @@ func GetLeftEmissionAmount() uint64 { return leftEmissionAmount } +// GetBurnAmount returns the amount of GNS that has been burned. +func GetBurnAmount() uint64 { + return burnAmount +} + // GetMintedEmissionAmount returns the amount of GNS that has been minted by the emission contract. // It does not include initial minted amount. func GetMintedEmissionAmount() uint64 { @@ -236,3 +246,14 @@ func setLeftEmissionAmount(amount uint64) { func setMintedEmissionAmount(amount uint64) { mintedEmissionAmount = amount } + +// assertTooManyEmission asserts if the amount of gns to mint is too many. +// It checks if the amount of gns to mint is greater than the left emission amount or the total emission amount. +func assertTooManyEmission(amount uint64) { + if amount > GetLeftEmissionAmount() || (amount+GetMintedEmissionAmount()) > MAX_EMISSION_AMOUNT { + panic(addDetailToError( + errTooManyEmission, + ufmt.Sprintf("amount: %d", amount), + )) + } +} diff --git a/_deploy/r/gnoswap/gns/gns_test.gno b/_deploy/r/gnoswap/gns/gns_test.gno index 870d507e..758d94b0 100644 --- a/_deploy/r/gnoswap/gns/gns_test.gno +++ b/_deploy/r/gnoswap/gns/gns_test.gno @@ -34,14 +34,14 @@ func TestIsLastBlockOfHalvingYear(t *testing.T) { want bool }, 0, 24) - for i := int64(1); i <= 12; i++ { + for i := HALVING_START_YEAR; i <= HALVING_END_YEAR; i++ { tests = append(tests, struct { name string height int64 want bool }{ name: fmt.Sprintf("last block of halving year %d", i), - height: GetHalvingYearBlock(i), + height: GetHalvingYearEndBlock(i), want: true, }) @@ -51,7 +51,7 @@ func TestIsLastBlockOfHalvingYear(t *testing.T) { want bool }{ name: fmt.Sprintf("not last block of halving year %d", i), - height: GetHalvingYearBlock(i) - 1, + height: GetHalvingYearEndBlock(i) - 1, want: false, }) } @@ -120,13 +120,13 @@ func TestSkipIfEmissionEnded(t *testing.T) { func TestGetterSetter(t *testing.T) { t.Run("last minted height", func(t *testing.T) { - value := int64(1234) + value := int64(123) setLastMintedHeight(value) uassert.Equal(t, value, GetLastMintedHeight()) }) t.Run("left emission amount", func(t *testing.T) { - value := uint64(123456) + value := uint64(0) setLeftEmissionAmount(value) uassert.Equal(t, value, GetLeftEmissionAmount()) }) diff --git a/_deploy/r/gnoswap/gns/halving_test.gno b/_deploy/r/gnoswap/gns/halving_test.gno index 233a941b..2450d01f 100644 --- a/_deploy/r/gnoswap/gns/halving_test.gno +++ b/_deploy/r/gnoswap/gns/halving_test.gno @@ -16,22 +16,22 @@ var ( ) var FIRST_BLOCK_OF_YEAR = []int64{ - startHeight, - startHeight + BLOCK_PER_YEAR*1, - startHeight + BLOCK_PER_YEAR*2, - startHeight + BLOCK_PER_YEAR*3, - startHeight + BLOCK_PER_YEAR*4, - startHeight + BLOCK_PER_YEAR*5, - startHeight + BLOCK_PER_YEAR*6, - startHeight + BLOCK_PER_YEAR*7, - startHeight + BLOCK_PER_YEAR*8, - startHeight + BLOCK_PER_YEAR*9, - startHeight + BLOCK_PER_YEAR*10, - startHeight + BLOCK_PER_YEAR*11, + startHeight + (BLOCK_PER_YEAR * 0) + 1, + startHeight + (BLOCK_PER_YEAR * 1) + 2, + startHeight + (BLOCK_PER_YEAR * 2) + 3, + startHeight + (BLOCK_PER_YEAR * 3) + 4, + startHeight + (BLOCK_PER_YEAR * 4) + 5, + startHeight + (BLOCK_PER_YEAR * 5) + 6, + startHeight + (BLOCK_PER_YEAR * 6) + 7, + startHeight + (BLOCK_PER_YEAR * 7) + 8, + startHeight + (BLOCK_PER_YEAR * 8) + 9, + startHeight + (BLOCK_PER_YEAR * 9) + 10, + startHeight + (BLOCK_PER_YEAR * 10) + 11, + startHeight + (BLOCK_PER_YEAR * 11) + 12, } var FIRST_TIMESTAMP_OF_YEAR = []int64{ - startTimestamp, + startTimestamp + consts.TIMESTAMP_YEAR*0, startTimestamp + consts.TIMESTAMP_YEAR*1, startTimestamp + consts.TIMESTAMP_YEAR*2, startTimestamp + consts.TIMESTAMP_YEAR*3, @@ -60,45 +60,6 @@ var END_TIMESTAMP_OF_YEAR = []int64{ startTimestamp + consts.TIMESTAMP_YEAR*12, } -func TestSetAvgBlockTimeInMsByAdmin(t *testing.T) { - t.Run("panic if caller is not admin", func(t *testing.T) { - uassert.PanicsWithMessage(t, - "caller(g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) has no permission", - func() { - SetAvgBlockTimeInMsByAdmin(1) - }, - ) - }) - - t.Run("success if caller is admin", func(t *testing.T) { - std.TestSkipHeights(1) - std.TestSetRealm(adminRealm) - SetAvgBlockTimeInMsByAdmin(2) - uassert.Equal(t, GetAvgBlockTimeInMs(), int64(2)) - }) -} - -func TestSetAvgBlockTimeInMs(t *testing.T) { - t.Run("panic if caller is not governance contract", func(t *testing.T) { - uassert.PanicsWithMessage(t, - "caller(g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) has no permission", - func() { - SetAvgBlockTimeInMs(3) - }, - ) - }) - - t.Run("success if caller is governance contract", func(t *testing.T) { - std.TestSkipHeights(3) - std.TestSetRealm(govRealm) - SetAvgBlockTimeInMs(4) - uassert.Equal(t, GetAvgBlockTimeInMs(), int64(4)) - }) - - // reset to default for further test - setAvgBlockTimeInMs(consts.SECOND_IN_MILLISECOND * consts.BLOCK_GENERATION_INTERVAL) -} - func TestGetAmountByHeight(t *testing.T) { for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { firstBlockOfYear := FIRST_BLOCK_OF_YEAR[year-1] @@ -173,3 +134,39 @@ func TestGetHalvingInfo(t *testing.T) { halving := jsonStr.MustKey("halvings").MustArray() uassert.Equal(t, len(halving), 12) } + +func TestSetAvgBlockTimeInMsByAdmin(t *testing.T) { + t.Run("panic if caller is not admin", func(t *testing.T) { + uassert.PanicsWithMessage(t, + "caller(g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) has no permission", + func() { + SetAvgBlockTimeInMsByAdmin(1) + }, + ) + }) + + t.Run("success if caller is admin", func(t *testing.T) { + std.TestSkipHeights(1) + std.TestSetRealm(adminRealm) + SetAvgBlockTimeInMsByAdmin(2) + uassert.Equal(t, GetAvgBlockTimeInMs(), int64(2)) + }) +} + +func TestSetAvgBlockTimeInMs(t *testing.T) { + t.Run("panic if caller is not governance contract", func(t *testing.T) { + uassert.PanicsWithMessage(t, + "caller(g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm) has no permission", + func() { + SetAvgBlockTimeInMs(3) + }, + ) + }) + + t.Run("success if caller is governance contract", func(t *testing.T) { + std.TestSkipHeights(3) + std.TestSetRealm(govRealm) + SetAvgBlockTimeInMs(4) + uassert.Equal(t, GetAvgBlockTimeInMs(), int64(4)) + }) +} diff --git a/_deploy/r/gnoswap/gns/tests/gns_calculate_and_mint_test.gnoA b/_deploy/r/gnoswap/gns/tests/gns_calculate_and_mint_test.gnoA index a5cfd993..f6a91202 100644 --- a/_deploy/r/gnoswap/gns/tests/gns_calculate_and_mint_test.gnoA +++ b/_deploy/r/gnoswap/gns/tests/gns_calculate_and_mint_test.gnoA @@ -18,44 +18,45 @@ var ( func TestCalculateAmountToMint(t *testing.T) { t.Run("1 block for same year 01", func(t *testing.T) { amount := calculateAmountToMint(GetLastMintedHeight()+1, GetLastMintedHeight()+1) - uassert.Equal(t, amountPerBlockPerHalvingYear[1], amount) + uassert.Equal(t, amountPerBlockPerHalvingYear[0], amount) }) t.Run("2 block for same year 01", func(t *testing.T) { - amount := calculateAmountToMint(GetLastMintedHeight()+1, GetLastMintedHeight()+2) - uassert.Equal(t, amountPerBlockPerHalvingYear[2]*2, amount) + amount := calculateAmountToMint(GetLastMintedHeight()+2, GetLastMintedHeight()+3) + uassert.Equal(t, amountPerBlockPerHalvingYear[1]*2, amount) }) t.Run("entire block for year 01 + 1 block for year 02", func(t *testing.T) { - calculateAmountToMint(halvingYearBlock[1], halvingYearBlock[1]+1) + minted := calculateAmountToMint(GetLastMintedHeight()+4, GetHalvingYearBlock(2)) // minted all amount for year 01 - uassert.Equal(t, GetHalvingYearAmount(1), GetHalvingYearMintAmount(1)) + uassert.Equal(t, GetHalvingYearMaxAmount(1), GetHalvingYearMintAmount(1)) // minted 1 block for year 02 - uassert.Equal(t, amountPerBlockPerHalvingYear[2], GetHalvingYearMintAmount(2)) + uassert.Equal(t, amountPerBlockPerHalvingYear[1], GetHalvingYearMintAmount(2)) }) t.Run("entire block for 12 years", func(t *testing.T) { - calculateAmountToMint(halvingYearBlock[1], halvingYearBlock[12]) + calculateAmountToMint(GetHalvingYearBlock(1), GetHalvingYearBlock(12)) for year := int64(1); year <= 12; year++ { - uassert.Equal(t, GetHalvingYearAmount(year), GetHalvingYearMintAmount(year)) + uassert.Equal(t, GetHalvingYearMaxAmount(year), GetHalvingYearMintAmount(year)) } }) t.Run("no emission amount for after 12 years", func(t *testing.T) { - amount := calculateAmountToMint(halvingYearBlock[12], halvingYearBlock[12]+1) + amount := calculateAmountToMint(GetHalvingYearBlock(12), GetHalvingYearBlock(12)+1) uassert.Equal(t, uint64(0), amount) }) // clear for further test - halvingYearMintAmount = make(map[int64]uint64) + halvingYearMintAmount = []uint64{} } func TestMintGns(t *testing.T) { t.Run("panic for swap is halted", func(t *testing.T) { std.TestSetRealm(adminRealm) + std.TestSkipHeights(123) // pass some block to bypass last block check common.SetHaltByAdmin(true) // set halt uassert.PanicsWithMessage(t, "[GNOSWAP-COMMON-002] halted || gnoswap halted", func() { MintGns(a2u(consts.ADMIN)) @@ -72,20 +73,21 @@ func TestMintGns(t *testing.T) { t.Run("do not mint for same block", func(t *testing.T) { std.TestSetRealm(emissionRealm) + std.TestSkipHeights(-123) // revert height to get caught by last block check mintedAmount := MintGns(a2u(consts.ADMIN)) uassert.Equal(t, uint64(0), mintedAmount) }) t.Run("mint by year, until emission ends", func(t *testing.T) { for year := int64(1); year <= 12; year++ { - std.TestSkipHeights(BLOCK_PER_YEAR) + skipUntilLastHeightOfHalvingYear(t, year) std.TestSetRealm(emissionRealm) mintedAmount := MintGns(a2u(consts.ADMIN)) - uassert.Equal(t, halvingYearAmount[year], mintedAmount) - uassert.Equal(t, halvingYearAmount[year], halvingYearMintAmount[year]) - uassert.Equal(t, halvingYearAccuAmount[year], MintedEmissionAmount()) + uassert.Equal(t, GetHalvingYearMaxAmount(year), mintedAmount) + uassert.Equal(t, GetHalvingYearMaxAmount(year), GetHalvingYearMintAmount(year)) + uassert.Equal(t, GetHalvingYearAccuAmount(year), GetMintedEmissionAmount()) } }) @@ -97,3 +99,10 @@ func TestMintGns(t *testing.T) { uassert.Equal(t, uint64(0), mintedAmount) }) } + +func skipUntilLastHeightOfHalvingYear(t *testing.T, year int64) { + t.Helper() + + lastHeight := GetHalvingYearEndBlock(year) + std.TestSkipHeights(lastHeight - std.GetHeight()) +} diff --git a/_deploy/r/gnoswap/gns/tests/minted_and_left_emission_amount_test.gnoA b/_deploy/r/gnoswap/gns/tests/minted_and_left_emission_amount_test.gnoA index aee171e6..9a47d218 100644 --- a/_deploy/r/gnoswap/gns/tests/minted_and_left_emission_amount_test.gnoA +++ b/_deploy/r/gnoswap/gns/tests/minted_and_left_emission_amount_test.gnoA @@ -20,7 +20,7 @@ func TestCheckInitialData(t *testing.T) { }) t.Run("mintedAmount", func(t *testing.T) { - uassert.Equal(t, uint64(0), MintedEmissionAmount()) + uassert.Equal(t, uint64(0), GetMintedEmissionAmount()) }) t.Run("leftEmissionAmount", func(t *testing.T) { @@ -31,7 +31,7 @@ func TestCheckInitialData(t *testing.T) { func TestMintAndCheckRelativeData(t *testing.T) { // before mint oldTotalSupply := TotalSupply() - oldMintedAmount := MintedEmissionAmount() + oldMintedAmount := GetMintedEmissionAmount() oldLeftEmissionAmount := GetLeftEmissionAmount() // mint @@ -49,7 +49,7 @@ func TestMintAndCheckRelativeData(t *testing.T) { }) t.Run("increment of mintedAmount", func(t *testing.T) { - uassert.Equal(t, oldMintedAmount+mintAmountFor10Blocks, MintedEmissionAmount()) + uassert.Equal(t, oldMintedAmount+mintAmountFor10Blocks, GetMintedEmissionAmount()) }) t.Run("decrement of leftEmissionAmount", func(t *testing.T) { @@ -60,8 +60,9 @@ func TestMintAndCheckRelativeData(t *testing.T) { func TestBurnAndCheckRelativeData(t *testing.T) { // before burn oldTotalSupply := TotalSupply() - oldMintedAmount := MintedEmissionAmount() + oldMintedAmount := GetMintedEmissionAmount() oldLeftEmissionAmount := GetLeftEmissionAmount() + oldBurnAmount := GetBurnAmount() // burn burnAmount := uint64(100000000) @@ -75,15 +76,23 @@ func TestBurnAndCheckRelativeData(t *testing.T) { uassert.Equal(t, oldTotalSupply-burnAmount, TotalSupply()) }) - t.Run("decrement of mintedAmount", func(t *testing.T) { - uassert.Equal(t, oldMintedAmount-burnAmount, MintedEmissionAmount()) + t.Run("same for mintedAmount", func(t *testing.T) { + // it is already `minted` amount, therefore it is not affected by burn + uassert.Equal(t, oldMintedAmount, GetMintedEmissionAmount()) }) - t.Run("totalSupply should be same with (INITIAL_MINT_AMOUNT) + (mintedEmissionAmount)", func(t *testing.T) { - uassert.Equal(t, TotalSupply(), INITIAL_MINT_AMOUNT+MintedEmissionAmount()) + t.Run("totalSupply should be same or less than inital mint + acutal mint amount", func(t *testing.T) { + // burn does affect totalSupply + uassert.True(t, TotalSupply() <= INITIAL_MINT_AMOUNT+GetMintedEmissionAmount()) }) t.Run("same for leftEmissionAmount", func(t *testing.T) { + // leftEmissionAmount gets affected by only mint uassert.Equal(t, oldLeftEmissionAmount, GetLeftEmissionAmount()) }) + + t.Run("increment of burnAmount", func(t *testing.T) { + // `burn` only increments burnAmount + uassert.Equal(t, oldBurnAmount+burnAmount, GetBurnAmount()) + }) } diff --git a/_deploy/r/gnoswap/gns/tests/z1_filetest.gno b/_deploy/r/gnoswap/gns/tests/z1_filetest.gno index 674fd31b..c88626cf 100644 --- a/_deploy/r/gnoswap/gns/tests/z1_filetest.gno +++ b/_deploy/r/gnoswap/gns/tests/z1_filetest.gno @@ -35,33 +35,47 @@ func skip50Blocks() { uassert.Equal(t, std.GetHeight(), int64(173)) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.MintGns(a2u(user01Addr)) // 14269406 * 50 = 713470300 - uassert.Equal(t, uint64(713470300), gns.MintedEmissionAmount()) + mintedAmount := gns.MintGns(a2u(user01Addr)) // 14269406 * 50 = 713470300) + uassert.Equal(t, uint64(713470300), gns.GetMintedEmissionAmount()) } func blockTime2500ms() { std.TestSetRealm(std.NewUserRealm(consts.ADMIN)) gns.SetAvgBlockTimeInMsByAdmin(2500) - std.TestSkipHeights(1) + // for block time 2.5s, amount per block is 17836759 + + // first halving year end block = 15768122 + // first halving year end timestamp = 1234567990 + + // 50 block minted from L#38 + // > current height = 173 + // > current timestamp = 1234568140 + + // 1266103890 - 1234567990 = 31535900 // timestamp left for current halving year + // 31535900000 / 2500(new block avg time/ms) = 12614360 // number of block left for current halving year - // for block time 2.5s - // amount per block is 17836757 + // 713470300 // already minted amount + + // first halving year should mint 225000000000000 + // 225000000000000 - 713470300 = 224999286529700 + // 224999286529700 / 12614360 = 17836759 std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.MintGns(a2u(user01Addr)) // 17836757 - uassert.Equal(t, uint64(713470300+17836757), gns.MintedEmissionAmount()) // 731307057 + std.TestSkipHeights(1) + mintedAmount := gns.MintGns(a2u(user01Addr)) // 17836757 + uassert.Equal(t, uint64(713470300+17836757), gns.GetMintedEmissionAmount()) // 731307057 } func reachAlmostFirstHalving() { - // current height = 174 - // next halving = 12614533 - // 12614533 - 174 = 12614359 - std.TestSkipHeights(12614358) + firstEnds := gns.GetHalvingYearEndBlock(1) + blockLeftUntilEnd := firstEnds - std.GetHeight() + + std.TestSkipHeights(blockLeftUntilEnd - 1) // 1 block left until first halving year ends std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) gns.MintGns(a2u(user01Addr)) - uassert.Equal(t, uint64(224999969664063), gns.MintedEmissionAmount()) + uassert.Equal(t, uint64(224999969664063), gns.GetMintedEmissionAmount()) // 224999969664063 - 731307057 = 224999238357006 // 224999238357006 / 12614358 = 17836757 } @@ -72,7 +86,7 @@ func reachExactFirstHalving() { gns.MintGns(a2u(user01Addr)) // minted all amount for first halving year - uassert.Equal(t, uint64(225000000000000), gns.MintedEmissionAmount()) + uassert.Equal(t, uint64(225000000000000), gns.GetMintedEmissionAmount()) year := gns.GetHalvingYearByHeight(std.GetHeight()) uassert.Equal(t, int64(1), year) @@ -89,7 +103,7 @@ func startSecondHalving() { std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) gns.MintGns(a2u(user01Addr)) - uassert.Equal(t, uint64(225000000000000+14269406), gns.MintedEmissionAmount()) + uassert.Equal(t, uint64(225000000000000+14269406), gns.GetMintedEmissionAmount()) } func a2u(addr std.Address) pusers.AddressOrName { diff --git a/_deploy/r/gnoswap/gns/tests/z2_filetest.gno b/_deploy/r/gnoswap/gns/tests/z2_filetest.gno index 31b612bc..6b51fba2 100644 --- a/_deploy/r/gnoswap/gns/tests/z2_filetest.gno +++ b/_deploy/r/gnoswap/gns/tests/z2_filetest.gno @@ -36,37 +36,40 @@ func skip50Blocks() { std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) gns.MintGns(a2u(user01Addr)) // 14269406 * 50 = 713470300 - uassert.Equal(t, uint64(713470300), gns.MintedEmissionAmount()) + uassert.Equal(t, uint64(713470300), gns.GetMintedEmissionAmount()) } func blockTime4000ms() { std.TestSetRealm(std.NewUserRealm(consts.ADMIN)) gns.SetAvgBlockTimeInMsByAdmin(4000) - std.TestSkipHeights(1) - - // for block time 4s - // amount per block is 28538812 + // for block time 4s, amount per block is 28538812 std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.MintGns(a2u(user01Addr)) // 28538812 - uassert.Equal(t, uint64(713470300+28538812), gns.MintedEmissionAmount()) // 742009112 + std.TestSkipHeights(1) + mintedAmount := gns.MintGns(a2u(user01Addr)) // 28538812 + uassert.Equal(t, uint64(713470300+28538812), gns.GetMintedEmissionAmount()) // 742009112 firstYearAmountPerBlock := gns.GetAmountPerBlockPerHalvingYear(1) uassert.Equal(t, uint64(28538812), firstYearAmountPerBlock) - uassert.Equal(t, int64(7884148), gns.GetHalvingYearBlock(1)) - // FORMULA - // orig_start = 123 - // orig_1year = 15768123 ( 123 + 1 year block(15768000) ) - // 50 block mined from L#37 - // current = 173 - // 15768123 - 173 = 15767950 // number of block left to next halving + // next halving year start/end block + uassert.Equal(t, int64(7884149), gns.GetHalvingYearBlock(2)) + uassert.Equal(t, int64(15768149), gns.GetHalvingYearEndBlock(2)) + + // orig year01 start block = 123 + // 50 block mined from L#38 + // current block = 173 + // current timestamp = 1234567990 + // orig year01 end timestamp = 1266103890 + + // 1266103890 - 1234567990 = 31535900 // timestamp left for current halving year + // 31535900000(ms) / 4000(ms) = 7883975 // number of block left for current halving year - // 15767950 * 2 = 31535900 // number of timestamp left to next halving - // > before change, block time was 2s (2000ms) + // 173 + 7883975 = 7884148 // end block of current halving year + // 7884148 + 1 = 7884149 // start block of next halving year - // 31535900 / 4 = 7883975 // based on 4s block, number of block left to next halving - // current(173) + above left(7883975) = 7884148 + // 7884000 // based on 4s block, how many block in a year + // 7884149 + 7884000 = 15768149 // end block of next halving year } func reachFirstHalving() { @@ -79,7 +82,7 @@ func reachFirstHalving() { gns.MintGns(a2u(user01Addr)) // minted all amount for first halving year - uassert.Equal(t, uint64(225000000000000), gns.MintedEmissionAmount()) + uassert.Equal(t, uint64(225000000000000), gns.GetMintedEmissionAmount()) year := gns.GetHalvingYearByHeight(std.GetHeight()) uassert.Equal(t, int64(1), year) @@ -96,20 +99,20 @@ func startSecondHalving() { std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) gns.MintGns(a2u(user01Addr)) - uassert.Equal(t, uint64(225000000000000+14269406), gns.MintedEmissionAmount()) + uassert.Equal(t, uint64(225000000000000+14269406), gns.GetMintedEmissionAmount()) } func reachSecondHalving() { - // current := 7884149 - // nextHalving := 15768148 - // 15768148 - 7884149 = 7883999 + blockLeftUntilEndOfYear02 := gns.GetHalvingYearEndBlock(2) - std.GetHeight() - std.TestSkipHeights(7883999) + std.TestSkipHeights(int64(blockLeftUntilEndOfYear02)) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) gns.MintGns(a2u(user01Addr)) // minted all amount until second halving - uassert.Equal(t, uint64(225000000000000*2), gns.MintedEmissionAmount()) + year01Max := gns.GetHalvingYearMaxAmount(1) + year02Max := gns.GetHalvingYearMaxAmount(2) + uassert.Equal(t, year01Max+year02Max, gns.GetMintedEmissionAmount()) } func a2u(addr std.Address) pusers.AddressOrName { diff --git a/_deploy/r/gnoswap/gns/tests/z3_filetest.gno b/_deploy/r/gnoswap/gns/tests/z3_filetest.gno index cba84223..2337485c 100644 --- a/_deploy/r/gnoswap/gns/tests/z3_filetest.gno +++ b/_deploy/r/gnoswap/gns/tests/z3_filetest.gno @@ -37,52 +37,34 @@ func skip50Blocks() { std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) gns.MintGns(a2u(user01Addr)) // 14269406 * 50 = 713470300 - uassert.Equal(t, uint64(713470300), gns.MintedEmissionAmount()) + uassert.Equal(t, uint64(713470300), gns.GetMintedEmissionAmount()) } func blockTime4000ms() { std.TestSetRealm(std.NewUserRealm(consts.ADMIN)) gns.SetAvgBlockTimeInMsByAdmin(4000) - std.TestSkipHeights(1) - - // for block time 4s - // amount per block is 28538812 + // for block time 4s, amount per block is 28538812 + std.TestSkipHeights(1) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.MintGns(a2u(user01Addr)) // 28538812 - uassert.Equal(t, uint64(713470300+28538812), gns.MintedEmissionAmount()) // 742009112 - - firstYearAmountPerBlock := gns.GetAmountPerBlockPerHalvingYear(1) - uassert.Equal(t, uint64(28538812), firstYearAmountPerBlock) - uassert.Equal(t, int64(7884148), gns.GetHalvingYearBlock(1)) - // FORMULA - // orig_start = 123 - // orig_1year = 15768123 ( 123 + 1 year block(15768000) ) + gns.MintGns(a2u(user01Addr)) // 28538812 + uassert.Equal(t, uint64(713470300+28538812), gns.GetMintedEmissionAmount()) // 742009112 - // 50 block mined from L#37 - // current = 173 - // 15768123 - 173 = 15767950 // number of block left to next halving - - // 15767950 * 2 = 31535900 // number of timestamp left to next halving - // > before change, block time was 2s (2000ms) - - // 31535900 / 4 = 7883975 // based on 4s block, number of block left to next halving - // current(173) + above left(7883975) = 7884148 + // next halving year start/end block + uassert.Equal(t, int64(7884149), gns.GetHalvingYearBlock(2)) + uassert.Equal(t, int64(15768149), gns.GetHalvingYearEndBlock(2)) } func reachAboutHalfOfFirstHalving() { - // current := 174 - // nextHalving := 7884148 - // 7884148 - 174 = 7883974 - // 7883974 / 2 = 3941987 + // current block = 174 + // next halving year start block = 7884148 + // 7884148 - 174 = 7883974 // block left to next halving - std.TestSkipHeights(3941987) + std.TestSkipHeights(3941987) // 7883974 / 2 std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) gns.MintGns(a2u(user01Addr)) - // minted about 50% amount for first halving year - uassert.Equal(t, uint64(112500367908556), gns.MintedEmissionAmount()) - + // stil in first halving year year := gns.GetHalvingYearByHeight(std.GetHeight()) uassert.Equal(t, int64(1), year) } @@ -94,16 +76,14 @@ func blockTime3000ms() { } func reachFirstHalving() { - // current := 3942162 - // nextHalving := 11826135 - // 11826135 - 3942162 = 7883973 + blockLeftUntilEndOfYear01 := gns.GetHalvingYearEndBlock(1) - std.GetHeight() + std.TestSkipHeights(blockLeftUntilEndOfYear01) - std.TestSkipHeights(7883973) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) gns.MintGns(a2u(user01Addr)) // minted all amount for first halving year - uassert.Equal(t, uint64(225000000000000), gns.MintedEmissionAmount()) + uassert.Equal(t, gns.GetHalvingYearMaxAmount(1), gns.GetMintedEmissionAmount()) // we're at the end of first halving year year := gns.GetHalvingYearByHeight(std.GetHeight()) @@ -121,7 +101,7 @@ func startSecondHalving() { std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) gns.MintGns(a2u(user01Addr)) - uassert.Equal(t, uint64(225000000000000+14269406), gns.MintedEmissionAmount()) + uassert.Equal(t, uint64(225000000000000+14269406), gns.GetMintedEmissionAmount()) } func a2u(addr std.Address) pusers.AddressOrName { diff --git a/_deploy/r/gnoswap/gns/tests/z4_filetest.gno b/_deploy/r/gnoswap/gns/tests/z4_filetest.gno new file mode 100644 index 00000000..f4ea61ad --- /dev/null +++ b/_deploy/r/gnoswap/gns/tests/z4_filetest.gno @@ -0,0 +1,93 @@ +// reach all having years and minted all amount +// and then no gns will be minted + +// PKGPATH: gno.land/r/gnoswap/v1/gns_test +package gns_test + +import ( + "std" + "testing" + + "gno.land/p/demo/testutils" + "gno.land/p/demo/uassert" + "gno.land/p/demo/ufmt" + pusers "gno.land/p/demo/users" + + "gno.land/r/gnoswap/v1/consts" + "gno.land/r/gnoswap/v1/gns" +) + +var t *testing.T + +var ( + user01Addr = testutils.TestAddress("user01Addr") + user01Realm = std.NewUserRealm(user01Addr) +) + +func main() { + reachAlmostEndOfEmission() + skip50Blocks() + moreBlocksAfterEmissionEnds() +} + +func reachAlmostEndOfEmission() { + endHeight := gns.GetEndHeight() + untilEnds := endHeight - std.GetHeight() + std.TestSkipHeights(untilEnds - 10) // 10 blocks before end of emission + + std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) + minted := gns.MintGns(a2u(user01Addr)) + + // minted all amount for year 01 ~ 11 + for year := int64(1); year <= 11; year++ { + uassert.Equal( + t, + gns.GetHalvingYearMaxAmount(year), + gns.GetHalvingYearMintAmount(year), + ufmt.Sprintf("shoud been minted max amount for year %d", year), + ) + } + + // we're at the end of last halving year + year := gns.GetHalvingYearByHeight(std.GetHeight()) + uassert.Equal(t, int64(12), year) +} + +func skip50Blocks() { + // 10 block left until emission ends + // skipping 50 blocks will reach the end of emission + // and it should mint for only 10 blocks + + std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) + std.TestSkipHeights(50) + gns.MintGns(a2u(user01Addr)) + + // total supply + totalSupply := gns.TotalSupply() + uassert.Equal(t, gns.MAXIMUM_SUPPLY, totalSupply) + + // minted amount + mintedAmount := gns.GetMintedEmissionAmount() + uassert.Equal(t, gns.MAX_EMISSION_AMOUNT, mintedAmount) +} + +func moreBlocksAfterEmissionEnds() { + std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) + std.TestSkipHeights(10) + + // no gns will be minted after emission ends + minted := gns.MintGns(a2u(user01Addr)) + uassert.Equal(t, uint64(0), minted) + + // total supply + totalSupply := gns.TotalSupply() + uassert.Equal(t, gns.MAXIMUM_SUPPLY, totalSupply) + + // minted amount + mintedAmount := gns.GetMintedEmissionAmount() + uassert.Equal(t, gns.MAX_EMISSION_AMOUNT, mintedAmount) +} + +func a2u(addr std.Address) pusers.AddressOrName { + return pusers.AddressOrName(addr) +} From 4681cd8e33b8bd7981aa1da6a66d90a21e68ec88 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Fri, 20 Dec 2024 16:39:49 +0900 Subject: [PATCH 15/17] GSW-1845 refactor: calculate height for next halving when avg time changes --- _deploy/r/gnoswap/gns/_helper_test.gno | 23 +--- _deploy/r/gnoswap/gns/halving.gno | 122 ++++++++++++------ _deploy/r/gnoswap/gns/halving_test.gno | 30 ++--- .../tests/gns_calculate_and_mint_test.gnoA | 12 +- _deploy/r/gnoswap/gns/tests/z2_filetest.gno | 2 +- _deploy/r/gnoswap/gns/tests/z3_filetest.gno | 2 +- 6 files changed, 113 insertions(+), 78 deletions(-) diff --git a/_deploy/r/gnoswap/gns/_helper_test.gno b/_deploy/r/gnoswap/gns/_helper_test.gno index 8c3d0006..39e6c014 100644 --- a/_deploy/r/gnoswap/gns/_helper_test.gno +++ b/_deploy/r/gnoswap/gns/_helper_test.gno @@ -35,22 +35,9 @@ func resetGnsTokenObject(t *testing.T) { func resetHalvingRelatedObject(t *testing.T) { t.Helper() - for year := int64(1); year < 13; year++ { - setHalvingYearMaxAmount(year, HALVING_AMOUNTS_PER_YEAR[year-1]) - - if year == 1 { - setHalvingYearAccuAmount(year, HALVING_AMOUNTS_PER_YEAR[year-1]) - } else { - setHalvingYearAccuAmount(year, GetHalvingYearAccuAmount(year-1)+HALVING_AMOUNTS_PER_YEAR[year-1]) - } - - setHalvingYearBlock(year, startHeight+BLOCK_PER_YEAR*year) - setHalvingYearTimestamp(year, startTimestamp+(consts.TIMESTAMP_YEAR*year)) - setHalvingYearMintAmount(year, uint64(0)) - - amountPerYear := GetHalvingYearMaxAmount(year) // amount per year - amountPerDay := amountPerYear / consts.DAY_PER_YEAR // amount per day - amountPerBlock := amountPerDay / uint64(BLOCK_PER_DAY) // amount per block - setAmountPerBlockPerHalvingYear(year, uint64(amountPerBlock)) - } + startHeight = std.GetHeight() + startTimestamp = time.Now().Unix() + + initializeHalvingData() + setEndTimestamp(startTimestamp + consts.TIMESTAMP_YEAR*HALVING_END_YEAR) } diff --git a/_deploy/r/gnoswap/gns/halving.gno b/_deploy/r/gnoswap/gns/halving.gno index 88a3c8df..7a55d03b 100644 --- a/_deploy/r/gnoswap/gns/halving.gno +++ b/_deploy/r/gnoswap/gns/halving.gno @@ -44,8 +44,8 @@ const ( ) var ( - BLOCK_PER_YEAR = consts.TIMESTAMP_YEAR / consts.BLOCK_GENERATION_INTERVAL - BLOCK_PER_DAY = consts.TIMESTAMP_DAY / consts.BLOCK_GENERATION_INTERVAL + blockPerYear = consts.TIMESTAMP_YEAR / consts.BLOCK_GENERATION_INTERVAL + blockPerDay = consts.TIMESTAMP_DAY / consts.BLOCK_GENERATION_INTERVAL avgBlockTimeMs int64 = consts.SECOND_IN_MILLISECOND * consts.BLOCK_GENERATION_INTERVAL ) @@ -53,46 +53,65 @@ var ( var ( startHeight int64 startTimestamp int64 - - // (exactly) after 12 years, timestamp which gns emission will be ended - // can not be changed - endTimestamp int64 + endTimestamp int64 ) var ( - halvingYearBlock = make([]int64, HALVING_END_YEAR) // start block of each halving year - halvingYearTimestamp = make([]int64, HALVING_END_YEAR) // start timestamp of each halving year - - halvingYearMaxAmount = make([]uint64, HALVING_END_YEAR) - halvingYearMintAmount = make([]uint64, HALVING_END_YEAR) - halvingYearAccuAmount = make([]uint64, HALVING_END_YEAR) - amountPerBlockPerHalvingYear = make([]uint64, HALVING_END_YEAR) + halvingYearStartBlock = make([]int64, HALVING_END_YEAR) // start block of each halving year + halvingYearEndBlock = make([]int64, HALVING_END_YEAR) // end block of each halving year + halvingYearTimestamp = make([]int64, HALVING_END_YEAR) // start timestamp of each halving year + + halvingYearMaxAmount = make([]uint64, HALVING_END_YEAR) // max amount per year can be minted + halvingYearMintAmount = make([]uint64, HALVING_END_YEAR) // actual minted amount per year + halvingYearAccuAmount = make([]uint64, HALVING_END_YEAR) // accumulated minted amount per year + amountPerBlockPerHalvingYear = make([]uint64, HALVING_END_YEAR) // amount per block per year to mint ) func init() { startHeight = std.GetHeight() startTimestamp = time.Now().Unix() - for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { - setHalvingYearMaxAmount(year, HALVING_AMOUNTS_PER_YEAR[year-1]) + // initialize halving data + initializeHalvingData() - if year == 1 { - setHalvingYearAccuAmount(year, HALVING_AMOUNTS_PER_YEAR[year-1]) + // set end timestamp + // after 12 years, timestamp which gns emission will be ended + // it can not be changed + setEndTimestamp(startTimestamp + consts.TIMESTAMP_YEAR*HALVING_END_YEAR) +} + +// initializeHalvingData initializes the halving data +// it should be called only once, so we call this in init() +func initializeHalvingData() { + for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { + // set max emission amount per year + // each year can not mint more than this amount + currentYearMaxAmount := GetHalvingAmountsPerYear(year) + setHalvingYearMaxAmount(year, currentYearMaxAmount) + + if year == HALVING_START_YEAR { + setHalvingYearAccuAmount(year, currentYearMaxAmount) + setHalvingYearStartBlock(year, startHeight) + setHalvingYearEndBlock(year, startHeight+(blockPerYear*year)) } else { - setHalvingYearAccuAmount(year, GetHalvingYearAccuAmount(year-1)+HALVING_AMOUNTS_PER_YEAR[year-1]) + // accumulate amount until current year, is the sum of current year max amount and accumulated amount until previous year + setHalvingYearAccuAmount(year, currentYearMaxAmount+GetHalvingYearAccuAmount(year-1)) + + // start block of current year, is the next block of previous year end block + setHalvingYearStartBlock(year, GetHalvingYearEndBlock(year-1)+1) + + // end block of current year, is sum of start block and block per year + setHalvingYearEndBlock(year, GetHalvingYearStartBlock(year)+blockPerYear) } - setHalvingYearBlock(year, startHeight+BLOCK_PER_YEAR*(year-1)) setHalvingYearTimestamp(year, startTimestamp+(consts.TIMESTAMP_YEAR*(year-1))) - setHalvingYearMintAmount(year, uint64(0)) - amountPerYear := GetHalvingYearMaxAmount(year) // amount per year - amountPerDay := amountPerYear / consts.DAY_PER_YEAR // amount per day - amountPerBlock := amountPerDay / uint64(BLOCK_PER_DAY) // amount per block + amountPerDay := currentYearMaxAmount / consts.DAY_PER_YEAR + amountPerBlock := amountPerDay / uint64(blockPerDay) setAmountPerBlockPerHalvingYear(year, uint64(amountPerBlock)) - } - setEndTimestamp(startTimestamp + consts.TIMESTAMP_YEAR*HALVING_END_YEAR) + setHalvingYearMintAmount(year, uint64(0)) + } } func GetAvgBlockTimeInMs() int64 { @@ -139,6 +158,11 @@ func SetAvgBlockTimeInMs(ms int64) { func setAvgBlockTimeInMs(ms int64) { common.IsHalted() + // update block per year + value1 := int64(consts.TIMESTAMP_YEAR * consts.SECOND_IN_MILLISECOND) + value2 := int64(value1 / ms) + blockPerYear = value2 + now := time.Now().Unix() height := std.GetHeight() @@ -150,8 +174,7 @@ func setAvgBlockTimeInMs(ms int64) { timeLeftMs := timeLeft * consts.SECOND_IN_MILLISECOND // how many block left for current halving year - blockLeft := timeLeftMs / ms - + blockLeft := (timeLeftMs / ms) // how many reward left for current halving year minted := GetMintedEmissionAmount() amountLeft := GetHalvingYearAccuAmount(currentYear) - minted @@ -160,6 +183,8 @@ func setAvgBlockTimeInMs(ms int64) { adjustedAmountPerBlock := amountLeft / uint64(blockLeft) setAmountPerBlockPerHalvingYear(currentYear, adjustedAmountPerBlock) + yearEndHeight := int64(0) + nextYearStartHeight := int64(0) for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { if year < currentYear { // pass past halving years @@ -169,7 +194,20 @@ func setAvgBlockTimeInMs(ms int64) { yearEndTimestamp := GetHalvingYearTimestamp(year) + consts.TIMESTAMP_YEAR timeLeftForYear := yearEndTimestamp - now numBlock := (timeLeftForYear * consts.SECOND_IN_MILLISECOND) / ms - setHalvingYearBlock(year, height+numBlock) + yearEndHeight := height + numBlock + + if year == currentYear { + // for current year, update only end block + setHalvingYearEndBlock(year, yearEndHeight) + } else { + // update start block + prevYearEnd := GetHalvingYearEndBlock(year - 1) + nextYearStart := prevYearEnd + 1 + nextYearEnd := nextYearStart + blockPerYear + + setHalvingYearStartBlock(year, nextYearStart) + setHalvingYearEndBlock(year, nextYearEnd) + } } avgBlockTimeMs = ms @@ -192,8 +230,8 @@ func GetHalvingYearByHeight(height int64) int64 { } for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { - block := GetHalvingYearBlock(year) - if height <= block { + endBlock := GetHalvingYearEndBlock(year) + if height <= endBlock { return year } } @@ -216,12 +254,20 @@ func getHalvingYearAndEndTimestamp(timestamp int64) (int64, int64) { return year, startTimestamp + (consts.TIMESTAMP_YEAR * year) } -func GetHalvingYearBlock(year int64) int64 { - return halvingYearBlock[year-1] +func GetHalvingYearStartBlock(year int64) int64 { + return halvingYearStartBlock[year-1] } -func setHalvingYearBlock(year int64, block int64) { - halvingYearBlock[year-1] = block +func setHalvingYearStartBlock(year int64, block int64) { + halvingYearStartBlock[year-1] = block +} + +func GetHalvingYearEndBlock(year int64) int64 { + return halvingYearEndBlock[year-1] +} + +func setHalvingYearEndBlock(year int64, block int64) { + halvingYearEndBlock[year-1] = block } func GetHalvingYearTimestamp(year int64) int64 { @@ -264,10 +310,14 @@ func setAmountPerBlockPerHalvingYear(year int64, amount uint64) { amountPerBlockPerHalvingYear[year-1] = amount } +func GetHalvingAmountsPerYear(year int64) uint64 { + return HALVING_AMOUNTS_PER_YEAR[year-1] +} + func GetEndHeight() int64 { // last block of last halving year(12) is last block of emission // later than this block, no more gns will be minted - return GetHalvingYearBlock(HALVING_END_YEAR) + return GetHalvingYearEndBlock(HALVING_END_YEAR) } func GetEndTimestamp() int64 { @@ -287,7 +337,7 @@ func GetHalvingInfo() string { for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { halvings = append(halvings, json.ObjectNode("", map[string]*json.Node{ "year": json.StringNode("year", strconv.FormatInt(year, 10)), - "block": json.NumberNode("block", float64(GetHalvingYearBlock(year))), + "block": json.NumberNode("block", float64(GetHalvingYearStartBlock(year))), "amount": json.NumberNode("amount", float64(GetAmountPerBlockPerHalvingYear(year))), })) } diff --git a/_deploy/r/gnoswap/gns/halving_test.gno b/_deploy/r/gnoswap/gns/halving_test.gno index 2450d01f..5010de73 100644 --- a/_deploy/r/gnoswap/gns/halving_test.gno +++ b/_deploy/r/gnoswap/gns/halving_test.gno @@ -16,18 +16,18 @@ var ( ) var FIRST_BLOCK_OF_YEAR = []int64{ - startHeight + (BLOCK_PER_YEAR * 0) + 1, - startHeight + (BLOCK_PER_YEAR * 1) + 2, - startHeight + (BLOCK_PER_YEAR * 2) + 3, - startHeight + (BLOCK_PER_YEAR * 3) + 4, - startHeight + (BLOCK_PER_YEAR * 4) + 5, - startHeight + (BLOCK_PER_YEAR * 5) + 6, - startHeight + (BLOCK_PER_YEAR * 6) + 7, - startHeight + (BLOCK_PER_YEAR * 7) + 8, - startHeight + (BLOCK_PER_YEAR * 8) + 9, - startHeight + (BLOCK_PER_YEAR * 9) + 10, - startHeight + (BLOCK_PER_YEAR * 10) + 11, - startHeight + (BLOCK_PER_YEAR * 11) + 12, + startHeight + (blockPerYear * 0) + 1, + startHeight + (blockPerYear * 1) + 2, + startHeight + (blockPerYear * 2) + 3, + startHeight + (blockPerYear * 3) + 4, + startHeight + (blockPerYear * 4) + 5, + startHeight + (blockPerYear * 5) + 6, + startHeight + (blockPerYear * 6) + 7, + startHeight + (blockPerYear * 7) + 8, + startHeight + (blockPerYear * 8) + 9, + startHeight + (blockPerYear * 9) + 10, + startHeight + (blockPerYear * 10) + 11, + startHeight + (blockPerYear * 11) + 12, } var FIRST_TIMESTAMP_OF_YEAR = []int64{ @@ -97,9 +97,9 @@ func TestGetHalvingYearAndEndTimestamp(t *testing.T) { }) } -func TestHalvingYearBlock(t *testing.T) { - setHalvingYearBlock(1, 100) - uassert.Equal(t, GetHalvingYearBlock(1), int64(100)) +func TestHalvingYearStartBlock(t *testing.T) { + setHalvingYearStartBlock(1, 100) + uassert.Equal(t, GetHalvingYearStartBlock(1), int64(100)) } func TestHalvingYearTimestamp(t *testing.T) { diff --git a/_deploy/r/gnoswap/gns/tests/gns_calculate_and_mint_test.gnoA b/_deploy/r/gnoswap/gns/tests/gns_calculate_and_mint_test.gnoA index f6a91202..2cb56ff1 100644 --- a/_deploy/r/gnoswap/gns/tests/gns_calculate_and_mint_test.gnoA +++ b/_deploy/r/gnoswap/gns/tests/gns_calculate_and_mint_test.gnoA @@ -27,7 +27,7 @@ func TestCalculateAmountToMint(t *testing.T) { }) t.Run("entire block for year 01 + 1 block for year 02", func(t *testing.T) { - minted := calculateAmountToMint(GetLastMintedHeight()+4, GetHalvingYearBlock(2)) + minted := calculateAmountToMint(GetLastMintedHeight()+4, GetHalvingYearStartBlock(2)) // minted all amount for year 01 uassert.Equal(t, GetHalvingYearMaxAmount(1), GetHalvingYearMintAmount(1)) @@ -37,7 +37,7 @@ func TestCalculateAmountToMint(t *testing.T) { }) t.Run("entire block for 12 years", func(t *testing.T) { - calculateAmountToMint(GetHalvingYearBlock(1), GetHalvingYearBlock(12)) + calculateAmountToMint(GetHalvingYearStartBlock(1), GetHalvingYearEndBlock(12)) for year := int64(1); year <= 12; year++ { uassert.Equal(t, GetHalvingYearMaxAmount(year), GetHalvingYearMintAmount(year)) @@ -45,12 +45,9 @@ func TestCalculateAmountToMint(t *testing.T) { }) t.Run("no emission amount for after 12 years", func(t *testing.T) { - amount := calculateAmountToMint(GetHalvingYearBlock(12), GetHalvingYearBlock(12)+1) + amount := calculateAmountToMint(GetHalvingYearStartBlock(12), GetHalvingYearEndBlock(12)+1) uassert.Equal(t, uint64(0), amount) }) - - // clear for further test - halvingYearMintAmount = []uint64{} } func TestMintGns(t *testing.T) { @@ -79,6 +76,7 @@ func TestMintGns(t *testing.T) { }) t.Run("mint by year, until emission ends", func(t *testing.T) { + resetObject(t) for year := int64(1); year <= 12; year++ { skipUntilLastHeightOfHalvingYear(t, year) @@ -92,7 +90,7 @@ func TestMintGns(t *testing.T) { }) t.Run("no more emission after it ends", func(t *testing.T) { - std.TestSkipHeights(BLOCK_PER_YEAR) + std.TestSkipHeights(blockPerYear) std.TestSetRealm(emissionRealm) mintedAmount := MintGns(a2u(consts.ADMIN)) diff --git a/_deploy/r/gnoswap/gns/tests/z2_filetest.gno b/_deploy/r/gnoswap/gns/tests/z2_filetest.gno index 6b51fba2..9a018bb7 100644 --- a/_deploy/r/gnoswap/gns/tests/z2_filetest.gno +++ b/_deploy/r/gnoswap/gns/tests/z2_filetest.gno @@ -53,7 +53,7 @@ func blockTime4000ms() { uassert.Equal(t, uint64(28538812), firstYearAmountPerBlock) // next halving year start/end block - uassert.Equal(t, int64(7884149), gns.GetHalvingYearBlock(2)) + uassert.Equal(t, int64(7884149), gns.GetHalvingYearStartBlock(2)) uassert.Equal(t, int64(15768149), gns.GetHalvingYearEndBlock(2)) // orig year01 start block = 123 diff --git a/_deploy/r/gnoswap/gns/tests/z3_filetest.gno b/_deploy/r/gnoswap/gns/tests/z3_filetest.gno index 2337485c..532030f8 100644 --- a/_deploy/r/gnoswap/gns/tests/z3_filetest.gno +++ b/_deploy/r/gnoswap/gns/tests/z3_filetest.gno @@ -51,7 +51,7 @@ func blockTime4000ms() { uassert.Equal(t, uint64(713470300+28538812), gns.GetMintedEmissionAmount()) // 742009112 // next halving year start/end block - uassert.Equal(t, int64(7884149), gns.GetHalvingYearBlock(2)) + uassert.Equal(t, int64(7884149), gns.GetHalvingYearStartBlock(2)) uassert.Equal(t, int64(15768149), gns.GetHalvingYearEndBlock(2)) } From 1acb500ff288e6a2ca116a8aded7147796f3f140 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Fri, 20 Dec 2024 19:01:34 +0900 Subject: [PATCH 16/17] GSW-1845 test: fix and add more test --- _deploy/r/gnoswap/gns/gns.gno | 2 ++ _deploy/r/gnoswap/gns/gns_test.gno | 32 +++++++++++++++++++++ _deploy/r/gnoswap/gns/tests/z1_filetest.gno | 6 ++-- _deploy/r/gnoswap/gns/tests/z2_filetest.gno | 16 +++++++++++ _deploy/r/gnoswap/gns/tests/z3_filetest.gno | 5 ++-- 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/_deploy/r/gnoswap/gns/gns.gno b/_deploy/r/gnoswap/gns/gns.gno index f647460a..99836ae8 100644 --- a/_deploy/r/gnoswap/gns/gns.gno +++ b/_deploy/r/gnoswap/gns/gns.gno @@ -74,6 +74,7 @@ func MintGns(address pusers.AddressOrName) uint64 { setMintedEmissionAmount(GetMintedEmissionAmount() + amountToMint) setLeftEmissionAmount(GetLeftEmissionAmount() - amountToMint) + // mint calculated amount to address err := privateLedger.Mint(users.Resolve(address), amountToMint) if err != nil { panic(err.Error()) @@ -150,6 +151,7 @@ func checkErr(err error) { func calculateAmountToMint(fromHeight, toHeight int64) uint64 { fromYear := GetHalvingYearByHeight(fromHeight) + // if toHeight is greater than emission end height, set toHeight to emission end height if toHeight > GetEndHeight() { toHeight = GetEndHeight() } diff --git a/_deploy/r/gnoswap/gns/gns_test.gno b/_deploy/r/gnoswap/gns/gns_test.gno index 758d94b0..33ae2200 100644 --- a/_deploy/r/gnoswap/gns/gns_test.gno +++ b/_deploy/r/gnoswap/gns/gns_test.gno @@ -27,6 +27,38 @@ var ( bob = testutils.TestAddress("bob") ) +func TestAssertTooManyEmission(t *testing.T) { + tests := []struct { + name string + amount uint64 + shouldPanic bool + panicMsg string + }{ + { + name: "should panic if emission amount is too large", + amount: MAXIMUM_SUPPLY, + shouldPanic: true, + panicMsg: "[GNOSWAP-GNS-002] too many emission reward || amount: 1000000000000000", + }, + { + name: "should not panic if emission amount is not too large", + amount: 123, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.shouldPanic { + uassert.PanicsWithMessage(t, tt.panicMsg, func() { + assertTooManyEmission(tt.amount) + }) + } else { + uassert.NotPanics(t, func() { assertTooManyEmission(tt.amount) }) + } + }) + } +} + func TestIsLastBlockOfHalvingYear(t *testing.T) { tests := make([]struct { name string diff --git a/_deploy/r/gnoswap/gns/tests/z1_filetest.gno b/_deploy/r/gnoswap/gns/tests/z1_filetest.gno index c88626cf..d9842419 100644 --- a/_deploy/r/gnoswap/gns/tests/z1_filetest.gno +++ b/_deploy/r/gnoswap/gns/tests/z1_filetest.gno @@ -35,7 +35,8 @@ func skip50Blocks() { uassert.Equal(t, std.GetHeight(), int64(173)) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - mintedAmount := gns.MintGns(a2u(user01Addr)) // 14269406 * 50 = 713470300) + mintedAmount := gns.MintGns(a2u(user01Addr)) + uassert.Equal(t, uint64(713470300), mintedAmount) // 14269406 * 50 uassert.Equal(t, uint64(713470300), gns.GetMintedEmissionAmount()) } @@ -62,7 +63,8 @@ func blockTime2500ms() { std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) std.TestSkipHeights(1) - mintedAmount := gns.MintGns(a2u(user01Addr)) // 17836757 + mintedAmount := gns.MintGns(a2u(user01Addr)) + uassert.Equal(t, uint64(17836757), mintedAmount) uassert.Equal(t, uint64(713470300+17836757), gns.GetMintedEmissionAmount()) // 731307057 } diff --git a/_deploy/r/gnoswap/gns/tests/z2_filetest.gno b/_deploy/r/gnoswap/gns/tests/z2_filetest.gno index 9a018bb7..c5ec13db 100644 --- a/_deploy/r/gnoswap/gns/tests/z2_filetest.gno +++ b/_deploy/r/gnoswap/gns/tests/z2_filetest.gno @@ -44,6 +44,22 @@ func blockTime4000ms() { gns.SetAvgBlockTimeInMsByAdmin(4000) // for block time 4s, amount per block is 28538812 + // first halving year end block = 15768122 + // first halving year end timestamp = 1234567990 + + // 50 block minted from L#38 + // > current height = 173 + // > current timestamp = 1234568140 + + // 1266103890 - 1234567990 = 31535900 // timestamp left for current halving year + // 31535900000 / 4000(new block avg time/ms) = 7883975 // number of block left for current halving year + + // 713470300 // already minted amount + + // first halving year should mint 225000000000000 + // 225000000000000 - 713470300 = 224999286529700 + // 224999286529700 / 7883975 ≈ 28538812 + std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) std.TestSkipHeights(1) mintedAmount := gns.MintGns(a2u(user01Addr)) // 28538812 diff --git a/_deploy/r/gnoswap/gns/tests/z3_filetest.gno b/_deploy/r/gnoswap/gns/tests/z3_filetest.gno index 532030f8..1f81f34f 100644 --- a/_deploy/r/gnoswap/gns/tests/z3_filetest.gno +++ b/_deploy/r/gnoswap/gns/tests/z3_filetest.gno @@ -43,7 +43,6 @@ func skip50Blocks() { func blockTime4000ms() { std.TestSetRealm(std.NewUserRealm(consts.ADMIN)) gns.SetAvgBlockTimeInMsByAdmin(4000) - // for block time 4s, amount per block is 28538812 std.TestSkipHeights(1) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) @@ -57,10 +56,10 @@ func blockTime4000ms() { func reachAboutHalfOfFirstHalving() { // current block = 174 - // next halving year start block = 7884148 + // end block of first halving year = 7884148 // 7884148 - 174 = 7883974 // block left to next halving - std.TestSkipHeights(3941987) // 7883974 / 2 + std.TestSkipHeights(3941987) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) gns.MintGns(a2u(user01Addr)) From eb504f2c96f300a735f796ba47522435900bb8cc Mon Sep 17 00:00:00 2001 From: 0xTopaz Date: Fri, 27 Dec 2024 15:07:53 +0900 Subject: [PATCH 17/17] fix: default interval time to 2 sec --- _deploy/r/gnoswap/consts/consts.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_deploy/r/gnoswap/consts/consts.gno b/_deploy/r/gnoswap/consts/consts.gno index c4a3a897..2b400c5d 100644 --- a/_deploy/r/gnoswap/consts/consts.gno +++ b/_deploy/r/gnoswap/consts/consts.gno @@ -12,7 +12,7 @@ const ( TOKEN_REGISTER_NAMESPACE string = "gno.land/r/g1er355fkjksqpdtwmhf5penwa82p0rhqxkkyhk5" - BLOCK_GENERATION_INTERVAL int64 = 1 // seconds + BLOCK_GENERATION_INTERVAL int64 = 2 // seconds ) // WRAP & UNWRAP