From 6aba331e1d7fcd80eb3a9a9db6ee0e75a22fd9ed Mon Sep 17 00:00:00 2001 From: Lockwarr Date: Thu, 26 Sep 2024 14:04:41 +0300 Subject: [PATCH] feat: new minting formula --- x/mint/abci.go | 52 +++++++++++++++++---------- x/mint/abci_test.go | 72 ++++++++++++++++++------------------- x/mint/types/minter.go | 65 +++++++++++++++++---------------- x/mint/types/minter_test.go | 24 ++++++------- 4 files changed, 115 insertions(+), 98 deletions(-) diff --git a/x/mint/abci.go b/x/mint/abci.go index b18c3c40..4984f9cc 100644 --- a/x/mint/abci.go +++ b/x/mint/abci.go @@ -47,9 +47,9 @@ func calcTimeDifference(blockTime, prevBlockTime, maxMintableSeconds sdkmath.Uin } func calcTokens(blockTime sdkmath.Uint, minter *types.Minter, maxMintableSeconds sdkmath.Uint) sdkmath.Uint { - if minter.TotalMinted.GTE(types.MintingCap) { - return sdkmath.ZeroUint() - } + // if minter.TotalMinted.GTE(types.MintingCap) { + // return sdkmath.ZeroUint() + // } if minter.PrevBlockTimestamp.IsZero() { // we do not know how much time has passed since the previous block, thus nothing will be mined @@ -59,7 +59,7 @@ func calcTokens(blockTime sdkmath.Uint, minter *types.Minter, maxMintableSeconds nsecPassed := calcTimeDifference(blockTime, minter.PrevBlockTimestamp, maxMintableSeconds) if minter.NormTimePassed.LT(types.MonthsInFormula) { - // First 96 months follow the minting formula + // First 120 months follow the minting formula // As the integral starts from NormOffset (ie > 0), previous total needs to be incremented by predetermined amount previousTotal := minter.TotalMinted.Add(normInitialTotal) newNormTime := minter.NormTimePassed.Add(calcFunctionIncrement(nsecPassed)) @@ -69,17 +69,31 @@ func calcTokens(blockTime sdkmath.Uint, minter *types.Minter, maxMintableSeconds return updateMinter(minter, blockTime, newNormTime, delta) } else { - // After reaching 96 normalized time, mint fixed amount of tokens per month until we reach the minting cap - normIncrement := calcFixedIncrement(nsecPassed) - delta := sdkmath.NewUint((normIncrement.Mul(types.DecFromUint(types.FixedMintedAmount))).TruncateInt().Uint64()) + return sdkmath.ZeroUint() + } - if minter.TotalMinted.Add(delta).GT(types.MintingCap) { - // Trim off excess tokens if the cap is reached - delta = types.MintingCap.Sub(minter.TotalMinted) - } + // if minter.NormTimePassed.LT(types.MonthsInFormula) { + // // First 96 months follow the minting formula + // // As the integral starts from NormOffset (ie > 0), previous total needs to be incremented by predetermined amount + // previousTotal := minter.TotalMinted.Add(normInitialTotal) + // newNormTime := minter.NormTimePassed.Add(calcFunctionIncrement(nsecPassed)) + // nextTotal := types.CalcTokensByIntegral(newNormTime) - return updateMinter(minter, blockTime, minter.NormTimePassed.Add(normIncrement), delta) - } + // delta := nextTotal.Sub(previousTotal) + + // return updateMinter(minter, blockTime, newNormTime, delta) + // } else { + // // After reaching 96 normalized time, mint fixed amount of tokens per month until we reach the minting cap + // normIncrement := calcFixedIncrement(nsecPassed) + // delta := sdkmath.NewUint((normIncrement.Mul(types.DecFromUint(types.FixedMintedAmount))).TruncateInt().Uint64()) + + // // if minter.TotalMinted.Add(delta).GT(types.MintingCap) { + // // Trim off excess tokens if the cap is reached + // // delta = types.MintingCap.Sub(minter.TotalMinted) + // // } + + // return updateMinter(minter, blockTime, minter.NormTimePassed.Add(normIncrement), delta) + // } } func updateMinter(minter *types.Minter, blockTime sdkmath.Uint, newNormTime sdkmath.LegacyDec, newlyMinted sdkmath.Uint) sdkmath.Uint { @@ -136,9 +150,9 @@ func predictMintedByFixedAmount(totalMinted sdkmath.Uint, normTimePassed, timeAh newlyMinted := fixedPeriod.MulInt(sdkmath.Int(types.FixedMintedAmount)) // Trim off excess tokens if the cap is reached - if totalMinted.Add(sdkmath.Uint(newlyMinted.TruncateInt())).GT(types.MintingCap) { - return types.MintingCap.Sub(totalMinted), nil - } + // if totalMinted.Add(sdkmath.Uint(newlyMinted.TruncateInt())).GT(types.MintingCap) { + // return types.MintingCap.Sub(totalMinted), nil + // } return sdkmath.Uint(newlyMinted.TruncateInt()), nil } @@ -164,9 +178,9 @@ func predictTotalMinted(totalMinted sdkmath.Uint, normTimePassed, timeAhead sdkm func BeginBlocker(ctx context.Context, k keeper.Keeper) error { c := sdk.UnwrapSDKContext(ctx) minter := k.GetMinter(ctx) - if minter.TotalMinted.GTE(types.MintingCap) { - return errors.New("minting cap has been reached") - } + // if minter.TotalMinted.GTE(types.MintingCap) { + // return errors.New("minting cap has been reached") + // } defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker) diff --git a/x/mint/abci_test.go b/x/mint/abci_test.go index 117f1b1a..378fe350 100644 --- a/x/mint/abci_test.go +++ b/x/mint/abci_test.go @@ -188,41 +188,41 @@ func Test_CalcTokensFixed_WhenNotHittingMintCapInAMonth_OutputsExpectedTokensWit } } -func Test_CalcTokensFixed_WhenHittingMintCapInAMonth_DoesNotExceedMaxMintingCap(t *testing.T) { - _, _, _, timeOffset := defaultParams() - - offsetNanoInMonth := timeOffset.Add(uintFromDec(nanoSecondsInMonth)) - - halfFixedAmount := types.FixedMintedAmount.Quo(sdkmath.NewUint(2)) - totalMinted := types.MintingCap.Sub(halfFixedAmount) - minter := types.NewMinter(types.MonthsInFormula, totalMinted, timeOffset, sdkmath.ZeroUint()) - mintedCoins := sdkmath.NewUint(0) - r := rand.New(rand.NewSource(util.GetCurrentTimeUnixNano())) - - for timeOffset.LT(offsetNanoInMonth) { - i := sdkmath.NewUint(randomTimeBetweenBlocks(5, 60, r)) - - coins := calcTokens(timeOffset.Add(i), &minter, fiveMinutesInNano) - mintedCoins = mintedCoins.Add(coins) - timeOffset = timeOffset.Add(i) - } - - fmt.Printf("%v Returned Total, %v Total Minted(in store), %v Norm Time \n", - mintedCoins, minter.TotalMinted, minter.NormTimePassed) - mintThreshold := sdkmath.NewUint(1_000_000) // 1 token - if types.MintingCap.Sub(minter.TotalMinted).GT(sdkmath.ZeroUint()) { - t.Errorf("Minting Cap exceeded, minted total %v, with minting cap %v", - minter.TotalMinted, types.MintingCap) - } - if types.GetAbsDiff(halfFixedAmount, mintedCoins).GT(mintThreshold) { - t.Errorf("Minted unexpected amount of tokens, expected [%v +/- %v] returned and in store, actual minted %v", - halfFixedAmount, mintThreshold, mintedCoins) - } - if (types.MonthsInFormula.Add(sdkmath.LegacyMustNewDecFromStr("0.5"))).Sub(minter.NormTimePassed).Abs().GT(normTimeThreshold) { - t.Errorf("Received unexpected normalized time, expected [%v +/- %v], actual %v", - types.MonthsInFormula.Add(sdkmath.LegacyMustNewDecFromStr("0.5")), normTimeThreshold, minter.NormTimePassed) - } -} +// func Test_CalcTokensFixed_WhenHittingMintCapInAMonth_DoesNotExceedMaxMintingCap(t *testing.T) { +// _, _, _, timeOffset := defaultParams() + +// offsetNanoInMonth := timeOffset.Add(uintFromDec(nanoSecondsInMonth)) + +// halfFixedAmount := types.FixedMintedAmount.Quo(sdkmath.NewUint(2)) +// totalMinted := types.MintingCap.Sub(halfFixedAmount) +// minter := types.NewMinter(types.MonthsInFormula, totalMinted, timeOffset, sdkmath.ZeroUint()) +// mintedCoins := sdkmath.NewUint(0) +// r := rand.New(rand.NewSource(util.GetCurrentTimeUnixNano())) + +// for timeOffset.LT(offsetNanoInMonth) { +// i := sdkmath.NewUint(randomTimeBetweenBlocks(5, 60, r)) + +// coins := calcTokens(timeOffset.Add(i), &minter, fiveMinutesInNano) +// mintedCoins = mintedCoins.Add(coins) +// timeOffset = timeOffset.Add(i) +// } + +// fmt.Printf("%v Returned Total, %v Total Minted(in store), %v Norm Time \n", +// mintedCoins, minter.TotalMinted, minter.NormTimePassed) +// mintThreshold := sdkmath.NewUint(1_000_000) // 1 token +// if types.MintingCap.Sub(minter.TotalMinted).GT(sdkmath.ZeroUint()) { +// t.Errorf("Minting Cap exceeded, minted total %v, with minting cap %v", +// minter.TotalMinted, types.MintingCap) +// } +// if types.GetAbsDiff(halfFixedAmount, mintedCoins).GT(mintThreshold) { +// t.Errorf("Minted unexpected amount of tokens, expected [%v +/- %v] returned and in store, actual minted %v", +// halfFixedAmount, mintThreshold, mintedCoins) +// } +// if (types.MonthsInFormula.Add(sdkmath.LegacyMustNewDecFromStr("0.5"))).Sub(minter.NormTimePassed).Abs().GT(normTimeThreshold) { +// t.Errorf("Received unexpected normalized time, expected [%v +/- %v], actual %v", +// types.MonthsInFormula.Add(sdkmath.LegacyMustNewDecFromStr("0.5")), normTimeThreshold, minter.NormTimePassed) +// } +// } func Test_CalcTokens_WhenMintingAllTokens_OutputsExactExpectedTokens(t *testing.T) { minter, mintedCoins, mintedMonth, timeOffset := defaultParams() @@ -261,7 +261,7 @@ func Test_CalcTokens_WhenMintingAllTokens_OutputsExactExpectedTokens(t *testing. fmt.Printf("%v Returned Total, %v Total Minted(in store), %v Norm Time \n", mintedCoins, minter.TotalMinted, minter.NormTimePassed) - require.Equal(t, types.MintingCap, minter.TotalMinted) + // require.Equal(t, types.MintingCap, minter.TotalMinted) require.EqualValues(t, minter.TotalMinted, mintedCoins) } diff --git a/x/mint/types/minter.go b/x/mint/types/minter.go index 2aa89d2c..61f0f636 100644 --- a/x/mint/types/minter.go +++ b/x/mint/types/minter.go @@ -8,18 +8,20 @@ import ( "github.com/Nolus-Protocol/nolus-core/custom/util" ) -// Minting formula f(x)=-4.33275 x^3 + 944.61206 x^2 - 88567.25194 x + 3.86335×10^6 integrated over 0.47 to 96 -// afterwards minting 103125 tokens each month until reaching the minting cap of 150*10^6 tokens. +// Legacy Minting formula integral-4.33275 x^3 + 952.82456 x^2 - 88567.49981 x + 3.86381×10^6 dx = -1.08319 x^4 + 317.608 x^3 - 44283.7 x^2 + 3863810 x + constant + +// Current Minting formula integral-0.11175 x^3 + 50.82456 x^2 - 1767.49981 x + 0.83381×10^6 dx = -0.0279375 x^4 + 16.9415 x^3 - 883.75 x^2 + 833810 x + constant +// Minting formula f(x)=-4.33275 x^3 + 944.61206 x^2 - 88567.25194 x + 3.86335×10^6 integrated over 0.17 to 120 var ( - QuadCoef = sdkmath.LegacyMustNewDecFromStr("-1.08319") - CubeCoef = sdkmath.LegacyMustNewDecFromStr("314.871") - SquareCoef = sdkmath.LegacyMustNewDecFromStr("-44283.6") - Coef = sdkmath.LegacyMustNewDecFromStr("3863350") - MintingCap = util.ConvertToMicroNolusInt64(150000000) + QuadCoef = sdkmath.LegacyMustNewDecFromStr("-0.0279375") + CubeCoef = sdkmath.LegacyMustNewDecFromStr("16.9415") + SquareCoef = sdkmath.LegacyMustNewDecFromStr("-883.75") + Coef = sdkmath.LegacyMustNewDecFromStr("833810") + // MintingCap = util.ConvertToMicroNolusInt64(150000000) FixedMintedAmount = util.ConvertToMicroNolusInt64(103125) - NormOffset = sdkmath.LegacyMustNewDecFromStr("0.47") - MonthsInFormula = sdkmath.LegacyMustNewDecFromStr("96") + NormOffset = sdkmath.LegacyMustNewDecFromStr("0.17") TotalMonths = sdkmath.LegacyMustNewDecFromStr("120") + MonthsInFormula = TotalMonths AbsMonthsRange = MonthsInFormula.Sub(NormOffset) NormMonthsRange = AbsMonthsRange.Quo(MonthsInFormula) ) @@ -58,23 +60,24 @@ func ValidateMinter(minter Minter) error { minter.NormTimePassed.String()) } - if minter.NormTimePassed.GT(TotalMonths) { - return fmt.Errorf("mint parameter normTimePassed: %v should not be bigger than TotalMonths: %v", minter.NormTimePassed, TotalMonths) - } + // if minter.NormTimePassed.GT(TotalMonths) { + // return fmt.Errorf("mint parameter normTimePassed: %v should not be bigger than TotalMonths: %v", minter.NormTimePassed, TotalMonths) + // } - if minter.TotalMinted.GT(MintingCap) { - return fmt.Errorf("mint parameter totalMinted: %v can not be bigger than MintingCap: %v", - minter.TotalMinted, MintingCap) - } + // if minter.TotalMinted.GT(MintingCap) { + // return fmt.Errorf("mint parameter totalMinted: %v can not be bigger than MintingCap: %v", + // minter.TotalMinted, MintingCap) + // } calculatedMintedTokens := calcMintedTokens(minter) - if minter.NormTimePassed.GT(TotalMonths.Sub(sdkmath.LegacyNewDec(1))) { - if calculatedMintedTokens.GT(MintingCap) || MintingCap.Sub(calculatedMintedTokens).GT(FixedMintedAmount) { - return fmt.Errorf("mint parameters are not conformant with the minting schedule, for %s month minted %s unls", - minter.NormTimePassed, calculatedMintedTokens) - } - } else if !calculatedMintedTokens.Equal(minter.TotalMinted) { + // if minter.NormTimePassed.GT(TotalMonths.Sub(sdkmath.LegacyNewDec(1))) { + // if calculatedMintedTokens.GT(MintingCap) || MintingCap.Sub(calculatedMintedTokens).GT(FixedMintedAmount) { + // return fmt.Errorf("mint parameters are not conformant with the minting schedule, for %s month minted %s unls", + // minter.NormTimePassed, calculatedMintedTokens) + // } + // } else + if !calculatedMintedTokens.Equal(minter.TotalMinted) { return fmt.Errorf("minted unexpected amount of tokens for %s months. act: %v, exp: %v", minter.NormTimePassed, minter.TotalMinted, calculatedMintedTokens) } @@ -83,15 +86,15 @@ func ValidateMinter(minter Minter) error { } func calcMintedTokens(m Minter) sdkmath.Uint { - if m.NormTimePassed.GTE(MonthsInFormula) { - fixedMonthsPeriod := sdkmath.NewUint(m.NormTimePassed.Sub(MonthsInFormula).TruncateInt().Uint64()) - fixedMonthsTokens := fixedMonthsPeriod.Mul(FixedMintedAmount) - calculatedTokensByIntegral := CalcTokensByIntegral(MonthsInFormula).Sub(CalcTokensByIntegral(NormOffset)) - - return calculatedTokensByIntegral.Add(fixedMonthsTokens) - } else { - return CalcTokensByIntegral(m.NormTimePassed).Sub(CalcTokensByIntegral(NormOffset)) - } + // if m.NormTimePassed.GTE(MonthsInFormula) { + // fixedMonthsPeriod := sdkmath.NewUint(m.NormTimePassed.Sub(MonthsInFormula).TruncateInt().Uint64()) + // fixedMonthsTokens := fixedMonthsPeriod.Mul(FixedMintedAmount) + // calculatedTokensByIntegral := CalcTokensByIntegral(MonthsInFormula).Sub(CalcTokensByIntegral(NormOffset)) + + // return calculatedTokensByIntegral.Add(fixedMonthsTokens) + // } else { + return CalcTokensByIntegral(m.NormTimePassed).Sub(CalcTokensByIntegral(NormOffset)) + // } } // Integral: -1.08319 x^4 + 314.871 x^3 - 44283.6 x^2 + 3.86335×10^6 x diff --git a/x/mint/types/minter_test.go b/x/mint/types/minter_test.go index 5e281f96..a8b7edf5 100644 --- a/x/mint/types/minter_test.go +++ b/x/mint/types/minter_test.go @@ -75,18 +75,18 @@ func Test_ValidateMinter(t *testing.T) { totalMinted: DefaultInitialMinter().TotalMinted, expErr: true, }, - { - title: "norm time passed bigger then the minting schedule cap should return error", - normTimePassed: TotalMonths.Add(sdkmath.LegacyMustNewDecFromStr("0.1")), - totalMinted: DefaultInitialMinter().TotalMinted, - expErr: true, - }, - { - title: "total minted bigger then minting cap should return error", - normTimePassed: DefaultInitialMinter().NormTimePassed, - totalMinted: MintingCap.Add(sdkmath.NewUint(1)), - expErr: true, - }, + // { + // title: "norm time passed bigger then the minting schedule cap should return error", + // normTimePassed: TotalMonths.Add(sdkmath.LegacyMustNewDecFromStr("0.1")), + // totalMinted: DefaultInitialMinter().TotalMinted, + // expErr: true, + // }, + // { + // title: "total minted bigger then minting cap should return error", + // normTimePassed: DefaultInitialMinter().NormTimePassed, + // totalMinted: MintingCap.Add(sdkmath.NewUint(1)), + // expErr: true, + // }, { title: "total minted not fitting the minting schedule should return error", normTimePassed: sdkmath.LegacyMustNewDecFromStr("2.46020833"),