Skip to content

Commit

Permalink
feat: new minting formula
Browse files Browse the repository at this point in the history
  • Loading branch information
Lockwarr committed Oct 3, 2024
1 parent 435ff98 commit 6aba331
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 98 deletions.
52 changes: 33 additions & 19 deletions x/mint/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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))
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}
Expand All @@ -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)

Expand Down
72 changes: 36 additions & 36 deletions x/mint/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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)
}

Expand Down
65 changes: 34 additions & 31 deletions x/mint/types/minter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)
Expand Down Expand Up @@ -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)
}
Expand All @@ -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
Expand Down
24 changes: 12 additions & 12 deletions x/mint/types/minter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down

0 comments on commit 6aba331

Please sign in to comment.