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

fix(mint): fix pruning panic, add developer and community funding #161

Merged
merged 10 commits into from
Jun 30, 2022
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ build-linux:
GOOS=linux GOARCH=amd64 LEDGER_ENABLED=false $(MAKE) build

$(BUILD_TARGETS): go.sum $(BUILDDIR)/
CGO_ENABLED=0 go $@ -mod=readonly $(BUILD_FLAGS) $(BUILD_ARGS) ./cmd/elestod
CGO_ENABLED=0 go $@ -mod=readonly $(BUILD_FLAGS) $(BUILD_ARGS) ./...

$(BUILDDIR)/:
mkdir -p $(BUILDDIR)/
Expand Down
26 changes: 16 additions & 10 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ import (
const (
AccountAddressPrefix = "elesto"
Name = "elesto"
upgradeName = "testnet-upgrade-2022-06-21" // Latest upgrade to be applied for the chain
upgradeName = "testnetUpgrade20220706" // Latest upgrade to be applied for the chain
)

// this line is used by starport scaffolding # stargate/wasm/app/enabledProposals
Expand Down Expand Up @@ -351,14 +351,6 @@ func New(
)
app.StakingKeeper = &sk

app.MintKeeper = mintkeeper.NewKeeper(
appCodec,
keys[minttypes.StoreKey],
app.GetSubspace(minttypes.ModuleName),
app.AccountKeeper,
app.BankKeeper,
authtypes.FeeCollectorName,
)
app.DistrKeeper = distrkeeper.NewKeeper(
appCodec,
keys[distrtypes.StoreKey],
Expand All @@ -369,6 +361,15 @@ func New(
authtypes.FeeCollectorName,
app.ModuleAccountAddrs(),
)
app.MintKeeper = mintkeeper.NewKeeper(
appCodec,
keys[minttypes.StoreKey],
app.GetSubspace(minttypes.ModuleName),
app.AccountKeeper,
app.BankKeeper,
app.DistrKeeper,
authtypes.FeeCollectorName,
)
app.SlashingKeeper = slashingkeeper.NewKeeper(
appCodec,
keys[slashingtypes.StoreKey],
Expand Down Expand Up @@ -655,7 +656,12 @@ func New(
}

if upgradeInfo.Name == upgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) {
storeUpgrades := storetypes.StoreUpgrades{}
storeUpgrades := storetypes.StoreUpgrades{
Added: []string{
icahosttypes.StoreKey,
credential.StoreKey,
},
}

// configure store loader that checks if version == upgradeHeight and applies store upgrades
app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades))
Expand Down
26 changes: 21 additions & 5 deletions x/mint/abci.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mint

import (
"fmt"
"math"
"time"

Expand Down Expand Up @@ -58,11 +59,26 @@ func BeginBlocker(ctx sdk.Context, k keeper.Keeper) {
panic(err)
}

// TODO: 80/10/10 splitted between
// - 80: default fee collector account
// - 10: team account
// - 10: community pool
// send the minted coins to the fee collector account
// calculate 10% off mintedCoins
// this is handled in sdk.Ints already, some rounding error might persist.
tenPercentRawAmt := mintedCoin.Amount.MulRaw(10).QuoRaw(100)
tenPercentAmt := sdk.NewCoins(sdk.NewCoin(params.MintDenom, tenPercentRawAmt))

// mintedCoins now has devFundAmt less coins, two times
// one for the dev fund, one for the community pool
mintedCoins = mintedCoins.Sub(tenPercentAmt).Sub(tenPercentAmt)

// send them from mint moduleAccount to the dev fund address
if err := k.CollectAmount(ctx, params.TeamAddress, tenPercentAmt); err != nil {
panic(fmt.Errorf("cannot send coins to team account, %w", err))
}

// fund the community pool
if err := k.FundCommunityPool(ctx, tenPercentAmt); err != nil {
panic(fmt.Errorf("cannot fund community pool, %w", err))
}

// send the remaining minted coins to the fee collector account
if err := k.AddInflationToFeeCollector(ctx, mintedCoins); err != nil {
panic(err)
}
Expand Down
55 changes: 50 additions & 5 deletions x/mint/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,21 @@ func (s *ModuleTestSuite) TestInflationRate() {

initialSupply := 200_000_000_000_000

params := s.app.MintKeeper.GetParams(s.ctx)

ctx := s.ctx.WithBlockHeight(int64(0))

err := s.keeper.MintCoins(ctx, sdk.NewCoins(sdk.NewInt64Coin("stake", int64(initialSupply))))
err := s.keeper.MintCoins(ctx, sdk.NewCoins(sdk.NewInt64Coin(params.MintDenom, int64(initialSupply))))
s.Require().NoError(err)
s.Require().EqualValues(s.keeper.GetSupply(
s.ctx.WithBlockHeight(1),
"stake",
params.MintDenom,
).Amount.Int64(), int64(initialSupply))

s.T().Log("circulating supply at block 0:", s.keeper.GetSupply(ctx, "stake").String())
s.T().Log("circulating supply at block 0:", s.keeper.GetSupply(ctx, params.MintDenom).String())

lastCommunityFundAmount := sdk.DecCoins{}
lastDevFundAmount := sdk.NewCoin(params.MintDenom, sdk.ZeroInt())

for year := 0; year <= simulationYears; year++ {
// Adding 1 here because we're running the simulation on the first day of the following year.
Expand All @@ -95,15 +100,55 @@ func (s *ModuleTestSuite) TestInflationRate() {

mint.BeginBlocker(ctx, s.keeper)

communityFundAmount := s.app.DistrKeeper.GetFeePoolCommunityCoins(s.ctx)
floatCommunityAmount, err := communityFundAmount.AmountOf(params.MintDenom).Float64()
s.NoError(err)

lastFloatCommunityAmount, err := lastCommunityFundAmount.AmountOf(params.MintDenom).Float64()
s.NoError(err)

taddr, err := sdk.AccAddressFromBech32(s.app.MintKeeper.GetParams(s.ctx).TeamAddress)
s.NoError(err)

teamBalance := s.app.BankKeeper.GetBalance(s.ctx, taddr, params.MintDenom)

s.T().Log("community pool amount", lastCommunityFundAmount.String())
s.T().Log("developer fund amount", lastDevFundAmount.String())

if year < 10 {
s.Greater(
floatCommunityAmount,
lastFloatCommunityAmount,
)

s.Greater(
teamBalance.Amount.Int64(),
lastDevFundAmount.Amount.Int64(),
)
} else {
s.EqualValues(
floatCommunityAmount,
lastFloatCommunityAmount,
)

s.EqualValues(
teamBalance.Amount.Int64(),
lastDevFundAmount.Amount.Int64(),
)
}

lastCommunityFundAmount = communityFundAmount
lastDevFundAmount = teamBalance

// Since running this simulation for each block would make this test take too much time,
// we mint the total amount of tokens minted in one year, minus 1 block since the `mint.BeginBlocker()`
// call already mints once for us.
blockInflationAmount := mint.BlockInflationAmount[year]
mintAmount := sdk.NewInt(int64(blockInflationAmount) * int64(blocksPerYear-1))
mintedCoin := sdk.NewCoin("stake", mintAmount)
mintedCoin := sdk.NewCoin(params.MintDenom, mintAmount)
mintedCoins := sdk.NewCoins(mintedCoin)
s.Require().NoError(s.keeper.MintCoins(ctx, mintedCoins))
supply := s.keeper.GetSupply(ctx, "stake")
supply := s.keeper.GetSupply(ctx, params.MintDenom)
s.T().Log("inflation for year", year, ":", "supply", supply)

supplyInTokens := supply.Amount.Quo(sdk.NewInt(1000000)).ToDec().RoundInt64()
Expand Down
22 changes: 21 additions & 1 deletion x/mint/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ type Keeper struct {
cdc codec.BinaryCodec
storeKey sdk.StoreKey
paramSpace paramtypes.Subspace
accountKeeper types.AccountKeeper
bankKeeper types.BankKeeper
distrKeeper types.DistributionKeeper
feeCollectorName string
}

// NewKeeper creates a new mint Keeper instance
func NewKeeper(
cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace, ak types.AccountKeeper, bk types.BankKeeper, feeCollectorName string,
cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace, ak types.AccountKeeper, bk types.BankKeeper, dk types.DistributionKeeper, feeCollectorName string,
) Keeper {
// ensure mint module account is set
if addr := ak.GetModuleAddress(types.ModuleName); addr == nil {
Expand All @@ -38,6 +40,8 @@ func NewKeeper(
storeKey: key,
paramSpace: paramSpace,
bankKeeper: bk,
distrKeeper: dk,
accountKeeper: ak,
feeCollectorName: feeCollectorName,
}
}
Expand Down Expand Up @@ -88,3 +92,19 @@ func (k Keeper) CollectAmount(ctx sdk.Context, address string, amount sdk.Coins)
func (k Keeper) GetSupply(ctx sdk.Context, denom string) sdk.Coin {
return k.bankKeeper.GetSupply(ctx, denom)
}

// FundCommunityPool funds the x/distribution community pool with amount coins, directly from
// this module's ModuleAccount.
func (k Keeper) FundCommunityPool(ctx sdk.Context, amount sdk.Coins) error {
if amount.Empty() {
// skip as no coins need to be minted
return nil
}

addr := k.accountKeeper.GetModuleAddress(types.ModuleName)
if addr == nil {
panic("the mint module account has not been set")
}

return k.distrKeeper.FundCommunityPool(ctx, amount, addr)
}
5 changes: 5 additions & 0 deletions x/mint/keeper/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/elesto-dao/elesto/v2/x/mint/migrations/testnetUpgrade20220621"
"github.com/elesto-dao/elesto/v2/x/mint/migrations/testnetUpgrade20220706"
)

// Migrator is a struct for handling in-place store migrations.
Expand All @@ -20,3 +21,7 @@ func NewMigrator(keeper Keeper) Migrator {
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return testnetUpgrade20220621.MigrateParams(ctx, m.keeper)
}

func (m Migrator) Migrate2to3(ctx sdk.Context) error {
return testnetUpgrade20220706.Migrate(ctx, m.keeper)
}
22 changes: 22 additions & 0 deletions x/mint/migrations/testnetUpgrade20220706/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package testnetUpgrade20220706

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

mintTypes "github.com/elesto-dao/elesto/v2/x/mint/types"
)

type ExpectedKeeper interface {
SetParams(ctx sdk.Context, params mintTypes.Params)
MintCoins(ctx sdk.Context, amt sdk.Coins) error
GetSupply(ctx sdk.Context, denom string) sdk.Coin
}

func Migrate(ctx sdk.Context, keeper ExpectedKeeper) error {
// reset params, and hardcode the mint denom as "utsp"
p := mintTypes.DefaultParams()
p.MintDenom = "utsp"
keeper.SetParams(ctx, p)

return nil
}
75 changes: 75 additions & 0 deletions x/mint/migrations/testnetUpgrade20220706/store_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package testnetUpgrade20220706_test

import (
"fmt"
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/elesto-dao/elesto/v2/app"
"github.com/elesto-dao/elesto/v2/x/mint/migrations/testnetUpgrade20220706"
mintTypes "github.com/elesto-dao/elesto/v2/x/mint/types"
"github.com/stretchr/testify/require"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)

func (b *bogusMigrationKeeper) SetParams(ctx sdk.Context, params mintTypes.Params) {
if b.failSetParams {
panic("cannot set params")
}
}

func (b *bogusMigrationKeeper) MintCoins(ctx sdk.Context, amt sdk.Coins) error {
if b.failMint {
return fmt.Errorf("cannot mint")
}

return nil
}

func (b *bogusMigrationKeeper) GetSupply(ctx sdk.Context, denom string) sdk.Coin {
if b.failGetSupply {
c := sdk.Coin{}
c.Denom = "a"

return c
}
for _, t := range b.supply {
if t.Denom == denom {
return t
}
}

return sdk.Coin{}
}

type bogusMigrationKeeper struct {
failSetParams bool
failMint bool
failBurn bool
failGetSupply bool
supply sdk.Coins
}

func TestMigrate(t *testing.T) {
app := app.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})

testnetUpgrade20220706.Migrate(ctx, app.MintKeeper)

require.Equal(t, "utsp", app.MintKeeper.GetParams(ctx).MintDenom)
require.Equal(t, "stake", mintTypes.DefaultParams().MintDenom)
}


func TestFailSetParams(t *testing.T) {
app := app.Setup(false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})

keeper := &bogusMigrationKeeper{
failSetParams: true,
}

require.Panics(t, func() {
_ = testnetUpgrade20220706.Migrate(ctx, keeper)
})
}
6 changes: 5 additions & 1 deletion x/mint/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ func (am AppModule) RegisterServices(cfg module.Configurator) {
if err := cfg.RegisterMigration(types.ModuleName, 1, migrator.Migrate1to2); err != nil {
panic(fmt.Errorf("cannot migrate x/mint store from version 1 to version 2, %w", err))
}

if err := cfg.RegisterMigration(types.ModuleName, 2, migrator.Migrate2to3); err != nil {
panic(fmt.Errorf("cannot migrate x/mint store from version 2 to version 3, %w", err))
}
}

// InitGenesis performs genesis initialization for the mint module. It returns
Expand All @@ -149,7 +153,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw
}

// ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return 2 }
func (AppModule) ConsensusVersion() uint64 { return 3 }

// BeginBlock returns the begin blocker for the mint module.
func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) {
Expand Down
3 changes: 1 addition & 2 deletions x/mint/simulation/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"

Expand Down Expand Up @@ -42,7 +41,7 @@ func TestRandomizedGenState(t *testing.T) {
var genState types.GenesisState
simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &genState)

require.Equal(t, sdk.DefaultBondDenom, genState.Params.MintDenom)
require.Equal(t, "stake", genState.Params.MintDenom)
require.Equal(t, types.DefaultParams().BlocksPerYear, genState.Params.BlocksPerYear)
require.Equal(t, types.DefaultParams().MaxSupply, genState.Params.MaxSupply)
}
Expand Down
5 changes: 5 additions & 0 deletions x/mint/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ type BankKeeper interface {
MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error
GetSupply(ctx sdk.Context, denom string) sdk.Coin
}

// DistributionKeeper defines the contract required for distribution APIs.
type DistributionKeeper interface {
FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error
}