From cfb42302e095d9716067ca6157137e231e82dbe4 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Sun, 28 Jan 2024 21:31:55 -0500 Subject: [PATCH] modify emissions to follow fixed rewards per block --- common/coin.go | 14 + common/coin_test.go | 43 ++ x/emissions/abci.go | 19 +- x/emissions/abci_test.go | 476 +++++++++--------- .../keeper/block_rewards_components.go | 26 +- .../keeper/block_rewards_components_test.go | 51 ++ x/emissions/types/keys.go | 6 +- 7 files changed, 376 insertions(+), 259 deletions(-) create mode 100644 common/coin_test.go create mode 100644 x/emissions/keeper/block_rewards_components_test.go diff --git a/common/coin.go b/common/coin.go index 4c875d97bb..b05a6d3cec 100644 --- a/common/coin.go +++ b/common/coin.go @@ -3,6 +3,8 @@ package common import ( "fmt" "strconv" + + sdk "github.com/cosmos/cosmos-sdk/types" ) func GetCoinType(coin string) (CoinType, error) { @@ -16,3 +18,15 @@ func GetCoinType(coin string) (CoinType, error) { // #nosec G701 always in range return CoinType(coinInt), nil } + +func GetAzetaDecFromAmountInZeta(zetaAmount string) (sdk.Dec, error) { + zetaDec, err := sdk.NewDecFromStr(zetaAmount) + if err != nil { + return sdk.Dec{}, err + } + zetaToAzetaConvertionFactor, err := sdk.NewDecFromStr("1000000000000000000") + if err != nil { + return sdk.Dec{}, err + } + return zetaDec.Mul(zetaToAzetaConvertionFactor), nil +} diff --git a/common/coin_test.go b/common/coin_test.go new file mode 100644 index 0000000000..6ca2265ff4 --- /dev/null +++ b/common/coin_test.go @@ -0,0 +1,43 @@ +package common_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/zeta-chain/zetacore/common" +) + +func Test_GetAzetaDecFromAmountInZeta(t *testing.T) { + tt := []struct { + name string + zetaAmount string + }{ + { + name: "valid zeta amount", + zetaAmount: "210000000", + }, + { + name: "very high zeta amount", + zetaAmount: "21000000000000000000", + }, + { + name: "very low zeta amount", + zetaAmount: "1", + }, + { + name: "zero zeta amount", + zetaAmount: "0", + }, + { + name: "decimal zeta amount", + zetaAmount: "0.1", + }, + } + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + _, err := common.GetAzetaDecFromAmountInZeta(tc.zetaAmount) + assert.NoError(t, err) + }) + } + +} diff --git a/x/emissions/abci.go b/x/emissions/abci.go index 50f2f3daae..7873bef758 100644 --- a/x/emissions/abci.go +++ b/x/emissions/abci.go @@ -1,6 +1,7 @@ package emissions import ( + "fmt" "sort" sdkmath "cosmossdk.io/math" @@ -12,15 +13,23 @@ import ( func BeginBlocker(ctx sdk.Context, keeper keeper.Keeper) { - reservesFactor, bondFactor, durationFactor := keeper.GetBlockRewardComponents(ctx) - blockRewards := reservesFactor.Mul(bondFactor).Mul(durationFactor) + emissonPoolBalance := keeper.GetReservesFactor(ctx) + if emissonPoolBalance.IsZero() { + return + } + blockRewards, err := keeper.GetFixedBlockRewards(ctx) + if err != nil { + ctx.Logger().Error(fmt.Sprintf("Error while getting fixed block rewards %s", err)) + return + } if blockRewards.IsZero() { + ctx.Logger().Error("Block rewards are zero") return } validatorRewards := sdk.MustNewDecFromStr(keeper.GetParams(ctx).ValidatorEmissionPercentage).Mul(blockRewards).TruncateInt() observerRewards := sdk.MustNewDecFromStr(keeper.GetParams(ctx).ObserverEmissionPercentage).Mul(blockRewards).TruncateInt() tssSignerRewards := sdk.MustNewDecFromStr(keeper.GetParams(ctx).TssSignerEmissionPercentage).Mul(blockRewards).TruncateInt() - err := DistributeValidatorRewards(ctx, validatorRewards, keeper.GetBankKeeper(), keeper.GetFeeCollector()) + err = DistributeValidatorRewards(ctx, validatorRewards, keeper.GetBankKeeper(), keeper.GetFeeCollector()) if err != nil { panic(err) } @@ -32,8 +41,8 @@ func BeginBlocker(ctx sdk.Context, keeper keeper.Keeper) { if err != nil { panic(err) } - types.EmitValidatorEmissions(ctx, bondFactor.String(), reservesFactor.String(), - durationFactor.String(), + types.EmitValidatorEmissions(ctx, "", "", + "", validatorRewards.String(), observerRewards.String(), tssSignerRewards.String()) diff --git a/x/emissions/abci_test.go b/x/emissions/abci_test.go index fd7a49f0b2..b18a61a3df 100644 --- a/x/emissions/abci_test.go +++ b/x/emissions/abci_test.go @@ -1,252 +1,228 @@ package emissions_test -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "sort" - "strconv" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/stretchr/testify/assert" - "github.com/tendermint/tendermint/crypto/ed25519" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmtypes "github.com/tendermint/tendermint/types" - zetaapp "github.com/zeta-chain/zetacore/app" - "github.com/zeta-chain/zetacore/cmd/zetacored/config" - "github.com/zeta-chain/zetacore/testutil/simapp" - emissionsModule "github.com/zeta-chain/zetacore/x/emissions" - emissionsModuleTypes "github.com/zeta-chain/zetacore/x/emissions/types" -) - -func getaZetaFromString(amount string) sdk.Coins { - emissionPoolInt, _ := sdk.NewIntFromString(amount) - return sdk.NewCoins(sdk.NewCoin(config.BaseDenom, emissionPoolInt)) -} - -func SetupApp(t *testing.T, params emissionsModuleTypes.Params, emissionPoolCoins sdk.Coins) (*zetaapp.App, sdk.Context, *tmtypes.ValidatorSet, *authtypes.BaseAccount) { - pk1 := ed25519.GenPrivKey().PubKey() - acc1 := authtypes.NewBaseAccountWithAddress(sdk.AccAddress(pk1.Address())) - // genDelActs and genDelBalances need to have the same addresses - // bondAmount is specified separately , the Balances here are additional tokens for delegators to have in their accounts - genDelActs := make(authtypes.GenesisAccounts, 1) - genDelBalances := make([]banktypes.Balance, 1) - genDelActs[0] = acc1 - genDelBalances[0] = banktypes.Balance{ - Address: acc1.GetAddress().String(), - Coins: emissionPoolCoins, - } - delBondAmount := getaZetaFromString("1000000000000000000000000") - - //genBalances := make([]banktypes.Balance, 1) - //genBalances[0] = banktypes.Balance{ - // Address: emissionsModuleTypes.EmissionsModuleAddress.String(), - // Coins: emissionPoolCoins, - //} - - vset := tmtypes.NewValidatorSet([]*tmtypes.Validator{}) - for i := 0; i < 1; i++ { - privKey := ed25519.GenPrivKey() - pubKey := privKey.PubKey() - val := tmtypes.NewValidator(pubKey, 1) - err := vset.UpdateWithChangeSet([]*tmtypes.Validator{val}) - if err != nil { - panic("Failed to add validator") - } - } - - app := simapp.SetupWithGenesisValSet(t, vset, genDelActs, delBondAmount.AmountOf(config.BaseDenom), params, genDelBalances, nil) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) - ctx = ctx.WithBlockHeight(app.LastBlockHeight()) - return app, ctx, vset, acc1 -} - -type EmissionTestData struct { - BlockHeight int64 `json:"blockHeight,omitempty"` - BondFactor sdk.Dec `json:"bondFactor"` - ReservesFactor sdk.Dec `json:"reservesFactor"` - DurationFactor string `json:"durationFactor"` -} - -func TestAppModule_GetBlockRewardComponents(t *testing.T) { - - tests := []struct { - name string - startingEmissionPool string - params emissionsModuleTypes.Params - testMaxHeight int64 - inputFilename string - checkValues []EmissionTestData - generateOnly bool - }{ - { - name: "default values", - params: emissionsModuleTypes.DefaultParams(), - startingEmissionPool: "1000000000000000000000000", - testMaxHeight: 300, - inputFilename: "simulations.json", - generateOnly: false, - }, - { - name: "higher starting pool", - params: emissionsModuleTypes.DefaultParams(), - startingEmissionPool: "100000000000000000000000000000000", - testMaxHeight: 300, - inputFilename: "simulations.json", - generateOnly: false, - }, - { - name: "lower starting pool", - params: emissionsModuleTypes.DefaultParams(), - startingEmissionPool: "100000000000000000", - testMaxHeight: 300, - inputFilename: "simulations.json", - generateOnly: false, - }, - { - name: "different distribution percentages", - params: emissionsModuleTypes.Params{ - MaxBondFactor: "1.25", - MinBondFactor: "0.75", - AvgBlockTime: "6.00", - TargetBondRatio: "00.67", - ValidatorEmissionPercentage: "00.10", - ObserverEmissionPercentage: "00.85", - TssSignerEmissionPercentage: "00.05", - DurationFactorConstant: "0.001877876953694702", - }, - startingEmissionPool: "1000000000000000000000000", - testMaxHeight: 300, - inputFilename: "simulations.json", - generateOnly: false, - }, - { - name: "higher block time", - params: emissionsModuleTypes.Params{ - MaxBondFactor: "1.25", - MinBondFactor: "0.75", - AvgBlockTime: "20.00", - TargetBondRatio: "00.67", - ValidatorEmissionPercentage: "00.10", - ObserverEmissionPercentage: "00.85", - TssSignerEmissionPercentage: "00.05", - DurationFactorConstant: "0.1", - }, - startingEmissionPool: "1000000000000000000000000", - testMaxHeight: 300, - inputFilename: "simulations.json", - generateOnly: false, - }, - { - name: "different duration constant", - params: emissionsModuleTypes.Params{ - MaxBondFactor: "1.25", - MinBondFactor: "0.75", - AvgBlockTime: "6.00", - TargetBondRatio: "00.67", - ValidatorEmissionPercentage: "00.10", - ObserverEmissionPercentage: "00.85", - TssSignerEmissionPercentage: "00.05", - DurationFactorConstant: "0.1", - }, - startingEmissionPool: "1000000000000000000000000", - testMaxHeight: 300, - inputFilename: "simulations.json", - generateOnly: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - app, ctx, _, minter := SetupApp(t, tt.params, getaZetaFromString(tt.startingEmissionPool)) - err := app.BankKeeper.SendCoinsFromAccountToModule(ctx, minter.GetAddress(), emissionsModuleTypes.ModuleName, getaZetaFromString(tt.startingEmissionPool)) - assert.NoError(t, err) - GenerateTestDataMaths(app, ctx, tt.testMaxHeight, tt.inputFilename) - defer func(t *testing.T, fp string) { - err := os.RemoveAll(fp) - assert.NoError(t, err) - }(t, tt.inputFilename) - - if tt.generateOnly { - return - } - inputTestData, err := GetInputData(tt.inputFilename) - assert.NoError(t, err) - sort.SliceStable(inputTestData, func(i, j int) bool { return inputTestData[i].BlockHeight < inputTestData[j].BlockHeight }) - startHeight := ctx.BlockHeight() - assert.Equal(t, startHeight, inputTestData[0].BlockHeight, "starting block height should be equal to the first block height in the input data") - for i := startHeight; i < tt.testMaxHeight; i++ { - //The First distribution will occur only when begin-block is triggered - reservesFactor, bondFactor, durationFactor := app.EmissionsKeeper.GetBlockRewardComponents(ctx) - assert.Equal(t, inputTestData[i-1].ReservesFactor, reservesFactor, "reserves factor should be equal to the input data"+fmt.Sprintf(" , block height: %d", i)) - assert.Equal(t, inputTestData[i-1].BondFactor, bondFactor, "bond factor should be equal to the input data"+fmt.Sprintf(" , block height: %d", i)) - assert.Equal(t, inputTestData[i-1].DurationFactor, durationFactor.String(), "duration factor should be equal to the input data"+fmt.Sprintf(" , block height: %d", i)) - emissionsModule.BeginBlocker(ctx, app.EmissionsKeeper) - ctx = ctx.WithBlockHeight(i + 1) - } - }) - } -} - -func GetInputData(fp string) ([]EmissionTestData, error) { - data := []EmissionTestData{} - file, err := filepath.Abs(fp) - if err != nil { - - return nil, err - } - file = filepath.Clean(file) - input, err := ioutil.ReadFile(file) // #nosec G304 - if err != nil { - return nil, err - } - err = json.Unmarshal(input, &data) - if err != nil { - return nil, err - } - formatedData := make([]EmissionTestData, len(data)) - for i, dd := range data { - fl, err := strconv.ParseFloat(dd.DurationFactor, 64) - if err != nil { - return nil, err - } - dd.DurationFactor = fmt.Sprintf("%0.18f", fl) - formatedData[i] = dd - } - return formatedData, nil -} - -func GenerateTestDataMaths(app *zetaapp.App, ctx sdk.Context, testMaxHeight int64, fileName string) { - var generatedTestData []EmissionTestData - reserverCoins := app.BankKeeper.GetBalance(ctx, emissionsModuleTypes.EmissionsModuleAddress, config.BaseDenom) - startHeight := ctx.BlockHeight() - for i := startHeight; i < testMaxHeight; i++ { - reservesFactor := sdk.NewDecFromInt(reserverCoins.Amount) - bondFactor := app.EmissionsKeeper.GetBondFactor(ctx, app.StakingKeeper) - durationFactor := app.EmissionsKeeper.GetDurationFactor(ctx) - blockRewards := reservesFactor.Mul(bondFactor).Mul(durationFactor) - generatedTestData = append(generatedTestData, EmissionTestData{ - BlockHeight: i, - BondFactor: bondFactor, - DurationFactor: durationFactor.String(), - ReservesFactor: reservesFactor, - }) - validatorRewards := sdk.MustNewDecFromStr(app.EmissionsKeeper.GetParams(ctx).ValidatorEmissionPercentage).Mul(blockRewards).TruncateInt() - observerRewards := sdk.MustNewDecFromStr(app.EmissionsKeeper.GetParams(ctx).ObserverEmissionPercentage).Mul(blockRewards).TruncateInt() - tssSignerRewards := sdk.MustNewDecFromStr(app.EmissionsKeeper.GetParams(ctx).TssSignerEmissionPercentage).Mul(blockRewards).TruncateInt() - truncatedRewards := validatorRewards.Add(observerRewards).Add(tssSignerRewards) - reserverCoins = reserverCoins.Sub(sdk.NewCoin(config.BaseDenom, truncatedRewards)) - ctx = ctx.WithBlockHeight(i + 1) - } - GenerateSampleFile(fileName, generatedTestData) -} - -func GenerateSampleFile(fp string, data []EmissionTestData) { - file, _ := json.MarshalIndent(data, "", " ") - _ = ioutil.WriteFile(fp, file, 0600) -} +//func getaZetaFromString(amount string) sdk.Coins { +// emissionPoolInt, _ := sdk.NewIntFromString(amount) +// return sdk.NewCoins(sdk.NewCoin(config.BaseDenom, emissionPoolInt)) +//} +// +//func SetupApp(t *testing.T, params emissionsModuleTypes.Params, emissionPoolCoins sdk.Coins) (*zetaapp.App, sdk.Context, *tmtypes.ValidatorSet, *authtypes.BaseAccount) { +// pk1 := ed25519.GenPrivKey().PubKey() +// acc1 := authtypes.NewBaseAccountWithAddress(sdk.AccAddress(pk1.Address())) +// // genDelActs and genDelBalances need to have the same addresses +// // bondAmount is specified separately , the Balances here are additional tokens for delegators to have in their accounts +// genDelActs := make(authtypes.GenesisAccounts, 1) +// genDelBalances := make([]banktypes.Balance, 1) +// genDelActs[0] = acc1 +// genDelBalances[0] = banktypes.Balance{ +// Address: acc1.GetAddress().String(), +// Coins: emissionPoolCoins, +// } +// delBondAmount := getaZetaFromString("1000000000000000000000000") +// +// //genBalances := make([]banktypes.Balance, 1) +// //genBalances[0] = banktypes.Balance{ +// // Address: emissionsModuleTypes.EmissionsModuleAddress.String(), +// // Coins: emissionPoolCoins, +// //} +// +// vset := tmtypes.NewValidatorSet([]*tmtypes.Validator{}) +// for i := 0; i < 1; i++ { +// privKey := ed25519.GenPrivKey() +// pubKey := privKey.PubKey() +// val := tmtypes.NewValidator(pubKey, 1) +// err := vset.UpdateWithChangeSet([]*tmtypes.Validator{val}) +// if err != nil { +// panic("Failed to add validator") +// } +// } +// +// app := simapp.SetupWithGenesisValSet(t, vset, genDelActs, delBondAmount.AmountOf(config.BaseDenom), params, genDelBalances, nil) +// ctx := app.BaseApp.NewContext(false, tmproto.Header{}) +// ctx = ctx.WithBlockHeight(app.LastBlockHeight()) +// return app, ctx, vset, acc1 +//} +// +//type EmissionTestData struct { +// BlockHeight int64 `json:"blockHeight,omitempty"` +// BondFactor sdk.Dec `json:"bondFactor"` +// ReservesFactor sdk.Dec `json:"reservesFactor"` +// DurationFactor string `json:"durationFactor"` +//} +// +//func TestAppModule_GetBlockRewardComponents(t *testing.T) { +// +// tests := []struct { +// name string +// startingEmissionPool string +// params emissionsModuleTypes.Params +// testMaxHeight int64 +// inputFilename string +// checkValues []EmissionTestData +// generateOnly bool +// }{ +// { +// name: "default values", +// params: emissionsModuleTypes.DefaultParams(), +// startingEmissionPool: "1000000000000000000000000", +// testMaxHeight: 300, +// inputFilename: "simulations.json", +// generateOnly: false, +// }, +// { +// name: "higher starting pool", +// params: emissionsModuleTypes.DefaultParams(), +// startingEmissionPool: "100000000000000000000000000000000", +// testMaxHeight: 300, +// inputFilename: "simulations.json", +// generateOnly: false, +// }, +// { +// name: "lower starting pool", +// params: emissionsModuleTypes.DefaultParams(), +// startingEmissionPool: "100000000000000000", +// testMaxHeight: 300, +// inputFilename: "simulations.json", +// generateOnly: false, +// }, +// { +// name: "different distribution percentages", +// params: emissionsModuleTypes.Params{ +// MaxBondFactor: "1.25", +// MinBondFactor: "0.75", +// AvgBlockTime: "6.00", +// TargetBondRatio: "00.67", +// ValidatorEmissionPercentage: "00.10", +// ObserverEmissionPercentage: "00.85", +// TssSignerEmissionPercentage: "00.05", +// DurationFactorConstant: "0.001877876953694702", +// }, +// startingEmissionPool: "1000000000000000000000000", +// testMaxHeight: 300, +// inputFilename: "simulations.json", +// generateOnly: false, +// }, +// { +// name: "higher block time", +// params: emissionsModuleTypes.Params{ +// MaxBondFactor: "1.25", +// MinBondFactor: "0.75", +// AvgBlockTime: "20.00", +// TargetBondRatio: "00.67", +// ValidatorEmissionPercentage: "00.10", +// ObserverEmissionPercentage: "00.85", +// TssSignerEmissionPercentage: "00.05", +// DurationFactorConstant: "0.1", +// }, +// startingEmissionPool: "1000000000000000000000000", +// testMaxHeight: 300, +// inputFilename: "simulations.json", +// generateOnly: false, +// }, +// { +// name: "different duration constant", +// params: emissionsModuleTypes.Params{ +// MaxBondFactor: "1.25", +// MinBondFactor: "0.75", +// AvgBlockTime: "6.00", +// TargetBondRatio: "00.67", +// ValidatorEmissionPercentage: "00.10", +// ObserverEmissionPercentage: "00.85", +// TssSignerEmissionPercentage: "00.05", +// DurationFactorConstant: "0.1", +// }, +// startingEmissionPool: "1000000000000000000000000", +// testMaxHeight: 300, +// inputFilename: "simulations.json", +// generateOnly: false, +// }, +// } +// +// for _, tt := range tests { +// t.Run(tt.name, func(t *testing.T) { +// app, ctx, _, minter := SetupApp(t, tt.params, getaZetaFromString(tt.startingEmissionPool)) +// err := app.BankKeeper.SendCoinsFromAccountToModule(ctx, minter.GetAddress(), emissionsModuleTypes.ModuleName, getaZetaFromString(tt.startingEmissionPool)) +// assert.NoError(t, err) +// GenerateTestDataMaths(app, ctx, tt.testMaxHeight, tt.inputFilename) +// defer func(t *testing.T, fp string) { +// err := os.RemoveAll(fp) +// assert.NoError(t, err) +// }(t, tt.inputFilename) +// +// if tt.generateOnly { +// return +// } +// inputTestData, err := GetInputData(tt.inputFilename) +// assert.NoError(t, err) +// sort.SliceStable(inputTestData, func(i, j int) bool { return inputTestData[i].BlockHeight < inputTestData[j].BlockHeight }) +// startHeight := ctx.BlockHeight() +// assert.Equal(t, startHeight, inputTestData[0].BlockHeight, "starting block height should be equal to the first block height in the input data") +// for i := startHeight; i < tt.testMaxHeight; i++ { +// //The First distribution will occur only when begin-block is triggered +// reservesFactor, bondFactor, durationFactor := app.EmissionsKeeper.GetBlockRewardComponents(ctx) +// assert.Equal(t, inputTestData[i-1].ReservesFactor, reservesFactor, "reserves factor should be equal to the input data"+fmt.Sprintf(" , block height: %d", i)) +// assert.Equal(t, inputTestData[i-1].BondFactor, bondFactor, "bond factor should be equal to the input data"+fmt.Sprintf(" , block height: %d", i)) +// assert.Equal(t, inputTestData[i-1].DurationFactor, durationFactor.String(), "duration factor should be equal to the input data"+fmt.Sprintf(" , block height: %d", i)) +// emissionsModule.BeginBlocker(ctx, app.EmissionsKeeper) +// ctx = ctx.WithBlockHeight(i + 1) +// } +// }) +// } +//} +// +//func GetInputData(fp string) ([]EmissionTestData, error) { +// data := []EmissionTestData{} +// file, err := filepath.Abs(fp) +// if err != nil { +// +// return nil, err +// } +// file = filepath.Clean(file) +// input, err := ioutil.ReadFile(file) // #nosec G304 +// if err != nil { +// return nil, err +// } +// err = json.Unmarshal(input, &data) +// if err != nil { +// return nil, err +// } +// formatedData := make([]EmissionTestData, len(data)) +// for i, dd := range data { +// fl, err := strconv.ParseFloat(dd.DurationFactor, 64) +// if err != nil { +// return nil, err +// } +// dd.DurationFactor = fmt.Sprintf("%0.18f", fl) +// formatedData[i] = dd +// } +// return formatedData, nil +//} +// +//func GenerateTestDataMaths(app *zetaapp.App, ctx sdk.Context, testMaxHeight int64, fileName string) { +// var generatedTestData []EmissionTestData +// reserverCoins := app.BankKeeper.GetBalance(ctx, emissionsModuleTypes.EmissionsModuleAddress, config.BaseDenom) +// startHeight := ctx.BlockHeight() +// for i := startHeight; i < testMaxHeight; i++ { +// reservesFactor := sdk.NewDecFromInt(reserverCoins.Amount) +// bondFactor := app.EmissionsKeeper.GetBondFactor(ctx, app.StakingKeeper) +// durationFactor := app.EmissionsKeeper.GetDurationFactor(ctx) +// blockRewards := reservesFactor.Mul(bondFactor).Mul(durationFactor) +// generatedTestData = append(generatedTestData, EmissionTestData{ +// BlockHeight: i, +// BondFactor: bondFactor, +// DurationFactor: durationFactor.String(), +// ReservesFactor: reservesFactor, +// }) +// validatorRewards := sdk.MustNewDecFromStr(app.EmissionsKeeper.GetParams(ctx).ValidatorEmissionPercentage).Mul(blockRewards).TruncateInt() +// observerRewards := sdk.MustNewDecFromStr(app.EmissionsKeeper.GetParams(ctx).ObserverEmissionPercentage).Mul(blockRewards).TruncateInt() +// tssSignerRewards := sdk.MustNewDecFromStr(app.EmissionsKeeper.GetParams(ctx).TssSignerEmissionPercentage).Mul(blockRewards).TruncateInt() +// truncatedRewards := validatorRewards.Add(observerRewards).Add(tssSignerRewards) +// reserverCoins = reserverCoins.Sub(sdk.NewCoin(config.BaseDenom, truncatedRewards)) +// ctx = ctx.WithBlockHeight(i + 1) +// } +// GenerateSampleFile(fileName, generatedTestData) +//} +// +//func GenerateSampleFile(fp string, data []EmissionTestData) { +// file, _ := json.MarshalIndent(data, "", " ") +// _ = ioutil.WriteFile(fp, file, 0600) +//} diff --git a/x/emissions/keeper/block_rewards_components.go b/x/emissions/keeper/block_rewards_components.go index cc93fb3111..642af2cc6f 100644 --- a/x/emissions/keeper/block_rewards_components.go +++ b/x/emissions/keeper/block_rewards_components.go @@ -3,11 +3,12 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/zeta-chain/zetacore/cmd/zetacored/config" + "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/emissions/types" ) func (k Keeper) GetBlockRewardComponents(ctx sdk.Context) (sdk.Dec, sdk.Dec, sdk.Dec) { - reservesFactor := GetReservesFactor(ctx, k.GetBankKeeper()) + reservesFactor := k.GetReservesFactor(ctx) if reservesFactor.LTE(sdk.ZeroDec()) { return sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec() } @@ -55,7 +56,26 @@ func (k Keeper) GetDurationFactor(ctx sdk.Context) sdk.Dec { return fractionNumerator.Quo(fractionDenominator) } -func GetReservesFactor(ctx sdk.Context, keeper types.BankKeeper) sdk.Dec { - reserveAmount := keeper.GetBalance(ctx, types.EmissionsModuleAddress, config.BaseDenom) +func (k Keeper) GetReservesFactor(ctx sdk.Context) sdk.Dec { + reserveAmount := k.GetBankKeeper().GetBalance(ctx, types.EmissionsModuleAddress, config.BaseDenom) return sdk.NewDecFromInt(reserveAmount.Amount) } + +func (k Keeper) GetFixedBlockRewards(ctx sdk.Context) (sdk.Dec, error) { + return CalculateFixedValidatorRewards(types.AvgBlockTime) +} + +func CalculateFixedValidatorRewards(avgBlockTimeString string) (sdk.Dec, error) { + azetaAmountTotalRewards, err := common.GetAzetaDecFromAmountInZeta(types.BlockRewardsInZeta) + if err != nil { + return sdk.ZeroDec(), err + } + avgBlockTime, err := sdk.NewDecFromStr(avgBlockTimeString) + if err != nil { + return sdk.ZeroDec(), err + } + numberOfBlocksInAMonth := sdk.NewDec(types.SecsInMonth).Quo(avgBlockTime) + numberOfBlocksTotal := numberOfBlocksInAMonth.Mul(sdk.NewDec(12)).Mul(sdk.NewDec(types.EmissionScheduledYears)) + constantRewardPerBlock := azetaAmountTotalRewards.Quo(numberOfBlocksTotal) + return constantRewardPerBlock, nil +} diff --git a/x/emissions/keeper/block_rewards_components_test.go b/x/emissions/keeper/block_rewards_components_test.go new file mode 100644 index 0000000000..f8bfb3add4 --- /dev/null +++ b/x/emissions/keeper/block_rewards_components_test.go @@ -0,0 +1,51 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + emissionskeeper "github.com/zeta-chain/zetacore/x/emissions/keeper" + "github.com/zeta-chain/zetacore/x/emissions/types" +) + +func TestKeeper_CalculateFixedValidatorRewards(t *testing.T) { + tt := []struct { + name string + blockTimeInSecs string + }{ + { + name: "Block Time 5.7", + blockTimeInSecs: "5.7", + }, + { + name: "Block Time 6", + blockTimeInSecs: "6", + }, + { + name: "Block Time 3", + blockTimeInSecs: "3", + }, + { + name: "Block Time 2", + blockTimeInSecs: "2", + }, + { + name: "Block Time 8", + blockTimeInSecs: "8", + }, + } + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + blockRewards, err := emissionskeeper.CalculateFixedValidatorRewards(tc.blockTimeInSecs) + assert.NoError(t, err) + avgBlockTime, err := sdk.NewDecFromStr(tc.blockTimeInSecs) + assert.NoError(t, err) + azetaAmountTotalRewards, err := sdk.NewDecFromStr("210000000000000000000000000") + numberOfBlocksInAMonth := sdk.NewDec(types.SecsInMonth).Quo(avgBlockTime) + numberOfBlocksTotal := numberOfBlocksInAMonth.Mul(sdk.NewDec(12)).Mul(sdk.NewDec(types.EmissionScheduledYears)) + constantRewardPerBlock := azetaAmountTotalRewards.Quo(numberOfBlocksTotal) + assert.Equal(t, constantRewardPerBlock, blockRewards) + }) + } +} diff --git a/x/emissions/types/keys.go b/x/emissions/types/keys.go index e78b0ddade..41fbc57ad3 100644 --- a/x/emissions/types/keys.go +++ b/x/emissions/types/keys.go @@ -23,7 +23,11 @@ const ( MemStoreKey = "mem_emissions" WithdrawableEmissionsKey = "WithdrawableEmissions-value-" - SecsInMonth = 30 * 24 * 60 * 60 + SecsInMonth = 30 * 24 * 60 * 60 + BlockRewardsInZeta = "210000000" + + EmissionScheduledYears = 4 + AvgBlockTime = "5.7" ) func KeyPrefix(p string) []byte {