From 4570a040bed1aa71e06efa34ca9129889ab752c3 Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Fri, 21 Apr 2023 11:11:59 -0400 Subject: [PATCH 01/16] update proto --- cmd/seid/cmd/iavl_parser.go | 2 - go.mod | 2 + go.sum | 3 + proto/mint/v1beta1/mint.proto | 27 +-- proto/mint/v1beta1/query.proto | 22 +- utils/metrics/metrics_util.go | 12 + x/mint/keeper/hooks.go | 42 +--- x/mint/keeper/hooks_test.go | 24 +- x/mint/keeper/keeper.go | 68 ++++-- x/mint/keeper/keeper_test.go | 125 ++++++++++ x/mint/simulation/genesis.go | 7 +- x/mint/types/keys.go | 3 - x/mint/types/mint.pb.go | 385 +++++++++++++++++++++++------- x/mint/types/minter.go | 130 +++++++--- x/mint/types/minter_test.go | 170 ++++++------- x/mint/types/params.go | 36 ++- x/mint/types/params_test.go | 157 ++++++++++++ x/mint/types/query.pb.go | 314 ++++++++++++++++++------ x/oracle/simulation/operations.go | 4 +- 19 files changed, 1126 insertions(+), 407 deletions(-) create mode 100644 x/mint/keeper/keeper_test.go create mode 100644 x/mint/types/params_test.go diff --git a/cmd/seid/cmd/iavl_parser.go b/cmd/seid/cmd/iavl_parser.go index 663a589ef9..32dcfaccf8 100644 --- a/cmd/seid/cmd/iavl_parser.go +++ b/cmd/seid/cmd/iavl_parser.go @@ -31,8 +31,6 @@ func MintParser(key []byte) ([]string, error) { switch { case bytes.HasPrefix(key, minttypes.MinterKey): keyItems = append(keyItems, "MinterKey") - case bytes.HasPrefix(key, minttypes.LastTokenReleaseDate): - keyItems = append(keyItems, "LastTokenReleaseDate") default: keyItems = append(keyItems, UNRECOGNIZED) } diff --git a/go.mod b/go.mod index e0f030de2e..8d724756c4 100644 --- a/go.mod +++ b/go.mod @@ -95,6 +95,7 @@ require ( github.com/firefart/nonamedreturns v1.0.1 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/fzipp/gocyclo v0.5.1 // indirect + github.com/ghodss/yaml v1.0.0 // indirect github.com/go-critic/go-critic v0.6.3 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.0 // indirect @@ -141,6 +142,7 @@ require ( github.com/gostaticanalysis/nilerr v0.1.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect diff --git a/go.sum b/go.sum index e12634d677..e8f6fff8c7 100644 --- a/go.sum +++ b/go.sum @@ -340,6 +340,7 @@ github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3n github.com/fzipp/gocyclo v0.5.1 h1:L66amyuYogbxl0j2U+vGqJXusPF2IkduvXLnYD5TFgw= github.com/fzipp/gocyclo v0.5.1/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= @@ -596,6 +597,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 h1:gDLXvp5S9izjldquuoAhDzccbskOL6tDC5jMSyx3zxE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2/go.mod h1:7pdNwVWBBHGiCxa9lAszqCJMbfTISJ7oMftp8+UGV08= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= diff --git a/proto/mint/v1beta1/mint.proto b/proto/mint/v1beta1/mint.proto index 8cab26865e..a4a14dedab 100644 --- a/proto/mint/v1beta1/mint.proto +++ b/proto/mint/v1beta1/mint.proto @@ -7,25 +7,20 @@ import "gogoproto/gogo.proto"; // Minter represents the most recent message Minter { - string last_mint_amount = 1 [ - (gogoproto.moretags) = "yaml:\"last_mint_amount\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false - ]; - string last_mint_date = 2 [ - (gogoproto.moretags) = "yaml:\"last_mint_date\"" - ]; - int64 last_mint_height = 3 [ - (gogoproto.moretags) = "yaml:\"last_mint_height\"" - ]; - string denom = 4 [ - (gogoproto.moretags) = "yaml:\"denom\"" - ]; + string start_date = 1; // yyyy-mm-dd + string end_date = 2; // yyyy-mm-dd + string denom = 3; + uint64 total_mint_amount = 4; + uint64 remaining_mint_amount = 5; + uint64 last_mint_amount = 6; + string last_mint_date = 7; + uint64 last_mint_height = 8; // yyyy-mm-dd } message ScheduledTokenRelease { - string date = 1; // yyyy-mm-dd - int64 token_release_amount = 2; + string start_date = 1; // yyyy-mm-dd + string end_date = 2; // yyyy-mm-dd + uint64 token_release_amount = 3; } // Params holds parameters for the mint module. diff --git a/proto/mint/v1beta1/query.proto b/proto/mint/v1beta1/query.proto index a259ce3250..f6f57a7772 100644 --- a/proto/mint/v1beta1/query.proto +++ b/proto/mint/v1beta1/query.proto @@ -37,18 +37,12 @@ message QueryMinterRequest {} // QueryMinterResponse is the response type for the // Query/Minter RPC method. message QueryMinterResponse { - string last_mint_amount = 1 [ - (gogoproto.moretags) = "yaml:\"last_mint_amount\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", - (gogoproto.nullable) = false - ]; - string last_mint_date = 2 [ - (gogoproto.moretags) = "yaml:\"last_mint_date\"" - ]; - int64 last_mint_height = 3 [ - (gogoproto.moretags) = "yaml:\"last_mint_height\"" - ]; - string denom = 4 [ - (gogoproto.moretags) = "yaml:\"denom\"" - ]; + string start_date = 1 [(gogoproto.moretags) = "yaml:\"start_date\""]; + string end_date = 2 [(gogoproto.moretags) = "yaml:\"end_date\""]; + string denom = 3 [(gogoproto.moretags) = "yaml:\"denom\""]; + uint64 total_mint_amount = 4 [(gogoproto.moretags) = "yaml:\"total_mint_amount\""]; + uint64 remaining_mint_amount = 5 [(gogoproto.moretags) = "yaml:\"remaining_mint_amount\""]; + uint64 last_mint_amount = 6 [(gogoproto.moretags) = "yaml:\"last_mint_amount\""]; + string last_mint_date = 7 [(gogoproto.moretags) = "yaml:\"last_mint_date\""]; + uint64 last_mint_height = 8 [(gogoproto.moretags) = "yaml:\"last_mint_height\""]; } diff --git a/utils/metrics/metrics_util.go b/utils/metrics/metrics_util.go index 34808646be..3ecbaefe23 100644 --- a/utils/metrics/metrics_util.go +++ b/utils/metrics/metrics_util.go @@ -185,3 +185,15 @@ func IncrValidatorSlashed(proposer string) { []metrics.Label{telemetry.NewLabel("proposer", proposer)}, ) } + +// Measures number of times a denom's price is updated +// Metric Name: +// +// sei_oracle_price_update_count +func SetCoinsMinted(amount uint64, denom string) { + telemetry.SetGaugeWithLabels( + []string{"sei", "mint", "coins"}, + float32(amount), + []metrics.Label{telemetry.NewLabel("denom", denom)}, + ) +} diff --git a/x/mint/keeper/hooks.go b/x/mint/keeper/hooks.go index 06cc435b1a..3b60a9331b 100644 --- a/x/mint/keeper/hooks.go +++ b/x/mint/keeper/hooks.go @@ -1,38 +1,23 @@ package keeper import ( - "fmt" - - "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" epochTypes "github.com/sei-protocol/sei-chain/x/epoch/types" - "github.com/sei-protocol/sei-chain/x/mint/types" ) func (k Keeper) BeforeEpochStart(ctx sdk.Context, epoch epochTypes.Epoch) { } func (k Keeper) AfterEpochEnd(ctx sdk.Context, epoch epochTypes.Epoch) { - params := k.GetParams(ctx) - minter := k.GetMinter(ctx) + latestMinter := k.GetOrUpdateLatestMinter(ctx, epoch) + coinsToMint := latestMinter.GetReleaseAmountToday() - // If the current yyyy-mm-dd of the epoch timestamp matches any of the scheduled token release then proceed to mint - lastRelaseDate := minter.GetLastMintDateTime() - scheduledTokenRelease := types.GetScheduledTokenRelease(epoch, lastRelaseDate, params.GetTokenReleaseSchedule()) - if scheduledTokenRelease == nil { - ctx.Logger().Debug(fmt.Sprintf("No release at epoch time %s; last release %s", epoch.GetCurrentEpochStartTime().String(), lastRelaseDate.Format(types.TokenReleaseDateFormat))) + if coinsToMint.IsZero() { + k.Logger(ctx).Debug("No coins to mint", "minter", latestMinter) return } - newMinter := types.NewMinter( - sdk.NewDec(scheduledTokenRelease.TokenReleaseAmount), - scheduledTokenRelease.GetDate(), - epoch.GetCurrentEpochHeight(), - params.GetMintDenom(), - ) - // mint coins, update supply - coinsToMint := newMinter.GetCoins() if err := k.MintCoins(ctx, coinsToMint); err != nil { panic(err) } @@ -41,22 +26,9 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epoch epochTypes.Epoch) { panic(err) } - mintedCoin := newMinter.GetCoin() - if mintedCoin.Amount.IsInt64() { - mintedCoins := float32(mintedCoin.Amount.Int64()) - ctx.Logger().Info(fmt.Sprintf("Minted %f at block time %s", mintedCoins, epoch.CurrentEpochStartTime.String())) - defer telemetry.ModuleSetGauge(types.ModuleName, mintedCoins, "minted_tokens") - } - - k.SetMinter(ctx, newMinter) - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeMint, - sdk.NewAttribute(types.AttributeEpochNumber, fmt.Sprintf("%d", epoch.GetCurrentEpoch())), - sdk.NewAttribute(types.AttributeKeyEpochProvisions, minter.GetLastMintDate()), - sdk.NewAttribute(sdk.AttributeKeyAmount, mintedCoin.Amount.String()), - ), - ) + // Released Succssfully, decrement the remaining amount by the daily release amount and update minter + latestMinter.RecordSuccessfulMint(ctx, epoch) + k.SetMinter(ctx, latestMinter) } type Hooks struct { diff --git a/x/mint/keeper/hooks_test.go b/x/mint/keeper/hooks_test.go index 4780030b30..2b49811ddf 100644 --- a/x/mint/keeper/hooks_test.go +++ b/x/mint/keeper/hooks_test.go @@ -16,6 +16,10 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) +func getGenesisTime() time.Time { + return time.Date(2022, time.Month(7), 18, 10, 0, 0, 0, time.UTC) +} + func getEpoch(genesisTime time.Time, currTime time.Time) types.Epoch { // Epochs increase every minute, so derive based on the time return types.Epoch{ @@ -35,8 +39,16 @@ func TestEndOfEpochMintedCoinDistribution(t *testing.T) { genesisTime := time.Date(2022, time.Month(7), 18, 10, 0, 0, 0, time.UTC) tokenReleaseSchedle := []minttypes.ScheduledTokenRelease{ - {Date: genesisTime.AddDate(1, 0, 0).Format(minttypes.TokenReleaseDateFormat), TokenReleaseAmount: 2500000}, - {Date: genesisTime.AddDate(2, 0, 0).Format(minttypes.TokenReleaseDateFormat), TokenReleaseAmount: 1250000}, + { + StartDate: genesisTime.AddDate(1, 0, 0).Format(minttypes.TokenReleaseDateFormat), + EndDate: genesisTime.AddDate(1, 60, 0).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 2500000, + }, + { + StartDate: genesisTime.AddDate(2, 0, 0).Format(minttypes.TokenReleaseDateFormat), + EndDate: genesisTime.AddDate(3, 0, 0).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 1250000, + }, } mintParams := minttypes.NewParams( "usei", @@ -59,7 +71,7 @@ func TestEndOfEpochMintedCoinDistribution(t *testing.T) { mintParams = seiApp.MintKeeper.GetParams(ctx) // Year 1 - mintedCoinYear1 := seiApp.MintKeeper.GetMinter(ctx).GetCoin() + mintedCoinYear1 := seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmountCoin() postsupplyYear1 := seiApp.BankKeeper.GetSupply(ctx, mintParams.MintDenom) require.True(t, postsupplyYear1.IsEqual(presupply.Add(mintedCoinYear1))) require.Equal(t, mintedCoinYear1.Amount.Int64(), int64(2500000)) @@ -73,7 +85,7 @@ func TestEndOfEpochMintedCoinDistribution(t *testing.T) { seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch) mintParams = seiApp.MintKeeper.GetParams(ctx) - mintedCoinYear2 := seiApp.MintKeeper.GetMinter(ctx).GetCoin() + mintedCoinYear2 := seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmountCoin() postsupplyYear2 := seiApp.BankKeeper.GetSupply(ctx, mintParams.MintDenom) require.True(t, postsupplyYear2.IsEqual(postsupplyYear1.Add(mintedCoinYear2))) require.Equal(t, mintedCoinYear2.Amount.Int64(), int64(1250000)) @@ -90,7 +102,7 @@ func TestNoEpochPassedNoDistribution(t *testing.T) { mintParams := seiApp.MintKeeper.GetParams(ctx) genesisTime := time.Date(2022, time.Month(7), 18, 10, 0, 0, 0, time.UTC) presupply := seiApp.BankKeeper.GetSupply(ctx, mintParams.MintDenom) - startLastMintAmount := seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmount() + startLastMintAmount := seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmountCoin() // Loops through epochs under a year for i := 0; i < 60*24*7*52-1; i++ { currTime := genesisTime.Add(time.Minute) @@ -103,6 +115,6 @@ func TestNoEpochPassedNoDistribution(t *testing.T) { require.True(t, currSupply.IsEqual(presupply)) } // Ensure that EpochProvision hasn't changed - endLastMintAmount := seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmount() + endLastMintAmount := seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmountCoin() require.True(t, startLastMintAmount.Equal(endLastMintAmount)) } diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index ed12dd5535..c4caddfe90 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + epochTypes "github.com/sei-protocol/sei-chain/x/epoch/types" "github.com/sei-protocol/sei-chain/x/mint/types" ) @@ -63,30 +64,6 @@ func (k *Keeper) SetHooks(h types.MintHooks) *Keeper { return k } -func (k Keeper) GetLastTokenReleaseDate(ctx sdk.Context) time.Time { - store := ctx.KVStore(k.storeKey) - b := store.Get(types.LastTokenReleaseDate) - if b == nil { - // Return 0001-01-01 00:00:00 +0000 UTC - return time.Time{} - } - lastTokenReleaseDate, err := time.Parse(types.TokenReleaseDateFormat, string(b)) - if err != nil { - panic(fmt.Errorf("invalid last token release date: %s", err)) - } - return lastTokenReleaseDate -} - -func (k Keeper) SetLastTokenReleaseDate(ctx sdk.Context, date string) { - store := ctx.KVStore(k.storeKey) - // MarshalText returns timestamp in RFC3339 format - _, err := time.Parse(types.TokenReleaseDateFormat, date) - if err != nil { - panic(fmt.Errorf("invalid unable to get timestamp string: %s", err)) - } - store.Set(types.LastTokenReleaseDate, []byte(date)) -} - // get the minter func (k Keeper) GetMinter(ctx sdk.Context) (minter types.Minter) { store := ctx.KVStore(k.storeKey) @@ -96,7 +73,7 @@ func (k Keeper) GetMinter(ctx sdk.Context) (minter types.Minter) { } k.cdc.MustUnmarshal(b, &minter) - return + return minter } // set the minter @@ -148,3 +125,44 @@ func (k Keeper) AddCollectedFees(ctx sdk.Context, fees sdk.Coins) error { func (k Keeper) GetProportions(ctx sdk.Context, mintedCoin sdk.Coin, ratio sdk.Dec) sdk.Coin { return sdk.NewCoin(mintedCoin.Denom, mintedCoin.Amount.ToDec().Mul(ratio).TruncateInt()) } + +// GetProportions gets the balance of the `MintedDenom` from minted coins and returns coins according to the `AllocationRatio`. +func (k Keeper) GetOrUpdateLatestMinter( + ctx sdk.Context, + epoch epochTypes.Epoch, +) types.Minter { + params := k.GetParams(ctx) + currentReleaseMinter := k.GetMinter(ctx) + nextScheduledRelease := GetNextScheduledTokenRelease(epoch, params.TokenReleaseSchedule, currentReleaseMinter) + // There's still an ongoing release + if currentReleaseMinter.OngoingRelease() || nextScheduledRelease == nil { + k.Logger(ctx).Debug("Ongoing token release or no nextScheduledRelease", "minter", currentReleaseMinter, "nextScheduledRelease", nextScheduledRelease) + return currentReleaseMinter + } + + return types.NewMinter( + nextScheduledRelease.GetStartDate(), + nextScheduledRelease.GetEndDate(), + params.GetMintDenom(), + nextScheduledRelease.GetTokenReleaseAmount(), + ) +} + +func GetNextScheduledTokenRelease( + epoch epochTypes.Epoch, + tokenReleaseSchedule []types.ScheduledTokenRelease, + currentMinter types.Minter, +) *types.ScheduledTokenRelease { + for _, scheduledRelease := range tokenReleaseSchedule { + scheduledStartDate, err := time.Parse(types.TokenReleaseDateFormat, scheduledRelease.GetStartDate()) + if err != nil { + // This should not happen as the scheduled release date is validated when the param is updated + panic(fmt.Errorf("invalid scheduled release date: %s", err)) + } + // If blocktime is after the currentScheduled date and it's after the current release + if epoch.GetCurrentEpochStartTime().After(scheduledStartDate) && scheduledStartDate.After(currentMinter.GetEndDateTime()) { + return &scheduledRelease + } + } + return nil +} diff --git a/x/mint/keeper/keeper_test.go b/x/mint/keeper/keeper_test.go new file mode 100644 index 0000000000..fc11363caf --- /dev/null +++ b/x/mint/keeper/keeper_test.go @@ -0,0 +1,125 @@ +package keeper_test + +import ( + "testing" + "time" + + epochTypes "github.com/sei-protocol/sei-chain/x/epoch/types" + mintKeeper "github.com/sei-protocol/sei-chain/x/mint/keeper" + "github.com/sei-protocol/sei-chain/x/mint/types" + mintTypes "github.com/sei-protocol/sei-chain/x/mint/types" + minttypes "github.com/sei-protocol/sei-chain/x/mint/types" + "github.com/stretchr/testify/require" +) + +func TestGetNextScheduledTokenRelease(t *testing.T) { + t.Parallel() + + currentTime := time.Now() + epoch := epochTypes.Epoch{ + CurrentEpochStartTime: currentTime, + CurrentEpochHeight: 100, + } + currentMinter := mintTypes.DefaultInitialMinter() + + tokenReleaseSchedule := []mintTypes.ScheduledTokenRelease{ + { + StartDate: currentTime.AddDate(0, 0, 30).Format(minttypes.TokenReleaseDateFormat), + EndDate: currentTime.AddDate(0, 2, 0).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 200, + }, + { + StartDate: currentTime.AddDate(1, 0, 0).Format(minttypes.TokenReleaseDateFormat), + EndDate: currentTime.AddDate(2, 0, 0).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 300, + }, + { + StartDate: currentTime.AddDate(0, 0, 1).Format(minttypes.TokenReleaseDateFormat), + EndDate: currentTime.AddDate(0, 0, 15).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 100, + }, + } + + t.Run("Get the next scheduled token release", func(t *testing.T) { + epoch.CurrentEpochStartTime = currentTime.AddDate(0, 0, 1) + nextScheduledRelease := mintKeeper.GetNextScheduledTokenRelease(epoch, tokenReleaseSchedule, currentMinter) + require.NotNil(t, nextScheduledRelease) + require.Equal(t, int64(100), nextScheduledRelease.TokenReleaseAmount) + }) + + t.Run("No next scheduled token release, assume we are on the second period", func(t *testing.T) { + secondMinter := mintTypes.NewMinter( + currentTime.AddDate(0, 0, 30).Format(minttypes.TokenReleaseDateFormat), + currentTime.AddDate(0, 2, 0).Format(minttypes.TokenReleaseDateFormat), + "usei", + 200, + ) + epoch.CurrentEpochStartTime = currentTime.AddDate(0, 5, 0) + nextScheduledRelease := mintKeeper.GetNextScheduledTokenRelease(epoch, tokenReleaseSchedule, secondMinter) + require.Nil(t, nextScheduledRelease) + }) + + t.Run("test case where we skip the start date due to outage for two days", func(t *testing.T) { + // No next scheduled token release intially + epoch.CurrentEpochStartTime = currentTime.AddDate(0, 0, 0) + nextScheduledRelease := mintKeeper.GetNextScheduledTokenRelease(epoch, tokenReleaseSchedule, currentMinter) + require.Nil(t, nextScheduledRelease) + + // First mint was +1 but the chain recoverd on +3 + epoch.CurrentEpochStartTime = currentTime.AddDate(0, 0, 3) + nextScheduledRelease = mintKeeper.GetNextScheduledTokenRelease(epoch, tokenReleaseSchedule, currentMinter) + require.Equal(t, int64(100), nextScheduledRelease.GetTokenReleaseAmount()) + require.Equal(t, currentTime.AddDate(0, 0, 1).Format(minttypes.TokenReleaseDateFormat), nextScheduledRelease.GetStartDate()) + }) +} + +func TestGetOrUpdateLatestMinter(t *testing.T) { + t.Parallel() + app, ctx := createTestApp(false) + mintKeeper := app.MintKeeper + currentTime := time.Now() + epoch := epochTypes.Epoch{ + CurrentEpochStartTime: currentTime, + } + + t.Run("No ongoing release", func(t *testing.T) { + currentMinter := mintKeeper.GetOrUpdateLatestMinter(ctx, epoch) + require.False(t, currentMinter.OngoingRelease()) + }) + + t.Run("No ongoing release, but there's a scheduled release", func(t *testing.T) { + mintKeeper.SetMinter(ctx, mintTypes.NewMinter( + currentTime.Format(minttypes.TokenReleaseDateFormat), + currentTime.AddDate(1,0,0).Format(minttypes.TokenReleaseDateFormat), + "usei", + 1000, + )) + epoch.CurrentEpochStartTime = currentTime + currentMinter := mintKeeper.GetOrUpdateLatestMinter(ctx, epoch) + require.True(t, currentMinter.OngoingRelease()) + require.Equal(t, currentTime.Format(minttypes.TokenReleaseDateFormat), currentMinter.StartDate) + mintKeeper.SetMinter(ctx, mintTypes.DefaultInitialMinter()) + }) + + t.Run("TokenReleaseSchedule not sorted", func(t *testing.T) { + params := mintKeeper.GetParams(ctx) + params.TokenReleaseSchedule = []types.ScheduledTokenRelease{ + { + StartDate: currentTime.AddDate(0,20,0).Format(minttypes.TokenReleaseDateFormat), + EndDate: currentTime.AddDate(0,45,0).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 2000, + }, + { + StartDate: currentTime.Format(minttypes.TokenReleaseDateFormat), + EndDate: currentTime.AddDate(0,15,0).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 1000, + }, + } + mintKeeper.SetParams(ctx, params) + + epoch.CurrentEpochStartTime = currentTime + currentMinter := mintKeeper.GetOrUpdateLatestMinter(ctx, epoch) + require.True(t, currentMinter.OngoingRelease()) + require.Equal(t, currentTime.Format(minttypes.TokenReleaseDateFormat), currentMinter.StartDate) + }) +} diff --git a/x/mint/simulation/genesis.go b/x/mint/simulation/genesis.go index a40317914a..becec94b28 100644 --- a/x/mint/simulation/genesis.go +++ b/x/mint/simulation/genesis.go @@ -16,15 +16,16 @@ import ( // RandomizedGenState generates a random GenesisState for mint. func RandomizedGenState(simState *module.SimulationState) { mintDenom := sdk.DefaultBondDenom - randomProvision := rand.Int63n(1000000) + randomProvision := uint64(rand.Int63n(1000000)) currentDate := time.Now() // Epochs are every minute, set reduction period to be 1 year tokenReleaseSchedule := []types.ScheduledTokenRelease{} for i := 1; i <= 10; i++ { scheduledTokenRelease := types.ScheduledTokenRelease{ - Date: currentDate.AddDate(1, 0, 0).Format(types.TokenReleaseDateFormat), - TokenReleaseAmount: randomProvision / int64(i), + StartDate: currentDate.AddDate(1, 0, 0).Format(types.TokenReleaseDateFormat), + EndDate: currentDate.AddDate(3, 0, 0).Format(types.TokenReleaseDateFormat), + TokenReleaseAmount: randomProvision / uint64(i), } tokenReleaseSchedule = append(tokenReleaseSchedule, scheduledTokenRelease) } diff --git a/x/mint/types/keys.go b/x/mint/types/keys.go index bbcc13251f..833a4fc57e 100644 --- a/x/mint/types/keys.go +++ b/x/mint/types/keys.go @@ -3,9 +3,6 @@ package types // MinterKey is the key to use for the keeper store. var MinterKey = []byte{0x00} -// LastTokenReleaseDate is the key to use for when the last token release was done. -var LastTokenReleaseDate = []byte{0x03} - const ( // module name ModuleName = "mint" diff --git a/x/mint/types/mint.pb.go b/x/mint/types/mint.pb.go index 3716c63266..231e356730 100644 --- a/x/mint/types/mint.pb.go +++ b/x/mint/types/mint.pb.go @@ -5,7 +5,6 @@ package types import ( fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -26,10 +25,14 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Minter represents the most recent type Minter struct { - LastMintAmount github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=last_mint_amount,json=lastMintAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"last_mint_amount" yaml:"last_mint_amount"` - LastMintDate string `protobuf:"bytes,2,opt,name=last_mint_date,json=lastMintDate,proto3" json:"last_mint_date,omitempty" yaml:"last_mint_date"` - LastMintHeight int64 `protobuf:"varint,3,opt,name=last_mint_height,json=lastMintHeight,proto3" json:"last_mint_height,omitempty" yaml:"last_mint_height"` - Denom string `protobuf:"bytes,4,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` + StartDate string `protobuf:"bytes,1,opt,name=start_date,json=startDate,proto3" json:"start_date,omitempty"` + EndDate string `protobuf:"bytes,2,opt,name=end_date,json=endDate,proto3" json:"end_date,omitempty"` + Denom string `protobuf:"bytes,3,opt,name=denom,proto3" json:"denom,omitempty"` + TotalMintAmount uint64 `protobuf:"varint,4,opt,name=total_mint_amount,json=totalMintAmount,proto3" json:"total_mint_amount,omitempty"` + RemainingMintAmount uint64 `protobuf:"varint,5,opt,name=remaining_mint_amount,json=remainingMintAmount,proto3" json:"remaining_mint_amount,omitempty"` + LastMintAmount uint64 `protobuf:"varint,6,opt,name=last_mint_amount,json=lastMintAmount,proto3" json:"last_mint_amount,omitempty"` + LastMintDate string `protobuf:"bytes,7,opt,name=last_mint_date,json=lastMintDate,proto3" json:"last_mint_date,omitempty"` + LastMintHeight uint64 `protobuf:"varint,8,opt,name=last_mint_height,json=lastMintHeight,proto3" json:"last_mint_height,omitempty"` } func (m *Minter) Reset() { *m = Minter{} } @@ -65,18 +68,18 @@ func (m *Minter) XXX_DiscardUnknown() { var xxx_messageInfo_Minter proto.InternalMessageInfo -func (m *Minter) GetLastMintDate() string { +func (m *Minter) GetStartDate() string { if m != nil { - return m.LastMintDate + return m.StartDate } return "" } -func (m *Minter) GetLastMintHeight() int64 { +func (m *Minter) GetEndDate() string { if m != nil { - return m.LastMintHeight + return m.EndDate } - return 0 + return "" } func (m *Minter) GetDenom() string { @@ -86,9 +89,45 @@ func (m *Minter) GetDenom() string { return "" } +func (m *Minter) GetTotalMintAmount() uint64 { + if m != nil { + return m.TotalMintAmount + } + return 0 +} + +func (m *Minter) GetRemainingMintAmount() uint64 { + if m != nil { + return m.RemainingMintAmount + } + return 0 +} + +func (m *Minter) GetLastMintAmount() uint64 { + if m != nil { + return m.LastMintAmount + } + return 0 +} + +func (m *Minter) GetLastMintDate() string { + if m != nil { + return m.LastMintDate + } + return "" +} + +func (m *Minter) GetLastMintHeight() uint64 { + if m != nil { + return m.LastMintHeight + } + return 0 +} + type ScheduledTokenRelease struct { - Date string `protobuf:"bytes,1,opt,name=date,proto3" json:"date,omitempty"` - TokenReleaseAmount int64 `protobuf:"varint,2,opt,name=token_release_amount,json=tokenReleaseAmount,proto3" json:"token_release_amount,omitempty"` + StartDate string `protobuf:"bytes,1,opt,name=start_date,json=startDate,proto3" json:"start_date,omitempty"` + EndDate string `protobuf:"bytes,2,opt,name=end_date,json=endDate,proto3" json:"end_date,omitempty"` + TokenReleaseAmount uint64 `protobuf:"varint,3,opt,name=token_release_amount,json=tokenReleaseAmount,proto3" json:"token_release_amount,omitempty"` } func (m *ScheduledTokenRelease) Reset() { *m = ScheduledTokenRelease{} } @@ -124,14 +163,21 @@ func (m *ScheduledTokenRelease) XXX_DiscardUnknown() { var xxx_messageInfo_ScheduledTokenRelease proto.InternalMessageInfo -func (m *ScheduledTokenRelease) GetDate() string { +func (m *ScheduledTokenRelease) GetStartDate() string { if m != nil { - return m.Date + return m.StartDate } return "" } -func (m *ScheduledTokenRelease) GetTokenReleaseAmount() int64 { +func (m *ScheduledTokenRelease) GetEndDate() string { + if m != nil { + return m.EndDate + } + return "" +} + +func (m *ScheduledTokenRelease) GetTokenReleaseAmount() uint64 { if m != nil { return m.TokenReleaseAmount } @@ -201,36 +247,35 @@ func init() { func init() { proto.RegisterFile("mint/v1beta1/mint.proto", fileDescriptor_06339c129491fd39) } var fileDescriptor_06339c129491fd39 = []byte{ - // 453 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0xc1, 0x6a, 0xdb, 0x40, - 0x10, 0xd5, 0xda, 0xae, 0x21, 0xdb, 0x10, 0xc2, 0xe2, 0x34, 0x4a, 0x4b, 0x24, 0xb3, 0xd0, 0xe0, - 0x4b, 0x56, 0x49, 0x7b, 0xcb, 0xa5, 0xd4, 0xb8, 0x90, 0x1e, 0x0a, 0x45, 0xed, 0xa9, 0x50, 0xcc, - 0x5a, 0x1a, 0xac, 0x25, 0x92, 0x36, 0x78, 0xd7, 0xa5, 0xf9, 0x88, 0x42, 0x8f, 0x3d, 0xf6, 0x07, - 0xfa, 0x09, 0xbd, 0xe7, 0x98, 0x63, 0xe9, 0x41, 0x14, 0xfb, 0x0f, 0xf4, 0x05, 0x65, 0x77, 0x23, - 0xaa, 0x06, 0xe7, 0xa4, 0xd9, 0x37, 0x6f, 0xde, 0xbc, 0x19, 0x0d, 0xde, 0x2f, 0x44, 0xa9, 0xa3, - 0x4f, 0xa7, 0x33, 0xd0, 0xfc, 0x34, 0x32, 0x0f, 0x76, 0xb9, 0x90, 0x5a, 0x92, 0x03, 0x05, 0xc2, - 0x46, 0x89, 0xcc, 0x99, 0x02, 0x91, 0x64, 0x5c, 0x94, 0xcc, 0x10, 0x1e, 0x0f, 0xe6, 0x72, 0x2e, - 0x6d, 0x2e, 0x32, 0x91, 0x2b, 0xa0, 0x3f, 0x3a, 0xb8, 0xff, 0x46, 0x94, 0x1a, 0x16, 0x44, 0xe1, - 0xdd, 0x9c, 0x2b, 0x3d, 0x35, 0xec, 0x29, 0x2f, 0xe4, 0xb2, 0xd4, 0x3e, 0x1a, 0xa2, 0xd1, 0xd6, - 0xf8, 0xf5, 0x75, 0x15, 0x7a, 0xbf, 0xab, 0xf0, 0x68, 0x2e, 0x74, 0xb6, 0x9c, 0xb1, 0x44, 0x16, - 0x51, 0x22, 0x55, 0x21, 0xd5, 0xed, 0xe7, 0x58, 0xa5, 0x17, 0x91, 0xbe, 0xba, 0x04, 0xc5, 0x26, - 0x90, 0xd4, 0x55, 0xb8, 0x7f, 0xc5, 0x8b, 0xfc, 0x8c, 0xde, 0xd5, 0xa3, 0xf1, 0x8e, 0x81, 0x4c, - 0xc3, 0x97, 0x16, 0x20, 0x2f, 0xf0, 0xce, 0x3f, 0x52, 0xca, 0x35, 0xf8, 0x1d, 0xdb, 0xf2, 0xa0, - 0xae, 0xc2, 0xbd, 0xbb, 0x22, 0x26, 0x4f, 0xe3, 0xed, 0x46, 0x62, 0xc2, 0x35, 0x90, 0x57, 0x6d, - 0xd7, 0x19, 0x88, 0x79, 0xa6, 0xfd, 0xee, 0x10, 0x8d, 0xba, 0xe3, 0x27, 0x9b, 0x7c, 0x38, 0x46, - 0xcb, 0xc7, 0xb9, 0x05, 0xc8, 0x11, 0x7e, 0x90, 0x42, 0x29, 0x0b, 0xbf, 0x67, 0xdb, 0xef, 0xd6, - 0x55, 0xb8, 0xed, 0x6a, 0x2d, 0x4c, 0x63, 0x97, 0xa6, 0x1f, 0xf1, 0xde, 0xbb, 0x24, 0x83, 0x74, - 0x99, 0x43, 0xfa, 0x5e, 0x5e, 0x40, 0x19, 0x43, 0x0e, 0x5c, 0x01, 0x21, 0xb8, 0x67, 0xed, 0xdb, - 0x8d, 0xc5, 0x36, 0x26, 0x27, 0x78, 0xa0, 0x0d, 0x67, 0xba, 0x70, 0xa4, 0x66, 0xab, 0x66, 0xc4, - 0x6e, 0x4c, 0x74, 0xab, 0xde, 0xad, 0x83, 0xfe, 0x44, 0xb8, 0xff, 0x96, 0x2f, 0x78, 0xa1, 0xc8, - 0x21, 0xc6, 0x6e, 0x68, 0x6b, 0xcb, 0xc9, 0x6e, 0x19, 0x64, 0x62, 0x00, 0xf2, 0x05, 0xe1, 0x47, - 0xff, 0x8b, 0xab, 0x5b, 0x5f, 0x7e, 0x67, 0xd8, 0x1d, 0x3d, 0x7c, 0x76, 0xc2, 0xee, 0xbd, 0x05, - 0xb6, 0x71, 0x84, 0xf1, 0x53, 0xf3, 0x9b, 0xeb, 0x2a, 0x3c, 0x74, 0x83, 0x6f, 0x56, 0xa7, 0xf1, - 0xa0, 0xed, 0xbb, 0x51, 0x3a, 0xeb, 0x7d, 0xfb, 0x1e, 0x7a, 0xe3, 0xf3, 0xeb, 0x55, 0x80, 0x6e, - 0x56, 0x01, 0xfa, 0xb3, 0x0a, 0xd0, 0xd7, 0x75, 0xe0, 0xdd, 0xac, 0x03, 0xef, 0xd7, 0x3a, 0xf0, - 0x3e, 0xb0, 0xd6, 0xed, 0x28, 0x10, 0xc7, 0x8d, 0x33, 0xfb, 0xb0, 0xd6, 0xa2, 0xcf, 0xf6, 0x92, - 0xdd, 0x1d, 0xcd, 0xfa, 0x96, 0xf0, 0xfc, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4b, 0x7e, 0xc4, - 0xcc, 0xeb, 0x02, 0x00, 0x00, + // 442 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x52, 0x31, 0x6f, 0xd3, 0x40, + 0x18, 0xf5, 0x25, 0x69, 0xda, 0x1e, 0xa8, 0x80, 0x49, 0xc1, 0x45, 0xaa, 0x13, 0x59, 0x20, 0x45, + 0x48, 0xd8, 0x6d, 0xd9, 0xba, 0x51, 0x75, 0xe8, 0x82, 0x84, 0x02, 0x13, 0x8b, 0x75, 0xb1, 0x3f, + 0xd9, 0x27, 0xec, 0xbb, 0xca, 0xf7, 0x05, 0xd1, 0x99, 0x19, 0x89, 0x91, 0x91, 0xdf, 0xc0, 0xce, + 0xde, 0xb1, 0x23, 0x53, 0x85, 0x92, 0x7f, 0xc0, 0x2f, 0x40, 0xf7, 0xb9, 0x06, 0x5b, 0x0a, 0x13, + 0x9b, 0xbf, 0xf7, 0xde, 0xbd, 0xef, 0x3d, 0xdf, 0xf1, 0x87, 0xa5, 0x54, 0x18, 0xbd, 0x3f, 0x9c, + 0x03, 0x8a, 0xc3, 0xc8, 0x0e, 0xe1, 0x79, 0xa5, 0x51, 0xbb, 0x7b, 0x06, 0x24, 0x7d, 0x25, 0xba, + 0x08, 0x0d, 0xc8, 0x24, 0x17, 0x52, 0x85, 0x56, 0xf0, 0x68, 0x94, 0xe9, 0x4c, 0x13, 0x17, 0xd9, + 0xaf, 0xfa, 0x40, 0xf0, 0xad, 0xc7, 0x87, 0x2f, 0xa5, 0x42, 0xa8, 0xdc, 0x7d, 0xce, 0x0d, 0x8a, + 0x0a, 0xe3, 0x54, 0x20, 0x78, 0x6c, 0xc2, 0xa6, 0xdb, 0xb3, 0x6d, 0x42, 0x4e, 0x05, 0x82, 0xbb, + 0xc7, 0xb7, 0x40, 0xa5, 0x35, 0xd9, 0x23, 0x72, 0x13, 0x54, 0x4a, 0xd4, 0x88, 0x6f, 0xa4, 0xa0, + 0x74, 0xe9, 0xf5, 0x09, 0xaf, 0x07, 0xf7, 0x29, 0xbf, 0x87, 0x1a, 0x45, 0x11, 0xdb, 0xf5, 0xb1, + 0x28, 0xf5, 0x42, 0xa1, 0x37, 0x98, 0xb0, 0xe9, 0x60, 0x76, 0x87, 0x08, 0xbb, 0xf7, 0x05, 0xc1, + 0xee, 0x11, 0xdf, 0xad, 0xa0, 0x14, 0x52, 0x49, 0x95, 0x75, 0xf4, 0x1b, 0xa4, 0xbf, 0xff, 0x87, + 0x6c, 0x9d, 0x99, 0xf2, 0xbb, 0x85, 0x30, 0xd8, 0x91, 0x0f, 0x49, 0xbe, 0x63, 0xf1, 0x96, 0xf2, + 0x31, 0xdf, 0xf9, 0xab, 0xa4, 0x02, 0x9b, 0x14, 0xf4, 0x76, 0xa3, 0xa3, 0x16, 0x1d, 0xbf, 0x1c, + 0x64, 0x96, 0xa3, 0xb7, 0xd5, 0xf5, 0x3b, 0x23, 0x34, 0xf8, 0xc8, 0xf8, 0xee, 0xeb, 0x24, 0x87, + 0x74, 0x51, 0x40, 0xfa, 0x46, 0xbf, 0x03, 0x35, 0x83, 0x02, 0x84, 0x81, 0xff, 0xf8, 0x87, 0x07, + 0x7c, 0x84, 0xd6, 0x29, 0xae, 0x6a, 0xab, 0xa6, 0x51, 0x9f, 0x12, 0xb8, 0xd8, 0xda, 0x52, 0xb7, + 0x0a, 0xbe, 0x33, 0x3e, 0x7c, 0x25, 0x2a, 0x51, 0x1a, 0xbb, 0xb6, 0xee, 0x46, 0xb7, 0x70, 0xb3, + 0xd6, 0x22, 0xa7, 0x74, 0x13, 0x9f, 0x18, 0x7f, 0xd0, 0x35, 0x37, 0x37, 0xe9, 0xbd, 0xde, 0xa4, + 0x3f, 0xbd, 0x75, 0x74, 0x10, 0xfe, 0xf3, 0xdd, 0x84, 0x6b, 0x8b, 0x9e, 0x3c, 0xb9, 0xbc, 0x1e, + 0x3b, 0xbf, 0xae, 0xc7, 0xfb, 0x17, 0xa2, 0x2c, 0x8e, 0x83, 0xf5, 0xee, 0xc1, 0x6c, 0xd4, 0xce, + 0xdd, 0x38, 0x1d, 0x0f, 0xbe, 0x7c, 0x1d, 0x3b, 0x27, 0x67, 0x97, 0x4b, 0x9f, 0x5d, 0x2d, 0x7d, + 0xf6, 0x73, 0xe9, 0xb3, 0xcf, 0x2b, 0xdf, 0xb9, 0x5a, 0xf9, 0xce, 0x8f, 0x95, 0xef, 0xbc, 0x0d, + 0x33, 0x89, 0xf9, 0x62, 0x1e, 0x26, 0xba, 0x8c, 0x0c, 0xc8, 0x67, 0x4d, 0x32, 0x1a, 0x28, 0x5a, + 0xf4, 0x81, 0x5e, 0x7d, 0x84, 0x17, 0xe7, 0x60, 0xe6, 0x43, 0x12, 0x3c, 0xff, 0x1d, 0x00, 0x00, + 0xff, 0xff, 0x9f, 0x5b, 0x5a, 0x63, 0x17, 0x03, 0x00, 0x00, } func (m *Minter) Marshal() (dAtA []byte, err error) { @@ -253,35 +298,54 @@ func (m *Minter) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintMint(dAtA, i, uint64(len(m.Denom))) - i-- - dAtA[i] = 0x22 - } if m.LastMintHeight != 0 { i = encodeVarintMint(dAtA, i, uint64(m.LastMintHeight)) i-- - dAtA[i] = 0x18 + dAtA[i] = 0x40 } if len(m.LastMintDate) > 0 { i -= len(m.LastMintDate) copy(dAtA[i:], m.LastMintDate) i = encodeVarintMint(dAtA, i, uint64(len(m.LastMintDate))) i-- + dAtA[i] = 0x3a + } + if m.LastMintAmount != 0 { + i = encodeVarintMint(dAtA, i, uint64(m.LastMintAmount)) + i-- + dAtA[i] = 0x30 + } + if m.RemainingMintAmount != 0 { + i = encodeVarintMint(dAtA, i, uint64(m.RemainingMintAmount)) + i-- + dAtA[i] = 0x28 + } + if m.TotalMintAmount != 0 { + i = encodeVarintMint(dAtA, i, uint64(m.TotalMintAmount)) + i-- + dAtA[i] = 0x20 + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintMint(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x1a + } + if len(m.EndDate) > 0 { + i -= len(m.EndDate) + copy(dAtA[i:], m.EndDate) + i = encodeVarintMint(dAtA, i, uint64(len(m.EndDate))) + i-- dAtA[i] = 0x12 } - { - size := m.LastMintAmount.Size() - i -= size - if _, err := m.LastMintAmount.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintMint(dAtA, i, uint64(size)) + if len(m.StartDate) > 0 { + i -= len(m.StartDate) + copy(dAtA[i:], m.StartDate) + i = encodeVarintMint(dAtA, i, uint64(len(m.StartDate))) + i-- + dAtA[i] = 0xa } - i-- - dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -308,12 +372,19 @@ func (m *ScheduledTokenRelease) MarshalToSizedBuffer(dAtA []byte) (int, error) { if m.TokenReleaseAmount != 0 { i = encodeVarintMint(dAtA, i, uint64(m.TokenReleaseAmount)) i-- - dAtA[i] = 0x10 + dAtA[i] = 0x18 + } + if len(m.EndDate) > 0 { + i -= len(m.EndDate) + copy(dAtA[i:], m.EndDate) + i = encodeVarintMint(dAtA, i, uint64(len(m.EndDate))) + i-- + dAtA[i] = 0x12 } - if len(m.Date) > 0 { - i -= len(m.Date) - copy(dAtA[i:], m.Date) - i = encodeVarintMint(dAtA, i, uint64(len(m.Date))) + if len(m.StartDate) > 0 { + i -= len(m.StartDate) + copy(dAtA[i:], m.StartDate) + i = encodeVarintMint(dAtA, i, uint64(len(m.StartDate))) i-- dAtA[i] = 0xa } @@ -381,19 +452,34 @@ func (m *Minter) Size() (n int) { } var l int _ = l - l = m.LastMintAmount.Size() - n += 1 + l + sovMint(uint64(l)) - l = len(m.LastMintDate) + l = len(m.StartDate) if l > 0 { n += 1 + l + sovMint(uint64(l)) } - if m.LastMintHeight != 0 { - n += 1 + sovMint(uint64(m.LastMintHeight)) + l = len(m.EndDate) + if l > 0 { + n += 1 + l + sovMint(uint64(l)) } l = len(m.Denom) if l > 0 { n += 1 + l + sovMint(uint64(l)) } + if m.TotalMintAmount != 0 { + n += 1 + sovMint(uint64(m.TotalMintAmount)) + } + if m.RemainingMintAmount != 0 { + n += 1 + sovMint(uint64(m.RemainingMintAmount)) + } + if m.LastMintAmount != 0 { + n += 1 + sovMint(uint64(m.LastMintAmount)) + } + l = len(m.LastMintDate) + if l > 0 { + n += 1 + l + sovMint(uint64(l)) + } + if m.LastMintHeight != 0 { + n += 1 + sovMint(uint64(m.LastMintHeight)) + } return n } @@ -403,7 +489,11 @@ func (m *ScheduledTokenRelease) Size() (n int) { } var l int _ = l - l = len(m.Date) + l = len(m.StartDate) + if l > 0 { + n += 1 + l + sovMint(uint64(l)) + } + l = len(m.EndDate) if l > 0 { n += 1 + l + sovMint(uint64(l)) } @@ -469,7 +559,7 @@ func (m *Minter) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LastMintAmount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field StartDate", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -497,13 +587,11 @@ func (m *Minter) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.LastMintAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.StartDate = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LastMintDate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field EndDate", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -531,13 +619,13 @@ func (m *Minter) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.LastMintDate = string(dAtA[iNdEx:postIndex]) + m.EndDate = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field LastMintHeight", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) } - m.LastMintHeight = 0 + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowMint @@ -547,14 +635,84 @@ func (m *Minter) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.LastMintHeight |= int64(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMint + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalMintAmount", wireType) + } + m.TotalMintAmount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalMintAmount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RemainingMintAmount", wireType) + } + m.RemainingMintAmount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RemainingMintAmount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LastMintAmount", wireType) + } + m.LastMintAmount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LastMintAmount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LastMintDate", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -582,8 +740,27 @@ func (m *Minter) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Denom = string(dAtA[iNdEx:postIndex]) + m.LastMintDate = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LastMintHeight", wireType) + } + m.LastMintHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LastMintHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipMint(dAtA[iNdEx:]) @@ -636,7 +813,7 @@ func (m *ScheduledTokenRelease) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Date", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field StartDate", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -664,9 +841,41 @@ func (m *ScheduledTokenRelease) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Date = string(dAtA[iNdEx:postIndex]) + m.StartDate = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EndDate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMint + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EndDate = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field TokenReleaseAmount", wireType) } @@ -680,7 +889,7 @@ func (m *ScheduledTokenRelease) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.TokenReleaseAmount |= int64(b&0x7F) << shift + m.TokenReleaseAmount |= uint64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/mint/types/minter.go b/x/mint/types/minter.go index f0c4cc1037..d46916fe4c 100644 --- a/x/mint/types/minter.go +++ b/x/mint/types/minter.go @@ -5,27 +5,37 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/sei-protocol/sei-chain/utils/metrics" epochTypes "github.com/sei-protocol/sei-chain/x/epoch/types" ) // NewMinter returns a new Minter object with the given inflation and annual // provisions values. -func NewMinter(lastMintAmount sdk.Dec, lastMintDate string, lastMintHeight int64, denom string) Minter { +func NewMinter( + startDate string, + endDate string, + denom string, + totalMintAmount uint64, +) Minter { return Minter{ - LastMintAmount: lastMintAmount, - LastMintDate: lastMintDate, - LastMintHeight: lastMintHeight, - Denom: denom, + StartDate: startDate, + EndDate: endDate, + Denom: sdk.DefaultBondDenom, + TotalMintAmount: totalMintAmount, + RemainingMintAmount: totalMintAmount, + LastMintDate: time.Time{}.Format(TokenReleaseDateFormat), + LastMintHeight: 0, + LastMintAmount: 0, } } -// InitialMinter returns an initial Minter object with a given inflation value. +// InitialMinter returns an initial Minter object with default values with no previous mints func InitialMinter() Minter { return NewMinter( - sdk.NewDec(0), - "1970-01-01", - 0, + time.Time{}.Format(TokenReleaseDateFormat), + time.Time{}.Format(TokenReleaseDateFormat), sdk.DefaultBondDenom, + 0, ) } @@ -37,45 +47,95 @@ func DefaultInitialMinter() Minter { // validate minter func ValidateMinter(minter Minter) error { + if minter.GetTotalMintAmount() < minter.GetRemainingMintAmount() { + return fmt.Errorf("total mint amount cannot be less than remaining mint amount") + } + endDate := minter.GetEndDateTime() + startDate := minter.GetStartDateTime() + if endDate.Before(startDate) { + return fmt.Errorf("end date must be after start date %s < %s", endDate, startDate) + } return nil } func (m Minter) GetLastMintDateTime() time.Time { - lastTokenReleaseDate, err := time.Parse(TokenReleaseDateFormat, m.GetLastMintDate()) + lastMinteDateTime, err := time.Parse(TokenReleaseDateFormat, m.GetLastMintDate()) + if err != nil { + // This should not happen as the date is validated when the minter is created + panic(fmt.Errorf("invalid end date for current minter: %s, minter=%s", err, m.String())) + } + return lastMinteDateTime +} + +func (m Minter) GetStartDateTime() time.Time { + startDateTime, err := time.Parse(TokenReleaseDateFormat, m.GetStartDate()) + if err != nil { + // This should not happen as the date is validated when the minter is created + panic(fmt.Errorf("invalid end date for current minter: %s, minter=%s", err, m.String())) + } + return startDateTime +} + +func (m Minter) GetEndDateTime() time.Time { + endDateTime, err := time.Parse(TokenReleaseDateFormat, m.GetEndDate()) if err != nil { - panic(fmt.Errorf("invalid last token release date: %s", err)) + // This should not happen as the date is validated when the minter is created + panic(fmt.Errorf("invalid end date for current minter: %s, minter=%s", err, m.String())) } - return lastTokenReleaseDate + return endDateTime } -func (m Minter) GetCoin() sdk.Coin { - return sdk.NewCoin(m.GetDenom(), m.LastMintAmount.TruncateInt()) +func (m Minter) GetLastMintAmountCoin() sdk.Coin { + return sdk.NewCoin(m.GetDenom(), sdk.NewInt(int64(m.GetLastMintAmount()))) } -func (m Minter) GetCoins() sdk.Coins { - return sdk.NewCoins(m.GetCoin()) +func (m Minter) GetReleaseAmountToday() sdk.Coins { + return sdk.NewCoins(sdk.NewCoin(m.GetDenom(), sdk.NewInt(int64(m.getReleaseAmountToday())))) } -func (m Minter) GetLastMintAmount() sdk.Dec { - return m.LastMintAmount +func (m Minter) RecordSuccessfulMint(ctx sdk.Context, epoch epochTypes.Epoch) { + m.RemainingMintAmount -= m.getReleaseAmountToday() + m.LastMintDate = epoch.CurrentEpochStartTime.Format(TokenReleaseDateFormat) + m.LastMintHeight = uint64(epoch.CurrentEpochHeight) + m.LastMintAmount = m.getReleaseAmountToday() + metrics.SetCoinsMinted(m.getReleaseAmountToday(), m.GetDenom()) + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + EventTypeMint, + sdk.NewAttribute(AttributeEpochNumber, fmt.Sprintf("%d", epoch.GetCurrentEpoch())), + sdk.NewAttribute(AttributeKeyEpochProvisions, m.GetLastMintDate()), + sdk.NewAttribute(sdk.AttributeKeyAmount, m.GetReleaseAmountToday().String()), + ), + ) } -/* Returns ScheduledRelease if the date of the block matches the scheduled release date. - * You may only schedule one release of tokens on each day, the date must be in - * types.TokenReleaseDateFormat. - */ -func GetScheduledTokenRelease( - epoch epochTypes.Epoch, - lastTokenReleaseDate time.Time, - tokenReleaseSchedule []ScheduledTokenRelease, -) *ScheduledTokenRelease { - blockDateString := epoch.GetCurrentEpochStartTime().Format(TokenReleaseDateFormat) - lastTokenReleaseDateString := lastTokenReleaseDate.Format(TokenReleaseDateFormat) - for _, scheduledRelease := range tokenReleaseSchedule { - scheduledReleaseDate := scheduledRelease.GetDate() - if blockDateString >= scheduledReleaseDate && scheduledReleaseDate > lastTokenReleaseDateString { - return &scheduledRelease - } +func (m Minter) getReleaseAmountToday() uint64 { + numberOfDaysLeft := m.getNumberOfDaysLeft() + if numberOfDaysLeft == 0 { + return 0 } - return nil + return m.GetRemainingMintAmount() / numberOfDaysLeft +} + +func (m Minter) getNumberOfDaysLeft() uint64 { + startDate := m.GetStartDateTime() + endDate := m.GetEndDateTime() + return daysBetween(endDate, startDate) +} + +func (m Minter) OngoingRelease() bool { + endDateTime := m.GetEndDateTime() + return m.GetRemainingMintAmount() > 0 && time.Now().Before(endDateTime) +} + +func daysBetween(a, b time.Time) uint64 { + // Always return a positive value between the dates + if a.Before(b) { + a, b = b, a + } + duration := a.Sub(b) + hours := duration.Hours() + // Rounds down, the last day should be 1 day diff so it will always release any remaining amount + return uint64(hours / 24) } diff --git a/x/mint/types/minter_test.go b/x/mint/types/minter_test.go index 1471fa06db..4e18db82df 100644 --- a/x/mint/types/minter_test.go +++ b/x/mint/types/minter_test.go @@ -4,107 +4,9 @@ import ( "testing" "time" - "github.com/sei-protocol/sei-chain/x/epoch/types" "github.com/stretchr/testify/require" ) -func getGenesisTime() time.Time { - return time.Date(2022, time.Month(7), 18, 10, 0, 0, 0, time.UTC) -} - -func getEpoch(currTime time.Time) types.Epoch { - genesisTime := getGenesisTime() - // Epochs increase every minute, so derive based on the time - return types.Epoch{ - GenesisTime: genesisTime, - EpochDuration: time.Minute, - CurrentEpoch: uint64(currTime.Sub(genesisTime).Minutes()), - CurrentEpochStartTime: currTime, - CurrentEpochHeight: 0, - } -} - -func getTestTokenReleaseSchedule(currTime time.Time, numReleases int) []ScheduledTokenRelease { - tokenReleaseSchedule := []ScheduledTokenRelease{} - - for i := 1; i <= numReleases; i++ { - // Token release every year - currTime = currTime.AddDate(1, 0, 0) - scheduledRelease := ScheduledTokenRelease{Date: currTime.Format(TokenReleaseDateFormat), TokenReleaseAmount: 2500000 / int64(i)} - tokenReleaseSchedule = append(tokenReleaseSchedule, scheduledRelease) - } - - return tokenReleaseSchedule -} - -// Next epoch provisions benchmarking -// cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz -// BenchmarkGetScheduledTokenRelease-16 319.7 ns/op 56 B/op 3 allocs/op -func BenchmarkGetScheduledTokenRelease(b *testing.B) { - b.ReportAllocs() - - genesisTime := getGenesisTime() - epoch := getEpoch(genesisTime) - tokenReleaseSchedule := getTestTokenReleaseSchedule(genesisTime, 10) - - // run the GetScheduledTokenRelease function b.N times - for n := 0; n < b.N; n++ { - GetScheduledTokenRelease( - epoch, - genesisTime, - tokenReleaseSchedule, - ) - } -} - -func TestGetScheduledTokenReleaseNil(t *testing.T) { - genesisTime := getGenesisTime() - epoch := getEpoch(genesisTime.AddDate(20, 0, 0)) - tokenReleaseSchedule := getTestTokenReleaseSchedule(genesisTime, 10) - - scheduledTokenRelease := GetScheduledTokenRelease( - epoch, - genesisTime.AddDate(10, 0, 0), - tokenReleaseSchedule, - ) - // Should return nil if there are no scheduled releases - require.Nil(t, scheduledTokenRelease) -} - -func TestGetScheduledTokenRelease(t *testing.T) { - genesisTime := getGenesisTime() - epoch := getEpoch(genesisTime.AddDate(5, 0, 0)) - tokenReleaseSchedule := getTestTokenReleaseSchedule(genesisTime, 10) - - scheduledTokenRelease := GetScheduledTokenRelease( - epoch, - genesisTime.AddDate(4, 0, 0), - tokenReleaseSchedule, - ) - - require.NotNil(t, scheduledTokenRelease) - require.Equal(t, scheduledTokenRelease.GetTokenReleaseAmount(), int64(2500000/5)) - require.Equal(t, scheduledTokenRelease.GetDate(), genesisTime.AddDate(5, 0, 0).Format(TokenReleaseDateFormat)) -} - -func TestGetScheduledTokenReleaseOverdue(t *testing.T) { - genesisTime := getGenesisTime() - tokenReleaseSchedule := getTestTokenReleaseSchedule(genesisTime, 10) - scheduledTokenRelease := GetScheduledTokenRelease( - // 10 days past the first token release schedule - // possible if the chain was down more than a day - getEpoch(genesisTime.AddDate(3, 0, 10)), - // Last release was the year before - genesisTime.AddDate(2, 0, 0), - tokenReleaseSchedule, - ) - - require.NotNil(t, scheduledTokenRelease) - // Year 3 release should still happen (second time) - require.Equal(t, scheduledTokenRelease.GetTokenReleaseAmount(), int64(2500000/3)) - require.Equal(t, scheduledTokenRelease.GetDate(), genesisTime.AddDate(3, 0, 0).Format(TokenReleaseDateFormat)) -} - func TestParamsUsei(t *testing.T) { params := DefaultParams() err := params.Validate() @@ -114,3 +16,75 @@ func TestParamsUsei(t *testing.T) { err = params.Validate() require.NotNil(t, err) } + +func TestDaysBetween(t *testing.T) { + t.Parallel() + testCases := []struct { + name string + date1 string + date2 string + expected uint64 + }{ + { + name: "Same day", + date1: "2023-04-20T00:00:00Z", + date2: "2023-04-20T23:59:59Z", + expected: 0, + }, + { + name: "One day apart", + date1: "2023-04-20T00:00:00Z", + date2: "2023-04-21T00:00:00Z", + expected: 1, + }, + { + name: "Five days apart", + date1: "2023-04-20T00:00:00Z", + date2: "2023-04-25T00:00:00Z", + expected: 5, + }, + { + name: "Inverted dates", + date1: "2023-04-25T00:00:00Z", + date2: "2023-04-20T00:00:00Z", + expected: 5, + }, + { + name: "Less than 24 hours apart, crossing day boundary", + date1: "2023-04-20T23:00:00Z", + date2: "2023-04-21T22:59:59Z", + expected: 0, + }, + { + name: "Exactly 24 hours apart", + date1: "2023-04-20T12:34:56Z", + date2: "2023-04-21T12:34:56Z", + expected: 1, + }, + { + name: "One minute less than 24 hours apart", + date1: "2023-04-20T12:34:56Z", + date2: "2023-04-21T12:33:56Z", + expected: 0, + }, + { + name: "Inverted dates with times", + date1: "2023-04-25T15:30:00Z", + date2: "2023-04-20T10:00:00Z", + expected: 5, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + date1, _ := time.Parse(time.RFC3339, tc.date1) + date2, _ := time.Parse(time.RFC3339, tc.date2) + + result := daysBetween(date1, date2) + + if result != tc.expected { + t.Errorf("Expected days between %s and %s to be %d, but got %d", tc.date1, tc.date2, tc.expected, result) + } + }) + } +} diff --git a/x/mint/types/params.go b/x/mint/types/params.go index 08b3751fed..2f4f4c8619 100644 --- a/x/mint/types/params.go +++ b/x/mint/types/params.go @@ -3,6 +3,7 @@ package types import ( "errors" "fmt" + "sort" "strings" "time" @@ -28,7 +29,7 @@ func NewParams( ) Params { return Params{ MintDenom: mintDenom, - TokenReleaseSchedule: tokenReleaseSchedule, + TokenReleaseSchedule: sortTokenReleaseCalendar(tokenReleaseSchedule), } } @@ -85,19 +86,44 @@ func validateMintDenom(i interface{}) error { return nil } +func sortTokenReleaseCalendar(tokenReleaseSchedule []ScheduledTokenRelease) []ScheduledTokenRelease { + sort.Slice(tokenReleaseSchedule, func(i, j int) bool { + startDate1, _ := time.Parse(TokenReleaseDateFormat, tokenReleaseSchedule[i].GetStartDate()) + startDate2, _ := time.Parse(TokenReleaseDateFormat, tokenReleaseSchedule[j].GetStartDate()) + return startDate1.Before(startDate2) + }) + return tokenReleaseSchedule +} + func validateTokenReleaseSchedule(i interface{}) error { tokenReleaseSchedule, ok := i.([]ScheduledTokenRelease) if !ok { return fmt.Errorf("invalid parameter type: %T", i) } + + tokenReleaseSchedule = sortTokenReleaseCalendar(tokenReleaseSchedule) + + prevReleaseEndDate := time.Time{} for _, scheduledTokenRelease := range tokenReleaseSchedule { - if scheduledTokenRelease.GetTokenReleaseAmount() < 0 { - return fmt.Errorf("token release amount must be non-negative: %d", scheduledTokenRelease.GetTokenReleaseAmount()) + startDate, err := time.Parse(TokenReleaseDateFormat, scheduledTokenRelease.GetStartDate()) + if err != nil { + return fmt.Errorf("error: invalid start date format use yyyy-mm-dd: %s", err) } - _, err := time.Parse(TokenReleaseDateFormat, scheduledTokenRelease.GetDate()) + + endDate, err := time.Parse(TokenReleaseDateFormat, scheduledTokenRelease.GetEndDate()) if err != nil { - return fmt.Errorf("error: invalid date format use yyyy-mm-dd: %s", err) + return fmt.Errorf("error: invalid end date format use yyyy-mm-dd: %s", err) } + + if startDate.After(endDate) { + return fmt.Errorf("error: start date must be before end date %s > %s", startDate, endDate) + } + + if startDate.Before(prevReleaseEndDate) { + return fmt.Errorf("error: overlapping release period detected startDate=%s < prevReleaseEndDate=%s", startDate, prevReleaseEndDate) + } + prevReleaseEndDate = endDate } + return nil } diff --git a/x/mint/types/params_test.go b/x/mint/types/params_test.go new file mode 100644 index 0000000000..ad8b1887db --- /dev/null +++ b/x/mint/types/params_test.go @@ -0,0 +1,157 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestValidateTokenReleaseSchedule(t *testing.T) { + t.Parallel() + t.Run("valid release schedule", func(t *testing.T) { + validSchedule := []ScheduledTokenRelease{ + { + StartDate: "2023-01-01", + EndDate: "2023-01-31", + TokenReleaseAmount: 1000, + }, + { + StartDate: "2023-02-01", + EndDate: "2023-02-28", + TokenReleaseAmount: 2000, + }, + } + err := validateTokenReleaseSchedule(validSchedule) + assert.Nil(t, err) + }) + + t.Run("invalid parameter type", func(t *testing.T) { + invalidParam := "invalid" + err := validateTokenReleaseSchedule(invalidParam) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "invalid parameter type") + }) + + t.Run("invalid start date format", func(t *testing.T) { + invalidStartDate := []ScheduledTokenRelease{ + { + StartDate: "invalid", + EndDate: "2023-01-31", + TokenReleaseAmount: 1000, + }, + } + err := validateTokenReleaseSchedule(invalidStartDate) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "invalid start date format") + }) + + t.Run("invalid end date format", func(t *testing.T) { + invalidEndDate := []ScheduledTokenRelease{ + { + StartDate: "2023-01-01", + EndDate: "invalid", + TokenReleaseAmount: 1000, + }, + } + err := validateTokenReleaseSchedule(invalidEndDate) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "invalid end date format") + }) + + t.Run("start date not before end date", func(t *testing.T) { + invalidDateOrder := []ScheduledTokenRelease{ + { + StartDate: "2023-01-31", + EndDate: "2023-01-01", + TokenReleaseAmount: 1000, + }, + } + err := validateTokenReleaseSchedule(invalidDateOrder) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "start date must be before end date") + }) + + t.Run("overlapping release period", func(t *testing.T) { + overlappingPeriod := []ScheduledTokenRelease{ + { + StartDate: "2023-01-01", + EndDate: "2023-01-31", + TokenReleaseAmount: 1000, + }, + { + StartDate: "2023-01-15", + EndDate: "2023-01-31", + TokenReleaseAmount: 2000, + }, + } + err := validateTokenReleaseSchedule(overlappingPeriod) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "overlapping release period detected") + }) + t.Run("non-overlapping periods with different order", func(t *testing.T) { + nonOverlappingPeriods := []ScheduledTokenRelease{ + { + StartDate: "2023-03-01", + EndDate: "2023-03-31", + TokenReleaseAmount: 3000, + }, + { + StartDate: "2023-01-01", + EndDate: "2023-01-31", + TokenReleaseAmount: 1000, + }, + { + StartDate: "2023-02-01", + EndDate: "2023-02-28", + TokenReleaseAmount: 2000, + }, + } + err := validateTokenReleaseSchedule(nonOverlappingPeriods) + assert.Nil(t, err) + }) + + t.Run("unsorted input with overlapping windows", func(t *testing.T) { + unsortedOverlapping := []ScheduledTokenRelease{ + { + StartDate: "2023-03-01", + EndDate: "2023-03-31", + TokenReleaseAmount: 3000, + }, + { + StartDate: "2023-01-15", + EndDate: "2023-02-14", + TokenReleaseAmount: 2000, + }, + { + StartDate: "2023-01-01", + EndDate: "2023-01-31", + TokenReleaseAmount: 1000, + }, + } + err := validateTokenReleaseSchedule(unsortedOverlapping) + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "overlapping release period detected") + }) + + t.Run("end date equals start date of next period is fine", func(t *testing.T) { + endEqualsStart := []ScheduledTokenRelease{ + { + StartDate: "2023-01-01", + EndDate: "2023-01-31", + TokenReleaseAmount: 1000, + }, + { + StartDate: "2023-01-31", + EndDate: "2023-02-28", + TokenReleaseAmount: 2000, + }, + { + StartDate: "2023-02-28", + EndDate: "2023-03-31", + TokenReleaseAmount: 3000, + }, + } + err := validateTokenReleaseSchedule(endEqualsStart) + assert.Nil(t, err) + }) +} diff --git a/x/mint/types/query.pb.go b/x/mint/types/query.pb.go index 290f990655..7113ca7147 100644 --- a/x/mint/types/query.pb.go +++ b/x/mint/types/query.pb.go @@ -6,7 +6,6 @@ package types import ( context "context" fmt "fmt" - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -154,10 +153,14 @@ var xxx_messageInfo_QueryMinterRequest proto.InternalMessageInfo // QueryMinterResponse is the response type for the // Query/Minter RPC method. type QueryMinterResponse struct { - LastMintAmount github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=last_mint_amount,json=lastMintAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"last_mint_amount" yaml:"last_mint_amount"` - LastMintDate string `protobuf:"bytes,2,opt,name=last_mint_date,json=lastMintDate,proto3" json:"last_mint_date,omitempty" yaml:"last_mint_date"` - LastMintHeight int64 `protobuf:"varint,3,opt,name=last_mint_height,json=lastMintHeight,proto3" json:"last_mint_height,omitempty" yaml:"last_mint_height"` - Denom string `protobuf:"bytes,4,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` + StartDate string `protobuf:"bytes,1,opt,name=start_date,json=startDate,proto3" json:"start_date,omitempty" yaml:"start_date"` + EndDate string `protobuf:"bytes,2,opt,name=end_date,json=endDate,proto3" json:"end_date,omitempty" yaml:"end_date"` + Denom string `protobuf:"bytes,3,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` + TotalMintAmount uint64 `protobuf:"varint,4,opt,name=total_mint_amount,json=totalMintAmount,proto3" json:"total_mint_amount,omitempty" yaml:"total_mint_amount"` + RemainingMintAmount uint64 `protobuf:"varint,5,opt,name=remaining_mint_amount,json=remainingMintAmount,proto3" json:"remaining_mint_amount,omitempty" yaml:"remaining_mint_amount"` + LastMintAmount uint64 `protobuf:"varint,6,opt,name=last_mint_amount,json=lastMintAmount,proto3" json:"last_mint_amount,omitempty" yaml:"last_mint_amount"` + LastMintDate string `protobuf:"bytes,7,opt,name=last_mint_date,json=lastMintDate,proto3" json:"last_mint_date,omitempty" yaml:"last_mint_date"` + LastMintHeight uint64 `protobuf:"varint,8,opt,name=last_mint_height,json=lastMintHeight,proto3" json:"last_mint_height,omitempty" yaml:"last_mint_height"` } func (m *QueryMinterResponse) Reset() { *m = QueryMinterResponse{} } @@ -193,18 +196,18 @@ func (m *QueryMinterResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryMinterResponse proto.InternalMessageInfo -func (m *QueryMinterResponse) GetLastMintDate() string { +func (m *QueryMinterResponse) GetStartDate() string { if m != nil { - return m.LastMintDate + return m.StartDate } return "" } -func (m *QueryMinterResponse) GetLastMintHeight() int64 { +func (m *QueryMinterResponse) GetEndDate() string { if m != nil { - return m.LastMintHeight + return m.EndDate } - return 0 + return "" } func (m *QueryMinterResponse) GetDenom() string { @@ -214,6 +217,41 @@ func (m *QueryMinterResponse) GetDenom() string { return "" } +func (m *QueryMinterResponse) GetTotalMintAmount() uint64 { + if m != nil { + return m.TotalMintAmount + } + return 0 +} + +func (m *QueryMinterResponse) GetRemainingMintAmount() uint64 { + if m != nil { + return m.RemainingMintAmount + } + return 0 +} + +func (m *QueryMinterResponse) GetLastMintAmount() uint64 { + if m != nil { + return m.LastMintAmount + } + return 0 +} + +func (m *QueryMinterResponse) GetLastMintDate() string { + if m != nil { + return m.LastMintDate + } + return "" +} + +func (m *QueryMinterResponse) GetLastMintHeight() uint64 { + if m != nil { + return m.LastMintHeight + } + return 0 +} + func init() { proto.RegisterType((*QueryParamsRequest)(nil), "seiprotocol.seichain.mint.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "seiprotocol.seichain.mint.QueryParamsResponse") @@ -224,37 +262,42 @@ func init() { func init() { proto.RegisterFile("mint/v1beta1/query.proto", fileDescriptor_b0718dda172d2cb4) } var fileDescriptor_b0718dda172d2cb4 = []byte{ - // 480 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x4d, 0x6e, 0x13, 0x31, - 0x14, 0xce, 0xa4, 0x6d, 0x24, 0x4c, 0x55, 0x55, 0xa6, 0xa8, 0xd3, 0x00, 0x33, 0x65, 0x24, 0xaa, - 0x6e, 0x62, 0xab, 0x65, 0xc7, 0xa6, 0x22, 0x2a, 0x52, 0x59, 0x20, 0xc1, 0x2c, 0x58, 0xb0, 0xa9, - 0x9c, 0xc9, 0xd3, 0xc4, 0x22, 0x63, 0x4f, 0x63, 0x07, 0x91, 0x2d, 0x07, 0x40, 0x48, 0x9c, 0x82, - 0x2b, 0x70, 0x82, 0x2e, 0x2b, 0xb1, 0x41, 0x2c, 0x46, 0x28, 0xe1, 0x04, 0x39, 0x01, 0xb2, 0x3d, - 0x03, 0x99, 0xf0, 0x93, 0xae, 0x6c, 0x7f, 0xef, 0x7b, 0xdf, 0xf7, 0xc9, 0xef, 0x21, 0x3f, 0xe3, - 0x42, 0xd3, 0x37, 0x47, 0x3d, 0xd0, 0xec, 0x88, 0x5e, 0x8c, 0x61, 0x34, 0x21, 0xf9, 0x48, 0x6a, - 0x89, 0xf7, 0x14, 0x70, 0x7b, 0x4b, 0xe4, 0x90, 0x28, 0xe0, 0xc9, 0x80, 0x71, 0x41, 0x0c, 0xbd, - 0xbd, 0x93, 0xca, 0x54, 0xda, 0x1a, 0x35, 0x37, 0xd7, 0xd0, 0xbe, 0x9b, 0x4a, 0x99, 0x0e, 0x81, - 0xb2, 0x9c, 0x53, 0x26, 0x84, 0xd4, 0x4c, 0x73, 0x29, 0x54, 0x59, 0xdd, 0xad, 0x19, 0x99, 0x87, - 0x2b, 0x44, 0x3b, 0x08, 0xbf, 0x30, 0xb6, 0xcf, 0xd9, 0x88, 0x65, 0x2a, 0x86, 0x8b, 0x31, 0x28, - 0x1d, 0xbd, 0x44, 0xb7, 0x6a, 0xa8, 0xca, 0xa5, 0x50, 0x80, 0x4f, 0x50, 0x2b, 0xb7, 0x88, 0xef, - 0xed, 0x7b, 0x87, 0x37, 0x8f, 0xef, 0x93, 0x7f, 0xa6, 0x24, 0xae, 0xb5, 0xbb, 0x7e, 0x59, 0x84, - 0x8d, 0xb8, 0x6c, 0xfb, 0xe5, 0xf6, 0x8c, 0x0b, 0x0d, 0xa3, 0xca, 0xed, 0x73, 0xb3, 0xb4, 0xab, - 0xe0, 0xd2, 0x4e, 0xa1, 0xed, 0x21, 0x53, 0xfa, 0xdc, 0xe8, 0x9d, 0xb3, 0x4c, 0x8e, 0x85, 0xb6, - 0xc6, 0x37, 0xba, 0x4f, 0x8d, 0xea, 0xb7, 0x22, 0x3c, 0x48, 0xb9, 0x1e, 0x8c, 0x7b, 0x24, 0x91, - 0x19, 0x4d, 0xa4, 0xca, 0xa4, 0x2a, 0x8f, 0x8e, 0xea, 0xbf, 0xa6, 0x7a, 0x92, 0x83, 0x22, 0xa7, - 0x90, 0xcc, 0x8b, 0x70, 0x77, 0xc2, 0xb2, 0xe1, 0xa3, 0x68, 0x59, 0x2f, 0x8a, 0xb7, 0x0c, 0x64, - 0x8c, 0x1f, 0x5b, 0x00, 0x9f, 0xa0, 0xad, 0xdf, 0xa4, 0x3e, 0xd3, 0xe0, 0x37, 0xad, 0xe5, 0xde, - 0xbc, 0x08, 0x6f, 0x2f, 0x8b, 0x98, 0x7a, 0x14, 0x6f, 0x56, 0x12, 0xa7, 0x4c, 0x03, 0x7e, 0xb2, - 0x98, 0x7a, 0x00, 0x3c, 0x1d, 0x68, 0x7f, 0x6d, 0xdf, 0x3b, 0x5c, 0xeb, 0xde, 0xf9, 0x5b, 0x0e, - 0xc7, 0x58, 0xc8, 0x71, 0x66, 0x01, 0x7c, 0x80, 0x36, 0xfa, 0x20, 0x64, 0xe6, 0xaf, 0x5b, 0xfb, - 0xed, 0x79, 0x11, 0x6e, 0xba, 0x5e, 0x0b, 0x47, 0xb1, 0x2b, 0x1f, 0x7f, 0x6a, 0xa2, 0x0d, 0xfb, - 0x79, 0xf8, 0xbd, 0x87, 0x5a, 0xee, 0xd7, 0x71, 0xe7, 0x3f, 0x83, 0xf9, 0x73, 0xdc, 0x6d, 0x72, - 0x5d, 0xba, 0x1b, 0x4c, 0xf4, 0xe0, 0xdd, 0x97, 0x1f, 0x1f, 0x9b, 0x21, 0xbe, 0x47, 0x2b, 0x2e, - 0xad, 0xed, 0x97, 0x9b, 0xb6, 0x0d, 0xe4, 0x46, 0xba, 0x3a, 0x50, 0x6d, 0x23, 0x56, 0x07, 0xaa, - 0x6f, 0xca, 0xca, 0x40, 0x99, 0xa5, 0x77, 0xcf, 0x2e, 0xa7, 0x81, 0x77, 0x35, 0x0d, 0xbc, 0xef, - 0xd3, 0xc0, 0xfb, 0x30, 0x0b, 0x1a, 0x57, 0xb3, 0xa0, 0xf1, 0x75, 0x16, 0x34, 0x5e, 0x91, 0x85, - 0x45, 0x52, 0xc0, 0x3b, 0x95, 0xb7, 0x7d, 0x38, 0xc1, 0xb7, 0x4e, 0xd2, 0x2e, 0x55, 0xaf, 0x65, - 0x09, 0x0f, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0xd7, 0x29, 0x8f, 0x16, 0xc1, 0x03, 0x00, 0x00, + // 549 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0xcd, 0x6e, 0xd3, 0x40, + 0x18, 0x8c, 0x43, 0x92, 0xb6, 0x4b, 0xd5, 0x1f, 0xa7, 0x51, 0xdd, 0x10, 0xec, 0xb0, 0x12, 0xa8, + 0x97, 0xda, 0x6a, 0xe1, 0xc4, 0xa5, 0x22, 0x02, 0x29, 0x17, 0x24, 0xb0, 0x10, 0x07, 0x2e, 0xd1, + 0x26, 0x59, 0x39, 0x2b, 0xc5, 0xbb, 0xae, 0x77, 0x83, 0xc8, 0x95, 0x07, 0x40, 0x08, 0x9e, 0x82, + 0x37, 0xe9, 0xb1, 0x12, 0x17, 0x4e, 0x16, 0x4a, 0x78, 0x02, 0x3f, 0x01, 0xf2, 0xb7, 0x71, 0x1b, + 0xb7, 0x94, 0xf4, 0xe6, 0x9d, 0x6f, 0xbe, 0x99, 0xf1, 0x6a, 0x16, 0x59, 0x21, 0xe3, 0xca, 0xfb, + 0x78, 0xdc, 0xa7, 0x8a, 0x1c, 0x7b, 0x67, 0x13, 0x1a, 0x4f, 0xdd, 0x28, 0x16, 0x4a, 0x98, 0x07, + 0x92, 0x32, 0xf8, 0x1a, 0x88, 0xb1, 0x2b, 0x29, 0x1b, 0x8c, 0x08, 0xe3, 0x6e, 0x46, 0x6f, 0xee, + 0x05, 0x22, 0x10, 0x30, 0xf3, 0xb2, 0x2f, 0xbd, 0xd0, 0x6c, 0x05, 0x42, 0x04, 0x63, 0xea, 0x91, + 0x88, 0x79, 0x84, 0x73, 0xa1, 0x88, 0x62, 0x82, 0xcb, 0xc5, 0x74, 0xbf, 0x60, 0x94, 0x1d, 0xf4, + 0x00, 0xef, 0x21, 0xf3, 0x6d, 0x66, 0xfb, 0x86, 0xc4, 0x24, 0x94, 0x3e, 0x3d, 0x9b, 0x50, 0xa9, + 0xf0, 0x7b, 0x54, 0x2f, 0xa0, 0x32, 0x12, 0x5c, 0x52, 0xf3, 0x14, 0xd5, 0x22, 0x40, 0x2c, 0xa3, + 0x6d, 0x1c, 0xde, 0x3f, 0x79, 0xe4, 0xde, 0x9a, 0xd2, 0xd5, 0xab, 0x9d, 0xca, 0x79, 0xe2, 0x94, + 0xfc, 0xc5, 0xda, 0xa5, 0xdb, 0x6b, 0xc6, 0x15, 0x8d, 0x73, 0xb7, 0x6f, 0x95, 0x85, 0x5d, 0x0e, + 0x2f, 0xec, 0x9e, 0x21, 0x24, 0x15, 0x89, 0x55, 0x6f, 0x48, 0x14, 0x05, 0xcb, 0x8d, 0x4e, 0x23, + 0x4d, 0x9c, 0xdd, 0x29, 0x09, 0xc7, 0xcf, 0xf1, 0xd5, 0x0c, 0xfb, 0x1b, 0x70, 0x78, 0x49, 0x14, + 0x35, 0x5d, 0xb4, 0x4e, 0xf9, 0x50, 0xef, 0x94, 0x61, 0xa7, 0x9e, 0x26, 0xce, 0xb6, 0xde, 0xc9, + 0x27, 0xd8, 0x5f, 0xa3, 0x7c, 0x08, 0xfc, 0x27, 0xa8, 0x3a, 0xa4, 0x5c, 0x84, 0xd6, 0x3d, 0x20, + 0xef, 0xa4, 0x89, 0xb3, 0xa9, 0xc9, 0x00, 0x63, 0x5f, 0x8f, 0xcd, 0x2e, 0xda, 0x55, 0x42, 0x91, + 0x71, 0x2f, 0xfb, 0xbd, 0x1e, 0x09, 0xc5, 0x84, 0x2b, 0xab, 0xd2, 0x36, 0x0e, 0x2b, 0x9d, 0x56, + 0x9a, 0x38, 0x96, 0xde, 0xb9, 0x41, 0xc1, 0xfe, 0x36, 0x60, 0xd9, 0xbf, 0xbd, 0x00, 0xc4, 0x7c, + 0x87, 0x1a, 0x31, 0x0d, 0x09, 0xe3, 0x8c, 0x07, 0x05, 0xb5, 0x2a, 0xa8, 0xb5, 0xd3, 0xc4, 0x69, + 0x69, 0xb5, 0x7f, 0xd2, 0xb0, 0x5f, 0xbf, 0xc4, 0x97, 0x54, 0x5f, 0xa1, 0x9d, 0x31, 0x91, 0xaa, + 0x20, 0x58, 0x03, 0xc1, 0x07, 0x69, 0xe2, 0xec, 0x6b, 0xc1, 0xeb, 0x0c, 0xec, 0x6f, 0x65, 0xd0, + 0x92, 0xcc, 0x29, 0xda, 0xba, 0x22, 0xc1, 0x25, 0xae, 0xc1, 0xbd, 0x1c, 0xa4, 0x89, 0xd3, 0xb8, + 0x2e, 0xa2, 0xaf, 0x72, 0x33, 0x97, 0x80, 0xfb, 0x2c, 0xe4, 0x18, 0x51, 0x16, 0x8c, 0x94, 0xb5, + 0x7e, 0x7b, 0x0e, 0xcd, 0x58, 0xca, 0xd1, 0x05, 0xe0, 0xe4, 0x47, 0x19, 0x55, 0xa1, 0x14, 0xe6, + 0x17, 0x03, 0xd5, 0x74, 0x9b, 0xcc, 0xa3, 0xff, 0x14, 0xee, 0x66, 0x8d, 0x9b, 0xee, 0x5d, 0xe9, + 0xba, 0x70, 0xf8, 0xf1, 0xe7, 0x9f, 0x7f, 0xbe, 0x97, 0x1d, 0xf3, 0xa1, 0x97, 0x73, 0xbd, 0xc2, + 0xbb, 0xd1, 0x2d, 0x86, 0x40, 0xba, 0xaa, 0xab, 0x03, 0x15, 0x9a, 0xbe, 0x3a, 0x50, 0xf1, 0x05, + 0xac, 0x0c, 0x14, 0x02, 0xbd, 0xd3, 0x3d, 0x9f, 0xd9, 0xc6, 0xc5, 0xcc, 0x36, 0x7e, 0xcf, 0x6c, + 0xe3, 0xeb, 0xdc, 0x2e, 0x5d, 0xcc, 0xed, 0xd2, 0xaf, 0xb9, 0x5d, 0xfa, 0xe0, 0x06, 0x4c, 0x8d, + 0x26, 0x7d, 0x77, 0x20, 0xc2, 0x4c, 0xe2, 0x28, 0xf7, 0x86, 0x83, 0x16, 0xfc, 0xa4, 0x25, 0xd5, + 0x34, 0xa2, 0xb2, 0x5f, 0x03, 0xc2, 0xd3, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x4c, 0x6e, 0x23, + 0xe2, 0x99, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -476,35 +519,54 @@ func (m *QueryMinterResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) - i-- - dAtA[i] = 0x22 - } if m.LastMintHeight != 0 { i = encodeVarintQuery(dAtA, i, uint64(m.LastMintHeight)) i-- - dAtA[i] = 0x18 + dAtA[i] = 0x40 } if len(m.LastMintDate) > 0 { i -= len(m.LastMintDate) copy(dAtA[i:], m.LastMintDate) i = encodeVarintQuery(dAtA, i, uint64(len(m.LastMintDate))) i-- + dAtA[i] = 0x3a + } + if m.LastMintAmount != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.LastMintAmount)) + i-- + dAtA[i] = 0x30 + } + if m.RemainingMintAmount != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.RemainingMintAmount)) + i-- + dAtA[i] = 0x28 + } + if m.TotalMintAmount != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.TotalMintAmount)) + i-- + dAtA[i] = 0x20 + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x1a + } + if len(m.EndDate) > 0 { + i -= len(m.EndDate) + copy(dAtA[i:], m.EndDate) + i = encodeVarintQuery(dAtA, i, uint64(len(m.EndDate))) + i-- dAtA[i] = 0x12 } - { - size := m.LastMintAmount.Size() - i -= size - if _, err := m.LastMintAmount.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintQuery(dAtA, i, uint64(size)) + if len(m.StartDate) > 0 { + i -= len(m.StartDate) + copy(dAtA[i:], m.StartDate) + i = encodeVarintQuery(dAtA, i, uint64(len(m.StartDate))) + i-- + dAtA[i] = 0xa } - i-- - dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -554,19 +616,34 @@ func (m *QueryMinterResponse) Size() (n int) { } var l int _ = l - l = m.LastMintAmount.Size() - n += 1 + l + sovQuery(uint64(l)) - l = len(m.LastMintDate) + l = len(m.StartDate) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } - if m.LastMintHeight != 0 { - n += 1 + sovQuery(uint64(m.LastMintHeight)) + l = len(m.EndDate) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) } l = len(m.Denom) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } + if m.TotalMintAmount != 0 { + n += 1 + sovQuery(uint64(m.TotalMintAmount)) + } + if m.RemainingMintAmount != 0 { + n += 1 + sovQuery(uint64(m.RemainingMintAmount)) + } + if m.LastMintAmount != 0 { + n += 1 + sovQuery(uint64(m.LastMintAmount)) + } + l = len(m.LastMintDate) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.LastMintHeight != 0 { + n += 1 + sovQuery(uint64(m.LastMintHeight)) + } return n } @@ -790,7 +867,7 @@ func (m *QueryMinterResponse) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LastMintAmount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field StartDate", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -818,13 +895,11 @@ func (m *QueryMinterResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.LastMintAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.StartDate = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LastMintDate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field EndDate", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -852,13 +927,13 @@ func (m *QueryMinterResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.LastMintDate = string(dAtA[iNdEx:postIndex]) + m.EndDate = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field LastMintHeight", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) } - m.LastMintHeight = 0 + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowQuery @@ -868,14 +943,84 @@ func (m *QueryMinterResponse) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.LastMintHeight |= int64(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalMintAmount", wireType) + } + m.TotalMintAmount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalMintAmount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RemainingMintAmount", wireType) + } + m.RemainingMintAmount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RemainingMintAmount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LastMintAmount", wireType) + } + m.LastMintAmount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LastMintAmount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LastMintDate", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -903,8 +1048,27 @@ func (m *QueryMinterResponse) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Denom = string(dAtA[iNdEx:postIndex]) + m.LastMintDate = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LastMintHeight", wireType) + } + m.LastMintHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LastMintHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) diff --git a/x/oracle/simulation/operations.go b/x/oracle/simulation/operations.go index 3988c4b164..2028e73625 100644 --- a/x/oracle/simulation/operations.go +++ b/x/oracle/simulation/operations.go @@ -65,7 +65,7 @@ func WeightedOperations( } // SimulateMsgAggregateExchangeRateVote generates a MsgAggregateExchangeRateVote with random values. -//nolint: funlen +// nolint: funlen func SimulateMsgAggregateExchangeRateVote(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, @@ -122,7 +122,7 @@ func SimulateMsgAggregateExchangeRateVote(ak types.AccountKeeper, bk types.BankK } // SimulateMsgDelegateFeedConsent generates a MsgDelegateFeedConsent with random values. -//nolint: funlen +// nolint: funlen func SimulateMsgDelegateFeedConsent(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, From 48f9c813116d48ca3815bf3575d7c6017f5f351e Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Mon, 24 Apr 2023 09:28:10 -0400 Subject: [PATCH 02/16] Fix test --- scripts/initialize_local_chain.sh | 3 +- x/mint/keeper/hooks.go | 7 +- x/mint/keeper/hooks_test.go | 322 +++++++++++++++++++++++++----- x/mint/keeper/keeper.go | 13 +- x/mint/keeper/keeper_test.go | 20 +- x/mint/simulation/genesis_test.go | 3 +- x/mint/types/minter.go | 59 ++++-- x/mint/types/minter_test.go | 217 +++++++++++++++++++- x/mint/types/params.go | 8 +- x/oracle/simulation/operations.go | 4 +- 10 files changed, 560 insertions(+), 96 deletions(-) diff --git a/scripts/initialize_local_chain.sh b/scripts/initialize_local_chain.sh index f2593ecb68..4bb68bfd1f 100755 --- a/scripts/initialize_local_chain.sh +++ b/scripts/initialize_local_chain.sh @@ -47,7 +47,8 @@ python3 loadtest/scripts/populate_genesis_accounts.py 10 loc # update some params in genesis file for easier use of the chain localls (make gov props faster) cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["max_deposit_period"]="300s"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="30s"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json -cat ~/.sei/config/genesis.json | jq --arg release_date "$(date +"%Y-%m-%d")" '.app_state["mint"]["params"]["token_release_schedule"]=[{"date": $release_date, "token_release_amount": "999999999999"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json +cat ~/.sei/config/genesis.json | jq --arg start_date "$(date +"%Y-%m-%d")" --arg end_date "$(date -v+3d +"%Y-%m-%d")" '.app_state["mint"]["params"]["token_release_schedule"]=[{"start_date": $start_date, "end_date": $end_date, "token_release_amount": "999999999999"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json +cat ~/.sei/config/genesis.json | jq --arg start_date "$(date -v+3d +"%Y-%m-%d")" --arg end_date "$(date -v+5d +"%Y-%m-%d")" '.app_state["mint"]["params"]["token_release_schedule"] += [{"start_date": $start_date, "end_date": $end_date, "token_release_amount": "999999999999"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["voting_params"]["expedited_voting_period"]="10s"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json cat ~/.sei/config/genesis.json | jq '.app_state["oracle"]["params"]["vote_period"]="1"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json cat ~/.sei/config/genesis.json | jq '.app_state["distribution"]["params"]["community_tax"]="0.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json diff --git a/x/mint/keeper/hooks.go b/x/mint/keeper/hooks.go index 3b60a9331b..0230b1f37a 100644 --- a/x/mint/keeper/hooks.go +++ b/x/mint/keeper/hooks.go @@ -10,7 +10,7 @@ func (k Keeper) BeforeEpochStart(ctx sdk.Context, epoch epochTypes.Epoch) { func (k Keeper) AfterEpochEnd(ctx sdk.Context, epoch epochTypes.Epoch) { latestMinter := k.GetOrUpdateLatestMinter(ctx, epoch) - coinsToMint := latestMinter.GetReleaseAmountToday() + coinsToMint := latestMinter.GetReleaseAmountToday(epoch.CurrentEpochStartTime) if coinsToMint.IsZero() { k.Logger(ctx).Debug("No coins to mint", "minter", latestMinter) @@ -27,8 +27,9 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epoch epochTypes.Epoch) { } // Released Succssfully, decrement the remaining amount by the daily release amount and update minter - latestMinter.RecordSuccessfulMint(ctx, epoch) - k.SetMinter(ctx, latestMinter) + amountMinted := coinsToMint.AmountOf(latestMinter.GetDenom()) + updatedMinter := latestMinter.RecordSuccessfulMint(ctx, epoch, amountMinted.Uint64()) + k.SetMinter(ctx, updatedMinter) } type Hooks struct { diff --git a/x/mint/keeper/hooks_test.go b/x/mint/keeper/hooks_test.go index 2b49811ddf..6f4ff081f7 100644 --- a/x/mint/keeper/hooks_test.go +++ b/x/mint/keeper/hooks_test.go @@ -32,63 +32,225 @@ func getEpoch(genesisTime time.Time, currTime time.Time) types.Epoch { } func TestEndOfEpochMintedCoinDistribution(t *testing.T) { - seiApp := keepertest.TestApp() - ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) - ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetKey(types.StoreKey)))) + t.Parallel() - genesisTime := time.Date(2022, time.Month(7), 18, 10, 0, 0, 0, time.UTC) + t.Run("Initial should be zero", func(t *testing.T) { + seiApp := keepertest.TestApp() + ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) + ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetKey(types.StoreKey)))) - tokenReleaseSchedle := []minttypes.ScheduledTokenRelease{ - { - StartDate: genesisTime.AddDate(1, 0, 0).Format(minttypes.TokenReleaseDateFormat), - EndDate: genesisTime.AddDate(1, 60, 0).Format(minttypes.TokenReleaseDateFormat), - TokenReleaseAmount: 2500000, - }, - { - StartDate: genesisTime.AddDate(2, 0, 0).Format(minttypes.TokenReleaseDateFormat), - EndDate: genesisTime.AddDate(3, 0, 0).Format(minttypes.TokenReleaseDateFormat), - TokenReleaseAmount: 1250000, - }, - } - mintParams := minttypes.NewParams( - "usei", - tokenReleaseSchedle, - ) + header := tmproto.Header{ + Height: seiApp.LastBlockHeight() + 1, + Time: time.Now().UTC(), + } + seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header}) + require.Equal(t, int64(0), seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmountCoin().Amount.Int64()) + }) - seiApp.MintKeeper.SetParams(ctx, mintParams) + t.Run("even full release", func(t *testing.T) { + seiApp := keepertest.TestApp() + ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) + ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetKey(types.StoreKey)))) - header := tmproto.Header{Height: seiApp.LastBlockHeight() + 1} - seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header}) + header := tmproto.Header{ + Height: seiApp.LastBlockHeight() + 1, + Time: time.Now().UTC(), + } + seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header}) + genesisTime := header.Time + tokenReleaseSchedle := []minttypes.ScheduledTokenRelease{ + { + StartDate: genesisTime.AddDate(0, 0, 0).Format(minttypes.TokenReleaseDateFormat), + EndDate: genesisTime.AddDate(0, 0, 25).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 2500000, + }, + } + mintParams := minttypes.NewParams( + "usei", + tokenReleaseSchedle, + ) + seiApp.MintKeeper.SetParams(ctx, mintParams) - // Year 1 - currTime := genesisTime.AddDate(1, 0, 0) - currEpoch := getEpoch(genesisTime, currTime) - presupply := seiApp.BankKeeper.GetSupply(ctx, mintParams.MintDenom) + for i := 0; i < 25; i++ { + currTime := genesisTime.AddDate(0, 0, i) + currEpoch := getEpoch(genesisTime, currTime) + seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch) + seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch) + mintParams = seiApp.MintKeeper.GetParams(ctx) + + // 250k / 25 days = 100000 per day + expectedAmount := int64(100000) + newMinter := seiApp.MintKeeper.GetMinter(ctx) + + if i == 25 { + require.Zero(t, newMinter.GetRemainingMintAmount(), "Remaining amount should be zero") + break + } + + require.Equal(t, currTime.Format(minttypes.TokenReleaseDateFormat), newMinter.GetLastMintDate(), "Last mint date should be correct") + require.Equal(t, expectedAmount, newMinter.GetLastMintAmountCoin().Amount.Int64(), "Minted amount should be correct") + require.Equal(t, int64(2500000 - expectedAmount * int64(i+1)), int64(newMinter.GetRemainingMintAmount()), "Remaining amount should be correct") + } + }) + + t.Run("uneven full release", func(t *testing.T) { + seiApp := keepertest.TestApp() + ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) + ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetKey(types.StoreKey)))) + + header := tmproto.Header{ + Height: seiApp.LastBlockHeight() + 1, + Time: time.Now().UTC(), + } + seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header}) + genesisTime := header.Time + + tokenReleaseSchedle := []minttypes.ScheduledTokenRelease{ + { + StartDate: genesisTime.AddDate(0, 0, 0).Format(minttypes.TokenReleaseDateFormat), + EndDate: genesisTime.AddDate(0, 0, 24).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 2500000, + }, + } + mintParams := minttypes.NewParams( + "usei", + tokenReleaseSchedle, + ) + seiApp.MintKeeper.SetParams(ctx, mintParams) + + for i := 0; i < 25; i++ { + currTime := genesisTime.AddDate(0, 0, i) + currEpoch := getEpoch(genesisTime, currTime) + seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch) + seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch) + mintParams = seiApp.MintKeeper.GetParams(ctx) + + expectedAmount := int64(104166) + newMinter := seiApp.MintKeeper.GetMinter(ctx) + + // Uneven distribution still results in 250k total distributed + if i == 24 { + require.Zero(t, newMinter.GetRemainingMintAmount(), "Remaining amount should be zero") + break + } + + require.Equal(t, currTime.Format(minttypes.TokenReleaseDateFormat), newMinter.GetLastMintDate(), "Last mint date should be correct") + require.InDelta(t, expectedAmount, newMinter.GetLastMintAmountCoin().Amount.Int64(), 1, "Minted amount should be correct") + require.InDelta(t, int64(2500000 - expectedAmount * int64(i+1)), int64(newMinter.GetRemainingMintAmount()), 24, "Remaining amount should be correct") + } + }) + + t.Run("multiple full releases", func(t *testing.T) { + seiApp := keepertest.TestApp() + ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) + ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetKey(types.StoreKey)))) + + header := tmproto.Header{ + Height: seiApp.LastBlockHeight() + 1, + Time: time.Now().UTC(), + } + seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header}) + genesisTime := header.Time + + tokenReleaseSchedle := []minttypes.ScheduledTokenRelease{ + { + StartDate: genesisTime.AddDate(0, 0, 0).Format(minttypes.TokenReleaseDateFormat), + EndDate: genesisTime.AddDate(0, 0, 24).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 2500000, + }, + { + StartDate: genesisTime.AddDate(0, 0, 24).Format(minttypes.TokenReleaseDateFormat), + EndDate: genesisTime.AddDate(0, 0, 30).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 2500000, + }, + { + StartDate: genesisTime.AddDate(0, 0, 30).Format(minttypes.TokenReleaseDateFormat), + EndDate: genesisTime.AddDate(0, 0, 40).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 2500000, + }, + { + StartDate: genesisTime.AddDate(0, 0, 45).Format(minttypes.TokenReleaseDateFormat), + EndDate: genesisTime.AddDate(0, 0, 50).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 2500000, + }, + } + mintParams := minttypes.NewParams( + "usei", + tokenReleaseSchedle, + ) + seiApp.MintKeeper.SetParams(ctx, mintParams) + + for i := 0; i < 50; i++ { + currTime := genesisTime.AddDate(0, 0, i) + currEpoch := getEpoch(genesisTime, currTime) + seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch) + seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch) + mintParams = seiApp.MintKeeper.GetParams(ctx) - // Run hooks - seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch) - seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch) - mintParams = seiApp.MintKeeper.GetParams(ctx) - - // Year 1 - mintedCoinYear1 := seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmountCoin() - postsupplyYear1 := seiApp.BankKeeper.GetSupply(ctx, mintParams.MintDenom) - require.True(t, postsupplyYear1.IsEqual(presupply.Add(mintedCoinYear1))) - require.Equal(t, mintedCoinYear1.Amount.Int64(), int64(2500000)) - - // Year 2 - currTime = currTime.AddDate(1, 0, 0) - currEpoch = getEpoch(genesisTime, currTime) - - // Run hooks - seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch) - seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch) - mintParams = seiApp.MintKeeper.GetParams(ctx) - - mintedCoinYear2 := seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmountCoin() - postsupplyYear2 := seiApp.BankKeeper.GetSupply(ctx, mintParams.MintDenom) - require.True(t, postsupplyYear2.IsEqual(postsupplyYear1.Add(mintedCoinYear2))) - require.Equal(t, mintedCoinYear2.Amount.Int64(), int64(1250000)) + newMinter := seiApp.MintKeeper.GetMinter(ctx) + + // Should be zero by the end of each release and when there's no release scheduled + if i == 23 || i == 29 || i == 39 || i == 49 || (i >= 40 && i < 45) { + require.Zero(t, newMinter.GetRemainingMintAmount(), "Remaining amount should be zero at %s", currTime.Format(minttypes.TokenReleaseDateFormat)) + continue + } + + require.Equal(t, currTime.Format(minttypes.TokenReleaseDateFormat), newMinter.GetLastMintDate(), "Last mint date should be correct") + } + }) + + t.Run("outage during release", func(t *testing.T) { + seiApp := keepertest.TestApp() + ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()}) + ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetKey(types.StoreKey)))) + + header := tmproto.Header{ + Height: seiApp.LastBlockHeight() + 1, + Time: time.Now().UTC(), + } + seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header}) + genesisTime := header.Time + + tokenReleaseSchedle := []minttypes.ScheduledTokenRelease{ + { + StartDate: genesisTime.AddDate(0, 0, 0).Format(minttypes.TokenReleaseDateFormat), + EndDate: genesisTime.AddDate(0, 0, 24).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 2500000, + }, + } + mintParams := minttypes.NewParams( + "usei", + tokenReleaseSchedle, + ) + seiApp.MintKeeper.SetParams(ctx, mintParams) + + for i := 0; i < 13; i++ { + currTime := genesisTime.AddDate(0, 0, i) + currEpoch := getEpoch(genesisTime, currTime) + seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch) + seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch) + mintParams = seiApp.MintKeeper.GetParams(ctx) + + newMinter := seiApp.MintKeeper.GetMinter(ctx) + expectedAmount := int64(104166) + + require.Equal(t, currTime.Format(minttypes.TokenReleaseDateFormat), newMinter.GetLastMintDate(), "Last mint date should be correct") + require.InDelta(t, expectedAmount, newMinter.GetLastMintAmountCoin().Amount.Int64(), 1, "Minted amount should be correct") + require.InDelta(t, int64(2500000 - expectedAmount * int64(i+1)), int64(newMinter.GetRemainingMintAmount()), 24, "Remaining amount should be correct") + } + + // 3 day outage + postOutageTime := genesisTime.AddDate(0, 0, 15) + currEpoch := getEpoch(genesisTime, postOutageTime) + seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch) + seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch) + mintParams = seiApp.MintKeeper.GetParams(ctx) + + newMinter := seiApp.MintKeeper.GetMinter(ctx) + require.Equal(t, postOutageTime.Format(minttypes.TokenReleaseDateFormat), newMinter.GetLastMintDate(), "Last mint date should be correct") + require.InDelta(t, 127315, newMinter.GetLastMintAmountCoin().Amount.Int64(), 1, "Minted amount should be correct") + require.InDelta(t, int64(1018522), int64(newMinter.GetRemainingMintAmount()), 24, "Remaining amount should be correct") + }) } func TestNoEpochPassedNoDistribution(t *testing.T) { @@ -118,3 +280,61 @@ func TestNoEpochPassedNoDistribution(t *testing.T) { endLastMintAmount := seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmountCoin() require.True(t, startLastMintAmount.Equal(endLastMintAmount)) } + +func TestSortTokenReleaseCalendar(t *testing.T) { + testCases := []struct { + name string + input []minttypes.ScheduledTokenRelease + expectedOutput []minttypes.ScheduledTokenRelease + }{ + { + name: "Empty schedule", + input: []minttypes.ScheduledTokenRelease{}, + expectedOutput: []minttypes.ScheduledTokenRelease{}, + }, + { + name: "Already sorted schedule", + input: []minttypes.ScheduledTokenRelease{ + {StartDate: "2023-04-01", EndDate: "2023-04-10", TokenReleaseAmount: 100}, + {StartDate: "2023-04-11", EndDate: "2023-04-20", TokenReleaseAmount: 200}, + {StartDate: "2023-04-21", EndDate: "2023-04-30", TokenReleaseAmount: 300}, + }, + expectedOutput: []minttypes.ScheduledTokenRelease{ + {StartDate: "2023-04-01", EndDate: "2023-04-10", TokenReleaseAmount: 100}, + {StartDate: "2023-04-11", EndDate: "2023-04-20", TokenReleaseAmount: 200}, + {StartDate: "2023-04-21", EndDate: "2023-04-30", TokenReleaseAmount: 300}, + }, + }, + { + name: "Unsorted schedule", + input: []minttypes.ScheduledTokenRelease{ + {StartDate: "2023-04-21", EndDate: "2023-04-30", TokenReleaseAmount: 300}, + {StartDate: "2023-04-01", EndDate: "2023-04-10", TokenReleaseAmount: 100}, + {StartDate: "2023-04-11", EndDate: "2023-04-20", TokenReleaseAmount: 200}, + }, + expectedOutput: []minttypes.ScheduledTokenRelease{ + {StartDate: "2023-04-01", EndDate: "2023-04-10", TokenReleaseAmount: 100}, + {StartDate: "2023-04-11", EndDate: "2023-04-20", TokenReleaseAmount: 200}, + {StartDate: "2023-04-21", EndDate: "2023-04-30", TokenReleaseAmount: 300}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + sorted := minttypes.SortTokenReleaseCalendar(tc.input) + + if len(sorted) != len(tc.expectedOutput) { + t.Fatalf("Expected output length to be %d, but got %d", len(tc.expectedOutput), len(sorted)) + } + + for i, expected := range tc.expectedOutput { + if sorted[i].StartDate != expected.StartDate || + sorted[i].EndDate != expected.EndDate || + sorted[i].TokenReleaseAmount != expected.TokenReleaseAmount { + t.Errorf("Expected token release at index %d to be %+v, but got %+v", i, expected, sorted[i]) + } + } + }) + } +} diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index c4caddfe90..eb88eb7bd2 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -134,9 +134,10 @@ func (k Keeper) GetOrUpdateLatestMinter( params := k.GetParams(ctx) currentReleaseMinter := k.GetMinter(ctx) nextScheduledRelease := GetNextScheduledTokenRelease(epoch, params.TokenReleaseSchedule, currentReleaseMinter) + // There's still an ongoing release if currentReleaseMinter.OngoingRelease() || nextScheduledRelease == nil { - k.Logger(ctx).Debug("Ongoing token release or no nextScheduledRelease", "minter", currentReleaseMinter, "nextScheduledRelease", nextScheduledRelease) + k.Logger(ctx).Debug("Ongoing token release or no nextScheduledRelease", "minter", currentReleaseMinter) return currentReleaseMinter } @@ -159,9 +160,13 @@ func GetNextScheduledTokenRelease( // This should not happen as the scheduled release date is validated when the param is updated panic(fmt.Errorf("invalid scheduled release date: %s", err)) } - // If blocktime is after the currentScheduled date and it's after the current release - if epoch.GetCurrentEpochStartTime().After(scheduledStartDate) && scheduledStartDate.After(currentMinter.GetEndDateTime()) { - return &scheduledRelease + scheduledStartDateTime := scheduledStartDate.UTC() + + // If epoch is after the currentScheduled date and it's after the current release + if epoch.GetCurrentEpochStartTime().After(scheduledStartDateTime) { + if scheduledStartDateTime.After(currentMinter.GetEndDateTime()) || scheduledStartDateTime.Equal(currentMinter.GetEndDateTime()) { + return &scheduledRelease + } } } return nil diff --git a/x/mint/keeper/keeper_test.go b/x/mint/keeper/keeper_test.go index fc11363caf..b40c9105a1 100644 --- a/x/mint/keeper/keeper_test.go +++ b/x/mint/keeper/keeper_test.go @@ -15,7 +15,7 @@ import ( func TestGetNextScheduledTokenRelease(t *testing.T) { t.Parallel() - currentTime := time.Now() + currentTime := time.Now().UTC() epoch := epochTypes.Epoch{ CurrentEpochStartTime: currentTime, CurrentEpochHeight: 100, @@ -41,13 +41,23 @@ func TestGetNextScheduledTokenRelease(t *testing.T) { } t.Run("Get the next scheduled token release", func(t *testing.T) { - epoch.CurrentEpochStartTime = currentTime.AddDate(0, 0, 1) + // No next scheduled token release intially + epoch.CurrentEpochStartTime = currentTime.AddDate(0, 0, 0) nextScheduledRelease := mintKeeper.GetNextScheduledTokenRelease(epoch, tokenReleaseSchedule, currentMinter) + require.Nil(t, nextScheduledRelease) + + epoch.CurrentEpochStartTime = currentTime.AddDate(0, 0, 1) + nextScheduledRelease = mintKeeper.GetNextScheduledTokenRelease(epoch, tokenReleaseSchedule, currentMinter) require.NotNil(t, nextScheduledRelease) - require.Equal(t, int64(100), nextScheduledRelease.TokenReleaseAmount) + require.Equal(t, uint64(100), nextScheduledRelease.TokenReleaseAmount) }) t.Run("No next scheduled token release, assume we are on the second period", func(t *testing.T) { + // No next scheduled token release intially + epoch.CurrentEpochStartTime = currentTime.AddDate(0, 0, 0) + nextScheduledRelease := mintKeeper.GetNextScheduledTokenRelease(epoch, tokenReleaseSchedule, currentMinter) + require.Nil(t, nextScheduledRelease) + secondMinter := mintTypes.NewMinter( currentTime.AddDate(0, 0, 30).Format(minttypes.TokenReleaseDateFormat), currentTime.AddDate(0, 2, 0).Format(minttypes.TokenReleaseDateFormat), @@ -55,7 +65,7 @@ func TestGetNextScheduledTokenRelease(t *testing.T) { 200, ) epoch.CurrentEpochStartTime = currentTime.AddDate(0, 5, 0) - nextScheduledRelease := mintKeeper.GetNextScheduledTokenRelease(epoch, tokenReleaseSchedule, secondMinter) + nextScheduledRelease = mintKeeper.GetNextScheduledTokenRelease(epoch, tokenReleaseSchedule, secondMinter) require.Nil(t, nextScheduledRelease) }) @@ -68,7 +78,7 @@ func TestGetNextScheduledTokenRelease(t *testing.T) { // First mint was +1 but the chain recoverd on +3 epoch.CurrentEpochStartTime = currentTime.AddDate(0, 0, 3) nextScheduledRelease = mintKeeper.GetNextScheduledTokenRelease(epoch, tokenReleaseSchedule, currentMinter) - require.Equal(t, int64(100), nextScheduledRelease.GetTokenReleaseAmount()) + require.Equal(t, uint64(100), nextScheduledRelease.GetTokenReleaseAmount()) require.Equal(t, currentTime.AddDate(0, 0, 1).Format(minttypes.TokenReleaseDateFormat), nextScheduledRelease.GetStartDate()) }) } diff --git a/x/mint/simulation/genesis_test.go b/x/mint/simulation/genesis_test.go index 63213acbfe..6bfc1d05ed 100644 --- a/x/mint/simulation/genesis_test.go +++ b/x/mint/simulation/genesis_test.go @@ -40,8 +40,7 @@ func TestRandomizedGenState(t *testing.T) { simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &mintGenesis) require.Equal(t, "usei", mintGenesis.Params.MintDenom) - require.Equal(t, "0usei", mintGenesis.Minter.GetCoin().String()) - require.Equal(t, "0.000000000000000000", mintGenesis.Minter.GetLastMintAmount().String()) + require.Equal(t, "0usei", mintGenesis.Minter.GetLastMintAmountCoin().String()) } // TestRandomizedGenState tests abnormal scenarios of applying RandomizedGenState. diff --git a/x/mint/types/minter.go b/x/mint/types/minter.go index d46916fe4c..d6cc31aab8 100644 --- a/x/mint/types/minter.go +++ b/x/mint/types/minter.go @@ -64,7 +64,7 @@ func (m Minter) GetLastMintDateTime() time.Time { // This should not happen as the date is validated when the minter is created panic(fmt.Errorf("invalid end date for current minter: %s, minter=%s", err, m.String())) } - return lastMinteDateTime + return lastMinteDateTime.UTC() } func (m Minter) GetStartDateTime() time.Time { @@ -73,7 +73,7 @@ func (m Minter) GetStartDateTime() time.Time { // This should not happen as the date is validated when the minter is created panic(fmt.Errorf("invalid end date for current minter: %s, minter=%s", err, m.String())) } - return startDateTime + return startDateTime.UTC() } func (m Minter) GetEndDateTime() time.Time { @@ -82,60 +82,75 @@ func (m Minter) GetEndDateTime() time.Time { // This should not happen as the date is validated when the minter is created panic(fmt.Errorf("invalid end date for current minter: %s, minter=%s", err, m.String())) } - return endDateTime + return endDateTime.UTC() } func (m Minter) GetLastMintAmountCoin() sdk.Coin { return sdk.NewCoin(m.GetDenom(), sdk.NewInt(int64(m.GetLastMintAmount()))) } -func (m Minter) GetReleaseAmountToday() sdk.Coins { - return sdk.NewCoins(sdk.NewCoin(m.GetDenom(), sdk.NewInt(int64(m.getReleaseAmountToday())))) +func (m Minter) GetReleaseAmountToday(currentTime time.Time) sdk.Coins { + return sdk.NewCoins(sdk.NewCoin(m.GetDenom(), sdk.NewInt(int64(m.getReleaseAmountToday(currentTime))))) } -func (m Minter) RecordSuccessfulMint(ctx sdk.Context, epoch epochTypes.Epoch) { - m.RemainingMintAmount -= m.getReleaseAmountToday() +func (m Minter) RecordSuccessfulMint(ctx sdk.Context, epoch epochTypes.Epoch, mintedAmount uint64) Minter { + m.RemainingMintAmount -= mintedAmount m.LastMintDate = epoch.CurrentEpochStartTime.Format(TokenReleaseDateFormat) m.LastMintHeight = uint64(epoch.CurrentEpochHeight) - m.LastMintAmount = m.getReleaseAmountToday() - metrics.SetCoinsMinted(m.getReleaseAmountToday(), m.GetDenom()) - + m.LastMintAmount = mintedAmount + metrics.SetCoinsMinted(mintedAmount, m.GetDenom()) ctx.EventManager().EmitEvent( sdk.NewEvent( EventTypeMint, sdk.NewAttribute(AttributeEpochNumber, fmt.Sprintf("%d", epoch.GetCurrentEpoch())), sdk.NewAttribute(AttributeKeyEpochProvisions, m.GetLastMintDate()), - sdk.NewAttribute(sdk.AttributeKeyAmount, m.GetReleaseAmountToday().String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, fmt.Sprintf("%d", mintedAmount)), ), ) + return m } -func (m Minter) getReleaseAmountToday() uint64 { - numberOfDaysLeft := m.getNumberOfDaysLeft() +func (m Minter) getReleaseAmountToday(currentTime time.Time) uint64 { + // Not yet started or already minted today + if currentTime.Before(m.GetStartDateTime()) || currentTime.Format(TokenReleaseDateFormat) == m.GetLastMintDate() { + return 0 + } + + // if it's already past the end date then release the remaining amount + // likely caused by outage + if currentTime.After(m.GetEndDateTime()) && m.GetRemainingMintAmount() > 0 { + return m.GetRemainingMintAmount() + } + + numberOfDaysLeft := m.getNumberOfDaysLeft(currentTime) if numberOfDaysLeft == 0 { + fmt.Printf("Minter: Nothing Left!: %d\n", m.GetRemainingMintAmount()) return 0 } return m.GetRemainingMintAmount() / numberOfDaysLeft } -func (m Minter) getNumberOfDaysLeft() uint64 { - startDate := m.GetStartDateTime() - endDate := m.GetEndDateTime() - return daysBetween(endDate, startDate) +func (m Minter) getNumberOfDaysLeft(currentTime time.Time) uint64 { + // If the last mint date is after the start date then use the last mint date as there's an ongoing release + daysBetween := daysBetween(currentTime, m.GetEndDateTime()) + return daysBetween } func (m Minter) OngoingRelease() bool { - endDateTime := m.GetEndDateTime() - return m.GetRemainingMintAmount() > 0 && time.Now().Before(endDateTime) + return m.GetRemainingMintAmount() != 0 } func daysBetween(a, b time.Time) uint64 { + // Convert both times to UTC before comparing + aYear, aMonth, aDay := a.UTC().Date() + a = time.Date(aYear, aMonth, aDay, 0, 0, 0, 0, time.UTC) + bYear, bMonth, bDay := b.UTC().Date() + b = time.Date(bYear, bMonth, bDay, 0, 0, 0, 0, time.UTC) + // Always return a positive value between the dates if a.Before(b) { a, b = b, a } - duration := a.Sub(b) - hours := duration.Hours() - // Rounds down, the last day should be 1 day diff so it will always release any remaining amount + hours := a.Sub(b).Hours() return uint64(hours / 24) } diff --git a/x/mint/types/minter_test.go b/x/mint/types/minter_test.go index 4e18db82df..2691d435bc 100644 --- a/x/mint/types/minter_test.go +++ b/x/mint/types/minter_test.go @@ -31,6 +31,12 @@ func TestDaysBetween(t *testing.T) { date2: "2023-04-20T23:59:59Z", expected: 0, }, + { + name: "25 days apart", + date1: "2023-04-24T00:00:00Z", + date2: "2023-05-19T00:00:00Z", + expected: 25, + }, { name: "One day apart", date1: "2023-04-20T00:00:00Z", @@ -53,7 +59,7 @@ func TestDaysBetween(t *testing.T) { name: "Less than 24 hours apart, crossing day boundary", date1: "2023-04-20T23:00:00Z", date2: "2023-04-21T22:59:59Z", - expected: 0, + expected: 1, }, { name: "Exactly 24 hours apart", @@ -65,7 +71,7 @@ func TestDaysBetween(t *testing.T) { name: "One minute less than 24 hours apart", date1: "2023-04-20T12:34:56Z", date2: "2023-04-21T12:33:56Z", - expected: 0, + expected: 1, }, { name: "Inverted dates with times", @@ -88,3 +94,210 @@ func TestDaysBetween(t *testing.T) { }) } } + +func TestGetReleaseAmountToday(t *testing.T) { + t.Parallel() + testCases := []struct { + name string + minter Minter + currentTime time.Time + expectedAmount uint64 + }{ + { + name: "Regular scenario", + minter: Minter{ + StartDate: "2023-04-01", + EndDate: "2023-04-10", + Denom: "test", + TotalMintAmount: 100, + RemainingMintAmount: 60, + LastMintDate: "2023-04-04", + }, + currentTime: time.Date(2023, 4, 5, 0, 0, 0, 0, time.UTC), + expectedAmount: 12, + }, + { + name: "Don't mint on the same day", + minter: Minter{ + StartDate: "2023-04-01", + EndDate: "2023-04-10", + Denom: "test", + TotalMintAmount: 100, + RemainingMintAmount: 60, + LastMintDate: "2023-04-05", + }, + currentTime: time.Date(2023, 4, 5, 0, 0, 0, 0, time.UTC), + expectedAmount: 0, + }, + { + name: "No days left but remaining mint amount", + minter: Minter{ + StartDate: "2023-04-01", + EndDate: "2023-04-10", + Denom: "test", + TotalMintAmount: 100, + RemainingMintAmount: 60, + LastMintDate: "2023-04-11", + }, + currentTime: time.Date(2023, 4, 13, 0, 0, 0, 0, time.UTC), + expectedAmount: 60, + }, + { + name: "Past end date", + minter: Minter{ + StartDate: "2023-04-01", + EndDate: "2023-04-10", + Denom: "test", + TotalMintAmount: 100, + RemainingMintAmount: 60, + LastMintDate: "2023-04-09", + }, + currentTime: time.Date(2023, 4, 11, 0, 0, 0, 0, time.UTC), + expectedAmount: 60, + }, + { + name: "No remaining mint amount", + minter: Minter{ + StartDate: "2023-04-01", + EndDate: "2023-04-10", + Denom: "test", + TotalMintAmount: 100, + RemainingMintAmount: 0, + LastMintDate: "2023-04-05", + }, + currentTime: time.Date(2023, 4, 5, 0, 0, 0, 0, time.UTC), + expectedAmount: 0, + }, + { + name: "Not yet started", + minter: NewMinter( + "2023-04-01", + "2023-04-10", + "test", + 100, + ), + currentTime: time.Date(2023, 4, 0, 0, 0, 0, 0, time.UTC), + expectedAmount: 0, + }, + { + name: "First day", + minter: NewMinter( + "2023-04-01", + "2023-04-10", + "test", + 100, + ), + currentTime: time.Date(2023, 4, 1, 0, 0, 0, 0, time.UTC), + expectedAmount: 11, + }, + { + name: "No minter", + minter: InitialMinter(), + currentTime: time.Date(2023, 4, 5, 0, 0, 0, 0, time.UTC), + expectedAmount: 0, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + releaseAmount := tc.minter.getReleaseAmountToday(tc.currentTime) + if releaseAmount != tc.expectedAmount { + t.Errorf("Expected release amount to be %d, but got %d", tc.expectedAmount, releaseAmount) + } + }) + } +} + +func TestGetNumberOfDaysLeft(t *testing.T) { + t.Parallel() + testCases := []struct { + name string + minter Minter + expectedDaysLeft uint64 + currentTime time.Time + }{ + { + name: "Regular scenario", + minter: Minter{ + StartDate: "2023-04-01", + EndDate: "2023-04-10", + Denom: "test", + TotalMintAmount: 100, + RemainingMintAmount: 60, + LastMintDate: "2023-04-05", + }, + currentTime: time.Date(2023, 4, 5, 0, 0, 0, 0, time.UTC), + expectedDaysLeft: 5, + }, + { + name: "No days left but amount left", + minter: Minter{ + StartDate: "2023-04-01", + EndDate: "2023-04-10", + Denom: "test", + TotalMintAmount: 100, + RemainingMintAmount: 60, + LastMintDate: "2023-04-10", + }, + currentTime: time.Date(2023, 4, 10, 0, 0, 0, 0, time.UTC), + expectedDaysLeft: 0, + }, + { + name: "Past end date", + minter: Minter{ + StartDate: "2023-04-01", + EndDate: "2023-04-10", + Denom: "test", + TotalMintAmount: 100, + RemainingMintAmount: 60, + LastMintDate: "2023-04-09", + }, + currentTime: time.Date(2023, 4, 9, 0, 0, 0, 0, time.UTC), + expectedDaysLeft: 1, + }, + { + name: "Regular end date", + minter: NewMinter( + "2023-04-24", + "2023-05-19", + "test", + 100, + ), + expectedDaysLeft: 25, + currentTime: time.Date(2023, 4, 24, 0, 0, 0, 0, time.UTC), + }, + { + name: "No remaining mint amount", + minter: Minter{ + StartDate: "2023-04-01", + EndDate: "2023-04-10", + Denom: "test", + TotalMintAmount: 100, + RemainingMintAmount: 0, + LastMintDate: "2023-04-05", + }, + currentTime: time.Date(2023, 4, 5, 0, 0, 0, 0, time.UTC), + expectedDaysLeft: 5, + }, + { + name: "First mint", + minter: NewMinter( + "2023-04-01", + "2023-04-10", + "test", + 100, + ), + currentTime: time.Date(2023, 4, 1, 0, 0, 0, 0, time.UTC), + expectedDaysLeft: 9, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + daysLeft := tc.minter.getNumberOfDaysLeft(tc.currentTime) + if daysLeft != tc.expectedDaysLeft { + t.Errorf("Expected days left to be %d, but got %d", tc.expectedDaysLeft, daysLeft) + } + }) + } +} diff --git a/x/mint/types/params.go b/x/mint/types/params.go index 2f4f4c8619..58763dc544 100644 --- a/x/mint/types/params.go +++ b/x/mint/types/params.go @@ -29,7 +29,7 @@ func NewParams( ) Params { return Params{ MintDenom: mintDenom, - TokenReleaseSchedule: sortTokenReleaseCalendar(tokenReleaseSchedule), + TokenReleaseSchedule: SortTokenReleaseCalendar(tokenReleaseSchedule), } } @@ -86,7 +86,7 @@ func validateMintDenom(i interface{}) error { return nil } -func sortTokenReleaseCalendar(tokenReleaseSchedule []ScheduledTokenRelease) []ScheduledTokenRelease { +func SortTokenReleaseCalendar(tokenReleaseSchedule []ScheduledTokenRelease) []ScheduledTokenRelease { sort.Slice(tokenReleaseSchedule, func(i, j int) bool { startDate1, _ := time.Parse(TokenReleaseDateFormat, tokenReleaseSchedule[i].GetStartDate()) startDate2, _ := time.Parse(TokenReleaseDateFormat, tokenReleaseSchedule[j].GetStartDate()) @@ -101,10 +101,10 @@ func validateTokenReleaseSchedule(i interface{}) error { return fmt.Errorf("invalid parameter type: %T", i) } - tokenReleaseSchedule = sortTokenReleaseCalendar(tokenReleaseSchedule) + sortedTokenReleaseSchedule := SortTokenReleaseCalendar(tokenReleaseSchedule) prevReleaseEndDate := time.Time{} - for _, scheduledTokenRelease := range tokenReleaseSchedule { + for _, scheduledTokenRelease := range sortedTokenReleaseSchedule { startDate, err := time.Parse(TokenReleaseDateFormat, scheduledTokenRelease.GetStartDate()) if err != nil { return fmt.Errorf("error: invalid start date format use yyyy-mm-dd: %s", err) diff --git a/x/oracle/simulation/operations.go b/x/oracle/simulation/operations.go index 2028e73625..3988c4b164 100644 --- a/x/oracle/simulation/operations.go +++ b/x/oracle/simulation/operations.go @@ -65,7 +65,7 @@ func WeightedOperations( } // SimulateMsgAggregateExchangeRateVote generates a MsgAggregateExchangeRateVote with random values. -// nolint: funlen +//nolint: funlen func SimulateMsgAggregateExchangeRateVote(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, @@ -122,7 +122,7 @@ func SimulateMsgAggregateExchangeRateVote(ak types.AccountKeeper, bk types.BankK } // SimulateMsgDelegateFeedConsent generates a MsgDelegateFeedConsent with random values. -// nolint: funlen +//nolint: funlen func SimulateMsgDelegateFeedConsent(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, From a27fceb87a283b61d9e530a9f587783458b7321d Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:05:24 -0400 Subject: [PATCH 03/16] Mints --- x/mint/keeper/hooks.go | 1 + x/mint/keeper/keeper.go | 2 +- x/mint/types/minter.go | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x/mint/keeper/hooks.go b/x/mint/keeper/hooks.go index 0230b1f37a..716519a679 100644 --- a/x/mint/keeper/hooks.go +++ b/x/mint/keeper/hooks.go @@ -29,6 +29,7 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epoch epochTypes.Epoch) { // Released Succssfully, decrement the remaining amount by the daily release amount and update minter amountMinted := coinsToMint.AmountOf(latestMinter.GetDenom()) updatedMinter := latestMinter.RecordSuccessfulMint(ctx, epoch, amountMinted.Uint64()) + k.Logger(ctx).Info("Minted coins", "minter", updatedMinter, "amount", amountMinted) k.SetMinter(ctx, updatedMinter) } diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index eb88eb7bd2..f1bec00b9e 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -135,7 +135,7 @@ func (k Keeper) GetOrUpdateLatestMinter( currentReleaseMinter := k.GetMinter(ctx) nextScheduledRelease := GetNextScheduledTokenRelease(epoch, params.TokenReleaseSchedule, currentReleaseMinter) - // There's still an ongoing release + // There's still an ongoing release or there's no release scheduled if currentReleaseMinter.OngoingRelease() || nextScheduledRelease == nil { k.Logger(ctx).Debug("Ongoing token release or no nextScheduledRelease", "minter", currentReleaseMinter) return currentReleaseMinter diff --git a/x/mint/types/minter.go b/x/mint/types/minter.go index d6cc31aab8..e5bdc3cae9 100644 --- a/x/mint/types/minter.go +++ b/x/mint/types/minter.go @@ -124,7 +124,6 @@ func (m Minter) getReleaseAmountToday(currentTime time.Time) uint64 { numberOfDaysLeft := m.getNumberOfDaysLeft(currentTime) if numberOfDaysLeft == 0 { - fmt.Printf("Minter: Nothing Left!: %d\n", m.GetRemainingMintAmount()) return 0 } return m.GetRemainingMintAmount() / numberOfDaysLeft From 045e06a89a1d5e3ce14cad519bd0e1bed45fe83a Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Tue, 25 Apr 2023 23:24:51 -0400 Subject: [PATCH 04/16] Address unit test comments --- x/mint/keeper/hooks_test.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/x/mint/keeper/hooks_test.go b/x/mint/keeper/hooks_test.go index 6f4ff081f7..17f3b4d844 100644 --- a/x/mint/keeper/hooks_test.go +++ b/x/mint/keeper/hooks_test.go @@ -82,7 +82,7 @@ func TestEndOfEpochMintedCoinDistribution(t *testing.T) { expectedAmount := int64(100000) newMinter := seiApp.MintKeeper.GetMinter(ctx) - if i == 25 { + if i == 24 { require.Zero(t, newMinter.GetRemainingMintAmount(), "Remaining amount should be zero") break } @@ -250,6 +250,27 @@ func TestEndOfEpochMintedCoinDistribution(t *testing.T) { require.Equal(t, postOutageTime.Format(minttypes.TokenReleaseDateFormat), newMinter.GetLastMintDate(), "Last mint date should be correct") require.InDelta(t, 127315, newMinter.GetLastMintAmountCoin().Amount.Int64(), 1, "Minted amount should be correct") require.InDelta(t, int64(1018522), int64(newMinter.GetRemainingMintAmount()), 24, "Remaining amount should be correct") + + // Continue and ensure that eventually reaches zero + for i := 16; i < 25; i++ { + currTime := genesisTime.AddDate(0, 0, i) + currEpoch := getEpoch(genesisTime, currTime) + seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch) + seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch) + mintParams = seiApp.MintKeeper.GetParams(ctx) + + newMinter := seiApp.MintKeeper.GetMinter(ctx) + expectedAmount := int64(127315) + + if i == 24 { + require.Zero(t, newMinter.GetRemainingMintAmount(), "Remaining amount should be zero") + break + } + + require.Equal(t, currTime.Format(minttypes.TokenReleaseDateFormat), newMinter.GetLastMintDate(), "Last mint date should be correct") + require.InDelta(t, expectedAmount, newMinter.GetLastMintAmountCoin().Amount.Int64(), 1, "Minted amount should be correct") + } + }) } From 8285214753a3dc94bc9252bccb2ee0bce3f52297 Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Wed, 26 Apr 2023 13:22:15 -0400 Subject: [PATCH 05/16] lint --- proto/mint/v1beta1/mint.proto | 38 ++ x/mint/keeper/keeper.go | 19 +- x/mint/keeper/migrations.go | 66 ++ x/mint/keeper/migrations_test.go | 152 +++++ x/mint/module.go | 3 +- x/mint/types/keys.go | 2 + x/mint/types/mint.pb.go | 1036 ++++++++++++++++++++++++++---- x/mint/types/params.go | 13 + 8 files changed, 1185 insertions(+), 144 deletions(-) create mode 100644 x/mint/keeper/migrations_test.go diff --git a/proto/mint/v1beta1/mint.proto b/proto/mint/v1beta1/mint.proto index a4a14dedab..22c3e6a819 100644 --- a/proto/mint/v1beta1/mint.proto +++ b/proto/mint/v1beta1/mint.proto @@ -36,3 +36,41 @@ message Params { ]; } + +// Legacy Protobufs used for migration purposes + +// Minter represents the most recent +message Version2Minter { + string last_mint_amount = 1 [ + (gogoproto.moretags) = "yaml:\"last_mint_amount\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + string last_mint_date = 2 [ + (gogoproto.moretags) = "yaml:\"last_mint_date\"" + ]; + int64 last_mint_height = 3 [ + (gogoproto.moretags) = "yaml:\"last_mint_height\"" + ]; + string denom = 4 [ + (gogoproto.moretags) = "yaml:\"denom\"" + ]; +} + +message Version2ScheduledTokenRelease { + string date = 1; // yyyy-mm-dd + int64 token_release_amount = 2; +} + +// Params holds parameters for the mint module. +message Version2Params { + option (gogoproto.goproto_stringer) = false; + + // type of coin to mint + string mint_denom = 1; + // List of token release schedules + repeated Version2ScheduledTokenRelease token_release_schedule = 2 [ + (gogoproto.moretags) = "yaml:\"token_release_schedule\"", + (gogoproto.nullable) = false + ]; +} diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index f1bec00b9e..90c9d5bf4c 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -4,13 +4,12 @@ import ( "fmt" "time" - "github.com/tendermint/tendermint/libs/log" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" epochTypes "github.com/sei-protocol/sei-chain/x/epoch/types" "github.com/sei-protocol/sei-chain/x/mint/types" + "github.com/tendermint/tendermint/libs/log" ) // Keeper of the mint store @@ -149,6 +148,22 @@ func (k Keeper) GetOrUpdateLatestMinter( ) } +func (k Keeper) GetCdc() codec.BinaryCodec { + return k.cdc +} + +func (k Keeper) GetStoreKey() sdk.StoreKey { + return k.storeKey +} + +func (k Keeper) GetParamSpace() paramtypes.Subspace { + return k.paramSpace +} + +func (k *Keeper) SetParamSpace(subspace paramtypes.Subspace) { + k.paramSpace = subspace +} + func GetNextScheduledTokenRelease( epoch epochTypes.Epoch, tokenReleaseSchedule []types.ScheduledTokenRelease, diff --git a/x/mint/keeper/migrations.go b/x/mint/keeper/migrations.go index d1b92b2d80..fd3048f23a 100644 --- a/x/mint/keeper/migrations.go +++ b/x/mint/keeper/migrations.go @@ -1,6 +1,9 @@ package keeper import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/sei-protocol/sei-chain/x/mint/types" ) @@ -21,3 +24,66 @@ func (m Migrator) Migrate1to2(ctx sdk.Context) error { m.keeper.paramSpace.SetParamSet(ctx, &defaultParams) return nil } + +// Migrate1to2 migrates from version 1 to 2 +func (m Migrator) Migrate2to3(ctx sdk.Context) error { + ctx.Logger().Info("Migrating mint module from v2 to v3") + store := ctx.KVStore(m.keeper.storeKey) + // Migrate Minter First + minterBytes := store.Get(types.MinterKey) + if minterBytes == nil { + panic("stored minter should not have been nil") + } + + var oldMinter types.Version2Minter + m.keeper.cdc.MustUnmarshal(minterBytes, &oldMinter) + + newMinter := types.Minter{ + StartDate: oldMinter.GetLastMintDate(), + EndDate: oldMinter.GetLastMintDate(), + Denom: sdk.DefaultBondDenom, + TotalMintAmount: oldMinter.LastMintAmount.RoundInt().Uint64(), + RemainingMintAmount: 0, + LastMintDate: oldMinter.GetLastMintDate(), + LastMintHeight: uint64(oldMinter.GetLastMintHeight()), + LastMintAmount: oldMinter.LastMintAmount.RoundInt().Uint64(), + } + ctx.Logger().Info("Migrating mint module from v2 to v3", "oldMinter", oldMinter.String(), "newMinter", newMinter.String()) + m.keeper.SetMinter(ctx, newMinter) + + // Migrate TokenReleaseSchedule + + var oldTokenReleaseSchedules []types.Version2ScheduledTokenRelease + oldTokenReleaseSchedulesBytes := m.keeper.GetParamSpace().GetRaw(ctx, types.KeyTokenReleaseSchedule) + err := codec.NewLegacyAmino().UnmarshalJSON(oldTokenReleaseSchedulesBytes, &oldTokenReleaseSchedules) + if err != nil { + panic(fmt.Sprintf("Key not found or error: %s", err)) + } + + var oldMintDenom string + oldMintDenomBytes := m.keeper.GetParamSpace().GetRaw(ctx, types.KeyMintDenom) + err = codec.NewLegacyAmino().UnmarshalJSON(oldMintDenomBytes, &oldMintDenom) + if err != nil { + panic(fmt.Sprintf("Key not found or error: %s", err)) + } + ctx.Logger().Info("Migrating mint module from v2 to v3", "oldTokenReleaseSchedules", oldTokenReleaseSchedules, "oldMintDenom", oldMintDenom) + fmt.Println("Migrating mint module from v2 to v3", "oldTokenReleaseSchedules", oldTokenReleaseSchedules, "oldMintDenom", oldMintDenom) + + newTokenReleaseSchedule := []types.ScheduledTokenRelease{} + for _, oldTokenReleaseSchedule := range oldTokenReleaseSchedules { + newSchedule := types.ScheduledTokenRelease{ + TokenReleaseAmount: uint64(oldTokenReleaseSchedule.GetTokenReleaseAmount()), + StartDate: oldTokenReleaseSchedule.GetDate(), + EndDate: oldTokenReleaseSchedule.GetDate(), + } + newTokenReleaseSchedule = append(newTokenReleaseSchedule, newSchedule) + } + newParams := types.Params{ + MintDenom: oldMintDenom, + TokenReleaseSchedule: newTokenReleaseSchedule, + } + m.keeper.SetParams(ctx, newParams) + ctx.Logger().Info("Migrating mint module from v2 to v3", "newParams", newParams.String()) + + return nil +} diff --git a/x/mint/keeper/migrations_test.go b/x/mint/keeper/migrations_test.go new file mode 100644 index 0000000000..b3c151ffce --- /dev/null +++ b/x/mint/keeper/migrations_test.go @@ -0,0 +1,152 @@ +package keeper_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/store" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + typesparams "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/sei-protocol/sei-chain/x/mint/keeper" + "github.com/sei-protocol/sei-chain/x/mint/types" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmdb "github.com/tendermint/tm-db" +) + +type MockAccountKeeper struct { + ModuleAddress sdk.AccAddress + ModuleAccount authtypes.ModuleAccountI +} + +func (m MockAccountKeeper) GetModuleAddress(name string) sdk.AccAddress { + address, _ := sdk.AccAddressFromBech32("sei1t4xhq2pnhnf223zr4z5lw02vsrxwf74z604kja") + return address +} + +func (m MockAccountKeeper) SetModuleAccount(ctx sdk.Context, account authtypes.ModuleAccountI) { + m.ModuleAccount = account +} + +func (m MockAccountKeeper) GetModuleAccount(ctx sdk.Context, moduleName string) authtypes.ModuleAccountI { + return m.ModuleAccount +} + +func TestMigrate2to3(t *testing.T) { + + storeKey := sdk.NewKVStoreKey(types.StoreKey) + memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) + + db := tmdb.NewMemDB() + stateStore := store.NewCommitMultiStore(db) + stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) + stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) + require.NoError(t, stateStore.LoadLatestVersion()) + + registry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + + paramsSubspace := typesparams.NewSubspace(cdc, + codec.NewLegacyAmino(), + storeKey, + memStoreKey, + "MintParams", + ) + ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) + if !paramsSubspace.HasKeyTable() { + paramsSubspace = paramsSubspace.WithKeyTable(paramtypes.NewKeyTable().RegisterParamSet(&types.Version2Params{})) + } + store := ctx.KVStore(storeKey) + + // Set up the old Minter and Params + oldMinter := types.Version2Minter{ + LastMintAmount: sdk.NewDec(1000), + LastMintDate: "2021-01-01", + LastMintHeight: 100, + Denom: sdk.DefaultBondDenom, + } + + oldTokenReleaseSchedule := []types.Version2ScheduledTokenRelease{ + { + Date: "2021-02-01", + TokenReleaseAmount: 500, + }, + { + Date: "2021-03-01", + TokenReleaseAmount: 1000, + }, + } + + // Start up post upgrade with new Param Space + newParamsSubspace := typesparams.NewSubspace(cdc, + codec.NewLegacyAmino(), + storeKey, + memStoreKey, + "MintParams", + ) + mintKeeper := keeper.NewKeeper( + cdc, + storeKey, + newParamsSubspace, + nil, + MockAccountKeeper{}, + nil, + nil, + "fee_collector", + ) + + oldParams := types.Version2Params{ + MintDenom: sdk.DefaultBondDenom, + TokenReleaseSchedule: oldTokenReleaseSchedule, + } + + // Store the old Minter and Params + b := cdc.MustMarshal(&oldMinter) + store.Set(types.MinterKey, b) + paramsSubspace.SetParamSet(ctx, &oldParams) + + // Perform the migration + + // Use new keeper or param space here + migrator := keeper.NewMigrator(mintKeeper) + err := migrator.Migrate2to3(ctx) + require.NoError(t, err) + + // Check if the new Minter was stored correctly + minterBytes := store.Get(types.MinterKey) + if minterBytes == nil { + panic("stored minter should not have been nil") + } + var newMinter types.Minter + cdc.MustUnmarshal(minterBytes, &newMinter) + + require.Equal(t, oldMinter.LastMintDate, newMinter.StartDate) + require.Equal(t, oldMinter.LastMintDate, newMinter.EndDate) + require.Equal(t, oldMinter.LastMintDate, newMinter.LastMintDate) + require.Equal(t, oldMinter.LastMintHeight, int64(newMinter.LastMintHeight)) + require.Equal(t, oldMinter.LastMintAmount.RoundInt().Uint64(), newMinter.TotalMintAmount) + require.Equal(t, oldMinter.LastMintAmount.RoundInt().Uint64(), newMinter.LastMintAmount) + + // Check if the new Params were stored correctly + var newTokenReleaseSchedules []types.ScheduledTokenRelease + mintKeeper.GetParamSpace().Get(ctx, types.KeyTokenReleaseSchedule, &newTokenReleaseSchedules) + + var newMintDenom string + mintKeeper.GetParamSpace().Get(ctx, types.KeyMintDenom, &newMintDenom) + + require.Equal(t, oldParams.MintDenom, newMintDenom) + require.Len(t, newTokenReleaseSchedules, len(oldParams.TokenReleaseSchedule)) + + for i, oldSchedule := range oldParams.TokenReleaseSchedule { + newSchedule := newTokenReleaseSchedules[i] + + require.Equal(t, oldSchedule.Date, newSchedule.StartDate) + require.Equal(t, oldSchedule.Date, newSchedule.EndDate) + require.Equal(t, uint64(oldSchedule.TokenReleaseAmount), newSchedule.TokenReleaseAmount) + } +} diff --git a/x/mint/module.go b/x/mint/module.go index 054c85fa17..fbdacd5873 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -128,6 +128,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.keeper)) m := keeper.NewMigrator(am.keeper) _ = cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2) + _ = cfg.RegisterMigration(types.ModuleName, 2, m.Migrate2to3) } // InitGenesis performs genesis initialization for the mint module. It returns @@ -148,7 +149,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) {} diff --git a/x/mint/types/keys.go b/x/mint/types/keys.go index 833a4fc57e..f8e7c5ec88 100644 --- a/x/mint/types/keys.go +++ b/x/mint/types/keys.go @@ -10,6 +10,8 @@ const ( // StoreKey is the default store key for mint StoreKey = ModuleName + MemStoreKey = "mem_mint" + // QuerierRoute is the querier route for the minting store. QuerierRoute = StoreKey diff --git a/x/mint/types/mint.pb.go b/x/mint/types/mint.pb.go index 231e356730..26e0f995a3 100644 --- a/x/mint/types/mint.pb.go +++ b/x/mint/types/mint.pb.go @@ -5,6 +5,7 @@ package types import ( fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -238,44 +239,225 @@ func (m *Params) GetTokenReleaseSchedule() []ScheduledTokenRelease { return nil } +// Minter represents the most recent +type Version2Minter struct { + LastMintAmount github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=last_mint_amount,json=lastMintAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"last_mint_amount" yaml:"last_mint_amount"` + LastMintDate string `protobuf:"bytes,2,opt,name=last_mint_date,json=lastMintDate,proto3" json:"last_mint_date,omitempty" yaml:"last_mint_date"` + LastMintHeight int64 `protobuf:"varint,3,opt,name=last_mint_height,json=lastMintHeight,proto3" json:"last_mint_height,omitempty" yaml:"last_mint_height"` + Denom string `protobuf:"bytes,4,opt,name=denom,proto3" json:"denom,omitempty" yaml:"denom"` +} + +func (m *Version2Minter) Reset() { *m = Version2Minter{} } +func (m *Version2Minter) String() string { return proto.CompactTextString(m) } +func (*Version2Minter) ProtoMessage() {} +func (*Version2Minter) Descriptor() ([]byte, []int) { + return fileDescriptor_06339c129491fd39, []int{3} +} +func (m *Version2Minter) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Version2Minter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Version2Minter.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Version2Minter) XXX_Merge(src proto.Message) { + xxx_messageInfo_Version2Minter.Merge(m, src) +} +func (m *Version2Minter) XXX_Size() int { + return m.Size() +} +func (m *Version2Minter) XXX_DiscardUnknown() { + xxx_messageInfo_Version2Minter.DiscardUnknown(m) +} + +var xxx_messageInfo_Version2Minter proto.InternalMessageInfo + +func (m *Version2Minter) GetLastMintDate() string { + if m != nil { + return m.LastMintDate + } + return "" +} + +func (m *Version2Minter) GetLastMintHeight() int64 { + if m != nil { + return m.LastMintHeight + } + return 0 +} + +func (m *Version2Minter) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +type Version2ScheduledTokenRelease struct { + Date string `protobuf:"bytes,1,opt,name=date,proto3" json:"date,omitempty"` + TokenReleaseAmount int64 `protobuf:"varint,2,opt,name=token_release_amount,json=tokenReleaseAmount,proto3" json:"token_release_amount,omitempty"` +} + +func (m *Version2ScheduledTokenRelease) Reset() { *m = Version2ScheduledTokenRelease{} } +func (m *Version2ScheduledTokenRelease) String() string { return proto.CompactTextString(m) } +func (*Version2ScheduledTokenRelease) ProtoMessage() {} +func (*Version2ScheduledTokenRelease) Descriptor() ([]byte, []int) { + return fileDescriptor_06339c129491fd39, []int{4} +} +func (m *Version2ScheduledTokenRelease) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Version2ScheduledTokenRelease) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Version2ScheduledTokenRelease.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Version2ScheduledTokenRelease) XXX_Merge(src proto.Message) { + xxx_messageInfo_Version2ScheduledTokenRelease.Merge(m, src) +} +func (m *Version2ScheduledTokenRelease) XXX_Size() int { + return m.Size() +} +func (m *Version2ScheduledTokenRelease) XXX_DiscardUnknown() { + xxx_messageInfo_Version2ScheduledTokenRelease.DiscardUnknown(m) +} + +var xxx_messageInfo_Version2ScheduledTokenRelease proto.InternalMessageInfo + +func (m *Version2ScheduledTokenRelease) GetDate() string { + if m != nil { + return m.Date + } + return "" +} + +func (m *Version2ScheduledTokenRelease) GetTokenReleaseAmount() int64 { + if m != nil { + return m.TokenReleaseAmount + } + return 0 +} + +// Params holds parameters for the mint module. +type Version2Params struct { + // type of coin to mint + MintDenom string `protobuf:"bytes,1,opt,name=mint_denom,json=mintDenom,proto3" json:"mint_denom,omitempty"` + // List of token release schedules + TokenReleaseSchedule []Version2ScheduledTokenRelease `protobuf:"bytes,2,rep,name=token_release_schedule,json=tokenReleaseSchedule,proto3" json:"token_release_schedule" yaml:"token_release_schedule"` +} + +func (m *Version2Params) Reset() { *m = Version2Params{} } +func (*Version2Params) ProtoMessage() {} +func (*Version2Params) Descriptor() ([]byte, []int) { + return fileDescriptor_06339c129491fd39, []int{5} +} +func (m *Version2Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Version2Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Version2Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Version2Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Version2Params.Merge(m, src) +} +func (m *Version2Params) XXX_Size() int { + return m.Size() +} +func (m *Version2Params) XXX_DiscardUnknown() { + xxx_messageInfo_Version2Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Version2Params proto.InternalMessageInfo + +func (m *Version2Params) GetMintDenom() string { + if m != nil { + return m.MintDenom + } + return "" +} + +func (m *Version2Params) GetTokenReleaseSchedule() []Version2ScheduledTokenRelease { + if m != nil { + return m.TokenReleaseSchedule + } + return nil +} + func init() { proto.RegisterType((*Minter)(nil), "seiprotocol.seichain.mint.Minter") proto.RegisterType((*ScheduledTokenRelease)(nil), "seiprotocol.seichain.mint.ScheduledTokenRelease") proto.RegisterType((*Params)(nil), "seiprotocol.seichain.mint.Params") + proto.RegisterType((*Version2Minter)(nil), "seiprotocol.seichain.mint.Version2Minter") + proto.RegisterType((*Version2ScheduledTokenRelease)(nil), "seiprotocol.seichain.mint.Version2ScheduledTokenRelease") + proto.RegisterType((*Version2Params)(nil), "seiprotocol.seichain.mint.Version2Params") } func init() { proto.RegisterFile("mint/v1beta1/mint.proto", fileDescriptor_06339c129491fd39) } var fileDescriptor_06339c129491fd39 = []byte{ - // 442 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x52, 0x31, 0x6f, 0xd3, 0x40, - 0x18, 0xf5, 0x25, 0x69, 0xda, 0x1e, 0xa8, 0x80, 0x49, 0xc1, 0x45, 0xaa, 0x13, 0x59, 0x20, 0x45, - 0x48, 0xd8, 0x6d, 0xd9, 0xba, 0x51, 0x75, 0xe8, 0x82, 0x84, 0x02, 0x13, 0x8b, 0x75, 0xb1, 0x3f, - 0xd9, 0x27, 0xec, 0xbb, 0xca, 0xf7, 0x05, 0xd1, 0x99, 0x19, 0x89, 0x91, 0x91, 0xdf, 0xc0, 0xce, - 0xde, 0xb1, 0x23, 0x53, 0x85, 0x92, 0x7f, 0xc0, 0x2f, 0x40, 0xf7, 0xb9, 0x06, 0x5b, 0x0a, 0x13, - 0x9b, 0xbf, 0xf7, 0xde, 0xbd, 0xef, 0x3d, 0xdf, 0xf1, 0x87, 0xa5, 0x54, 0x18, 0xbd, 0x3f, 0x9c, - 0x03, 0x8a, 0xc3, 0xc8, 0x0e, 0xe1, 0x79, 0xa5, 0x51, 0xbb, 0x7b, 0x06, 0x24, 0x7d, 0x25, 0xba, - 0x08, 0x0d, 0xc8, 0x24, 0x17, 0x52, 0x85, 0x56, 0xf0, 0x68, 0x94, 0xe9, 0x4c, 0x13, 0x17, 0xd9, - 0xaf, 0xfa, 0x40, 0xf0, 0xad, 0xc7, 0x87, 0x2f, 0xa5, 0x42, 0xa8, 0xdc, 0x7d, 0xce, 0x0d, 0x8a, - 0x0a, 0xe3, 0x54, 0x20, 0x78, 0x6c, 0xc2, 0xa6, 0xdb, 0xb3, 0x6d, 0x42, 0x4e, 0x05, 0x82, 0xbb, - 0xc7, 0xb7, 0x40, 0xa5, 0x35, 0xd9, 0x23, 0x72, 0x13, 0x54, 0x4a, 0xd4, 0x88, 0x6f, 0xa4, 0xa0, - 0x74, 0xe9, 0xf5, 0x09, 0xaf, 0x07, 0xf7, 0x29, 0xbf, 0x87, 0x1a, 0x45, 0x11, 0xdb, 0xf5, 0xb1, - 0x28, 0xf5, 0x42, 0xa1, 0x37, 0x98, 0xb0, 0xe9, 0x60, 0x76, 0x87, 0x08, 0xbb, 0xf7, 0x05, 0xc1, - 0xee, 0x11, 0xdf, 0xad, 0xa0, 0x14, 0x52, 0x49, 0x95, 0x75, 0xf4, 0x1b, 0xa4, 0xbf, 0xff, 0x87, - 0x6c, 0x9d, 0x99, 0xf2, 0xbb, 0x85, 0x30, 0xd8, 0x91, 0x0f, 0x49, 0xbe, 0x63, 0xf1, 0x96, 0xf2, - 0x31, 0xdf, 0xf9, 0xab, 0xa4, 0x02, 0x9b, 0x14, 0xf4, 0x76, 0xa3, 0xa3, 0x16, 0x1d, 0xbf, 0x1c, - 0x64, 0x96, 0xa3, 0xb7, 0xd5, 0xf5, 0x3b, 0x23, 0x34, 0xf8, 0xc8, 0xf8, 0xee, 0xeb, 0x24, 0x87, - 0x74, 0x51, 0x40, 0xfa, 0x46, 0xbf, 0x03, 0x35, 0x83, 0x02, 0x84, 0x81, 0xff, 0xf8, 0x87, 0x07, - 0x7c, 0x84, 0xd6, 0x29, 0xae, 0x6a, 0xab, 0xa6, 0x51, 0x9f, 0x12, 0xb8, 0xd8, 0xda, 0x52, 0xb7, - 0x0a, 0xbe, 0x33, 0x3e, 0x7c, 0x25, 0x2a, 0x51, 0x1a, 0xbb, 0xb6, 0xee, 0x46, 0xb7, 0x70, 0xb3, - 0xd6, 0x22, 0xa7, 0x74, 0x13, 0x9f, 0x18, 0x7f, 0xd0, 0x35, 0x37, 0x37, 0xe9, 0xbd, 0xde, 0xa4, - 0x3f, 0xbd, 0x75, 0x74, 0x10, 0xfe, 0xf3, 0xdd, 0x84, 0x6b, 0x8b, 0x9e, 0x3c, 0xb9, 0xbc, 0x1e, - 0x3b, 0xbf, 0xae, 0xc7, 0xfb, 0x17, 0xa2, 0x2c, 0x8e, 0x83, 0xf5, 0xee, 0xc1, 0x6c, 0xd4, 0xce, - 0xdd, 0x38, 0x1d, 0x0f, 0xbe, 0x7c, 0x1d, 0x3b, 0x27, 0x67, 0x97, 0x4b, 0x9f, 0x5d, 0x2d, 0x7d, - 0xf6, 0x73, 0xe9, 0xb3, 0xcf, 0x2b, 0xdf, 0xb9, 0x5a, 0xf9, 0xce, 0x8f, 0x95, 0xef, 0xbc, 0x0d, - 0x33, 0x89, 0xf9, 0x62, 0x1e, 0x26, 0xba, 0x8c, 0x0c, 0xc8, 0x67, 0x4d, 0x32, 0x1a, 0x28, 0x5a, - 0xf4, 0x81, 0x5e, 0x7d, 0x84, 0x17, 0xe7, 0x60, 0xe6, 0x43, 0x12, 0x3c, 0xff, 0x1d, 0x00, 0x00, - 0xff, 0xff, 0x9f, 0x5b, 0x5a, 0x63, 0x17, 0x03, 0x00, 0x00, + // 601 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x41, 0x6b, 0x13, 0x41, + 0x14, 0xce, 0x26, 0x69, 0xda, 0x8e, 0x25, 0xd6, 0x35, 0xb1, 0x89, 0x92, 0xdd, 0xb0, 0x68, 0x09, + 0x42, 0x77, 0xdb, 0x78, 0x91, 0x5e, 0xc4, 0x10, 0xa1, 0x1e, 0x04, 0x89, 0xe2, 0xc1, 0x4b, 0x98, + 0xec, 0x3e, 0x92, 0xa5, 0xbb, 0x3b, 0x65, 0x67, 0x22, 0xf6, 0xec, 0x59, 0xf0, 0x22, 0x78, 0xf4, + 0x37, 0x08, 0x1e, 0xbd, 0xf7, 0x22, 0xf4, 0x28, 0x1e, 0x16, 0x49, 0xfe, 0x41, 0x7e, 0x81, 0xcc, + 0xdb, 0xac, 0xdd, 0xa4, 0xdb, 0x2a, 0xd8, 0xd3, 0xce, 0xbc, 0xf7, 0xcd, 0xf7, 0xde, 0x37, 0xef, + 0x9b, 0x25, 0x5b, 0xbe, 0x1b, 0x08, 0xeb, 0xcd, 0xde, 0x00, 0x04, 0xdd, 0xb3, 0xe4, 0xc6, 0x3c, + 0x0a, 0x99, 0x60, 0x6a, 0x9d, 0x83, 0x8b, 0x2b, 0x9b, 0x79, 0x26, 0x07, 0xd7, 0x1e, 0x51, 0x37, + 0x30, 0x25, 0xe0, 0x76, 0x65, 0xc8, 0x86, 0x0c, 0x73, 0x96, 0x5c, 0xc5, 0x07, 0x8c, 0x2f, 0x79, + 0x52, 0x7a, 0xe6, 0x06, 0x02, 0x42, 0xb5, 0x41, 0x08, 0x17, 0x34, 0x14, 0x7d, 0x87, 0x0a, 0xa8, + 0x29, 0x4d, 0xa5, 0xb5, 0xde, 0x5b, 0xc7, 0x48, 0x97, 0x0a, 0x50, 0xeb, 0x64, 0x0d, 0x02, 0x27, + 0x4e, 0xe6, 0x31, 0xb9, 0x0a, 0x81, 0x83, 0xa9, 0x0a, 0x59, 0x71, 0x20, 0x60, 0x7e, 0xad, 0x80, + 0xf1, 0x78, 0xa3, 0xde, 0x27, 0x37, 0x04, 0x13, 0xd4, 0xeb, 0xcb, 0xf2, 0x7d, 0xea, 0xb3, 0x71, + 0x20, 0x6a, 0xc5, 0xa6, 0xd2, 0x2a, 0xf6, 0xae, 0x63, 0x42, 0xd6, 0x7d, 0x8c, 0x61, 0xb5, 0x4d, + 0xaa, 0x21, 0xf8, 0xd4, 0x0d, 0xdc, 0x60, 0xb8, 0x80, 0x5f, 0x41, 0xfc, 0xcd, 0x3f, 0xc9, 0xd4, + 0x99, 0x16, 0xd9, 0xf4, 0x28, 0x17, 0x0b, 0xf0, 0x12, 0xc2, 0xcb, 0x32, 0x9e, 0x42, 0xde, 0x25, + 0xe5, 0x33, 0x24, 0x0a, 0x58, 0xc5, 0x46, 0x37, 0x12, 0x1c, 0xaa, 0x58, 0xe0, 0x1b, 0x81, 0x3b, + 0x1c, 0x89, 0xda, 0xda, 0x22, 0xdf, 0x01, 0x46, 0x8d, 0x77, 0x0a, 0xa9, 0xbe, 0xb0, 0x47, 0xe0, + 0x8c, 0x3d, 0x70, 0x5e, 0xb2, 0x43, 0x08, 0x7a, 0xe0, 0x01, 0xe5, 0xf0, 0x1f, 0x77, 0xb8, 0x4b, + 0x2a, 0x42, 0x32, 0xf5, 0xc3, 0x98, 0x2a, 0x51, 0x54, 0xc0, 0x0e, 0x54, 0x91, 0xaa, 0x12, 0xab, + 0x32, 0xbe, 0x29, 0xa4, 0xf4, 0x9c, 0x86, 0xd4, 0xe7, 0xb2, 0x6c, 0xac, 0x0d, 0xa7, 0x30, 0x2f, + 0x2b, 0x23, 0x5d, 0x9c, 0xc4, 0x7b, 0x85, 0xdc, 0x5a, 0x24, 0xe7, 0xf3, 0xee, 0x6b, 0xf9, 0x66, + 0xa1, 0x75, 0xad, 0xbd, 0x6b, 0x5e, 0xe8, 0x1b, 0x33, 0x53, 0x68, 0xe7, 0xde, 0x49, 0xa4, 0xe7, + 0x66, 0x91, 0xde, 0x38, 0xa6, 0xbe, 0xb7, 0x6f, 0x64, 0xb3, 0x1b, 0xbd, 0x4a, 0xba, 0xef, 0x84, + 0x69, 0xbf, 0xf8, 0xe9, 0xb3, 0x9e, 0x33, 0xbe, 0xe6, 0x49, 0xf9, 0x15, 0x84, 0xdc, 0x65, 0x41, + 0x7b, 0x6e, 0x41, 0x9e, 0x31, 0x52, 0x54, 0xd3, 0x79, 0x2a, 0xeb, 0xfd, 0x8c, 0xf4, 0xed, 0xa1, + 0x2b, 0x46, 0xe3, 0x81, 0x69, 0x33, 0xdf, 0xb2, 0x19, 0xf7, 0x19, 0x9f, 0x7f, 0x76, 0xb8, 0x73, + 0x68, 0x89, 0xe3, 0x23, 0xe0, 0x66, 0x17, 0xec, 0x59, 0xa4, 0x6f, 0xc5, 0x9d, 0x2d, 0xf3, 0x19, + 0xe7, 0xdc, 0xf1, 0xe8, 0x9c, 0x3b, 0x70, 0x34, 0x9d, 0xfa, 0x2c, 0xd2, 0xab, 0xcb, 0x24, 0x32, + 0x6f, 0x2c, 0x19, 0xe7, 0x49, 0x86, 0x71, 0xe4, 0xd8, 0x0a, 0x9d, 0x3b, 0x59, 0x7d, 0xc4, 0x08, + 0x63, 0xd9, 0x55, 0xea, 0x76, 0xf2, 0x8a, 0x8a, 0x58, 0x7e, 0x73, 0x16, 0xe9, 0x1b, 0xf1, 0x59, + 0x0c, 0x1b, 0xf3, 0x77, 0x65, 0x00, 0x69, 0x24, 0xd7, 0x96, 0x6d, 0x42, 0x95, 0x14, 0x53, 0xf6, + 0xc3, 0xf5, 0x85, 0xf6, 0x92, 0x52, 0x0b, 0x99, 0xf6, 0xfa, 0xae, 0x9c, 0x8d, 0xe7, 0xdf, 0x6c, + 0xf6, 0xf1, 0x6f, 0x36, 0x7b, 0x78, 0x89, 0xcd, 0x2e, 0x95, 0x74, 0x05, 0x76, 0xeb, 0x1c, 0x9c, + 0x4c, 0x34, 0xe5, 0x74, 0xa2, 0x29, 0xbf, 0x26, 0x9a, 0xf2, 0x61, 0xaa, 0xe5, 0x4e, 0xa7, 0x5a, + 0xee, 0xc7, 0x54, 0xcb, 0xbd, 0x36, 0x53, 0x9e, 0xe2, 0xe0, 0xee, 0x24, 0x1d, 0xe2, 0x06, 0x5b, + 0xb4, 0xde, 0xe2, 0x4f, 0x36, 0xf6, 0xd7, 0xa0, 0x84, 0x80, 0x07, 0xbf, 0x03, 0x00, 0x00, 0xff, + 0xff, 0xec, 0x81, 0x8e, 0x2d, 0x86, 0x05, 0x00, 0x00, } func (m *Minter) Marshal() (dAtA []byte, err error) { @@ -435,6 +617,137 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *Version2Minter) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Version2Minter) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Version2Minter) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintMint(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x22 + } + if m.LastMintHeight != 0 { + i = encodeVarintMint(dAtA, i, uint64(m.LastMintHeight)) + i-- + dAtA[i] = 0x18 + } + if len(m.LastMintDate) > 0 { + i -= len(m.LastMintDate) + copy(dAtA[i:], m.LastMintDate) + i = encodeVarintMint(dAtA, i, uint64(len(m.LastMintDate))) + i-- + dAtA[i] = 0x12 + } + { + size := m.LastMintAmount.Size() + i -= size + if _, err := m.LastMintAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintMint(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *Version2ScheduledTokenRelease) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Version2ScheduledTokenRelease) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Version2ScheduledTokenRelease) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.TokenReleaseAmount != 0 { + i = encodeVarintMint(dAtA, i, uint64(m.TokenReleaseAmount)) + i-- + dAtA[i] = 0x10 + } + if len(m.Date) > 0 { + i -= len(m.Date) + copy(dAtA[i:], m.Date) + i = encodeVarintMint(dAtA, i, uint64(len(m.Date))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Version2Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Version2Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Version2Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TokenReleaseSchedule) > 0 { + for iNdEx := len(m.TokenReleaseSchedule) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TokenReleaseSchedule[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintMint(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.MintDenom) > 0 { + i -= len(m.MintDenom) + copy(dAtA[i:], m.MintDenom) + i = encodeVarintMint(dAtA, i, uint64(len(m.MintDenom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintMint(dAtA []byte, offset int, v uint64) int { offset -= sovMint(v) base := offset @@ -519,16 +832,460 @@ func (m *Params) Size() (n int) { n += 1 + l + sovMint(uint64(l)) } } - return n -} + return n +} + +func (m *Version2Minter) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.LastMintAmount.Size() + n += 1 + l + sovMint(uint64(l)) + l = len(m.LastMintDate) + if l > 0 { + n += 1 + l + sovMint(uint64(l)) + } + if m.LastMintHeight != 0 { + n += 1 + sovMint(uint64(m.LastMintHeight)) + } + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovMint(uint64(l)) + } + return n +} + +func (m *Version2ScheduledTokenRelease) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Date) + if l > 0 { + n += 1 + l + sovMint(uint64(l)) + } + if m.TokenReleaseAmount != 0 { + n += 1 + sovMint(uint64(m.TokenReleaseAmount)) + } + return n +} + +func (m *Version2Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.MintDenom) + if l > 0 { + n += 1 + l + sovMint(uint64(l)) + } + if len(m.TokenReleaseSchedule) > 0 { + for _, e := range m.TokenReleaseSchedule { + l = e.Size() + n += 1 + l + sovMint(uint64(l)) + } + } + return n +} + +func sovMint(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozMint(x uint64) (n int) { + return sovMint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Minter) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Minter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Minter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StartDate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMint + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StartDate = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EndDate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMint + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EndDate = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMint + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalMintAmount", wireType) + } + m.TotalMintAmount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalMintAmount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RemainingMintAmount", wireType) + } + m.RemainingMintAmount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RemainingMintAmount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LastMintAmount", wireType) + } + m.LastMintAmount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LastMintAmount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastMintDate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMint + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LastMintDate = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LastMintHeight", wireType) + } + m.LastMintHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LastMintHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMint(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMint + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ScheduledTokenRelease) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ScheduledTokenRelease: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ScheduledTokenRelease: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StartDate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMint + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StartDate = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EndDate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMint + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMint + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EndDate = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenReleaseAmount", wireType) + } + m.TokenReleaseAmount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TokenReleaseAmount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipMint(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMint + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } -func sovMint(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozMint(x uint64) (n int) { - return sovMint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil } -func (m *Minter) Unmarshal(dAtA []byte) error { +func (m *Params) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -551,15 +1308,15 @@ func (m *Minter) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Minter: wiretype end group for non-group") + return fmt.Errorf("proto: Params: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Minter: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field StartDate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MintDenom", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -587,13 +1344,13 @@ func (m *Minter) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.StartDate = string(dAtA[iNdEx:postIndex]) + m.MintDenom = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field EndDate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field TokenReleaseSchedule", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowMint @@ -603,27 +1360,79 @@ func (m *Minter) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthMint } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthMint } if postIndex > l { return io.ErrUnexpectedEOF } - m.EndDate = string(dAtA[iNdEx:postIndex]) + m.TokenReleaseSchedule = append(m.TokenReleaseSchedule, ScheduledTokenRelease{}) + if err := m.TokenReleaseSchedule[len(m.TokenReleaseSchedule)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 3: + default: + iNdEx = preIndex + skippy, err := skipMint(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthMint + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Version2Minter) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowMint + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Version2Minter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Version2Minter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LastMintAmount", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -651,13 +1460,15 @@ func (m *Minter) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Denom = string(dAtA[iNdEx:postIndex]) + if err := m.LastMintAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TotalMintAmount", wireType) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastMintDate", wireType) } - m.TotalMintAmount = 0 + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowMint @@ -667,35 +1478,29 @@ func (m *Minter) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.TotalMintAmount |= uint64(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field RemainingMintAmount", wireType) + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthMint } - m.RemainingMintAmount = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMint - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.RemainingMintAmount |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthMint } - case 6: + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LastMintDate = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field LastMintAmount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LastMintHeight", wireType) } - m.LastMintAmount = 0 + m.LastMintHeight = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowMint @@ -705,14 +1510,14 @@ func (m *Minter) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.LastMintAmount |= uint64(b&0x7F) << shift + m.LastMintHeight |= int64(b&0x7F) << shift if b < 0x80 { break } } - case 7: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LastMintDate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -740,27 +1545,8 @@ func (m *Minter) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.LastMintDate = string(dAtA[iNdEx:postIndex]) + m.Denom = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 8: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field LastMintHeight", wireType) - } - m.LastMintHeight = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMint - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.LastMintHeight |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := skipMint(dAtA[iNdEx:]) @@ -782,7 +1568,7 @@ func (m *Minter) Unmarshal(dAtA []byte) error { } return nil } -func (m *ScheduledTokenRelease) Unmarshal(dAtA []byte) error { +func (m *Version2ScheduledTokenRelease) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -805,15 +1591,15 @@ func (m *ScheduledTokenRelease) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ScheduledTokenRelease: wiretype end group for non-group") + return fmt.Errorf("proto: Version2ScheduledTokenRelease: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ScheduledTokenRelease: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Version2ScheduledTokenRelease: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field StartDate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Date", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -841,41 +1627,9 @@ func (m *ScheduledTokenRelease) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.StartDate = string(dAtA[iNdEx:postIndex]) + m.Date = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field EndDate", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowMint - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthMint - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthMint - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.EndDate = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field TokenReleaseAmount", wireType) } @@ -889,7 +1643,7 @@ func (m *ScheduledTokenRelease) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.TokenReleaseAmount |= uint64(b&0x7F) << shift + m.TokenReleaseAmount |= int64(b&0x7F) << shift if b < 0x80 { break } @@ -915,7 +1669,7 @@ func (m *ScheduledTokenRelease) Unmarshal(dAtA []byte) error { } return nil } -func (m *Params) Unmarshal(dAtA []byte) error { +func (m *Version2Params) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -938,10 +1692,10 @@ func (m *Params) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Params: wiretype end group for non-group") + return fmt.Errorf("proto: Version2Params: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Version2Params: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1005,7 +1759,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.TokenReleaseSchedule = append(m.TokenReleaseSchedule, ScheduledTokenRelease{}) + m.TokenReleaseSchedule = append(m.TokenReleaseSchedule, Version2ScheduledTokenRelease{}) if err := m.TokenReleaseSchedule[len(m.TokenReleaseSchedule)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/x/mint/types/params.go b/x/mint/types/params.go index 58763dc544..0a269686a9 100644 --- a/x/mint/types/params.go +++ b/x/mint/types/params.go @@ -58,6 +58,11 @@ func (p Params) String() string { return string(out) } +func (p Version2Params) String() string { + out, _ := yaml.Marshal(p) + return string(out) +} + // Implements params.ParamSet func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { return paramtypes.ParamSetPairs{ @@ -66,6 +71,14 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { } } +// Used for v2 -> v3 migration +func (p *Version2Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyMintDenom, &p.MintDenom, func(i interface{}) error { return nil }), + paramtypes.NewParamSetPair(KeyTokenReleaseSchedule, &p.TokenReleaseSchedule, func(i interface{}) error { return nil }), + } +} + func validateMintDenom(i interface{}) error { denomString, ok := i.(string) denomTrimed := strings.TrimSpace(denomString) From 3f454037832e84c8b0f2a84b3418b3bb3c0194c4 Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:32:16 -0400 Subject: [PATCH 06/16] lint --- x/mint/keeper/migrations.go | 8 ++++---- x/oracle/simulation/operations.go | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/x/mint/keeper/migrations.go b/x/mint/keeper/migrations.go index fd3048f23a..849c022553 100644 --- a/x/mint/keeper/migrations.go +++ b/x/mint/keeper/migrations.go @@ -72,14 +72,14 @@ func (m Migrator) Migrate2to3(ctx sdk.Context) error { newTokenReleaseSchedule := []types.ScheduledTokenRelease{} for _, oldTokenReleaseSchedule := range oldTokenReleaseSchedules { newSchedule := types.ScheduledTokenRelease{ - TokenReleaseAmount: uint64(oldTokenReleaseSchedule.GetTokenReleaseAmount()), - StartDate: oldTokenReleaseSchedule.GetDate(), - EndDate: oldTokenReleaseSchedule.GetDate(), + TokenReleaseAmount: uint64(oldTokenReleaseSchedule.GetTokenReleaseAmount()), + StartDate: oldTokenReleaseSchedule.GetDate(), + EndDate: oldTokenReleaseSchedule.GetDate(), } newTokenReleaseSchedule = append(newTokenReleaseSchedule, newSchedule) } newParams := types.Params{ - MintDenom: oldMintDenom, + MintDenom: oldMintDenom, TokenReleaseSchedule: newTokenReleaseSchedule, } m.keeper.SetParams(ctx, newParams) diff --git a/x/oracle/simulation/operations.go b/x/oracle/simulation/operations.go index 3988c4b164..2028e73625 100644 --- a/x/oracle/simulation/operations.go +++ b/x/oracle/simulation/operations.go @@ -65,7 +65,7 @@ func WeightedOperations( } // SimulateMsgAggregateExchangeRateVote generates a MsgAggregateExchangeRateVote with random values. -//nolint: funlen +// nolint: funlen func SimulateMsgAggregateExchangeRateVote(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, @@ -122,7 +122,7 @@ func SimulateMsgAggregateExchangeRateVote(ak types.AccountKeeper, bk types.BankK } // SimulateMsgDelegateFeedConsent generates a MsgDelegateFeedConsent with random values. -//nolint: funlen +// nolint: funlen func SimulateMsgDelegateFeedConsent(ak types.AccountKeeper, bk types.BankKeeper, k keeper.Keeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, From 72a7452365a67a0a3a7a0f091ae237f36c727b84 Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Wed, 26 Apr 2023 15:11:17 -0400 Subject: [PATCH 07/16] remove prints --- x/mint/keeper/migrations.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/x/mint/keeper/migrations.go b/x/mint/keeper/migrations.go index 849c022553..83f0407600 100644 --- a/x/mint/keeper/migrations.go +++ b/x/mint/keeper/migrations.go @@ -18,14 +18,12 @@ func NewMigrator(keeper Keeper) Migrator { return Migrator{keeper: keeper} } -// Migrate1to2 migrates from version 1 to 2 func (m Migrator) Migrate1to2(ctx sdk.Context) error { defaultParams := types.DefaultParams() m.keeper.paramSpace.SetParamSet(ctx, &defaultParams) return nil } -// Migrate1to2 migrates from version 1 to 2 func (m Migrator) Migrate2to3(ctx sdk.Context) error { ctx.Logger().Info("Migrating mint module from v2 to v3") store := ctx.KVStore(m.keeper.storeKey) @@ -67,7 +65,6 @@ func (m Migrator) Migrate2to3(ctx sdk.Context) error { panic(fmt.Sprintf("Key not found or error: %s", err)) } ctx.Logger().Info("Migrating mint module from v2 to v3", "oldTokenReleaseSchedules", oldTokenReleaseSchedules, "oldMintDenom", oldMintDenom) - fmt.Println("Migrating mint module from v2 to v3", "oldTokenReleaseSchedules", oldTokenReleaseSchedules, "oldMintDenom", oldMintDenom) newTokenReleaseSchedule := []types.ScheduledTokenRelease{} for _, oldTokenReleaseSchedule := range oldTokenReleaseSchedules { From be26e2e3a2193371a0fe8174e329589c5beac4bf Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Wed, 26 Apr 2023 15:16:55 -0400 Subject: [PATCH 08/16] bweng-test handler --- app/upgrades.go | 1 + 1 file changed, 1 insertion(+) diff --git a/app/upgrades.go b/app/upgrades.go index 2c349961da..051f9888fb 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -62,6 +62,7 @@ var upgradesList = []string{ "2.0.44beta", "2.0.45beta", "2.0.46beta", + "2.0.46beta-bweng-test", } func (app App) RegisterUpgradeHandlers() { From 7449d33864b77fec56e1ebd182b89b920cfb63a3 Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Wed, 26 Apr 2023 18:06:03 -0400 Subject: [PATCH 09/16] refactor release amoujnt --- x/mint/keeper/hooks.go | 11 ++++++----- x/mint/keeper/migrations.go | 5 ++--- x/mint/types/minter.go | 27 +++++++++++++-------------- x/mint/types/minter_test.go | 26 ++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/x/mint/keeper/hooks.go b/x/mint/keeper/hooks.go index 716519a679..b1577db2ed 100644 --- a/x/mint/keeper/hooks.go +++ b/x/mint/keeper/hooks.go @@ -10,9 +10,9 @@ func (k Keeper) BeforeEpochStart(ctx sdk.Context, epoch epochTypes.Epoch) { func (k Keeper) AfterEpochEnd(ctx sdk.Context, epoch epochTypes.Epoch) { latestMinter := k.GetOrUpdateLatestMinter(ctx, epoch) - coinsToMint := latestMinter.GetReleaseAmountToday(epoch.CurrentEpochStartTime) + coinsToMint := latestMinter.GetReleaseAmountToday(epoch.CurrentEpochStartTime.UTC()) - if coinsToMint.IsZero() { + if coinsToMint.IsZero() || latestMinter.GetRemainingMintAmount() == 0 { k.Logger(ctx).Debug("No coins to mint", "minter", latestMinter) return } @@ -28,9 +28,10 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epoch epochTypes.Epoch) { // Released Succssfully, decrement the remaining amount by the daily release amount and update minter amountMinted := coinsToMint.AmountOf(latestMinter.GetDenom()) - updatedMinter := latestMinter.RecordSuccessfulMint(ctx, epoch, amountMinted.Uint64()) - k.Logger(ctx).Info("Minted coins", "minter", updatedMinter, "amount", amountMinted) - k.SetMinter(ctx, updatedMinter) + amountMinted.IsZero() + latestMinter.RecordSuccessfulMint(ctx, epoch, amountMinted.Uint64()) + k.Logger(ctx).Info("Minted coins", "minter", latestMinter, "amount", coinsToMint.String()) + k.SetMinter(ctx, latestMinter) } type Hooks struct { diff --git a/x/mint/keeper/migrations.go b/x/mint/keeper/migrations.go index 83f0407600..307dfef0a5 100644 --- a/x/mint/keeper/migrations.go +++ b/x/mint/keeper/migrations.go @@ -25,7 +25,6 @@ func (m Migrator) Migrate1to2(ctx sdk.Context) error { } func (m Migrator) Migrate2to3(ctx sdk.Context) error { - ctx.Logger().Info("Migrating mint module from v2 to v3") store := ctx.KVStore(m.keeper.storeKey) // Migrate Minter First minterBytes := store.Get(types.MinterKey) @@ -46,7 +45,7 @@ func (m Migrator) Migrate2to3(ctx sdk.Context) error { LastMintHeight: uint64(oldMinter.GetLastMintHeight()), LastMintAmount: oldMinter.LastMintAmount.RoundInt().Uint64(), } - ctx.Logger().Info("Migrating mint module from v2 to v3", "oldMinter", oldMinter.String(), "newMinter", newMinter.String()) + ctx.Logger().Info("Migrating minter from v2 to v3", "oldMinter", oldMinter.String(), "newMinter", newMinter.String()) m.keeper.SetMinter(ctx, newMinter) // Migrate TokenReleaseSchedule @@ -64,7 +63,7 @@ func (m Migrator) Migrate2to3(ctx sdk.Context) error { if err != nil { panic(fmt.Sprintf("Key not found or error: %s", err)) } - ctx.Logger().Info("Migrating mint module from v2 to v3", "oldTokenReleaseSchedules", oldTokenReleaseSchedules, "oldMintDenom", oldMintDenom) + ctx.Logger().Info("Migrating mint params from v2 to v3", "oldTokenReleaseSchedules", oldTokenReleaseSchedules, "oldMintDenom", oldMintDenom) newTokenReleaseSchedule := []types.ScheduledTokenRelease{} for _, oldTokenReleaseSchedule := range oldTokenReleaseSchedules { diff --git a/x/mint/types/minter.go b/x/mint/types/minter.go index e5bdc3cae9..d05cf1a5da 100644 --- a/x/mint/types/minter.go +++ b/x/mint/types/minter.go @@ -58,7 +58,7 @@ func ValidateMinter(minter Minter) error { return nil } -func (m Minter) GetLastMintDateTime() time.Time { +func (m *Minter) GetLastMintDateTime() time.Time { lastMinteDateTime, err := time.Parse(TokenReleaseDateFormat, m.GetLastMintDate()) if err != nil { // This should not happen as the date is validated when the minter is created @@ -67,7 +67,7 @@ func (m Minter) GetLastMintDateTime() time.Time { return lastMinteDateTime.UTC() } -func (m Minter) GetStartDateTime() time.Time { +func (m *Minter) GetStartDateTime() time.Time { startDateTime, err := time.Parse(TokenReleaseDateFormat, m.GetStartDate()) if err != nil { // This should not happen as the date is validated when the minter is created @@ -76,7 +76,7 @@ func (m Minter) GetStartDateTime() time.Time { return startDateTime.UTC() } -func (m Minter) GetEndDateTime() time.Time { +func (m *Minter) GetEndDateTime() time.Time { endDateTime, err := time.Parse(TokenReleaseDateFormat, m.GetEndDate()) if err != nil { // This should not happen as the date is validated when the minter is created @@ -85,15 +85,15 @@ func (m Minter) GetEndDateTime() time.Time { return endDateTime.UTC() } -func (m Minter) GetLastMintAmountCoin() sdk.Coin { +func (m *Minter) GetLastMintAmountCoin() sdk.Coin { return sdk.NewCoin(m.GetDenom(), sdk.NewInt(int64(m.GetLastMintAmount()))) } -func (m Minter) GetReleaseAmountToday(currentTime time.Time) sdk.Coins { - return sdk.NewCoins(sdk.NewCoin(m.GetDenom(), sdk.NewInt(int64(m.getReleaseAmountToday(currentTime))))) +func (m *Minter) GetReleaseAmountToday(currentTime time.Time) sdk.Coins { + return sdk.NewCoins(sdk.NewCoin(m.GetDenom(), sdk.NewInt(int64(m.getReleaseAmountToday(currentTime.UTC()))))) } -func (m Minter) RecordSuccessfulMint(ctx sdk.Context, epoch epochTypes.Epoch, mintedAmount uint64) Minter { +func (m *Minter) RecordSuccessfulMint(ctx sdk.Context, epoch epochTypes.Epoch, mintedAmount uint64) { m.RemainingMintAmount -= mintedAmount m.LastMintDate = epoch.CurrentEpochStartTime.Format(TokenReleaseDateFormat) m.LastMintHeight = uint64(epoch.CurrentEpochHeight) @@ -107,18 +107,17 @@ func (m Minter) RecordSuccessfulMint(ctx sdk.Context, epoch epochTypes.Epoch, mi sdk.NewAttribute(sdk.AttributeKeyAmount, fmt.Sprintf("%d", mintedAmount)), ), ) - return m } -func (m Minter) getReleaseAmountToday(currentTime time.Time) uint64 { +func (m *Minter) getReleaseAmountToday(currentTime time.Time) uint64 { // Not yet started or already minted today if currentTime.Before(m.GetStartDateTime()) || currentTime.Format(TokenReleaseDateFormat) == m.GetLastMintDate() { + println("not yet started or already minted today") return 0 } - // if it's already past the end date then release the remaining amount - // likely caused by outage - if currentTime.After(m.GetEndDateTime()) && m.GetRemainingMintAmount() > 0 { + // if it's already past the end date then release the remaining amount likely caused by outage + if currentTime.After(m.GetEndDateTime()) { return m.GetRemainingMintAmount() } @@ -129,13 +128,13 @@ func (m Minter) getReleaseAmountToday(currentTime time.Time) uint64 { return m.GetRemainingMintAmount() / numberOfDaysLeft } -func (m Minter) getNumberOfDaysLeft(currentTime time.Time) uint64 { +func (m *Minter) getNumberOfDaysLeft(currentTime time.Time) uint64 { // If the last mint date is after the start date then use the last mint date as there's an ongoing release daysBetween := daysBetween(currentTime, m.GetEndDateTime()) return daysBetween } -func (m Minter) OngoingRelease() bool { +func (m *Minter) OngoingRelease() bool { return m.GetRemainingMintAmount() != 0 } diff --git a/x/mint/types/minter_test.go b/x/mint/types/minter_test.go index 2691d435bc..bc9dcb56db 100644 --- a/x/mint/types/minter_test.go +++ b/x/mint/types/minter_test.go @@ -190,6 +190,32 @@ func TestGetReleaseAmountToday(t *testing.T) { currentTime: time.Date(2023, 4, 1, 0, 0, 0, 0, time.UTC), expectedAmount: 11, }, + { + name: "One day mint", + minter: NewMinter( + "2023-04-01", + "2023-04-01", + "test", + 100, + ), + currentTime: time.Date(2023, 4, 1, 0, 0, 0, 0, time.UTC), + expectedAmount: 100, + }, + { + name: "One day mint - alreaddy minted", + minter: Minter{ + StartDate: "2023-04-01", + EndDate: "2023-04-01", + Denom: "test", + TotalMintAmount: 100, + RemainingMintAmount: 0, + LastMintAmount: 100, + LastMintDate: "2023-04-01", + LastMintHeight: 0, + }, + currentTime: time.Date(2023, 4, 1, 0, 1, 0, 0, time.UTC), + expectedAmount: 0, + }, { name: "No minter", minter: InitialMinter(), From 69f574b5083280eef8aa12108b59796c8f322a0f Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Wed, 26 Apr 2023 18:36:01 -0400 Subject: [PATCH 10/16] fix same day buy --- x/mint/keeper/keeper.go | 5 +++-- x/mint/keeper/keeper_test.go | 34 ++++++++++++++++++++++++++++++++++ x/mint/types/minter.go | 2 +- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index 90c9d5bf4c..389f6d539a 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -134,9 +134,10 @@ func (k Keeper) GetOrUpdateLatestMinter( currentReleaseMinter := k.GetMinter(ctx) nextScheduledRelease := GetNextScheduledTokenRelease(epoch, params.TokenReleaseSchedule, currentReleaseMinter) - // There's still an ongoing release or there's no release scheduled - if currentReleaseMinter.OngoingRelease() || nextScheduledRelease == nil { + // There's still an ongoing release (> 0 remaining amount or same start date) or there's no release scheduled + if currentReleaseMinter.OngoingRelease() || nextScheduledRelease.GetStartDate() == currentReleaseMinter.GetStartDate() || nextScheduledRelease == nil { k.Logger(ctx).Debug("Ongoing token release or no nextScheduledRelease", "minter", currentReleaseMinter) + println("RETURN!") return currentReleaseMinter } diff --git a/x/mint/keeper/keeper_test.go b/x/mint/keeper/keeper_test.go index b40c9105a1..fd5ea4f791 100644 --- a/x/mint/keeper/keeper_test.go +++ b/x/mint/keeper/keeper_test.go @@ -111,6 +111,40 @@ func TestGetOrUpdateLatestMinter(t *testing.T) { mintKeeper.SetMinter(ctx, mintTypes.DefaultInitialMinter()) }) + t.Run("Ongoing release same day", func(t *testing.T) { + params := mintKeeper.GetParams(ctx) + params.TokenReleaseSchedule = []types.ScheduledTokenRelease{ + { + StartDate: currentTime.AddDate(0,0,0).Format(minttypes.TokenReleaseDateFormat), + EndDate: currentTime.AddDate(0,0,0).Format(minttypes.TokenReleaseDateFormat), + TokenReleaseAmount: 1000, + }, + } + mintKeeper.SetParams(ctx, params) + + minter := types.Minter{ + StartDate: currentTime.Format(minttypes.TokenReleaseDateFormat), + EndDate: currentTime.Format(minttypes.TokenReleaseDateFormat), + Denom: "usei", + TotalMintAmount: 100, + RemainingMintAmount: 0, + LastMintAmount: 100, + LastMintDate: "2023-04-01", + LastMintHeight: 0, + } + mintKeeper.SetMinter(ctx, minter) + + epoch.CurrentEpochStartTime = currentTime + currentMinter := mintKeeper.GetOrUpdateLatestMinter(ctx, epoch) + amount := currentMinter.GetReleaseAmountToday(currentTime).IsZero() + require.Zero(t, currentMinter.GetRemainingMintAmount()) + require.True(t, amount) + require.False(t, currentMinter.OngoingRelease()) + require.Equal(t, currentTime.Format(minttypes.TokenReleaseDateFormat), currentMinter.StartDate) + mintKeeper.SetMinter(ctx, mintTypes.DefaultInitialMinter()) + }) + + t.Run("TokenReleaseSchedule not sorted", func(t *testing.T) { params := mintKeeper.GetParams(ctx) params.TokenReleaseSchedule = []types.ScheduledTokenRelease{ diff --git a/x/mint/types/minter.go b/x/mint/types/minter.go index d05cf1a5da..f06848a8ba 100644 --- a/x/mint/types/minter.go +++ b/x/mint/types/minter.go @@ -85,7 +85,7 @@ func (m *Minter) GetEndDateTime() time.Time { return endDateTime.UTC() } -func (m *Minter) GetLastMintAmountCoin() sdk.Coin { +func (m Minter) GetLastMintAmountCoin() sdk.Coin { return sdk.NewCoin(m.GetDenom(), sdk.NewInt(int64(m.GetLastMintAmount()))) } From aea87b09cd1a819bad0f283b88e8c31fedee7f5c Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Wed, 26 Apr 2023 18:37:49 -0400 Subject: [PATCH 11/16] Remove --- x/mint/keeper/keeper.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/mint/keeper/keeper.go b/x/mint/keeper/keeper.go index 389f6d539a..1a403bd562 100644 --- a/x/mint/keeper/keeper.go +++ b/x/mint/keeper/keeper.go @@ -137,7 +137,6 @@ func (k Keeper) GetOrUpdateLatestMinter( // There's still an ongoing release (> 0 remaining amount or same start date) or there's no release scheduled if currentReleaseMinter.OngoingRelease() || nextScheduledRelease.GetStartDate() == currentReleaseMinter.GetStartDate() || nextScheduledRelease == nil { k.Logger(ctx).Debug("Ongoing token release or no nextScheduledRelease", "minter", currentReleaseMinter) - println("RETURN!") return currentReleaseMinter } From e91f12e6a6d2dd23173e533e38478a04b4aa38db Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Wed, 26 Apr 2023 18:38:11 -0400 Subject: [PATCH 12/16] Remove --- x/mint/types/minter.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/mint/types/minter.go b/x/mint/types/minter.go index f06848a8ba..4d1df92206 100644 --- a/x/mint/types/minter.go +++ b/x/mint/types/minter.go @@ -112,7 +112,6 @@ func (m *Minter) RecordSuccessfulMint(ctx sdk.Context, epoch epochTypes.Epoch, m func (m *Minter) getReleaseAmountToday(currentTime time.Time) uint64 { // Not yet started or already minted today if currentTime.Before(m.GetStartDateTime()) || currentTime.Format(TokenReleaseDateFormat) == m.GetLastMintDate() { - println("not yet started or already minted today") return 0 } From 62458f5b38c5655eae26b71816578c6197e907e5 Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Wed, 26 Apr 2023 18:49:32 -0400 Subject: [PATCH 13/16] clean up --- x/mint/keeper/hooks.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/mint/keeper/hooks.go b/x/mint/keeper/hooks.go index b1577db2ed..0fcc83eae4 100644 --- a/x/mint/keeper/hooks.go +++ b/x/mint/keeper/hooks.go @@ -28,7 +28,6 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epoch epochTypes.Epoch) { // Released Succssfully, decrement the remaining amount by the daily release amount and update minter amountMinted := coinsToMint.AmountOf(latestMinter.GetDenom()) - amountMinted.IsZero() latestMinter.RecordSuccessfulMint(ctx, epoch, amountMinted.Uint64()) k.Logger(ctx).Info("Minted coins", "minter", latestMinter, "amount", coinsToMint.String()) k.SetMinter(ctx, latestMinter) From e61b6d86744c180fbd66f5fd6f0f5a1b84efc073 Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Wed, 26 Apr 2023 19:03:33 -0400 Subject: [PATCH 14/16] Fix --- x/mint/types/minter.go | 7 ++----- x/mint/types/minter_test.go | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/x/mint/types/minter.go b/x/mint/types/minter.go index 4d1df92206..e6b64766c9 100644 --- a/x/mint/types/minter.go +++ b/x/mint/types/minter.go @@ -116,14 +116,11 @@ func (m *Minter) getReleaseAmountToday(currentTime time.Time) uint64 { } // if it's already past the end date then release the remaining amount likely caused by outage - if currentTime.After(m.GetEndDateTime()) { + numberOfDaysLeft := m.getNumberOfDaysLeft(currentTime) + if currentTime.After(m.GetEndDateTime()) || numberOfDaysLeft == 0 { return m.GetRemainingMintAmount() } - numberOfDaysLeft := m.getNumberOfDaysLeft(currentTime) - if numberOfDaysLeft == 0 { - return 0 - } return m.GetRemainingMintAmount() / numberOfDaysLeft } diff --git a/x/mint/types/minter_test.go b/x/mint/types/minter_test.go index bc9dcb56db..727c667de5 100644 --- a/x/mint/types/minter_test.go +++ b/x/mint/types/minter_test.go @@ -226,7 +226,7 @@ func TestGetReleaseAmountToday(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - releaseAmount := tc.minter.getReleaseAmountToday(tc.currentTime) + releaseAmount := tc.minter.getReleaseAmountToday(tc.currentTime.UTC()) if releaseAmount != tc.expectedAmount { t.Errorf("Expected release amount to be %d, but got %d", tc.expectedAmount, releaseAmount) } From f0f80ee43dd6aecdad814bc373b991532a3c1f32 Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Wed, 26 Apr 2023 19:24:56 -0400 Subject: [PATCH 15/16] rename migrations --- x/mint/keeper/migrations.go | 62 ++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/x/mint/keeper/migrations.go b/x/mint/keeper/migrations.go index 307dfef0a5..1b067f5c86 100644 --- a/x/mint/keeper/migrations.go +++ b/x/mint/keeper/migrations.go @@ -13,7 +13,7 @@ type Migrator struct { keeper Keeper } -// NewMigrator returns a new Migrator. +// NewMigrator returns a v3 Migrator. func NewMigrator(keeper Keeper) Migrator { return Migrator{keeper: keeper} } @@ -32,54 +32,54 @@ func (m Migrator) Migrate2to3(ctx sdk.Context) error { panic("stored minter should not have been nil") } - var oldMinter types.Version2Minter - m.keeper.cdc.MustUnmarshal(minterBytes, &oldMinter) + var v2Minter types.Version2Minter + m.keeper.cdc.MustUnmarshal(minterBytes, &v2Minter) - newMinter := types.Minter{ - StartDate: oldMinter.GetLastMintDate(), - EndDate: oldMinter.GetLastMintDate(), + v3Minter := types.Minter{ + StartDate: v2Minter.GetLastMintDate(), + EndDate: v2Minter.GetLastMintDate(), Denom: sdk.DefaultBondDenom, - TotalMintAmount: oldMinter.LastMintAmount.RoundInt().Uint64(), + TotalMintAmount: v2Minter.LastMintAmount.RoundInt().Uint64(), RemainingMintAmount: 0, - LastMintDate: oldMinter.GetLastMintDate(), - LastMintHeight: uint64(oldMinter.GetLastMintHeight()), - LastMintAmount: oldMinter.LastMintAmount.RoundInt().Uint64(), + LastMintDate: v2Minter.GetLastMintDate(), + LastMintHeight: uint64(v2Minter.GetLastMintHeight()), + LastMintAmount: v2Minter.LastMintAmount.RoundInt().Uint64(), } - ctx.Logger().Info("Migrating minter from v2 to v3", "oldMinter", oldMinter.String(), "newMinter", newMinter.String()) - m.keeper.SetMinter(ctx, newMinter) + ctx.Logger().Info("Migrating minter from v2 to v3", "v2Minter", v2Minter.String(), "v3Minter", v3Minter.String()) + m.keeper.SetMinter(ctx, v3Minter) // Migrate TokenReleaseSchedule - var oldTokenReleaseSchedules []types.Version2ScheduledTokenRelease - oldTokenReleaseSchedulesBytes := m.keeper.GetParamSpace().GetRaw(ctx, types.KeyTokenReleaseSchedule) - err := codec.NewLegacyAmino().UnmarshalJSON(oldTokenReleaseSchedulesBytes, &oldTokenReleaseSchedules) + var v2TokenReleaseSchedules []types.Version2ScheduledTokenRelease + v2TokenReleaseSchedulesBytes := m.keeper.GetParamSpace().GetRaw(ctx, types.KeyTokenReleaseSchedule) + err := codec.NewLegacyAmino().UnmarshalJSON(v2TokenReleaseSchedulesBytes, &v2TokenReleaseSchedules) if err != nil { panic(fmt.Sprintf("Key not found or error: %s", err)) } - var oldMintDenom string - oldMintDenomBytes := m.keeper.GetParamSpace().GetRaw(ctx, types.KeyMintDenom) - err = codec.NewLegacyAmino().UnmarshalJSON(oldMintDenomBytes, &oldMintDenom) + var v2MintDenom string + v2MintDenomBytes := m.keeper.GetParamSpace().GetRaw(ctx, types.KeyMintDenom) + err = codec.NewLegacyAmino().UnmarshalJSON(v2MintDenomBytes, &v2MintDenom) if err != nil { panic(fmt.Sprintf("Key not found or error: %s", err)) } - ctx.Logger().Info("Migrating mint params from v2 to v3", "oldTokenReleaseSchedules", oldTokenReleaseSchedules, "oldMintDenom", oldMintDenom) + ctx.Logger().Info("Migrating mint params from v2 to v3", "v2TokenReleaseSchedules", v2TokenReleaseSchedules, "v2MintDenom", v2MintDenom) - newTokenReleaseSchedule := []types.ScheduledTokenRelease{} - for _, oldTokenReleaseSchedule := range oldTokenReleaseSchedules { - newSchedule := types.ScheduledTokenRelease{ - TokenReleaseAmount: uint64(oldTokenReleaseSchedule.GetTokenReleaseAmount()), - StartDate: oldTokenReleaseSchedule.GetDate(), - EndDate: oldTokenReleaseSchedule.GetDate(), + v3TokenReleaseSchedule := []types.ScheduledTokenRelease{} + for _, v2TokenReleaseSchedule := range v2TokenReleaseSchedules { + v3Schedule := types.ScheduledTokenRelease{ + TokenReleaseAmount: uint64(v2TokenReleaseSchedule.GetTokenReleaseAmount()), + StartDate: v2TokenReleaseSchedule.GetDate(), + EndDate: v2TokenReleaseSchedule.GetDate(), } - newTokenReleaseSchedule = append(newTokenReleaseSchedule, newSchedule) + v3TokenReleaseSchedule = append(v3TokenReleaseSchedule, v3Schedule) } - newParams := types.Params{ - MintDenom: oldMintDenom, - TokenReleaseSchedule: newTokenReleaseSchedule, + v3Params := types.Params{ + MintDenom: v2MintDenom, + TokenReleaseSchedule: v3TokenReleaseSchedule, } - m.keeper.SetParams(ctx, newParams) - ctx.Logger().Info("Migrating mint module from v2 to v3", "newParams", newParams.String()) + m.keeper.SetParams(ctx, v3Params) + ctx.Logger().Info("Migrating mint module from v2 to v3", "v3Params", v3Params.String()) return nil } From 6f1cf0bb6c163dc69529f0cfe100ec9010b651b4 Mon Sep 17 00:00:00 2001 From: Brandon Weng <18161326+BrandonWeng@users.noreply.github.com> Date: Wed, 26 Apr 2023 19:31:09 -0400 Subject: [PATCH 16/16] Update upgrades.go --- app/upgrades.go | 1 - 1 file changed, 1 deletion(-) diff --git a/app/upgrades.go b/app/upgrades.go index 051f9888fb..2c349961da 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -62,7 +62,6 @@ var upgradesList = []string{ "2.0.44beta", "2.0.45beta", "2.0.46beta", - "2.0.46beta-bweng-test", } func (app App) RegisterUpgradeHandlers() {