Skip to content

Commit

Permalink
Intitial commit of Block Interval Auctions (#242)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: Eric Bolten <[email protected]>
  • Loading branch information
3 people authored Dec 14, 2023
1 parent 6dd3580 commit f837fbc
Show file tree
Hide file tree
Showing 10 changed files with 301 additions and 145 deletions.
1 change: 1 addition & 0 deletions integration_tests/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions proto/cellarfees/v1/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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;

}


21 changes: 21 additions & 0 deletions x/cellarfees/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
195 changes: 195 additions & 0 deletions x/cellarfees/keeper/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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()
Expand All @@ -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()
Expand All @@ -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()
Expand All @@ -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)
Expand All @@ -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))

}
2 changes: 2 additions & 0 deletions x/cellarfees/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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{
Expand Down
8 changes: 0 additions & 8 deletions x/cellarfees/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading

0 comments on commit f837fbc

Please sign in to comment.