diff --git a/_deploy/r/gnoswap/consts/consts.gno b/_deploy/r/gnoswap/consts/consts.gno index c4a3a8975..2b400c5de 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 diff --git a/_deploy/r/gnoswap/gns/_helper_test.gno b/_deploy/r/gnoswap/gns/_helper_test.gno index 2e9763908..39e6c0142 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,33 @@ 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() + + startHeight = std.GetHeight() + startTimestamp = time.Now().Unix() + + initializeHalvingData() + setEndTimestamp(startTimestamp + consts.TIMESTAMP_YEAR*HALVING_END_YEAR) +} diff --git a/_deploy/r/gnoswap/gns/errors.gno b/_deploy/r/gnoswap/gns/errors.gno index 55eb28cd1..2f4480fd2 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 d4c3a682f..99836ae85 100644 --- a/_deploy/r/gnoswap/gns/gns.gno +++ b/_deploy/r/gnoswap/gns/gns.gno @@ -22,58 +22,64 @@ 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 + + burnAmount uint64 ) 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 { 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 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) - err := privateLedger.Mint(users.Resolve(address), amountToMint) - if err != nil { - panic(err.Error()) - } // update setLastMintedHeight(currentHeight) setMintedEmissionAmount(GetMintedEmissionAmount() + amountToMint) setLeftEmissionAmount(GetLeftEmissionAmount() - amountToMint) + // mint calculated amount to address + err := privateLedger.Mint(users.Resolve(address), amountToMint) + if err != nil { + panic(err.Error()) + } + return amountToMint } @@ -81,6 +87,8 @@ func Burn(from pusers.AddressOrName, amount uint64) { owner.AssertCallerIsOwner() fromAddr := users.Resolve(from) checkErr(privateLedger.Burn(fromAddr, amount)) + + burnAmount += amount } func TotalSupply() uint64 { @@ -137,52 +145,52 @@ 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) - toYear := GetHalvingYearByHeight(toHeight) - if isEmissionEnded(fromYear) || isEmissionEnded(toYear) { - return 0 + // if toHeight is greater than emission end height, set toHeight to emission end height + if toHeight > GetEndHeight() { + toHeight = GetEndHeight() } + toYear := GetHalvingYearByHeight(toHeight) 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 := GetAmountByHeight(yearEndHeight) + 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 } @@ -190,7 +198,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. @@ -199,30 +207,36 @@ 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 +// 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 } +// 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 { return mintedEmissionAmount } -// Setter func setLastMintedHeight(height int64) { lastMintedHeight = height } @@ -234,3 +248,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 c7657f9bd..33ae2200c 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 @@ -34,14 +66,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: halvingYearBlock[i], + height: GetHalvingYearEndBlock(i), want: true, }) @@ -51,7 +83,7 @@ func TestIsLastBlockOfHalvingYear(t *testing.T) { want bool }{ name: fmt.Sprintf("not last block of halving year %d", i), - height: halvingYearBlock[i] - 1, + height: GetHalvingYearEndBlock(i) - 1, want: false, }) } @@ -81,7 +113,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 +125,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), }) } } @@ -108,15 +140,25 @@ 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) + 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()) }) @@ -237,7 +279,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) diff --git a/_deploy/r/gnoswap/gns/halving.gno b/_deploy/r/gnoswap/gns/halving.gno index 934a34bd0..7a55d03b3 100644 --- a/_deploy/r/gnoswap/gns/halving.gno +++ b/_deploy/r/gnoswap/gns/halving.gno @@ -2,6 +2,7 @@ package gns import ( "std" + "strconv" "time" "gno.land/p/demo/ufmt" @@ -22,74 +23,94 @@ import ( (365 days) 1 year = 31536000 block */ +const ( + HALVING_START_YEAR = int64(1) + HALVING_END_YEAR = int64(12) + + 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 + 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 + 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 ) var ( - initialized bool startHeight int64 startTimestamp int64 + endTimestamp int64 ) -var halvingYearBlock = make(map[int64]int64) // year => block -var halvingYearTimestamp = make(map[int64]int64) // year => timestamp +var ( + 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 +) -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 + startHeight = std.GetHeight() + startTimestamp = time.Now().Unix() -func init() { - height := std.GetHeight() + // initialize halving data + initializeHalvingData() - startHeight = height - startTimestamp = time.Now().Unix() + // 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) +} - initialized = true +// 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 { + // 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) + } - for i := int64(1); i < 13; i++ { - halvingYearBlock[i] = height + BLOCK_PER_YEAR*i - halvingYearTimestamp[i] = startTimestamp + (consts.TIMESTAMP_YEAR * i) + setHalvingYearTimestamp(year, startTimestamp+(consts.TIMESTAMP_YEAR*(year-1))) - amountPerYear := halvingYearAmount[i] // 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)) - amountPerBlockPerHalvingYear[i] = uint64(amountPerBlock) + setHalvingYearMintAmount(year, uint64(0)) } } @@ -137,91 +158,174 @@ func SetAvgBlockTimeInMs(ms int64) { func setAvgBlockTimeInMs(ms int64) { common.IsHalted() - // set it - avgBlockTimeMs = ms + // update block per year + value1 := int64(consts.TIMESTAMP_YEAR * consts.SECOND_IN_MILLISECOND) + value2 := int64(value1 / ms) + blockPerYear = value2 - // which year current time is in now := time.Now().Unix() height := std.GetHeight() - year, endTimestamp := GetHalvingYearByTimestamp(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 := MintedEmissionAmount() - amountLeft := halvingYearAccuAmount[year] - minted + // how many block left for current halving year + blockLeft := (timeLeftMs / ms) + // how many reward left for current halving year + minted := GetMintedEmissionAmount() + amountLeft := GetHalvingYearAccuAmount(currentYear) - minted - // how much reward per block + // how much reward should be minted per block for current halving year adjustedAmountPerBlock := amountLeft / uint64(blockLeft) + setAmountPerBlockPerHalvingYear(currentYear, adjustedAmountPerBlock) - // update it - amountPerBlockPerHalvingYear[year] = adjustedAmountPerBlock + yearEndHeight := int64(0) + nextYearStartHeight := int64(0) + for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { + if year < currentYear { + // pass past halving years + continue + } - // adjust halving block - for keyYear, _ := range halvingYearBlock { - yearEnd := halvingYearTimestamp[keyYear] + yearEndTimestamp := GetHalvingYearTimestamp(year) + consts.TIMESTAMP_YEAR + timeLeftForYear := yearEndTimestamp - now + numBlock := (timeLeftForYear * consts.SECOND_IN_MILLISECOND) / ms + 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) + } + } - if now >= yearEnd { - continue + avgBlockTimeMs = ms +} + +// 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 { + if isEmissionEnded(height) { + return 0 + } + + for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { + endBlock := GetHalvingYearEndBlock(year) + if height <= endBlock { + return year } + } + + return 0 +} - diff := yearEnd - now - numBlock := diff * consts.SECOND_IN_MILLISECOND / avgBlockTimeMs - halvingYearBlock[keyYear] = height + numBlock +// 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) { + if timestamp > endTimestamp { // after 12 years + return 0, 0 } + + 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 GetHalvingYearStartBlock(year int64) int64 { + return halvingYearStartBlock[year-1] +} + +func setHalvingYearStartBlock(year int64, block int64) { + halvingYearStartBlock[year-1] = block +} + +func GetHalvingYearEndBlock(year int64) int64 { + return halvingYearEndBlock[year-1] } -func GetHalvingYearAmount(year int64) uint64 { - return halvingYearAmount[year] +func setHalvingYearEndBlock(year int64, block int64) { + halvingYearEndBlock[year-1] = block +} + +func GetHalvingYearTimestamp(year int64) int64 { + return halvingYearTimestamp[year-1] +} + +func setHalvingYearTimestamp(year int64, timestamp int64) { + halvingYearTimestamp[year-1] = timestamp +} + +func GetHalvingYearMaxAmount(year int64) uint64 { + return halvingYearMaxAmount[year-1] +} + +func setHalvingYearMaxAmount(year int64, amount uint64) { + halvingYearMaxAmount[year-1] = amount } func GetHalvingYearMintAmount(year int64) uint64 { - return halvingYearMintAmount[year] + return halvingYearMintAmount[year-1] } -func SetHalvingYearMintAmount(year int64, amount uint64) { - halvingYearMintAmount[year] = amount +func setHalvingYearMintAmount(year int64, amount uint64) { + halvingYearMintAmount[year-1] = amount } -func GetAmountByHeight(height int64) uint64 { - halvingYear := GetHalvingYearByHeight(height) +func GetHalvingYearAccuAmount(year int64) uint64 { + return halvingYearAccuAmount[year-1] +} - return amountPerBlockPerHalvingYear[halvingYear] +func setHalvingYearAccuAmount(year int64, amount uint64) { + halvingYearAccuAmount[year-1] = amount } -func GetAmountByYear(year int64) uint64 { - return amountPerBlockPerHalvingYear[year] +func GetAmountPerBlockPerHalvingYear(year int64) uint64 { + return amountPerBlockPerHalvingYear[year-1] } -func GetHalvingYearByHeight(height int64) int64 { - // determine which halving year block is in - for year, block := range halvingYearBlock { - if height <= block { - return year - } - } +func setAmountPerBlockPerHalvingYear(year int64, amount uint64) { + amountPerBlockPerHalvingYear[year-1] = amount +} - return 0 +func GetHalvingAmountsPerYear(year int64) uint64 { + return HALVING_AMOUNTS_PER_YEAR[year-1] } -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 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 GetHalvingYearEndBlock(HALVING_END_YEAR) +} - return 0, 0 +func GetEndTimestamp() int64 { + return endTimestamp } -func GetHalvingYearBlock(year int64) int64 { - return halvingYearBlock[year] +func setEndTimestamp(timestamp int64) { + endTimestamp = timestamp } func GetHalvingInfo() string { @@ -229,11 +333,12 @@ func GetHalvingInfo() string { now := time.Now().Unix() halvings := make([]*json.Node, 0) - for year, block := range halvingYearBlock { + + for year := HALVING_START_YEAR; year <= HALVING_END_YEAR; year++ { halvings = append(halvings, json.ObjectNode("", map[string]*json.Node{ - "year": json.NumberNode("year", float64(year)), - "block": json.NumberNode("block", float64(block)), - "amount": json.NumberNode("amount", float64(amountPerBlockPerHalvingYear[year])), + "year": json.StringNode("year", strconv.FormatInt(year, 10)), + "block": json.NumberNode("block", float64(GetHalvingYearStartBlock(year))), + "amount": json.NumberNode("amount", float64(GetAmountPerBlockPerHalvingYear(year))), })) } @@ -252,19 +357,6 @@ func GetHalvingInfo() string { 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 isEmissionEnded(height int64) bool { + return height > GetEndHeight() } diff --git a/_deploy/r/gnoswap/gns/halving_test.gno b/_deploy/r/gnoswap/gns/halving_test.gno new file mode 100644 index 000000000..5010de73c --- /dev/null +++ b/_deploy/r/gnoswap/gns/halving_test.gno @@ -0,0 +1,172 @@ +package gns + +import ( + "std" + "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) + adminRealm = std.NewUserRealm(consts.ADMIN) +) + +var FIRST_BLOCK_OF_YEAR = []int64{ + 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{ + startTimestamp + consts.TIMESTAMP_YEAR*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, +} + +var END_TIMESTAMP_OF_YEAR = []int64{ + 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, +} + +func TestGetAmountByHeight(t *testing.T) { + 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) { + 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) { + 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 TestHalvingYearStartBlock(t *testing.T) { + setHalvingYearStartBlock(1, 100) + uassert.Equal(t, GetHalvingYearStartBlock(1), int64(100)) +} + +func TestHalvingYearTimestamp(t *testing.T) { + setHalvingYearTimestamp(2, 200) + uassert.Equal(t, GetHalvingYearTimestamp(2), int64(200)) +} + +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)) +} + +func TestHalvingYearAccuAmount(t *testing.T) { + setHalvingYearAccuAmount(5, 500) + uassert.Equal(t, GetHalvingYearAccuAmount(5), uint64(500)) +} + +func TestAmountPerBlockPerHalvingYear(t *testing.T) { + setAmountPerBlockPerHalvingYear(6, 600) + uassert.Equal(t, GetAmountPerBlockPerHalvingYear(6), uint64(600)) +} + +func TestGetHalvingInfo(t *testing.T) { + jsonStr, err := json.Unmarshal([]byte(GetHalvingInfo())) + uassert.NoError(t, err) + + 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 a5cfd9931..2cb56ff19 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,42 @@ 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, GetHalvingYearStartBlock(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(GetHalvingYearStartBlock(1), GetHalvingYearEndBlock(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(GetHalvingYearStartBlock(12), GetHalvingYearEndBlock(12)+1) uassert.Equal(t, uint64(0), amount) }) - - // clear for further test - halvingYearMintAmount = make(map[int64]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,28 +70,37 @@ 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) { + resetObject(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()) } }) 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)) 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/halving_test.gnoA b/_deploy/r/gnoswap/gns/tests/halving_test.gnoA deleted file mode 100644 index 57b6d5eef..000000000 --- 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) -} 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 aee171e6b..9a47d2187 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 553efdfbe..d98424197 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,33 +35,49 @@ 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()) + mintedAmount := gns.MintGns(a2u(user01Addr)) + uassert.Equal(t, uint64(713470300), mintedAmount) // 14269406 * 50 + 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 - // for block time 2.5s - // amount per block is 17836757 + // 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 + + // 713470300 // already minted amount + + // first halving year should mint 225000000000000 + // 225000000000000 - 713470300 = 224999286529700 + // 224999286529700 / 12614360 = 17836759 std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) // 17836757 - uassert.Equal(t, uint64(713470300+17836757), gns.TotalMinted()) // 731307057 + std.TestSkipHeights(1) + mintedAmount := gns.MintGns(a2u(user01Addr)) + uassert.Equal(t, uint64(17836757), mintedAmount) + 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.Mint(a2u(user01Addr)) + gns.MintGns(a2u(user01Addr)) - uassert.Equal(t, uint64(224999969664063), gns.TotalMinted()) + uassert.Equal(t, uint64(224999969664063), gns.GetMintedEmissionAmount()) // 224999969664063 - 731307057 = 224999238357006 // 224999238357006 / 12614358 = 17836757 } @@ -72,10 +85,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.GetMintedEmissionAmount()) year := gns.GetHalvingYearByHeight(std.GetHeight()) uassert.Equal(t, int64(1), year) @@ -91,8 +104,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.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 3bcbd4580..c5ec13db1 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,38 +35,57 @@ 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.GetMintedEmissionAmount()) } func blockTime4000ms() { std.TestSetRealm(std.NewUserRealm(consts.ADMIN)) gns.SetAvgBlockTimeInMsByAdmin(4000) - std.TestSkipHeights(1) + // 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 - // for block time 4s - // amount per block is 28538812 + // 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)) - gns.Mint(a2u(user01Addr)) // 28538812 - uassert.Equal(t, uint64(713470300+28538812), gns.TotalMinted()) // 742009112 + std.TestSkipHeights(1) + mintedAmount := gns.MintGns(a2u(user01Addr)) // 28538812 + uassert.Equal(t, uint64(713470300+28538812), gns.GetMintedEmissionAmount()) // 742009112 - firstYearAmountPerBlock := gns.GetAmountByYear(1) + 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.GetHalvingYearStartBlock(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,10 +95,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.GetMintedEmissionAmount()) year := gns.GetHalvingYearByHeight(std.GetHeight()) uassert.Equal(t, int64(1), year) @@ -98,21 +114,21 @@ 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.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.Mint(a2u(user01Addr)) + gns.MintGns(a2u(user01Addr)) // minted all amount until second halving - uassert.Equal(t, uint64(225000000000000*2), gns.TotalMinted()) + 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 b1ab87d1b..1f81f34f7 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,53 +36,34 @@ 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.GetMintedEmissionAmount()) } func blockTime4000ms() { std.TestSetRealm(std.NewUserRealm(consts.ADMIN)) gns.SetAvgBlockTimeInMsByAdmin(4000) - std.TestSkipHeights(1) - - // for block time 4s - // amount per block is 28538812 + std.TestSkipHeights(1) 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.GetMintedEmissionAmount()) // 742009112 - firstYearAmountPerBlock := gns.GetAmountByYear(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 - - // 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.GetHalvingYearStartBlock(2)) + uassert.Equal(t, int64(15768149), gns.GetHalvingYearEndBlock(2)) } func reachAboutHalfOfFirstHalving() { - // current := 174 - // nextHalving := 7884148 - // 7884148 - 174 = 7883974 - // 7883974 / 2 = 3941987 + // current block = 174 + // end block of first halving year = 7884148 + // 7884148 - 174 = 7883974 // block left to next halving std.TestSkipHeights(3941987) std.TestSetRealm(std.NewCodeRealm(consts.EMISSION_PATH)) - gns.Mint(a2u(user01Addr)) - - // minted about 50% amount for first halving year - uassert.Equal(t, uint64(112500367908556), gns.TotalMinted()) + gns.MintGns(a2u(user01Addr)) + // stil in first halving year year := gns.GetHalvingYearByHeight(std.GetHeight()) uassert.Equal(t, int64(1), year) } @@ -97,16 +75,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.Mint(a2u(user01Addr)) + gns.MintGns(a2u(user01Addr)) // minted all amount for first halving year - uassert.Equal(t, uint64(225000000000000), gns.TotalMinted()) + uassert.Equal(t, gns.GetHalvingYearMaxAmount(1), gns.GetMintedEmissionAmount()) // we're at the end of first halving year year := gns.GetHalvingYearByHeight(std.GetHeight()) @@ -123,8 +99,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.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 000000000..f4ea61add --- /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) +}