Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/Qb-1780: Maintain total supply #258

Merged
merged 1 commit into from
May 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ var (
registertypes.MetaNodeNotBondedPool: {authtypes.Minter},
registertypes.TotalUnissuedPrepay: {authtypes.Minter},

pottypes.ModuleName: {authtypes.Minter},
pottypes.FoundationAccount: {authtypes.Minter, authtypes.Burner},
pottypes.TotalRewardPool: nil,
//pottypes.TotalMinedTokens: {authtypes.Minter, authtypes.Burner},
Expand Down Expand Up @@ -509,7 +510,6 @@ func NewInitApp(
govtypes.ModuleName,
stakingtypes.ModuleName,
registertypes.ModuleName,
pottypes.ModuleName,
sdstypes.ModuleName,
evmtypes.ModuleName,
// no-op modules
Expand All @@ -525,6 +525,7 @@ func NewInitApp(
evidencetypes.ModuleName,
authz.ModuleName,
feegrant.ModuleName,
pottypes.ModuleName,
paramstypes.ModuleName,
upgradetypes.ModuleName,
vestingtypes.ModuleName,
Expand Down
5 changes: 5 additions & 0 deletions proto/stratos/pot/v1/pot.proto
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ message Params {
(gogoproto.moretags) = "yaml:\"community_tax\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec"
];
cosmos.base.v1beta1.Coin initial_total_supply = 6 [
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "initial_total_supply",
(gogoproto.moretags) = "yaml:\"initial_total_supply\""
];
}

message MiningRewardParam {
Expand Down
11 changes: 11 additions & 0 deletions x/pot/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
abci "github.com/tendermint/tendermint/abci/types"

sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"

"github.com/stratosnet/stratos-chain/x/pot/keeper"
"github.com/stratosnet/stratos-chain/x/pot/types"
Expand Down Expand Up @@ -53,5 +54,15 @@ func EndBlocker(ctx sdk.Context, req abci.RequestEndBlock, k keeper.Keeper) []ab
logger.Error("An error occurred while distributing the reward. ", "ErrMsg", err.Error())
}

// reset total supply to 100M stos
minter, amount := k.RestoreTotalSupply(ctx)
if minter.Empty() || amount.Empty() {
return []abci.ValidatorUpdate{}
}

ctx.EventManager().EmitEvent(
banktypes.NewCoinMintEvent(minter, amount),
)

return []abci.ValidatorUpdate{}
}
59 changes: 59 additions & 0 deletions x/pot/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package keeper

import (
"bytes"
"fmt"
"math"

"github.com/tendermint/tendermint/libs/log"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"

stratos "github.com/stratosnet/stratos-chain/types"
Expand Down Expand Up @@ -87,3 +89,60 @@ func (k Keeper) FoundationDeposit(ctx sdk.Context, amount sdk.Coins, from sdk.Ac
}
return nil
}

// Restore total supply to 100M stos
func (k Keeper) RestoreTotalSupply(ctx sdk.Context) (minter sdk.AccAddress, mintCoins sdk.Coins) {
// reset total supply to 100M stos
events := ctx.EventManager().Events()
attrKeyAmtBytes := []byte(sdk.AttributeKeyAmount)

totalBurnedCoins := sdk.Coins{}
for _, event := range events {
if event.Type == banktypes.EventTypeCoinBurn {
attributes := event.Attributes
for _, attr := range attributes {
if bytes.Equal(attr.Key, attrKeyAmtBytes) {
amount, err := sdk.ParseCoinsNormalized(string(attr.Value))
if err != nil {
ctx.Logger().Error("An error occurred while parsing burned amount. ", "ErrMsg", err.Error())
break
}
totalBurnedCoins = totalBurnedCoins.Add(amount...)
}
}
}
}

totalBurned := totalBurnedCoins.AmountOf(k.BondDenom(ctx))
if totalBurned.IsZero() {
return sdk.AccAddress{}, sdk.Coins{}
}

InitialTotalSupply := k.InitialTotalSupply(ctx).Amount
currentTotalSupply := k.bankKeeper.GetSupply(ctx, k.BondDenom(ctx)).Amount

if totalBurned.Add(currentTotalSupply).GT(InitialTotalSupply) {
mintCoins = sdk.NewCoins(
sdk.NewCoin(k.BondDenom(ctx), InitialTotalSupply.Sub(currentTotalSupply)),
)
} else {
mintCoins = totalBurnedCoins
}

// mint coins
err := k.bankKeeper.MintCoins(ctx, types.ModuleName, mintCoins)
if err != nil {
ctx.Logger().Error("Restore total supply failed:", err.Error())
return sdk.AccAddress{}, sdk.Coins{}
}

// send new mint coins to community pool
senderAddr := k.accountKeeper.GetModuleAddress(types.ModuleName)
err = k.distrKeeper.FundCommunityPool(ctx, mintCoins, senderAddr)
if err != nil {
ctx.Logger().Error("Restore total supply failed:", err.Error())
return sdk.AccAddress{}, sdk.Coins{}
}

return
}
6 changes: 6 additions & 0 deletions x/pot/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/stratosnet/stratos-chain/x/pot/types"
)

