From 9a15947d797cfb8ac2fda46bb4389515ebb2614e Mon Sep 17 00:00:00 2001 From: shreyasbhat0 Date: Fri, 27 Sep 2024 19:21:34 +0530 Subject: [PATCH] feat: update validator token allocation --- app/app.go | 20 ++++++- app/genesis.go | 22 ++++++- x/arkeo/keeper/keeper.go | 105 ++++++++++++++++++++------------- x/arkeo/keeper/manager.go | 69 ++++++++++++---------- x/arkeo/keeper/manager_test.go | 32 +++++----- 5 files changed, 156 insertions(+), 92 deletions(-) diff --git a/app/app.go b/app/app.go index 26a74819..65c61b64 100644 --- a/app/app.go +++ b/app/app.go @@ -12,6 +12,7 @@ import ( autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" clienthelpers "cosmossdk.io/client/v2/helpers" + "cosmossdk.io/math" runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services" "github.com/cosmos/cosmos-sdk/std" "github.com/cosmos/gogoproto/proto" @@ -620,7 +621,7 @@ func NewArkeoApp( groupmodule.NewAppModule(appCodec, app.Keepers.GroupKeeper, app.Keepers.AccountKeeper, app.Keepers.BankKeeper, app.interfaceRegistry), crisis.NewAppModule(&app.Keepers.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), gov.NewAppModule(appCodec, app.Keepers.GovKeeper, app.Keepers.AccountKeeper, app.Keepers.BankKeeper, app.GetSubspace(govtypes.ModuleName)), - mint.NewAppModule(appCodec, app.Keepers.MintKeeper, app.Keepers.AccountKeeper, minttypes.DefaultInflationCalculationFn, app.GetSubspace(minttypes.ModuleName)), + mint.NewAppModule(appCodec, app.Keepers.MintKeeper, app.Keepers.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)), slashing.NewAppModule(appCodec, app.Keepers.SlashingKeeper, app.Keepers.AccountKeeper, app.Keepers.BankKeeper, app.Keepers.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName), app.interfaceRegistry), distr.NewAppModule(appCodec, app.Keepers.DistrKeeper, app.Keepers.AccountKeeper, app.Keepers.BankKeeper, app.Keepers.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), staking.NewAppModule(appCodec, app.Keepers.StakingKeeper, app.Keepers.AccountKeeper, app.Keepers.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), @@ -760,7 +761,7 @@ func NewArkeoApp( capability.NewAppModule(appCodec, *app.Keepers.CapabilityKeeper, false), feegrantmodule.NewAppModule(appCodec, app.Keepers.AccountKeeper, app.Keepers.BankKeeper, app.Keepers.FeeGrantKeeper, app.interfaceRegistry), gov.NewAppModule(appCodec, app.Keepers.GovKeeper, app.Keepers.AccountKeeper, app.Keepers.BankKeeper, app.GetSubspace(govtypes.ModuleName)), - mint.NewAppModule(appCodec, app.Keepers.MintKeeper, app.Keepers.AccountKeeper, minttypes.DefaultInflationCalculationFn, app.GetSubspace(minttypes.ModuleName)), + mint.NewAppModule(appCodec, app.Keepers.MintKeeper, app.Keepers.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)), staking.NewAppModule(appCodec, app.Keepers.StakingKeeper, app.Keepers.AccountKeeper, app.Keepers.BankKeeper, app.GetSubspace(stakingtypes.ModuleName)), distr.NewAppModule(appCodec, app.Keepers.DistrKeeper, app.Keepers.AccountKeeper, app.Keepers.BankKeeper, app.Keepers.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)), slashing.NewAppModule(appCodec, app.Keepers.SlashingKeeper, app.Keepers.AccountKeeper, app.Keepers.BankKeeper, app.Keepers.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName), app.interfaceRegistry), @@ -852,6 +853,21 @@ func (app *ArkeoApp) InitChainer(ctx sdk.Context, req *abci.RequestInitChain) (* if err != nil { panic(err) } + mintGen := minttypes.GenesisState{ + Minter: minttypes.Minter{ + Inflation: math.LegacyMustNewDecFromStr("0.000000000000000000"), + AnnualProvisions: math.LegacyMustNewDecFromStr("0.000000000000000000"), + }, + Params: minttypes.Params{ + MintDenom: "uarkeo", + InflationRateChange: math.LegacyMustNewDecFromStr("0.000000000000000000"), + InflationMax: math.LegacyMustNewDecFromStr("0.000000000000000000"), + InflationMin: math.LegacyMustNewDecFromStr("0.000000000000000000"), + GoalBonded: math.LegacyNewDec(670000000000000000), + BlocksPerYear: 5256666, + }, + } + genesisState[minttypes.ModuleName] = app.cdc.MustMarshalJSON(&mintGen) return app.mm.InitGenesis(ctx, app.appCodec, genesisState) } diff --git a/app/genesis.go b/app/genesis.go index 5bf0c1da..399e3f17 100644 --- a/app/genesis.go +++ b/app/genesis.go @@ -3,7 +3,9 @@ package app import ( "encoding/json" + "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/codec" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" ) // The genesis state of the blockchain is represented here as a map of raw json @@ -17,5 +19,23 @@ type GenesisState map[string]json.RawMessage // NewDefaultGenesisState generates the default state for the application. func NewDefaultGenesisState(cdc codec.JSONCodec) GenesisState { - return ModuleBasics.DefaultGenesis(cdc) + defaultGenesis := ModuleBasics.DefaultGenesis(cdc) + // set mint module params for genesis state + mintGen := minttypes.GenesisState{ + Minter: minttypes.Minter{ + Inflation: math.LegacyMustNewDecFromStr("0.000000000000000000"), + AnnualProvisions: math.LegacyMustNewDecFromStr("0.000000000000000000"), + }, + Params: minttypes.Params{ + MintDenom: "uarkeo", + InflationRateChange: math.LegacyMustNewDecFromStr("0.000000000000000000"), + InflationMax: math.LegacyMustNewDecFromStr("0.000000000000000000"), + InflationMin: math.LegacyMustNewDecFromStr("0.000000000000000000"), + GoalBonded: math.LegacyNewDec(670000000000000000), + BlocksPerYear: 5256666, + }, + } + defaultGenesis[minttypes.ModuleName] = cdc.MustMarshalJSON(&mintGen) + + return defaultGenesis } diff --git a/x/arkeo/keeper/keeper.go b/x/arkeo/keeper/keeper.go index b5d1eaa5..f3335d17 100644 --- a/x/arkeo/keeper/keeper.go +++ b/x/arkeo/keeper/keeper.go @@ -63,10 +63,12 @@ type Keeper interface { GetActiveValidators(ctx cosmos.Context) ([]stakingtypes.Validator, error) GetAccount(ctx cosmos.Context, addr cosmos.AccAddress) cosmos.Account StakingSetParams(ctx cosmos.Context, params stakingtypes.Params) error - MintAndDistributeTokens(ctx cosmos.Context, newlyMinted cosmos.Coin) (cosmos.Coin, error) - GetCirculatingSupply(ctx cosmos.Context, denom string) (cosmos.Coin, error) - GetInflationRate(ctx cosmos.Context) (math.LegacyDec, error) + MintAndDistributeTokens(ctx cosmos.Context, newlyMinted sdk.DecCoin) (sdk.DecCoin, error) + GetCirculatingSupply(ctx cosmos.Context, denom string) (sdk.DecCoin, error) + GetInflationRate(ctx cosmos.Context) math.LegacyDec MoveTokensFromDistributionToFoundationPoolAccount(ctx cosmos.Context) error + AllocateTokensToValidator(ctx context.Context, val stakingtypes.ValidatorI, tokens sdk.DecCoins) error + BurnCoins(ctx context.Context, moduleName string, coins sdk.Coins) error // Query Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) @@ -382,114 +384,125 @@ func (k KVStore) GetAuthority() string { return k.authority } -func (k KVStore) GetCirculatingSupply(ctx cosmos.Context, denom string) (cosmos.Coin, error) { +func (k KVStore) GetCirculatingSupply(ctx cosmos.Context, denom string) (sdk.DecCoin, error) { sdkContext := sdk.UnwrapSDKContext(ctx) // Get Total Supply - fullTokenSupply, err := k.coinKeeper.TotalSupply(ctx, &banktypes.QueryTotalSupplyRequest{}) + fullTokenSupply, err := k.coinKeeper.SupplyOf(ctx, &banktypes.QuerySupplyOfRequest{Denom: configs.Denom}) if err != nil { sdkContext.Logger().Error("Failed to get full token supply data", err) - return cosmos.NewCoin(denom, sdkmath.NewInt(0)), err + return sdk.NewDecCoin(denom, sdkmath.NewInt(0)), err } - totalSupply := fullTokenSupply.Supply.AmountOf(configs.Denom) + totalSupply := fullTokenSupply.GetAmount().Amount + + sdkContext.Logger().Info(fmt.Sprintf("TotalSupply %v", totalSupply)) // Get the account addresses whose balances need to be exempted devAccountAddress, err := k.getFoundationDevAccountAddress() if err != nil { - return cosmos.NewCoin(denom, sdkmath.NewInt(0)), fmt.Errorf("failed to fetch foundational account %s", err) + return sdk.NewDecCoin(denom, sdkmath.NewInt(0)), fmt.Errorf("failed to fetch foundational account %s", err) } communityAccountAddress, err := k.getFoundationCommunityAccountAddress() if err != nil { - return cosmos.NewCoin(denom, sdkmath.NewInt(0)), fmt.Errorf("failed to fetch foundational account %s", err) + return sdk.NewDecCoin(denom, sdkmath.NewInt(0)), fmt.Errorf("failed to fetch foundational account %s", err) } grantAccountAddress, err := k.getFoundationGrantsAccountAddress() if err != nil { - return cosmos.NewCoin(denom, sdkmath.NewInt(0)), fmt.Errorf("failed to fetch foundational account %s", err) + return sdk.NewDecCoin(denom, sdkmath.NewInt(0)), fmt.Errorf("failed to fetch foundational account %s", err) } - // Module Address for which the circulating supply should be exempted - moduleAddressToExempt := []sdk.AccAddress{ + // Account Address for which the circulating supply should be exempted + addressToExempt := []sdk.AccAddress{ devAccountAddress, communityAccountAddress, grantAccountAddress, + k.stakingKeeper.GetBondedPool(ctx).GetAddress(), + k.GetModuleAccAddress(types.ModuleName), + k.GetModuleAccAddress("claimarkeo"), } exemptBalance := cosmos.NewInt(0) - // range over the module and create exempt balances - for _, moduleAddress := range moduleAddressToExempt { - moduleBalance := k.coinKeeper.GetBalance(ctx, moduleAddress, denom) - exemptBalance = exemptBalance.Add(moduleBalance.Amount) + sdkContext.Logger().Info("Starting to calculate exempt balances") + + // Range over the module accounts to create exempt balances + for _, address := range addressToExempt { + moduleBalance := k.coinKeeper.GetBalance(ctx, address, denom) + sdkContext.Logger().Info(fmt.Sprintf("Module address: %v, Balance: %v %v", address.String(), moduleBalance.Amount, denom)) + + if !moduleBalance.IsZero() { + exemptBalance = exemptBalance.Add(moduleBalance.Amount) + } else { + sdkContext.Logger().Info(fmt.Sprintf("Module address: %v has zero balance for denom: %v", address.String(), denom)) + } } - // total supply without balances of exempted module circulatingSupply := totalSupply.Sub(exemptBalance) + sdkContext.Logger().Info(fmt.Sprintf("Total supply %v exempted balance %v, final balance %v", totalSupply, exemptBalance, circulatingSupply)) - return cosmos.NewCoin(denom, circulatingSupply), nil + return sdk.NewDecCoin(denom, circulatingSupply), nil } -func (k KVStore) MintAndDistributeTokens(ctx cosmos.Context, newlyMinted cosmos.Coin) (sdk.Coin, error) { +func (k KVStore) MintAndDistributeTokens(ctx cosmos.Context, newlyMinted sdk.DecCoin) (sdk.DecCoin, error) { sdkContext := sdk.UnwrapSDKContext(ctx) params := k.GetParams(ctx) newlyMintedAmount := newlyMinted.Amount // mint newly added tokens to reserve - if err := k.MintToModule(ctx, types.ModuleName, newlyMinted); err != nil { + if err := k.MintToModule(ctx, types.ModuleName, sdk.NewCoin(newlyMinted.Denom, newlyMinted.Amount.RoundInt())); err != nil { sdkContext.Logger().Error(fmt.Sprintf("failed to mint %s", err)) - return cosmos.NewCoin(newlyMinted.Denom, sdkmath.NewInt(0)), err + return sdk.NewDecCoin(newlyMinted.Denom, sdkmath.NewInt(0)), err } - devFundAmount := newlyMintedAmount.Mul(params.DevFundPercentage).Quo(sdkmath.NewInt(100)) - communityPoolAmount := newlyMintedAmount.Mul(params.CommunityPoolPercentage).Quo(sdkmath.NewInt(100)) - grantFundAmount := newlyMintedAmount.Mul(params.GrantFundPercentage).Quo(sdkmath.NewInt(100)) + devFundAmount := newlyMintedAmount.Mul(params.DevFundPercentage.ToLegacyDec()).Quo(sdkmath.NewInt(100).ToLegacyDec()) + communityPoolAmount := newlyMintedAmount.Mul(params.CommunityPoolPercentage.ToLegacyDec()).Quo(sdkmath.NewInt(100).ToLegacyDec()) + grantFundAmount := newlyMintedAmount.Mul(params.GrantFundPercentage.ToLegacyDec()).Quo(sdkmath.NewInt(100).ToLegacyDec()) devAccountAddress, err := k.getFoundationDevAccountAddress() if err != nil { sdkContext.Logger().Error(fmt.Sprintf("failed to fetch foundational account %s", err)) - return cosmos.NewCoin(newlyMinted.Denom, sdkmath.NewInt(0)), fmt.Errorf("failed to fetch foundational account %s", err) + return sdk.NewDecCoin(newlyMinted.Denom, sdkmath.NewInt(0)), fmt.Errorf("failed to fetch foundational account %s", err) } communityAccountAddress, err := k.getFoundationCommunityAccountAddress() if err != nil { sdkContext.Logger().Error(fmt.Sprintf("failed to fetch foundational account %s", err)) - return cosmos.NewCoin(newlyMinted.Denom, sdkmath.NewInt(0)), fmt.Errorf("failed to fetch foundational account %s", err) + return sdk.NewDecCoin(newlyMinted.Denom, sdkmath.NewInt(0)), fmt.Errorf("failed to fetch foundational account %s", err) } grantAccountAddress, err := k.getFoundationGrantsAccountAddress() if err != nil { sdkContext.Logger().Error(fmt.Sprintf("failed to fetch foundational account %s", err)) - return cosmos.NewCoin(newlyMinted.Denom, sdkmath.NewInt(0)), fmt.Errorf("failed to fetch foundational account %s", err) + return sdk.NewDecCoin(newlyMinted.Denom, sdkmath.NewInt(0)), fmt.Errorf("failed to fetch foundational account %s", err) } - if err := k.SendFromModuleToAccount(ctx, types.ModuleName, devAccountAddress, cosmos.NewCoins(cosmos.NewCoin(newlyMinted.Denom, devFundAmount))); err != nil { + if err := k.SendFromModuleToAccount(ctx, types.ModuleName, devAccountAddress, cosmos.NewCoins(cosmos.NewCoin(newlyMinted.Denom, devFundAmount.RoundInt()))); err != nil { sdkContext.Logger().Error(fmt.Sprintf("failed to send amount to Dev foundational account %s", err)) - return cosmos.NewCoin(newlyMinted.Denom, sdkmath.NewInt(0)), fmt.Errorf("error sending amount to module %s", err) + return sdk.NewDecCoin(newlyMinted.Denom, sdkmath.NewInt(0)), fmt.Errorf("error sending amount to module %s", err) } - if err := k.SendFromModuleToAccount(ctx, types.ModuleName, communityAccountAddress, cosmos.NewCoins(cosmos.NewCoin(newlyMinted.Denom, communityPoolAmount))); err != nil { + if err := k.SendFromModuleToAccount(ctx, types.ModuleName, communityAccountAddress, cosmos.NewCoins(cosmos.NewCoin(newlyMinted.Denom, communityPoolAmount.RoundInt()))); err != nil { sdkContext.Logger().Error(fmt.Sprintf("failed to send amount to Community foundational account %s", err)) - return cosmos.NewCoin(newlyMinted.Denom, sdkmath.NewInt(0)), fmt.Errorf("error sending amount to module %s", err) + return sdk.NewDecCoin(newlyMinted.Denom, sdkmath.NewInt(0)), fmt.Errorf("error sending amount to module %s", err) } - if err := k.SendFromModuleToAccount(ctx, types.ModuleName, grantAccountAddress, cosmos.NewCoins(cosmos.NewCoin(newlyMinted.Denom, grantFundAmount))); err != nil { + if err := k.SendFromModuleToAccount(ctx, types.ModuleName, grantAccountAddress, cosmos.NewCoins(cosmos.NewCoin(newlyMinted.Denom, grantFundAmount.RoundInt()))); err != nil { sdkContext.Logger().Error(fmt.Sprintf("failed to send amount to Grant foundational account %s", err)) - return cosmos.NewCoin(newlyMinted.Denom, sdkmath.NewInt(0)), fmt.Errorf("error sending amount to module %s", err) + return sdk.NewDecCoin(newlyMinted.Denom, sdkmath.NewInt(0)), fmt.Errorf("error sending amount to module %s", err) } balance := newlyMintedAmount.Sub(devFundAmount).Sub(communityPoolAmount).Sub(grantFundAmount) - return cosmos.NewCoin(newlyMinted.Denom, balance), nil + return sdk.NewDecCoin(newlyMinted.Denom, balance.RoundInt()), nil } -func (k KVStore) GetInflationRate(ctx cosmos.Context) (math.LegacyDec, error) { - minter, err := k.mintKeeper.Minter.Get(ctx) - if err != nil { - return math.LegacyNewDec(0), err - } +func (k KVStore) GetInflationRate(ctx cosmos.Context) math.LegacyDec { + + params := k.GetParams(ctx) - return minter.Inflation, nil + return params.InflationChangePercentage.ToLegacyDec() } // transfer tokens form the Distribution to Foundation Community Pool @@ -506,7 +519,7 @@ func (k KVStore) MoveTokensFromDistributionToFoundationPoolAccount(ctx cosmos.Co return fmt.Errorf("failed to fetch foundational account %s", err) } - if amount.RoundInt64() > 0 { + if !amount.IsZero() { if err := k.distributionKeeper.DistributeFromFeePool(ctx, cosmos.NewCoins(cosmos.NewCoin(configs.Denom, amount.RoundInt())), communityAccountAddress); err != nil { if err.Error() == "community pool does not have sufficient coins to distribute" { ctx.Logger().Info(fmt.Sprintf("%s", err)) @@ -516,7 +529,9 @@ func (k KVStore) MoveTokensFromDistributionToFoundationPoolAccount(ctx cosmos.Co return err } } + } + return nil } @@ -531,3 +546,11 @@ func (k KVStore) getFoundationCommunityAccountAddress() (cosmos.AccAddress, erro func (k KVStore) getFoundationGrantsAccountAddress() (cosmos.AccAddress, error) { return sdk.AccAddressFromBech32(types.FoundationGrantsAccount) } + +func (k KVStore) AllocateTokensToValidator(ctx context.Context, val stakingtypes.ValidatorI, tokens sdk.DecCoins) error { + return k.distributionKeeper.AllocateTokensToValidator(ctx, val, tokens) +} + +func (k KVStore) BurnCoins(ctx context.Context, moduleName string, coins sdk.Coins) error { + return k.coinKeeper.BurnCoins(ctx, moduleName, coins) +} diff --git a/x/arkeo/keeper/manager.go b/x/arkeo/keeper/manager.go index d12d4bb5..d2eacf2d 100644 --- a/x/arkeo/keeper/manager.go +++ b/x/arkeo/keeper/manager.go @@ -36,7 +36,6 @@ func (mgr *Manager) BeginBlock(ctx cosmos.Context) error { if err != nil { return err } - ctx.Logger().Info(fmt.Sprintf("current version :%s", swVersion)) if ver > swVersion { panic( fmt.Sprintf("Unsupported Version: update your binary (your version: %d, network consensus version: %d)", @@ -72,13 +71,13 @@ func (mgr *Manager) BeginBlock(ctx cosmos.Context) error { ctx.Logger().Error("unable to send tokens from distribution to pool account", "error", err) } - validatorPayoutCycle := mgr.FetchConfig(ctx, configs.ValidatorPayoutCycle) + validatorPayoutCycle := sdkmath.LegacyNewDec(mgr.FetchConfig(ctx, configs.ValidatorPayoutCycle)) - emissionCurve := mgr.FetchConfig(ctx, configs.EmissionCurve) // Emission curve factor - blocksPerYear := mgr.FetchConfig(ctx, configs.BlocksPerYear) + emissionCurve := sdkmath.LegacyNewDec(mgr.FetchConfig(ctx, configs.EmissionCurve)) // Emission curve factor + blocksPerYear := sdkmath.LegacyNewDec(mgr.FetchConfig(ctx, configs.BlocksPerYear)) // Calculate Block Rewards - blockReward := mgr.calcBlockReward(ctx, circSupply.Amount.ToLegacyDec().RoundInt64(), emissionCurve, blocksPerYear, validatorPayoutCycle) + blockReward := mgr.calcBlockReward(ctx, circSupply.Amount, emissionCurve, blocksPerYear, validatorPayoutCycle) ctx.Logger().Info(fmt.Sprintf("Block Reward %v", blockReward)) // Distribute Minted To Pools @@ -221,7 +220,7 @@ func (mgr Manager) ContractEndBlock(ctx cosmos.Context) error { // units = U / (T / t) // Since the development goal at the moment is to get this chain up and // running, we can save this optimization for another day. -func (mgr Manager) ValidatorPayout(ctx cosmos.Context, votes []abci.VoteInfo, blockReward cosmos.Coin) error { +func (mgr Manager) ValidatorPayout(ctx cosmos.Context, votes []abci.VoteInfo, blockReward sdk.DecCoin) error { if blockReward.IsZero() { return nil } @@ -242,6 +241,7 @@ func (mgr Manager) ValidatorPayout(ctx cosmos.Context, votes []abci.VoteInfo, bl if total.IsZero() { return nil } + totalAllocated := cosmos.ZeroInt() for _, vote := range votes { if vote.BlockIdFlag.String() == "BLOCK_ID_FLAG_ABSENT" || vote.BlockIdFlag.String() == "BLOCK_ID_FLAG_UNKNOWN" { @@ -271,7 +271,7 @@ func (mgr Manager) ValidatorPayout(ctx cosmos.Context, votes []abci.VoteInfo, bl } acc := cosmos.AccAddress(val.GetOperator()) - totalReward := common.GetSafeShare(val.GetDelegatorShares().RoundInt(), total, blockReward.Amount) + totalReward := common.GetSafeShare(val.GetDelegatorShares().RoundInt(), total, blockReward.Amount.RoundInt()) validatorReward := cosmos.ZeroInt() rateBasisPts := val.GetCommission().MulInt64(100).RoundInt() @@ -292,51 +292,62 @@ func (mgr Manager) ValidatorPayout(ctx cosmos.Context, votes []abci.VoteInfo, bl delegateReward = delegateReward.Sub(valFee) validatorReward = validatorReward.Add(valFee) } + if err := mgr.keeper.SendFromModuleToAccount(ctx, types.ModuleName, delegateAcc, cosmos.NewCoins(cosmos.NewCoin(blockReward.Denom, delegateReward))); err != nil { ctx.Logger().Error("unable to pay rewards to delegate", "delegate", delegate.DelegatorAddress, "error", err) continue } ctx.Logger().Info("delegate rewarded", "delegate", delegateAcc.String(), "amount", delegateReward) + + totalAllocated = totalAllocated.Add(delegateReward) } if !validatorReward.IsZero() { - if err := mgr.keeper.SendFromModuleToAccount(ctx, types.ModuleName, acc, cosmos.NewCoins(cosmos.NewCoin(blockReward.Denom, validatorReward))); err != nil { + if err := mgr.keeper.AllocateTokensToValidator(ctx, val, sdk.NewDecCoins(sdk.NewDecCoin(blockReward.Denom, validatorReward))); err != nil { ctx.Logger().Error("unable to pay rewards to validator", "validator", val.GetOperator(), "error", err) continue } ctx.Logger().Info("validator additional rewards", "validator", acc.String(), "amount", validatorReward) + } if err := mgr.EmitValidatorPayoutEvent(ctx, acc, validatorReward); err != nil { ctx.Logger().Error("unable to emit validator payout event", "validator", acc.String(), "error", err) } + totalAllocated = totalAllocated.Add(validatorReward) + } + + if !totalAllocated.IsZero() { + if err := mgr.keeper.BurnCoins(ctx, types.ModuleName, cosmos.NewCoins(cosmos.NewCoin(blockReward.Denom, totalAllocated))); err != nil { + ctx.Logger().Error("unable to burn allocated rewards from module account", "amount", totalAllocated, "error", err) + return err + } + ctx.Logger().Info("total rewards deducted from module account", "amount", totalAllocated) } return nil } -func (mgr Manager) calcBlockReward(ctx cosmos.Context, totalReserve, emissionCurve, blocksPerYear, validatorPayoutCycle int64) cosmos.Coin { +func (mgr Manager) calcBlockReward(ctx cosmos.Context, totalReserve, emissionCurve, blocksPerYear, validatorPayoutCycle sdkmath.LegacyDec) sdk.DecCoin { sdkContext := sdk.UnwrapSDKContext(ctx) // Block Rewards will take the latest reserve, divide it by the emission // curve factor, then divide by blocks per year - if emissionCurve == 0 || blocksPerYear == 0 { + if emissionCurve.IsZero() || blocksPerYear.IsZero() { sdkContext.Logger().Info("block and emission-curve cannot be zero") - return cosmos.NewCoin(configs.Denom, sdkmath.NewInt(0)) + return sdk.NewDecCoin(configs.Denom, sdkmath.NewInt(0)) } - if validatorPayoutCycle == 0 || sdkContext.BlockHeight()%validatorPayoutCycle != 0 { + if validatorPayoutCycle.IsZero() || sdkContext.BlockHeight()%validatorPayoutCycle.RoundInt64() != 0 { sdkContext.Logger().Info("validator payout cycle cannot be zero") - return cosmos.NewCoin(configs.Denom, sdkmath.NewInt(0)) + return sdk.NewDecCoin(configs.Denom, sdkmath.NewInt(0)) } - trD := cosmos.NewDec(totalReserve) - ecD := cosmos.NewDec(emissionCurve) - bpyD := cosmos.NewDec((blocksPerYear / validatorPayoutCycle)) + bpyD := blocksPerYear.Quo(validatorPayoutCycle) - blockReward := trD.Quo(ecD).Quo(bpyD).RoundInt() + blockReward := totalReserve.Quo(emissionCurve).Quo(bpyD).RoundInt() - return cosmos.NewCoin(configs.Denom, blockReward) + return sdk.NewDecCoin(configs.Denom, blockReward) } func (mgr Manager) FetchConfig(ctx cosmos.Context, name configs.ConfigName) int64 { @@ -433,31 +444,25 @@ func (mgr Manager) contractDebt(ctx cosmos.Context, contract types.Contract) (co return debt, nil } -func (mgr Manager) circulatingSupplyAfterInflationCalc(ctx cosmos.Context) (cosmos.Coin, error) { +func (mgr Manager) circulatingSupplyAfterInflationCalc(ctx cosmos.Context) (sdk.DecCoin, error) { sdkContext := sdk.UnwrapSDKContext(ctx) // Get the circulating supply circulatingSupply, err := mgr.keeper.GetCirculatingSupply(ctx, configs.Denom) + sdkContext.Logger().Info(fmt.Sprintf("circulating supply: %d", circulatingSupply.Amount)) if err != nil { sdkContext.Logger().Error(fmt.Sprintf("failed to get circulating supply %s", err)) - return cosmos.NewCoin(configs.Denom, sdkmath.NewInt(0)), err + return sdk.NewDecCoin(configs.Denom, sdkmath.NewInt(0)), err } // Get the inflation rate - inflationRate, err := mgr.keeper.GetInflationRate(ctx) - if err != nil { - sdkContext.Logger().Error(fmt.Sprintf("failed to get inflation rate: %s", err)) - return cosmos.NewCoin(configs.Denom, sdkmath.NewInt(0)), err - } - - // Convert circulating supply to decimal for precise calculation - circulatingSupplyDec := sdkmath.LegacyNewDec(circulatingSupply.Amount.Int64()) + inflationRate := mgr.keeper.GetInflationRate(ctx) + sdkContext.Logger().Info(fmt.Sprintf("inflation rate: %d", inflationRate)) // Multiply circulating supply by inflation rate to get the newly minted token amount - newTokenAmountMintedDec := circulatingSupplyDec.Mul(inflationRate) + newTokenAmountMintedDec := circulatingSupply.Amount.Mul(inflationRate).QuoInt64(100) - // Convert the result back to integer and truncate any decimals - newTokenAmountMinted := newTokenAmountMintedDec.TruncateInt() + sdkContext.Logger().Info(fmt.Sprintf("minted token value: %v", newTokenAmountMintedDec)) - return cosmos.NewCoin(configs.Denom, newTokenAmountMinted), nil + return sdk.NewDecCoin(configs.Denom, newTokenAmountMintedDec.RoundInt()), nil } diff --git a/x/arkeo/keeper/manager_test.go b/x/arkeo/keeper/manager_test.go index a1da1d70..813ad769 100644 --- a/x/arkeo/keeper/manager_test.go +++ b/x/arkeo/keeper/manager_test.go @@ -315,37 +315,37 @@ func TestBlockRewardCalculation(t *testing.T) { // Total Reserve -> 100000000 // validator cycle -> 100 // reward = (totalReserve / emissionCurve) / (blocksPerYear / valCycle)) -> 2000 - valCycle := int64(100) - emissionCurve := int64(10) - blocksPerYear := int64(5000) - totalReserve := int64(1000000) + valCycle := sdkmath.LegacyNewDec(100) + emissionCurve := sdkmath.LegacyNewDec(10) + blocksPerYear := sdkmath.LegacyNewDec(5000) + totalReserve := sdkmath.LegacyNewDec(1000000) reward := mgr.calcBlockReward(ctx, totalReserve, emissionCurve, blocksPerYear, valCycle) - require.Equal(t, reward.Amount.Int64(), int64(2000)) + require.Equal(t, reward.Amount.RoundInt64(), int64(2000)) - valCycle = int64(10) - emissionCurve = int64(5) - blocksPerYear = int64(200) - totalReserve = int64(999999) + valCycle = sdkmath.LegacyNewDec(10) + emissionCurve = sdkmath.LegacyNewDec(5) + blocksPerYear = sdkmath.LegacyNewDec(200) + totalReserve = sdkmath.LegacyNewDec(999999) reward = mgr.calcBlockReward(ctx, totalReserve, emissionCurve, blocksPerYear, valCycle) - require.Equal(t, reward.Amount.Int64(), int64(10000)) // its 9999.99 rounded to 10000 + require.Equal(t, reward.Amount.RoundInt64(), int64(10000)) // its 9999.99 rounded to 10000 } func TestValidatorPayouts(t *testing.T) { ctx, k, sk := SetupKeeperWithStaking(t) mgr := NewManager(k, sk) - valCycle := int64(100) - emissionCurve := int64(10) - blocksPerYear := int64(5000) - totalReserve := int64(1000000000) + valCycle := sdkmath.NewInt(100).ToLegacyDec() + emissionCurve := sdkmath.NewInt(10).ToLegacyDec() + blocksPerYear := sdkmath.NewInt(5000).ToLegacyDec() + totalReserve := sdkmath.NewInt(1000000000).ToLegacyDec() blockReward := mgr.calcBlockReward(ctx, totalReserve, emissionCurve, blocksPerYear, valCycle) - require.Equal(t, blockReward.Amount.Int64(), int64(2000000)) + require.Equal(t, blockReward.Amount.RoundInt64(), int64(2000000)) pks := simtestutil.CreateTestPubKeys(3) pk1, err := common.NewPubKeyFromCrypto(pks[0]) @@ -466,7 +466,7 @@ func TestValidatorPayouts(t *testing.T) { require.Equal(t, totalBal.ToLegacyDec(), sdkmath.LegacyNewDec(996293)) moduleBalance = k.GetBalanceOfModule(ctx, types.ModuleName, configs.Denom) - require.Equal(t, moduleBalance.Int64(), int64(20000000000000)) + require.Equal(t, moduleBalance.ToLegacyDec().RoundInt64(), int64(20000000000000-996293)) } func checkBalance(ctx cosmos.Context, t *testing.T, k Keeper, acc cosmos.AccAddress, denom string, expectedAmt int64, total *sdkmath.Int) { bal := k.GetBalance(ctx, acc)