From f837fbcc655d720887f938ec478029ca2cf5ec34 Mon Sep 17 00:00:00 2001 From: Zaki Manian Date: Thu, 14 Dec 2023 21:22:51 +0000 Subject: [PATCH] Intitial commit of Block Interval Auctions (#242) * Intitial commit of Block Interval Auctions * Incremental unit test fixes * Incremental progress on unit tests for BeginBlock * Initial test for auction * Fix nit. Move modulus calc to own line * Only added traits to types that need them (#241) * Add another test * Add additional tests for Begin Block * Fix the panic in the tests * Fix interval auction (#244) * Update expected counter values (#245) --------- Co-authored-by: Collin Co-authored-by: Eric Bolten --- integration_tests/setup_test.go | 1 + proto/cellarfees/v1/params.proto | 3 + x/cellarfees/keeper/abci.go | 21 +++ x/cellarfees/keeper/abci_test.go | 195 ++++++++++++++++++++++++++++ x/cellarfees/keeper/genesis_test.go | 2 + x/cellarfees/keeper/hooks.go | 8 -- x/cellarfees/keeper/hooks_test.go | 114 ---------------- x/cellarfees/types/errors.go | 1 + x/cellarfees/types/params.go | 18 +++ x/cellarfees/types/params.pb.go | 83 ++++++++---- 10 files changed, 301 insertions(+), 145 deletions(-) diff --git a/integration_tests/setup_test.go b/integration_tests/setup_test.go index df55e24a..49469396 100644 --- a/integration_tests/setup_test.go +++ b/integration_tests/setup_test.go @@ -420,6 +420,7 @@ func (s *IntegrationTestSuite) initGenesis() { RewardEmissionPeriod: 100, InitialPriceDecreaseRate: sdk.MustNewDecFromStr("0.05"), PriceDecreaseBlockInterval: uint64(1000), + AuctionInterval: 50, } bz, err = cdc.MarshalJSON(&cellarfeesGenState) s.Require().NoError(err) diff --git a/proto/cellarfees/v1/params.proto b/proto/cellarfees/v1/params.proto index 4de08ba4..ab5cc7dc 100644 --- a/proto/cellarfees/v1/params.proto +++ b/proto/cellarfees/v1/params.proto @@ -19,6 +19,9 @@ message Params { [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false]; // Number of blocks between auction price decreases uint64 price_decrease_block_interval = 4; + // The interval between starting auctions + uint64 auction_interval = 5; + } diff --git a/x/cellarfees/keeper/abci.go b/x/cellarfees/keeper/abci.go index f81b607d..1ae5e266 100644 --- a/x/cellarfees/keeper/abci.go +++ b/x/cellarfees/keeper/abci.go @@ -10,6 +10,26 @@ import ( // account. Emissions are a constant value based on the last peak supply of distributable fees so that the reward supply // will decrease linearly until exhausted. func (k Keeper) BeginBlocker(ctx sdk.Context) { + + // Handle fee auctions + cellarfeesParams := k.GetParams(ctx) + + counters := k.GetFeeAccrualCounters(ctx) + + modulus := ctx.BlockHeader().Height % int64(cellarfeesParams.AuctionInterval) + + for _, counter := range counters.Counters { + + if counter.Count >= cellarfeesParams.FeeAccrualAuctionThreshold && modulus == 0 { + started := k.beginAuction(ctx, counter.Denom) + if started { + counters.ResetCounter(counter.Denom) + } + } + + } + k.SetFeeAccrualCounters(ctx, counters) + // Handle reward emissions moduleAccount := k.GetFeesAccount(ctx) remainingRewardsSupply := k.bankKeeper.GetBalance(ctx, moduleAccount.GetAddress(), params.BaseCoinUnit).Amount @@ -25,6 +45,7 @@ func (k Keeper) BeginBlocker(ctx sdk.Context) { if err != nil { panic(err) } + } // EndBlocker is called at the end of every block diff --git a/x/cellarfees/keeper/abci_test.go b/x/cellarfees/keeper/abci_test.go index e1954ff5..f6612a75 100644 --- a/x/cellarfees/keeper/abci_test.go +++ b/x/cellarfees/keeper/abci_test.go @@ -2,13 +2,18 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" "github.com/golang/mock/gomock" + gravitytypes "github.com/peggyjv/gravity-bridge/module/v4/x/gravity/types" appParams "github.com/peggyjv/sommelier/v7/app/params" + auctionTypes "github.com/peggyjv/sommelier/v7/x/auction/types" cellarfeesTypes "github.com/peggyjv/sommelier/v7/x/cellarfees/types" ) func (suite *KeeperTestSuite) TestBeginBlockerZeroRewardsBalance() { ctx, cellarfeesKeeper := suite.ctx, suite.cellarfeesKeeper + cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.DefaultFeeAccrualCounters()) + require := suite.Require() params := cellarfeesTypes.DefaultParams() @@ -26,6 +31,8 @@ func (suite *KeeperTestSuite) TestBeginBlockerZeroRewardsBalance() { func (suite *KeeperTestSuite) TestBeginBlockerWithRewardBalanceAndPreviousPeakZero() { ctx, cellarfeesKeeper := suite.ctx, suite.cellarfeesKeeper + cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.DefaultFeeAccrualCounters()) + require := suite.Require() params := cellarfeesTypes.DefaultParams() @@ -48,6 +55,7 @@ func (suite *KeeperTestSuite) TestBeginBlockerWithRewardBalanceAndPreviousPeakZe func (suite *KeeperTestSuite) TestBeginBlockerWithRewardBalanceAndHigherPreviousPeak() { ctx, cellarfeesKeeper := suite.ctx, suite.cellarfeesKeeper + cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.DefaultFeeAccrualCounters()) require := suite.Require() params := cellarfeesTypes.DefaultParams() @@ -72,6 +80,8 @@ func (suite *KeeperTestSuite) TestBeginBlockerWithRewardBalanceAndHigherPrevious func (suite *KeeperTestSuite) TestBeginBlockerWithRewardBalanceAndLowerPreviousPeak() { ctx, cellarfeesKeeper := suite.ctx, suite.cellarfeesKeeper + cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.DefaultFeeAccrualCounters()) + require := suite.Require() params := cellarfeesTypes.DefaultParams() @@ -97,6 +107,7 @@ func (suite *KeeperTestSuite) TestBeginBlockerWithRewardBalanceAndLowerPreviousP // If the emission calculation underflows to zero, it should be set to 1 func (suite *KeeperTestSuite) TestBeginBlockerEmissionCalculationUnderflowsToZero() { ctx, cellarfeesKeeper := suite.ctx, suite.cellarfeesKeeper + cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.DefaultFeeAccrualCounters()) require := suite.Require() params := cellarfeesTypes.DefaultParams() @@ -118,6 +129,8 @@ func (suite *KeeperTestSuite) TestBeginBlockerEmissionCalculationUnderflowsToZer // If the calculated emission is greater than the remaining supply, it should be set to the remaining supply func (suite *KeeperTestSuite) TestBeginBlockerEmissionGreaterThanRewardSupply() { ctx, cellarfeesKeeper := suite.ctx, suite.cellarfeesKeeper + cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.DefaultFeeAccrualCounters()) + require := suite.Require() params := cellarfeesTypes.DefaultParams() cellarfeesKeeper.SetParams(ctx, params) @@ -134,3 +147,185 @@ func (suite *KeeperTestSuite) TestBeginBlockerEmissionGreaterThanRewardSupply() require.NotPanics(func() { cellarfeesKeeper.BeginBlocker(ctx) }) } + +func (suite *KeeperTestSuite) TestAuctionBeginWithSufficientFunds() { + ctx, cellarfeesKeeper := suite.ctx, suite.cellarfeesKeeper + cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.DefaultFeeAccrualCounters()) + suite.SetupHooksTests(ctx, cellarfeesKeeper) + + require := suite.Require() + params := cellarfeesTypes.DefaultParams() + params.AuctionInterval = 1 + cellarfeesKeeper.SetParams(ctx, params) + cellarfeesKeeper.SetLastRewardSupplyPeak(ctx, sdk.NewInt(1000000)) + + hooks := Hooks{k: cellarfeesKeeper} + event := gravitytypes.SendToCosmosEvent{ + CosmosReceiver: feesAccount.GetAddress().String(), + Amount: sdk.NewInt(2), + EthereumSender: "0x0000000000000000000000000000000000000000", + TokenContract: "0x1111111111111111111111111111111111111111", + } + cellarID := common.HexToAddress(event.EthereumSender) + cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.FeeAccrualCounters{ + Counters: []cellarfeesTypes.FeeAccrualCounter{ + { + Denom: gravityFeeDenom, + Count: 1, + }, + }, + }) + expectedCounters := cellarfeesTypes.FeeAccrualCounters{ + Counters: []cellarfeesTypes.FeeAccrualCounter{ + { + Denom: gravityFeeDenom, + Count: 0, + }, + }, + } + + suite.corkKeeper.EXPECT().HasCellarID(ctx, cellarID).Return(true) + suite.gravityKeeper.EXPECT().ERC20ToDenomLookup(ctx, common.HexToAddress(event.TokenContract)).Return(false, gravityFeeDenom) + suite.accountKeeper.EXPECT().GetModuleAccount(ctx, cellarfeesTypes.ModuleName).Return(feesAccount) + + require.NotPanics(func() { hooks.AfterSendToCosmosEvent(ctx, event) }) + + // mocks + suite.accountKeeper.EXPECT().GetModuleAccount(ctx, cellarfeesTypes.ModuleName).Return(feesAccount) + + suite.bankKeeper.EXPECT().GetBalance(ctx, feesAccount.GetAddress(), appParams.BaseCoinUnit).Return(sdk.NewCoin(gravityFeeDenom, sdk.NewInt(0))) + + suite.bankKeeper.EXPECT().GetBalance(ctx, feesAccount.GetAddress(), gravityFeeDenom).Return(sdk.NewCoin(gravityFeeDenom, event.Amount)) + + expectedEmission := sdk.NewCoin(appParams.BaseCoinUnit, event.Amount) + suite.bankKeeper.EXPECT().SendCoinsFromModuleToModule(ctx, gomock.Any(), gomock.Any(), sdk.NewCoins(expectedEmission)).Times(1) + suite.auctionKeeper.EXPECT().GetActiveAuctions(ctx).Return([]*auctionTypes.Auction{}) + suite.bankKeeper.EXPECT().GetBalance(ctx, feesAccount.GetAddress(), gravityFeeDenom).Return(sdk.NewCoin(gravityFeeDenom, event.Amount)) + suite.auctionKeeper.EXPECT().BeginAuction(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1) + + require.NotPanics(func() { cellarfeesKeeper.BeginBlocker(ctx) }) + + require.Equal(expectedCounters, cellarfeesKeeper.GetFeeAccrualCounters(ctx)) + +} + +func (suite *KeeperTestSuite) TestAuctionBeginWithInSufficientFunds() { + ctx, cellarfeesKeeper := suite.ctx, suite.cellarfeesKeeper + cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.DefaultFeeAccrualCounters()) + suite.SetupHooksTests(ctx, cellarfeesKeeper) + + require := suite.Require() + params := cellarfeesTypes.DefaultParams() + params.AuctionInterval = 1 + cellarfeesKeeper.SetParams(ctx, params) + cellarfeesKeeper.SetLastRewardSupplyPeak(ctx, sdk.NewInt(1000000)) + + hooks := Hooks{k: cellarfeesKeeper} + event := gravitytypes.SendToCosmosEvent{ + CosmosReceiver: feesAccount.GetAddress().String(), + Amount: sdk.NewInt(1), + EthereumSender: "0x0000000000000000000000000000000000000000", + TokenContract: "0x1111111111111111111111111111111111111111", + } + cellarID := common.HexToAddress(event.EthereumSender) + cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.FeeAccrualCounters{ + Counters: []cellarfeesTypes.FeeAccrualCounter{ + { + Denom: gravityFeeDenom, + Count: 0, + }, + }, + }) + expectedCounters := cellarfeesTypes.FeeAccrualCounters{ + Counters: []cellarfeesTypes.FeeAccrualCounter{ + { + Denom: gravityFeeDenom, + Count: 1, + }, + }, + } + + suite.corkKeeper.EXPECT().HasCellarID(ctx, cellarID).Return(true) + suite.gravityKeeper.EXPECT().ERC20ToDenomLookup(ctx, common.HexToAddress(event.TokenContract)).Return(false, gravityFeeDenom) + suite.accountKeeper.EXPECT().GetModuleAccount(ctx, cellarfeesTypes.ModuleName).Return(feesAccount) + + require.NotPanics(func() { hooks.AfterSendToCosmosEvent(ctx, event) }) + + // mocks + suite.accountKeeper.EXPECT().GetModuleAccount(ctx, cellarfeesTypes.ModuleName).Return(feesAccount) + + suite.bankKeeper.EXPECT().GetBalance(ctx, feesAccount.GetAddress(), appParams.BaseCoinUnit).Return(sdk.NewCoin(gravityFeeDenom, sdk.NewInt(0))) + + suite.bankKeeper.EXPECT().GetBalance(ctx, feesAccount.GetAddress(), gravityFeeDenom).Return(sdk.NewCoin(gravityFeeDenom, event.Amount)) + + expectedEmission := sdk.NewCoin(appParams.BaseCoinUnit, event.Amount) + suite.bankKeeper.EXPECT().SendCoinsFromModuleToModule(ctx, gomock.Any(), gomock.Any(), sdk.NewCoins(expectedEmission)).Times(1) + suite.auctionKeeper.EXPECT().GetActiveAuctions(ctx).Return([]*auctionTypes.Auction{}) + suite.bankKeeper.EXPECT().GetBalance(ctx, feesAccount.GetAddress(), gravityFeeDenom).Return(sdk.NewCoin(gravityFeeDenom, event.Amount)) + suite.auctionKeeper.EXPECT().BeginAuction(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1) + + require.NotPanics(func() { cellarfeesKeeper.BeginBlocker(ctx) }) + + require.Equal(expectedCounters, cellarfeesKeeper.GetFeeAccrualCounters(ctx)) + +} + +func (suite *KeeperTestSuite) TestAuctionBeginWithSufficientFundsWrongBlockHeight() { + ctx, cellarfeesKeeper := suite.ctx, suite.cellarfeesKeeper + cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.DefaultFeeAccrualCounters()) + suite.SetupHooksTests(ctx, cellarfeesKeeper) + + require := suite.Require() + params := cellarfeesTypes.DefaultParams() + params.AuctionInterval = 1000 + cellarfeesKeeper.SetParams(ctx, params) + cellarfeesKeeper.SetLastRewardSupplyPeak(ctx, sdk.NewInt(1000000)) + + hooks := Hooks{k: cellarfeesKeeper} + event := gravitytypes.SendToCosmosEvent{ + CosmosReceiver: feesAccount.GetAddress().String(), + Amount: sdk.NewInt(2), + EthereumSender: "0x0000000000000000000000000000000000000000", + TokenContract: "0x1111111111111111111111111111111111111111", + } + cellarID := common.HexToAddress(event.EthereumSender) + cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.FeeAccrualCounters{ + Counters: []cellarfeesTypes.FeeAccrualCounter{ + { + Denom: gravityFeeDenom, + Count: 1, + }, + }, + }) + expectedCounters := cellarfeesTypes.FeeAccrualCounters{ + Counters: []cellarfeesTypes.FeeAccrualCounter{ + { + Denom: gravityFeeDenom, + Count: 2, + }, + }, + } + + suite.corkKeeper.EXPECT().HasCellarID(ctx, cellarID).Return(true) + suite.gravityKeeper.EXPECT().ERC20ToDenomLookup(ctx, common.HexToAddress(event.TokenContract)).Return(false, gravityFeeDenom) + suite.accountKeeper.EXPECT().GetModuleAccount(ctx, cellarfeesTypes.ModuleName).Return(feesAccount) + + require.NotPanics(func() { hooks.AfterSendToCosmosEvent(ctx, event) }) + + // mocks + suite.accountKeeper.EXPECT().GetModuleAccount(ctx, cellarfeesTypes.ModuleName).Return(feesAccount) + + suite.bankKeeper.EXPECT().GetBalance(ctx, feesAccount.GetAddress(), appParams.BaseCoinUnit).Return(sdk.NewCoin(gravityFeeDenom, sdk.NewInt(0))) + + suite.bankKeeper.EXPECT().GetBalance(ctx, feesAccount.GetAddress(), gravityFeeDenom).Return(sdk.NewCoin(gravityFeeDenom, event.Amount)) + + expectedEmission := sdk.NewCoin(appParams.BaseCoinUnit, event.Amount) + suite.bankKeeper.EXPECT().SendCoinsFromModuleToModule(ctx, gomock.Any(), gomock.Any(), sdk.NewCoins(expectedEmission)).Times(1) + suite.auctionKeeper.EXPECT().GetActiveAuctions(ctx).Return([]*auctionTypes.Auction{}) + suite.bankKeeper.EXPECT().GetBalance(ctx, feesAccount.GetAddress(), gravityFeeDenom).Return(sdk.NewCoin(gravityFeeDenom, event.Amount)) + + require.NotPanics(func() { cellarfeesKeeper.BeginBlocker(ctx) }) + + require.Equal(expectedCounters, cellarfeesKeeper.GetFeeAccrualCounters(ctx)) + +} diff --git a/x/cellarfees/keeper/genesis_test.go b/x/cellarfees/keeper/genesis_test.go index e5ff6dbd..f48e2a3e 100644 --- a/x/cellarfees/keeper/genesis_test.go +++ b/x/cellarfees/keeper/genesis_test.go @@ -51,6 +51,7 @@ func (suite *KeeperTestSuite) TestImportingPopulatedGenesis() { testGenesis.Params.InitialPriceDecreaseRate = sdk.MustNewDecFromStr("0.01") testGenesis.Params.PriceDecreaseBlockInterval = 10 testGenesis.Params.RewardEmissionPeriod = 600 + testGenesis.Params.AuctionInterval = 1000 require.NotPanics(func() { suite.accountKeeper.EXPECT().GetModuleAccount(ctx, feesAccount.GetName()).Return(feesAccount) @@ -82,6 +83,7 @@ func (suite *KeeperTestSuite) TestExportingPopulatedGenesis() { params.InitialPriceDecreaseRate = sdk.MustNewDecFromStr("0.01") params.PriceDecreaseBlockInterval = 10 params.RewardEmissionPeriod = 600 + params.AuctionInterval = 1000 cellarfeesKeeper.SetParams(ctx, params) counters := cellarfeesTypes.FeeAccrualCounters{ Counters: []cellarfeesTypes.FeeAccrualCounter{ diff --git a/x/cellarfees/keeper/hooks.go b/x/cellarfees/keeper/hooks.go index de2e2e59..70ecdfd8 100644 --- a/x/cellarfees/keeper/hooks.go +++ b/x/cellarfees/keeper/hooks.go @@ -57,16 +57,8 @@ func (h Hooks) AfterSendToCosmosEvent(ctx sdk.Context, event gravitytypes.SendTo return } - cellarfeesParams := h.k.GetParams(ctx) counters := h.k.GetFeeAccrualCounters(ctx) count := counters.IncrementCounter(denom) - if count >= cellarfeesParams.FeeAccrualAuctionThreshold { - started := h.k.beginAuction(ctx, denom) - if started { - counters.ResetCounter(denom) - } - } - h.k.SetFeeAccrualCounters(ctx, counters) ctx.EventManager().EmitEvents( diff --git a/x/cellarfees/keeper/hooks_test.go b/x/cellarfees/keeper/hooks_test.go index 60f71853..9238af47 100644 --- a/x/cellarfees/keeper/hooks_test.go +++ b/x/cellarfees/keeper/hooks_test.go @@ -3,9 +3,7 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" - "github.com/golang/mock/gomock" gravitytypes "github.com/peggyjv/gravity-bridge/module/v4/x/gravity/types" - auctionTypes "github.com/peggyjv/sommelier/v7/x/auction/types" cellarfeesTypes "github.com/peggyjv/sommelier/v7/x/cellarfees/types" ) @@ -85,115 +83,3 @@ func (suite *KeeperTestSuite) TestHooksDenomIsUsommDoesNothing() { require.NotPanics(func() { hooks.AfterSendToCosmosEvent(ctx, event) }) require.Equal(cellarfeesTypes.DefaultFeeAccrualCounters(), cellarfeesKeeper.GetFeeAccrualCounters(ctx)) } - -func (suite *KeeperTestSuite) TestHooksCountAccruesNoAuction() { - ctx, cellarfeesKeeper, require := suite.ctx, suite.cellarfeesKeeper, suite.Require() - suite.SetupHooksTests(ctx, cellarfeesKeeper) - - hooks := Hooks{k: cellarfeesKeeper} - event := gravitytypes.SendToCosmosEvent{ - CosmosReceiver: feesAccount.GetAddress().String(), - Amount: sdk.OneInt(), - EthereumSender: "0x0000000000000000000000000000000000000000", - TokenContract: "0x1111111111111111111111111111111111111111", - } - cellarID := common.HexToAddress(event.EthereumSender) - expectedCounters := cellarfeesTypes.FeeAccrualCounters{ - Counters: []cellarfeesTypes.FeeAccrualCounter{ - { - Denom: gravityFeeDenom, - Count: 1, - }, - }, - } - - // mocks - suite.corkKeeper.EXPECT().HasCellarID(ctx, cellarID).Return(true) - suite.gravityKeeper.EXPECT().ERC20ToDenomLookup(ctx, common.HexToAddress(event.TokenContract)).Return(false, gravityFeeDenom).Times(1) - suite.auctionKeeper.EXPECT().BeginAuction(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) - - require.NotPanics(func() { hooks.AfterSendToCosmosEvent(ctx, event) }) - require.Equal(expectedCounters, cellarfeesKeeper.GetFeeAccrualCounters(ctx)) -} - -func (suite *KeeperTestSuite) TestHooksCountAccruesAuctionStarts() { - ctx, cellarfeesKeeper, require := suite.ctx, suite.cellarfeesKeeper, suite.Require() - suite.SetupHooksTests(ctx, cellarfeesKeeper) - - hooks := Hooks{k: cellarfeesKeeper} - event := gravitytypes.SendToCosmosEvent{ - CosmosReceiver: feesAccount.GetAddress().String(), - Amount: sdk.OneInt(), - EthereumSender: "0x0000000000000000000000000000000000000000", - TokenContract: "0x1111111111111111111111111111111111111111", - } - cellarID := common.HexToAddress(event.EthereumSender) - cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.FeeAccrualCounters{ - Counters: []cellarfeesTypes.FeeAccrualCounter{ - { - Denom: gravityFeeDenom, - Count: 1, - }, - }, - }) - expectedCounters := cellarfeesTypes.FeeAccrualCounters{ - Counters: []cellarfeesTypes.FeeAccrualCounter{ - { - Denom: gravityFeeDenom, - Count: 0, - }, - }, - } - - // mocks - suite.corkKeeper.EXPECT().HasCellarID(ctx, cellarID).Return(true) - suite.gravityKeeper.EXPECT().ERC20ToDenomLookup(ctx, common.HexToAddress(event.TokenContract)).Return(false, gravityFeeDenom) - suite.accountKeeper.EXPECT().GetModuleAccount(ctx, cellarfeesTypes.ModuleName).Return(feesAccount) - suite.auctionKeeper.EXPECT().GetActiveAuctions(ctx).Return([]*auctionTypes.Auction{}) - suite.bankKeeper.EXPECT().GetBalance(ctx, feesAccount.GetAddress(), gravityFeeDenom).Return(sdk.NewCoin(gravityFeeDenom, event.Amount)) - suite.auctionKeeper.EXPECT().BeginAuction(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).Times(1) - - require.NotPanics(func() { hooks.AfterSendToCosmosEvent(ctx, event) }) - require.Equal(expectedCounters, cellarfeesKeeper.GetFeeAccrualCounters(ctx)) -} - -func (suite *KeeperTestSuite) TestHooksCountAccruesAuctionDoesNotStart() { - ctx, cellarfeesKeeper, require := suite.ctx, suite.cellarfeesKeeper, suite.Require() - suite.SetupHooksTests(ctx, cellarfeesKeeper) - - hooks := Hooks{k: cellarfeesKeeper} - event := gravitytypes.SendToCosmosEvent{ - CosmosReceiver: feesAccount.GetAddress().String(), - Amount: sdk.OneInt(), - EthereumSender: "0x0000000000000000000000000000000000000000", - TokenContract: "0x1111111111111111111111111111111111111111", - } - cellarID := common.HexToAddress(event.EthereumSender) - cellarfeesKeeper.SetFeeAccrualCounters(ctx, cellarfeesTypes.FeeAccrualCounters{ - Counters: []cellarfeesTypes.FeeAccrualCounter{ - { - Denom: gravityFeeDenom, - Count: 1, - }, - }, - }) - expectedCounters := cellarfeesTypes.FeeAccrualCounters{ - Counters: []cellarfeesTypes.FeeAccrualCounter{ - { - Denom: gravityFeeDenom, - Count: 2, - }, - }, - } - - // mocks - suite.corkKeeper.EXPECT().HasCellarID(ctx, cellarID).Return(true) - suite.gravityKeeper.EXPECT().ERC20ToDenomLookup(ctx, common.HexToAddress(event.TokenContract)).Return(false, gravityFeeDenom) - suite.accountKeeper.EXPECT().GetModuleAccount(ctx, cellarfeesTypes.ModuleName).Return(feesAccount) - suite.auctionKeeper.EXPECT().GetActiveAuctions(ctx).Return([]*auctionTypes.Auction{}) - suite.bankKeeper.EXPECT().GetBalance(ctx, feesAccount.GetAddress(), gravityFeeDenom).Return(sdk.NewCoin(gravityFeeDenom, event.Amount)) - suite.auctionKeeper.EXPECT().BeginAuction(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(auctionTypes.ErrDenomCannotBeEmpty).Times(1) - - require.NotPanics(func() { hooks.AfterSendToCosmosEvent(ctx, event) }) - require.Equal(expectedCounters, cellarfeesKeeper.GetFeeAccrualCounters(ctx)) -} diff --git a/x/cellarfees/types/errors.go b/x/cellarfees/types/errors.go index 4b16f765..8e55258b 100644 --- a/x/cellarfees/types/errors.go +++ b/x/cellarfees/types/errors.go @@ -12,4 +12,5 @@ var ( ErrInvalidPriceDecreaseBlockInterval = errorsmod.Register(ModuleName, 5, "invalid price decrease block interval") ErrInvalidFeeAccrualCounters = errorsmod.Register(ModuleName, 6, "invalid fee accrual counters") ErrInvalidLastRewardSupplyPeak = errorsmod.Register(ModuleName, 7, "invalid last reward supply peak") + ErrInvalidAuctionInterval = errorsmod.Register(ModuleName, 8, "invalid interval blocks between auctions") ) diff --git a/x/cellarfees/types/params.go b/x/cellarfees/types/params.go index 158eda7a..0d81222a 100644 --- a/x/cellarfees/types/params.go +++ b/x/cellarfees/types/params.go @@ -17,6 +17,8 @@ const ( DefaultInitialPriceDecreaseRate string = "0.0000648" // Blocks between each auction price decrease DefaultPriceDecreaseBlockInterval uint64 = 10 + // Blocks between each auction + DefaultAuctionInterval uint64 = 15000 ) // Parameter keys @@ -25,6 +27,7 @@ var ( KeyRewardEmissionPeriod = []byte("RewardEmissionPeriod") KeyInitialPriceDecreaseRate = []byte("InitialPriceDecreaseRate") KeyPriceDecreaseBlockInterval = []byte("PriceDecreaseBlockInterval") + KeyAuctionInterval = []byte("AuctionInterval") ) var _ paramtypes.ParamSet = &Params{} @@ -41,6 +44,7 @@ func DefaultParams() Params { RewardEmissionPeriod: DefaultRewardEmissionPeriod, InitialPriceDecreaseRate: sdk.MustNewDecFromStr(DefaultInitialPriceDecreaseRate), PriceDecreaseBlockInterval: DefaultPriceDecreaseBlockInterval, + AuctionInterval: DefaultAuctionInterval, } } @@ -51,6 +55,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyRewardEmissionPeriod, &p.RewardEmissionPeriod, validateRewardEmissionPeriod), paramtypes.NewParamSetPair(KeyInitialPriceDecreaseRate, &p.InitialPriceDecreaseRate, validateInitialPriceDecreaseRate), paramtypes.NewParamSetPair(KeyPriceDecreaseBlockInterval, &p.PriceDecreaseBlockInterval, validatePriceDecreaseBlockInterval), + paramtypes.NewParamSetPair(KeyAuctionInterval, &p.AuctionInterval, validateAuctionInterval), } } @@ -127,6 +132,19 @@ func validatePriceDecreaseBlockInterval(i interface{}) error { return nil } +func validateAuctionInterval(i interface{}) error { + interval, ok := i.(uint64) + if !ok { + return errorsmod.Wrapf(ErrInvalidAuctionInterval, "auction interval: %T", i) + } + + if interval == 0 { + return errorsmod.Wrapf(ErrInvalidAuctionInterval, "auction interval cannot be zero") + } + + return nil +} + // String implements the String interface func (p Params) String() string { out, _ := yaml.Marshal(p) diff --git a/x/cellarfees/types/params.pb.go b/x/cellarfees/types/params.pb.go index 5b4ba493..a3e6e546 100644 --- a/x/cellarfees/types/params.pb.go +++ b/x/cellarfees/types/params.pb.go @@ -35,6 +35,8 @@ type Params struct { InitialPriceDecreaseRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=initial_price_decrease_rate,json=initialPriceDecreaseRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"initial_price_decrease_rate"` // Number of blocks between auction price decreases PriceDecreaseBlockInterval uint64 `protobuf:"varint,4,opt,name=price_decrease_block_interval,json=priceDecreaseBlockInterval,proto3" json:"price_decrease_block_interval,omitempty"` + // The interval between starting auctions + AuctionInterval uint64 `protobuf:"varint,5,opt,name=auction_interval,json=auctionInterval,proto3" json:"auction_interval,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -90,6 +92,13 @@ func (m *Params) GetPriceDecreaseBlockInterval() uint64 { return 0 } +func (m *Params) GetAuctionInterval() uint64 { + if m != nil { + return m.AuctionInterval + } + return 0 +} + func init() { proto.RegisterType((*Params)(nil), "cellarfees.v1.Params") } @@ -97,29 +106,30 @@ func init() { func init() { proto.RegisterFile("cellarfees/v1/params.proto", fileDescriptor_f3220ed6f8663c98) } var fileDescriptor_f3220ed6f8663c98 = []byte{ - // 351 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x91, 0xbd, 0x4a, 0x33, 0x41, - 0x14, 0x86, 0x77, 0xf3, 0x85, 0xc0, 0xb7, 0x60, 0xb3, 0x04, 0x59, 0x22, 0x6e, 0x82, 0x85, 0xa4, - 0x71, 0x87, 0xa8, 0x20, 0xd8, 0x25, 0xc4, 0x42, 0xb0, 0x08, 0xc1, 0xca, 0x66, 0x98, 0xcc, 0x9e, - 0x6c, 0xc6, 0xcc, 0x64, 0x86, 0x99, 0xc9, 0x6a, 0xee, 0xc2, 0xd2, 0xd2, 0xdb, 0xf0, 0x0e, 0x52, - 0xa6, 0x14, 0x8b, 0x20, 0xc9, 0x8d, 0xc8, 0xfe, 0x88, 0x8b, 0xd5, 0x2e, 0x3c, 0xcf, 0xfb, 0xce, - 0x39, 0x1c, 0xaf, 0x45, 0x81, 0x73, 0xa2, 0xa7, 0x00, 0x06, 0xa5, 0x3d, 0xa4, 0x88, 0x26, 0xc2, - 0x44, 0x4a, 0x4b, 0x2b, 0xfd, 0x83, 0x5f, 0x16, 0xa5, 0xbd, 0x56, 0x33, 0x91, 0x89, 0xcc, 0x09, - 0xca, 0xfe, 0x0a, 0xe9, 0xe4, 0xbd, 0xe6, 0x35, 0x46, 0x79, 0xca, 0xef, 0x7b, 0xc7, 0x53, 0x00, - 0x4c, 0x28, 0xd5, 0x4b, 0xc2, 0x31, 0x59, 0x52, 0xcb, 0xe4, 0x02, 0xdb, 0x99, 0x06, 0x33, 0x93, - 0x3c, 0x0e, 0xdc, 0x8e, 0xdb, 0xad, 0x8f, 0x5b, 0x53, 0x80, 0x7e, 0xe1, 0xf4, 0x0b, 0xe5, 0xfe, - 0xc7, 0xf0, 0x2f, 0xbd, 0x43, 0x0d, 0x4f, 0x44, 0xc7, 0x18, 0x04, 0x33, 0x26, 0x8b, 0x2b, 0xd0, - 0x4c, 0xc6, 0x41, 0x2d, 0xcf, 0x36, 0x0b, 0x7a, 0x53, 0xc2, 0x51, 0xce, 0x7c, 0xe1, 0x1d, 0xb1, - 0x05, 0xb3, 0x8c, 0x70, 0xac, 0x34, 0xa3, 0x80, 0x63, 0xa0, 0x1a, 0x88, 0x01, 0xac, 0x89, 0x85, - 0xe0, 0x5f, 0xc7, 0xed, 0xfe, 0x1f, 0x44, 0xeb, 0x6d, 0xdb, 0xf9, 0xdc, 0xb6, 0x4f, 0x13, 0x66, - 0x67, 0xcb, 0x49, 0x44, 0xa5, 0x40, 0x54, 0x1a, 0x21, 0x4d, 0xf9, 0x39, 0x33, 0xf1, 0x1c, 0xd9, - 0x95, 0x02, 0x13, 0x0d, 0x81, 0x8e, 0x83, 0xb2, 0x72, 0x94, 0x35, 0x0e, 0xcb, 0xc2, 0x31, 0xb1, - 0x90, 0xed, 0xf9, 0xe7, 0x99, 0x09, 0x97, 0x74, 0x8e, 0xd9, 0xc2, 0x82, 0x4e, 0x09, 0x0f, 0xea, - 0xc5, 0x9e, 0xaa, 0x9a, 0x1c, 0x64, 0xca, 0x6d, 0x69, 0x5c, 0xd7, 0x5f, 0xdf, 0xda, 0xce, 0xe0, - 0x6e, 0xbd, 0x0b, 0xdd, 0xcd, 0x2e, 0x74, 0xbf, 0x76, 0xa1, 0xfb, 0xb2, 0x0f, 0x9d, 0xcd, 0x3e, - 0x74, 0x3e, 0xf6, 0xa1, 0xf3, 0x70, 0x5e, 0x19, 0x52, 0x41, 0x92, 0xac, 0x1e, 0x53, 0x64, 0xa4, - 0x10, 0xc0, 0x19, 0x68, 0x94, 0x5e, 0xa1, 0x67, 0x54, 0x39, 0x5c, 0x3e, 0xf4, 0xa4, 0x91, 0x1f, - 0xe4, 0xe2, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x42, 0xb4, 0x27, 0xe3, 0xd3, 0x01, 0x00, 0x00, + // 366 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x91, 0x41, 0x4b, 0xf3, 0x30, + 0x18, 0xc7, 0xdb, 0xbd, 0x7b, 0x07, 0x16, 0x44, 0x29, 0x43, 0xca, 0xc4, 0x6e, 0x78, 0x90, 0x79, + 0xb0, 0x61, 0x2a, 0x08, 0xde, 0x36, 0xe6, 0x41, 0xf0, 0x30, 0x86, 0x27, 0x2f, 0x21, 0x4b, 0x9f, + 0x75, 0x71, 0xe9, 0x52, 0x92, 0xac, 0xba, 0x6f, 0xe1, 0xd1, 0xa3, 0x1f, 0x67, 0xc7, 0x1d, 0xc5, + 0xc3, 0x90, 0xcd, 0x0f, 0x22, 0x4d, 0x3b, 0x1d, 0x9e, 0x5a, 0xf2, 0xff, 0xfd, 0x9e, 0xf0, 0xcf, + 0xe3, 0xd4, 0x28, 0x70, 0x4e, 0xe4, 0x10, 0x40, 0xa1, 0xb4, 0x85, 0x12, 0x22, 0x49, 0xac, 0x82, + 0x44, 0x0a, 0x2d, 0xdc, 0xdd, 0xdf, 0x2c, 0x48, 0x5b, 0xb5, 0x6a, 0x24, 0x22, 0x61, 0x12, 0x94, + 0xfd, 0xe5, 0xd0, 0xf1, 0x57, 0xc9, 0xa9, 0xf4, 0x8c, 0xe5, 0xb6, 0x9d, 0xa3, 0x21, 0x00, 0x26, + 0x94, 0xca, 0x29, 0xe1, 0x98, 0x4c, 0xa9, 0x66, 0x62, 0x82, 0xf5, 0x48, 0x82, 0x1a, 0x09, 0x1e, + 0x7a, 0x76, 0xc3, 0x6e, 0x96, 0xfb, 0xb5, 0x21, 0x40, 0x3b, 0x67, 0xda, 0x39, 0x72, 0xbf, 0x21, + 0xdc, 0x4b, 0xe7, 0x40, 0xc2, 0x13, 0x91, 0x21, 0x86, 0x98, 0x29, 0x95, 0xe9, 0x09, 0x48, 0x26, + 0x42, 0xaf, 0x64, 0xdc, 0x6a, 0x9e, 0xde, 0x14, 0x61, 0xcf, 0x64, 0x6e, 0xec, 0x1c, 0xb2, 0x09, + 0xd3, 0x8c, 0x70, 0x9c, 0x48, 0x46, 0x01, 0x87, 0x40, 0x25, 0x10, 0x05, 0x58, 0x12, 0x0d, 0xde, + 0xbf, 0x86, 0xdd, 0xdc, 0xe9, 0x04, 0xf3, 0x65, 0xdd, 0xfa, 0x58, 0xd6, 0x4f, 0x22, 0xa6, 0x47, + 0xd3, 0x41, 0x40, 0x45, 0x8c, 0xa8, 0x50, 0xb1, 0x50, 0xc5, 0xe7, 0x4c, 0x85, 0x63, 0xa4, 0x67, + 0x09, 0xa8, 0xa0, 0x0b, 0xb4, 0xef, 0x15, 0x23, 0x7b, 0xd9, 0xc4, 0x6e, 0x31, 0xb0, 0x4f, 0x34, + 0x64, 0x3d, 0xff, 0x5c, 0x33, 0xe0, 0x82, 0x8e, 0x31, 0x9b, 0x68, 0x90, 0x29, 0xe1, 0x5e, 0x39, + 0xef, 0x99, 0x6c, 0x9b, 0x9d, 0x0c, 0xb9, 0x2d, 0x08, 0xf7, 0xd4, 0xd9, 0xdf, 0x3c, 0xcf, 0x8f, + 0xf5, 0xdf, 0x58, 0x7b, 0xc5, 0xf9, 0x06, 0xbd, 0x2e, 0xbf, 0xbe, 0xd5, 0xad, 0xce, 0xdd, 0x7c, + 0xe5, 0xdb, 0x8b, 0x95, 0x6f, 0x7f, 0xae, 0x7c, 0xfb, 0x65, 0xed, 0x5b, 0x8b, 0xb5, 0x6f, 0xbd, + 0xaf, 0x7d, 0xeb, 0xe1, 0x7c, 0xab, 0x4f, 0x02, 0x51, 0x34, 0x7b, 0x4c, 0x91, 0x12, 0x71, 0x0c, + 0x9c, 0x81, 0x44, 0xe9, 0x15, 0x7a, 0x46, 0x5b, 0x3b, 0x36, 0xfd, 0x06, 0x15, 0xb3, 0xbb, 0x8b, + 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3d, 0x4d, 0xb2, 0xdd, 0xfe, 0x01, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -142,6 +152,11 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.AuctionInterval != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.AuctionInterval)) + i-- + dAtA[i] = 0x28 + } if m.PriceDecreaseBlockInterval != 0 { i = encodeVarintParams(dAtA, i, uint64(m.PriceDecreaseBlockInterval)) i-- @@ -198,6 +213,9 @@ func (m *Params) Size() (n int) { if m.PriceDecreaseBlockInterval != 0 { n += 1 + sovParams(uint64(m.PriceDecreaseBlockInterval)) } + if m.AuctionInterval != 0 { + n += 1 + sovParams(uint64(m.AuctionInterval)) + } return n } @@ -327,6 +345,25 @@ func (m *Params) Unmarshal(dAtA []byte) error { break } } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AuctionInterval", wireType) + } + m.AuctionInterval = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AuctionInterval |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:])