Expand Down Expand Up @@ -51,3 +52,8 @@ func (k Keeper) GetCommunityTax(ctx sdk.Context) (res sdk.Dec) {
k.paramSpace.Get(ctx, types.KeyCommunityTax, &res)
return
}

func (k Keeper) InitialTotalSupply(ctx sdk.Context) (res sdk.Coin) {
k.paramSpace.Get(ctx, types.KeyInitialTotalSupply, &res)
return
}
6 changes: 6 additions & 0 deletions x/pot/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const (
codeErrMissingTargetAddress
codeErrInsufficientMatureTotal
codeErrMatureEpoch
codeErrMiningRewardParams
codeErrCommunityTax
codeErrInitialTotalSupply
codeErrEmptyFromAddr
codeErrEmptyReporterAddr
codeErrEmptyWalletVolumes
Expand Down Expand Up @@ -50,6 +53,9 @@ var (
ErrMissingTargetAddress = sdkerrors.Register(ModuleName, codeErrMissingTargetAddress, "missing target address")
ErrInsufficientMatureTotal = sdkerrors.Register(ModuleName, codeErrInsufficientMatureTotal, "insufficient mature total")
ErrMatureEpoch = sdkerrors.Register(ModuleName, codeErrMatureEpoch, "the value of epoch must be positive and greater than its previous one")
ErrMiningRewardParams = sdkerrors.Register(ModuleName, codeErrMiningRewardParams, "invalid mining reward param")
ErrCommunityTax = sdkerrors.Register(ModuleName, codeErrCommunityTax, "invalid community tax param")
ErrInitialTotalSupply = sdkerrors.Register(ModuleName, codeErrInitialTotalSupply, "invalid initial total supply param")
ErrEmptyFromAddr = sdkerrors.Register(ModuleName, codeErrEmptyFromAddr, "missing from address")
ErrEmptyReporterAddr = sdkerrors.Register(ModuleName, codeErrEmptyReporterAddr, "missing reporter address")
ErrEmptyWalletVolumes = sdkerrors.Register(ModuleName, codeErrEmptyWalletVolumes, "wallet volumes list empty")
Expand Down
2 changes: 2 additions & 0 deletions x/pot/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ type BankKeeper interface {
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
SendCoinsFromModuleToModule(ctx sdk.Context, senderPool, recipientPool string, amt sdk.Coins) error
GetSupply(ctx sdk.Context, denom string) sdk.Coin
MintCoins(ctx sdk.Context, moduleName string, amounts sdk.Coins) error
}

type RegisterKeeper interface {
Expand Down
54 changes: 44 additions & 10 deletions x/pot/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@ var (
KeyMatureEpoch = []byte("MatureEpoch")
KeyMiningRewardParams = []byte("MiningRewardParams")
KeyCommunityTax = []byte("CommunityTax")
KeyInitialTotalSupply = []byte("InitialTotalSupply")

DefaultCommunityTax = sdk.NewDecWithPrec(2, 2) // 2%
DefaultCommunityTax = sdk.NewDecWithPrec(2, 2) // 2%
DefaultInitialTotalSupply = sdk.NewCoin(DefaultBondDenom,
sdk.NewInt(1e8).Mul(sdk.NewInt(stratos.StosToWei)),
) //100,000,000 stos
)

// ParamKeyTable for pot module
Expand All @@ -36,13 +40,16 @@ func ParamKeyTable() paramtypes.KeyTable {
}

// NewParams creates a new Params object
func NewParams(bondDenom string, rewardDenom string, matureEpoch int64, miningRewardParams []MiningRewardParam, communityTax sdk.Dec) Params {
func NewParams(bondDenom string, rewardDenom string, matureEpoch int64, miningRewardParams []MiningRewardParam,
communityTax sdk.Dec, initialTotalSupply sdk.Coin) Params {

return Params{
BondDenom: bondDenom,
RewardDenom: rewardDenom,
MatureEpoch: matureEpoch,
MiningRewardParams: miningRewardParams,
CommunityTax: communityTax,
InitialTotalSupply: initialTotalSupply,
}
}

Expand Down Expand Up @@ -85,17 +92,26 @@ func DefaultParams() Params {
sdk.NewCoin(DefaultRewardDenom, sdk.NewInt(2500000000)),
sdk.NewInt(7000), sdk.NewInt(1000), sdk.NewInt(2000)))

return NewParams(DefaultBondDenom, DefaultRewardDenom, DefaultMatureEpoch, miningRewardParams, DefaultCommunityTax)
return NewParams(
DefaultBondDenom,
DefaultRewardDenom,
DefaultMatureEpoch,
miningRewardParams,
DefaultCommunityTax,
DefaultInitialTotalSupply,
)
}

// HrpString implements the stringer interface for Params
func (p Params) HrpString() string {
return fmt.Sprintf(`Params:
BondDenom: %s
RewardDenom: %s
MatureEpoch: %d
MiningRewardParams: %s`,
p.BondDenom, p.RewardDenom, p.MatureEpoch, p.MiningRewardParams)
BondDenom: %s
RewardDenom: %s
MatureEpoch: %d
MiningRewardParams: %s
CommunitiyTax: %v
InitialTotalSupply: %v`,
p.BondDenom, p.RewardDenom, p.MatureEpoch, p.MiningRewardParams, p.CommunityTax, p.InitialTotalSupply)
}

// ParamSetPairs - Implements params.ParamSet
Expand All @@ -106,6 +122,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
paramtypes.NewParamSetPair(KeyMatureEpoch, &p.MatureEpoch, validateMatureEpoch),
paramtypes.NewParamSetPair(KeyMiningRewardParams, &p.MiningRewardParams, validateMiningRewardParams),
paramtypes.NewParamSetPair(KeyCommunityTax, &p.CommunityTax, validateCommunityTax),
paramtypes.NewParamSetPair(KeyInitialTotalSupply, &p.InitialTotalSupply, validateInitialTotalSupply),
}
}

Expand Down Expand Up @@ -188,6 +205,20 @@ func validateCommunityTax(i interface{}) error {
return nil
}

func validateInitialTotalSupply(i interface{}) error {
v, ok := i.(sdk.Coin)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if v.IsNil() {
return fmt.Errorf("total supply must be not nil")
}
if v.IsNegative() {
return fmt.Errorf("total supply must be positive: %s", v)
}
return nil
}

func (p Params) ValidateBasic() error {
if err := validateBondDenom(p.BondDenom); err != nil {
return sdkerrors.Wrap(ErrInvalidDenom, "failed to validate bond denomination")
Expand All @@ -199,10 +230,13 @@ func (p Params) ValidateBasic() error {
return sdkerrors.Wrap(ErrMatureEpoch, "failed to validate mature epoch")
}
if err := validateMiningRewardParams(p.MiningRewardParams); err != nil {
return sdkerrors.Wrap(ErrMatureEpoch, "failed to validate mining reward params")
return sdkerrors.Wrap(ErrMiningRewardParams, "failed to validate mining reward params")
}
if err := validateCommunityTax(p.CommunityTax); err != nil {
return sdkerrors.Wrap(ErrMatureEpoch, "failed to validate community tax")
return sdkerrors.Wrap(ErrCommunityTax, "failed to validate community tax")
}
if err := validateInitialTotalSupply(p.InitialTotalSupply); err != nil {
return sdkerrors.Wrap(ErrInitialTotalSupply, err.Error())
}
return nil
}
Loading