Proposer Bid Reward [ENG-534] (#24)

This commit is contained in:
Aleksandr Bezobchuk 2023-03-17 10:38:09 -04:00 committed by GitHub
parent fdfd12a81d
commit 99b4bc2da2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 640 additions and 307 deletions

View File

@ -8,7 +8,9 @@ import "amino/amino.proto";
option go_package = "github.com/skip-mev/pob/x/auction/types";
// GenesisState defines the genesis state of the x/auction module.
message GenesisState { Params params = 1 [ (gogoproto.nullable) = false ]; }
message GenesisState {
Params params = 1 [(gogoproto.nullable) = false];
}
// Params defines the parameters of the x/auction module.
message Params {
@ -17,29 +19,42 @@ message Params {
// max_bundle_size is the maximum number of transactions that can be bundled
// in a single bundle.
uint32 max_bundle_size = 1;
// escrow_account_address is the address of the account that will hold the
// funds for the auctions.
// escrow_account_address is the address of the account that will receive a
// portion of the bid proceeds.
string escrow_account_address = 2;
// reserve_fee specifies the bid floor for the auction.
repeated cosmos.base.v1beta1.Coin reserve_fee = 3 [
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true,
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];
// min_buy_in_fee specifies the fee that the bidder must pay to enter the auction.
// min_buy_in_fee specifies the fee that the bidder must pay to enter the
// auction.
repeated cosmos.base.v1beta1.Coin min_buy_in_fee = 4 [
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true,
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];
// min_bid_increment specifies the minimum amount that the next bid must be
// greater than the previous bid.
repeated cosmos.base.v1beta1.Coin min_bid_increment = 5 [
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true,
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];
// front_running_protection specifies whether front running and sandwich attack protection
// is enabled.
// front_running_protection specifies whether front running and sandwich
// attack protection is enabled.
bool front_running_protection = 6;
// proposer_fee defines the portion of the winning bid that goes to the block
// proposer that proposed the block.
string proposer_fee = 7 [
(gogoproto.nullable) = false,
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec"
];
}

View File

@ -70,7 +70,7 @@ func (k Keeper) ValidateAuctionBid(ctx sdk.Context, bidder sdk.AccAddress, bid,
// Ensure the bidder has enough funds to cover all the inclusion fees.
minBalance := bid.Add(minBuyInFee...)
balances := k.bankkeeper.GetAllBalances(ctx, bidder)
balances := k.bankKeeper.GetAllBalances(ctx, bidder)
if !balances.IsAllGTE(minBalance) {
return fmt.Errorf("insufficient funds to bid %s (reserve fee + bid) with balance %s", minBalance, balances)
}
@ -103,8 +103,8 @@ func (k Keeper) ValidateAuctionBundle(ctx sdk.Context, bidder sdk.AccAddress, tr
// Check that all subsequent transactions are signed by either
// 1. the same party as the first transaction
// 2. the same party for some arbitrary number of txs and then are all remaining txs are signed by the bidder.
for _, txbytes := range transactions[1:] {
txSigners, err := k.getTxSigners(txbytes)
for _, refTx := range transactions[1:] {
txSigners, err := k.getTxSigners(refTx)
if err != nil {
return err
}

View File

@ -4,16 +4,12 @@ import (
"math/rand"
"time"
"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/skip-mev/pob/x/auction/keeper"
auctiontypes "github.com/skip-mev/pob/x/auction/types"
)
func (suite *IntegrationTestSuite) TestValidateAuctionMsg() {
func (suite *KeeperTestSuite) TestValidateAuctionMsg() {
var (
// Tx building variables
accounts = []Account{} // tracks the order of signers in the bundle
@ -161,6 +157,8 @@ func (suite *IntegrationTestSuite) TestValidateAuctionMsg() {
suite.key,
suite.accountKeeper,
suite.bankKeeper,
suite.distrKeeper,
suite.stakingKeeper,
suite.authorityAccount.String(),
)
params := auctiontypes.Params{
@ -191,7 +189,7 @@ func (suite *IntegrationTestSuite) TestValidateAuctionMsg() {
}
}
func (suite *IntegrationTestSuite) TestValidateBundle() {
func (suite *KeeperTestSuite) TestValidateBundle() {
// TODO: Update this to be multi-dimensional to test multi-sig
// https://github.com/skip-mev/pob/issues/14
var accounts []Account // tracks the order of signers in the bundle
@ -301,33 +299,3 @@ func (suite *IntegrationTestSuite) TestValidateBundle() {
})
}
}
// createRandomTx creates a random transaction with a given account, nonce, and number of messages.
func createRandomTx(txCfg client.TxConfig, account Account, nonce, numberMsgs uint64) (authsigning.Tx, error) {
msgs := make([]sdk.Msg, numberMsgs)
for i := 0; i < int(numberMsgs); i++ {
msgs[i] = &banktypes.MsgSend{
FromAddress: account.Address.String(),
ToAddress: account.Address.String(),
}
}
txBuilder := txCfg.NewTxBuilder()
if err := txBuilder.SetMsgs(msgs...); err != nil {
return nil, err
}
sigV2 := signing.SignatureV2{
PubKey: account.PrivKey.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: txCfg.SignModeHandler().DefaultMode(),
Signature: nil,
},
Sequence: nonce,
}
if err := txBuilder.SetSignatures(sigV2); err != nil {
return nil, err
}
return txBuilder.GetTx(), nil
}

View File

@ -15,15 +15,24 @@ type Keeper struct {
cdc codec.BinaryCodec
storeKey storetypes.StoreKey
bankkeeper types.BankKeeper
bankKeeper types.BankKeeper
distrKeeper types.DistributionKeeper
stakingKeeper types.StakingKeeper
// The address that is capable of executing a MsgUpdateParams message. Typically this will be the
// governance module's address.
// The address that is capable of executing a MsgUpdateParams message.
// Typically this will be the governance module's address.
authority string
}
// NewKeeper creates a new keeper instance.
func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, accountKeeper types.AccountKeeper, bankkeeper types.BankKeeper, authority string) Keeper {
func NewKeeper(
cdc codec.BinaryCodec,
storeKey storetypes.StoreKey,
accountKeeper types.AccountKeeper,
bankKeeper types.BankKeeper,
distrKeeper types.DistributionKeeper,
stakingKeeper types.StakingKeeper,
authority string,
) Keeper {
// Ensure that the authority address is valid.
if _, err := sdk.AccAddressFromBech32(authority); err != nil {
panic(err)
@ -35,10 +44,12 @@ func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, accountKeepe
}
return Keeper{
cdc: cdc,
storeKey: storeKey,
bankkeeper: bankkeeper,
authority: authority,
cdc: cdc,
storeKey: storeKey,
bankKeeper: bankKeeper,
distrKeeper: distrKeeper,
stakingKeeper: stakingKeeper,
authority: authority,
}
}
@ -140,6 +151,16 @@ func (k Keeper) GetMinBidIncrement(ctx sdk.Context) (sdk.Coins, error) {
return params.MinBidIncrement, nil
}
// GetProposerFee returns the proposer fee for the auction module.
func (k Keeper) GetProposerFee(ctx sdk.Context) (sdk.Dec, error) {
params, err := k.GetParams(ctx)
if err != nil {
return sdk.ZeroDec(), err
}
return params.ProposerFee, nil
}
// FrontRunningProtectionEnabled returns true if front-running protection is enabled.
func (k Keeper) FrontRunningProtectionEnabled(ctx sdk.Context) (bool, error) {
params, err := k.GetParams(ctx)

View File

@ -1,22 +1,11 @@
package keeper_test
import (
"math/rand"
"reflect"
"testing"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/golang/mock/gomock"
"github.com/skip-mev/pob/mempool"
"github.com/skip-mev/pob/x/auction/ante"
@ -26,12 +15,14 @@ import (
"github.com/stretchr/testify/suite"
)
type IntegrationTestSuite struct {
type KeeperTestSuite struct {
suite.Suite
auctionKeeper keeper.Keeper
bankKeeper *MockBankKeeper
accountKeeper *MockAccountKeeper
distrKeeper *MockDistributionKeeper
stakingKeeper *MockStakingKeeper
encCfg encodingConfig
AuctionDecorator sdk.AnteDecorator
ctx sdk.Context
@ -43,22 +34,33 @@ type IntegrationTestSuite struct {
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
suite.Run(t, new(KeeperTestSuite))
}
func (suite *IntegrationTestSuite) SetupTest() {
func (suite *KeeperTestSuite) SetupTest() {
suite.encCfg = createTestEncodingConfig()
suite.key = sdk.NewKVStoreKey(types.StoreKey)
testCtx := testutil.DefaultContextWithDB(suite.T(), suite.key, sdk.NewTransientStoreKey("transient_test"))
suite.ctx = testCtx.Ctx
// Auction Keeper setup
ctrl := gomock.NewController(suite.T())
suite.accountKeeper = NewMockAccountKeeper(ctrl)
suite.accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(sdk.AccAddress{}).AnyTimes()
suite.bankKeeper = NewMockBankKeeper(ctrl)
suite.distrKeeper = NewMockDistributionKeeper(ctrl)
suite.stakingKeeper = NewMockStakingKeeper(ctrl)
suite.authorityAccount = sdk.AccAddress([]byte("authority"))
suite.auctionKeeper = keeper.NewKeeper(suite.encCfg.Codec, suite.key, suite.accountKeeper, suite.bankKeeper, suite.authorityAccount.String())
suite.auctionKeeper = keeper.NewKeeper(
suite.encCfg.Codec,
suite.key,
suite.accountKeeper,
suite.bankKeeper,
suite.distrKeeper,
suite.stakingKeeper,
suite.authorityAccount.String(),
)
err := suite.auctionKeeper.SetParams(suite.ctx, types.DefaultParams())
suite.Require().NoError(err)
@ -67,157 +69,3 @@ func (suite *IntegrationTestSuite) SetupTest() {
suite.AuctionDecorator = ante.NewAuctionDecorator(suite.auctionKeeper, suite.encCfg.TxConfig.TxDecoder(), suite.mempool)
suite.msgServer = keeper.NewMsgServerImpl(suite.auctionKeeper)
}
type encodingConfig struct {
InterfaceRegistry codectypes.InterfaceRegistry
Codec codec.Codec
TxConfig client.TxConfig
Amino *codec.LegacyAmino
}
func createTestEncodingConfig() encodingConfig {
cdc := codec.NewLegacyAmino()
interfaceRegistry := codectypes.NewInterfaceRegistry()
banktypes.RegisterInterfaces(interfaceRegistry)
cryptocodec.RegisterInterfaces(interfaceRegistry)
codec := codec.NewProtoCodec(interfaceRegistry)
return encodingConfig{
InterfaceRegistry: interfaceRegistry,
Codec: codec,
TxConfig: tx.NewTxConfig(codec, tx.DefaultSignModes),
Amino: cdc,
}
}
type Account struct {
PrivKey cryptotypes.PrivKey
PubKey cryptotypes.PubKey
Address sdk.AccAddress
ConsKey cryptotypes.PrivKey
}
func (acc Account) Equals(acc2 Account) bool {
return acc.Address.Equals(acc2.Address)
}
// RandomAccounts returns a slice of n random accounts.
func RandomAccounts(r *rand.Rand, n int) []Account {
accs := make([]Account, n)
for i := 0; i < n; i++ {
pkSeed := make([]byte, 15)
r.Read(pkSeed)
accs[i].PrivKey = secp256k1.GenPrivKeyFromSecret(pkSeed)
accs[i].PubKey = accs[i].PrivKey.PubKey()
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
accs[i].ConsKey = ed25519.GenPrivKeyFromSecret(pkSeed)
}
return accs
}
// MockAccountKeeper is a mock of AccountKeeper interface.
type MockAccountKeeper struct {
ctrl *gomock.Controller
recorder *MockAccountKeeperMockRecorder
}
// MockAccountKeeperMockRecorder is the mock recorder for MockAccountKeeper.
type MockAccountKeeperMockRecorder struct {
mock *MockAccountKeeper
}
// NewMockAccountKeeper creates a new mock instance.
func NewMockAccountKeeper(ctrl *gomock.Controller) *MockAccountKeeper {
mock := &MockAccountKeeper{ctrl: ctrl}
mock.recorder = &MockAccountKeeperMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockAccountKeeper) EXPECT() *MockAccountKeeperMockRecorder {
return m.recorder
}
// GetModuleAddress mocks base method.
func (m *MockAccountKeeper) GetModuleAddress(name string) sdk.AccAddress {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetModuleAddress", name)
ret0, _ := ret[0].(sdk.AccAddress)
return ret0
}
// GetModuleAddress indicates an expected call of GetModuleAddress.
func (mr *MockAccountKeeperMockRecorder) GetModuleAddress(name interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAddress", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAddress), name)
}
// MockBankKeeper is a mock of BankKeeper interface.
type MockBankKeeper struct {
ctrl *gomock.Controller
recorder *MockBankKeeperMockRecorder
}
// MockBankKeeperMockRecorder is the mock recorder for MockBankKeeper.
type MockBankKeeperMockRecorder struct {
mock *MockBankKeeper
}
// NewMockBankKeeper creates a new mock instance.
func NewMockBankKeeper(ctrl *gomock.Controller) *MockBankKeeper {
mock := &MockBankKeeper{ctrl: ctrl}
mock.recorder = &MockBankKeeperMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockBankKeeper) EXPECT() *MockBankKeeperMockRecorder {
return m.recorder
}
// GetAllBalances mocks base method.
func (m *MockBankKeeper) GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAllBalances", ctx, addr)
ret0 := ret[0].(sdk.Coins)
return ret0
}
// GetAllBalances indicates an expected call of GetAllBalances.
func (mr *MockBankKeeperMockRecorder) GetAllBalances(ctx, addr interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllBalances", reflect.TypeOf((*MockBankKeeper)(nil).GetAllBalances), ctx, addr)
}
// SendCoins mocks base method.
func (m *MockBankKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SendCoins", ctx, fromAddr, toAddr, amt)
return nil
}
// SendCoins indicates an expected call of SendCoins.
func (mr *MockBankKeeperMockRecorder) SendCoins(ctx, fromAddr, toAddr, amt interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoins", reflect.TypeOf((*MockBankKeeper)(nil).SendCoins), ctx, fromAddr, toAddr, amt)
}
// SendCoinsFromAccountToModule mocks base method.
func (m *MockBankKeeper) SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SendCoinsFromAccountToModule", ctx, senderAddr, recipientModule, amt)
ret0, _ := ret[0].(error)
return ret0
}
// SendCoinsFromAccountToModule indicates an expected call of SendCoinsFromAccountToModule.
func (mr *MockBankKeeperMockRecorder) SendCoinsFromAccountToModule(ctx, senderAddr, recipientModule, amt interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromAccountToModule", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromAccountToModule), ctx, senderAddr, recipientModule, amt)
}

View File

@ -0,0 +1,144 @@
package keeper_test
import (
"reflect"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/golang/mock/gomock"
)
type MockAccountKeeper struct {
ctrl *gomock.Controller
recorder *MockAccountKeeperMockRecorder
}
type MockAccountKeeperMockRecorder struct {
mock *MockAccountKeeper
}
func NewMockAccountKeeper(ctrl *gomock.Controller) *MockAccountKeeper {
mock := &MockAccountKeeper{ctrl: ctrl}
mock.recorder = &MockAccountKeeperMockRecorder{mock}
return mock
}
func (m *MockAccountKeeper) EXPECT() *MockAccountKeeperMockRecorder {
return m.recorder
}
func (m *MockAccountKeeper) GetModuleAddress(name string) sdk.AccAddress {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetModuleAddress", name)
ret0, _ := ret[0].(sdk.AccAddress)
return ret0
}
func (mr *MockAccountKeeperMockRecorder) GetModuleAddress(name interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAddress", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAddress), name)
}
type MockBankKeeper struct {
ctrl *gomock.Controller
recorder *MockBankKeeperMockRecorder
}
type MockBankKeeperMockRecorder struct {
mock *MockBankKeeper
}
func NewMockBankKeeper(ctrl *gomock.Controller) *MockBankKeeper {
mock := &MockBankKeeper{ctrl: ctrl}
mock.recorder = &MockBankKeeperMockRecorder{mock}
return mock
}
func (m *MockBankKeeper) EXPECT() *MockBankKeeperMockRecorder {
return m.recorder
}
func (m *MockBankKeeper) GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAllBalances", ctx, addr)
ret0 := ret[0].(sdk.Coins)
return ret0
}
func (mr *MockBankKeeperMockRecorder) GetAllBalances(ctx, addr interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllBalances", reflect.TypeOf((*MockBankKeeper)(nil).GetAllBalances), ctx, addr)
}
func (m *MockBankKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SendCoins", ctx, fromAddr, toAddr, amt)
return nil
}
func (mr *MockBankKeeperMockRecorder) SendCoins(ctx, fromAddr, toAddr, amt interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoins", reflect.TypeOf((*MockBankKeeper)(nil).SendCoins), ctx, fromAddr, toAddr, amt)
}
type MockDistributionKeeperRecorder struct {
mock *MockDistributionKeeper
}
type MockDistributionKeeper struct {
ctrl *gomock.Controller
recorder *MockDistributionKeeperRecorder
}
func NewMockDistributionKeeper(ctrl *gomock.Controller) *MockDistributionKeeper {
mock := &MockDistributionKeeper{ctrl: ctrl}
mock.recorder = &MockDistributionKeeperRecorder{mock}
return mock
}
func (m *MockDistributionKeeper) EXPECT() *MockDistributionKeeperRecorder {
return m.recorder
}
func (m *MockDistributionKeeper) GetPreviousProposerConsAddr(ctx sdk.Context) sdk.ConsAddress {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetPreviousProposerConsAddr", ctx)
ret0 := ret[0].(sdk.ConsAddress)
return ret0
}
func (mr *MockDistributionKeeperRecorder) GetPreviousProposerConsAddr(ctx any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPreviousProposerConsAddr", reflect.TypeOf((*MockDistributionKeeper)(nil).GetPreviousProposerConsAddr), ctx)
}
type MockStakingKeeperRecorder struct {
mock *MockStakingKeeper
}
type MockStakingKeeper struct {
ctrl *gomock.Controller
recorder *MockStakingKeeperRecorder
}
func NewMockStakingKeeper(ctrl *gomock.Controller) *MockStakingKeeper {
mock := &MockStakingKeeper{ctrl: ctrl}
mock.recorder = &MockStakingKeeperRecorder{mock}
return mock
}
func (m *MockStakingKeeper) EXPECT() *MockStakingKeeperRecorder {
return m.recorder
}
func (m *MockStakingKeeper) ValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) stakingtypes.ValidatorI {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ValidatorByConsAddr", ctx, consAddr)
ret0 := ret[0].(stakingtypes.ValidatorI)
return ret0
}
func (mr *MockStakingKeeperRecorder) ValidatorByConsAddr(ctx, consAddr any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatorByConsAddr", reflect.TypeOf((*MockStakingKeeper)(nil).ValidatorByConsAddr), ctx, consAddr)
}

View File

@ -20,18 +20,19 @@ func NewMsgServerImpl(keeper Keeper) *MsgServer {
return &MsgServer{Keeper: keeper}
}
// AuctionBid is the server implementation for Msg/AuctionBid.
func (m MsgServer) AuctionBid(goCtx context.Context, msg *types.MsgAuctionBid) (*types.MsgAuctionBidResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// This should never return an error because the address was validated when the message was ingressed.
// This should never return an error because the address was validated when
// the message was ingressed.
bidder, err := sdk.AccAddressFromBech32(msg.Bidder)
if err != nil {
return nil, err
}
// Ensure that the number of transactions is less than or equal to the maximum allowed.
maxBundleSize, err := m.Keeper.GetMaxBundleSize(ctx)
// Ensure that the number of transactions is less than or equal to the maximum
// allowed.
maxBundleSize, err := m.GetMaxBundleSize(ctx)
if err != nil {
return nil, err
}
@ -40,27 +41,54 @@ func (m MsgServer) AuctionBid(goCtx context.Context, msg *types.MsgAuctionBid) (
return nil, fmt.Errorf("the number of transactions in the bid is greater than the maximum allowed; expected <= %d, got %d", maxBundleSize, len(msg.Transactions))
}
// Attempt to send the bid to the module account.
if err := m.Keeper.bankkeeper.SendCoinsFromAccountToModule(ctx, bidder, types.ModuleName, msg.Bid); err != nil {
proposerFee, err := m.GetProposerFee(ctx)
if err != nil {
return nil, err
}
// TODO: figure out how to handle payments to the escrow address.
// Ref: https://github.com/skip-mev/pob/issues/11
escrow, err := m.Keeper.GetEscrowAccount(ctx)
if err != nil {
return nil, err
}
if proposerFee.IsZero() {
// send the entire bid to the escrow account when no proposer fee is set
if err := m.bankKeeper.SendCoins(ctx, bidder, escrow, msg.Bid); err != nil {
return nil, err
}
} else {
prevPropConsAddr := m.distrKeeper.GetPreviousProposerConsAddr(ctx)
prevProposer := m.stakingKeeper.ValidatorByConsAddr(ctx, prevPropConsAddr)
// determine the amount of the bid that goes to the (previous) proposer
bid := sdk.NewDecCoinsFromCoins(msg.Bid...)
proposerReward, _ := bid.MulDecTruncate(proposerFee).TruncateDecimal()
if err := m.bankKeeper.SendCoins(ctx, bidder, sdk.AccAddress(prevProposer.GetOperator()), proposerReward); err != nil {
return nil, err
}
// Determine the amount of the remaining bid that goes to the escrow account.
// If a decimal remainder exists, it'll stay with the bidding account.
escrowTotal := bid.Sub(sdk.NewDecCoinsFromCoins(proposerReward...))
escrowReward, _ := escrowTotal.TruncateDecimal()
if err := m.bankKeeper.SendCoins(ctx, bidder, escrow, escrowReward); err != nil {
return nil, err
}
}
return &types.MsgAuctionBidResponse{}, nil
}
// UpdateParams is the server implementation for Msg/UpdateParams.
func (m MsgServer) UpdateParams(goCtx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// Ensure that the message signer is the authority.
// ensure that the message signer is the authority
if msg.Authority != m.Keeper.GetAuthority() {
return nil, fmt.Errorf("this message can only be executed by the authority; expected %s, got %s", m.Keeper.GetAuthority(), msg.Authority)
}
// Update the parameters.
if err := m.Keeper.SetParams(ctx, msg.Params); err != nil {
return nil, err
}

View File

@ -0,0 +1,127 @@
package keeper_test
import (
"math/rand"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/skip-mev/pob/x/auction/types"
)
func (suite *KeeperTestSuite) TestMsgAuctionBid() {
rng := rand.New(rand.NewSource(time.Now().Unix()))
accounts := RandomAccounts(rng, 4)
bidder := accounts[0]
escrow := accounts[1]
proposerCons := accounts[2]
proposerOperator := accounts[3]
proposer := stakingtypes.Validator{
OperatorAddress: sdk.ValAddress(proposerOperator.Address).String(),
}
testCases := []struct {
name string
msg *types.MsgAuctionBid
malleate func()
expectErr bool
}{
{
name: "invalid bidder address",
msg: &types.MsgAuctionBid{
Bidder: "foo",
},
malleate: func() {},
expectErr: true,
},
{
name: "too many bundled transactions",
msg: &types.MsgAuctionBid{
Bidder: bidder.Address.String(),
Transactions: [][]byte{{0xFF}, {0xFF}, {0xFF}},
},
malleate: func() {
params := types.DefaultParams()
params.MaxBundleSize = 2
suite.auctionKeeper.SetParams(suite.ctx, params)
},
expectErr: true,
},
{
name: "valid bundle with no proposer fee",
msg: &types.MsgAuctionBid{
Bidder: bidder.Address.String(),
Bid: sdk.NewCoins(sdk.NewInt64Coin("foo", 1024)),
Transactions: [][]byte{{0xFF}, {0xFF}},
},
malleate: func() {
params := types.DefaultParams()
params.ProposerFee = sdk.ZeroDec()
params.EscrowAccountAddress = escrow.Address.String()
suite.auctionKeeper.SetParams(suite.ctx, params)
suite.bankKeeper.EXPECT().
SendCoins(
suite.ctx,
bidder.Address,
escrow.Address,
sdk.NewCoins(sdk.NewInt64Coin("foo", 1024)),
).
Return(nil).
AnyTimes()
},
expectErr: false,
},
{
name: "valid bundle with proposer fee",
msg: &types.MsgAuctionBid{
Bidder: bidder.Address.String(),
Bid: sdk.NewCoins(sdk.NewInt64Coin("foo", 3416)),
Transactions: [][]byte{{0xFF}, {0xFF}},
},
malleate: func() {
params := types.DefaultParams()
params.ProposerFee = sdk.MustNewDecFromStr("0.30")
params.EscrowAccountAddress = escrow.Address.String()
suite.auctionKeeper.SetParams(suite.ctx, params)
suite.distrKeeper.EXPECT().
GetPreviousProposerConsAddr(suite.ctx).
Return(proposerCons.ConsKey.PubKey().Address().Bytes())
suite.stakingKeeper.EXPECT().
ValidatorByConsAddr(suite.ctx, sdk.ConsAddress(proposerCons.ConsKey.PubKey().Address().Bytes())).
Return(proposer).
AnyTimes()
suite.bankKeeper.EXPECT().
SendCoins(suite.ctx, bidder.Address, proposerOperator.Address, sdk.NewCoins(sdk.NewInt64Coin("foo", 1024))).
Return(nil)
suite.bankKeeper.EXPECT().
SendCoins(suite.ctx, bidder.Address, escrow.Address, sdk.NewCoins(sdk.NewInt64Coin("foo", 2392))).
Return(nil)
},
expectErr: false,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
tc.malleate()
_, err := suite.msgServer.AuctionBid(suite.ctx, tc.msg)
if tc.expectErr {
suite.Require().Error(err)
} else {
suite.Require().NoError(err)
}
})
}
}
func (suite *KeeperTestSuite) TestMsgUpdateParams() {
suite.T().SkipNow()
}

View File

@ -0,0 +1,99 @@
package keeper_test
import (
"math/rand"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
type encodingConfig struct {
InterfaceRegistry codectypes.InterfaceRegistry
Codec codec.Codec
TxConfig client.TxConfig
Amino *codec.LegacyAmino
}
func createTestEncodingConfig() encodingConfig {
cdc := codec.NewLegacyAmino()
interfaceRegistry := codectypes.NewInterfaceRegistry()
banktypes.RegisterInterfaces(interfaceRegistry)
cryptocodec.RegisterInterfaces(interfaceRegistry)
codec := codec.NewProtoCodec(interfaceRegistry)
return encodingConfig{
InterfaceRegistry: interfaceRegistry,
Codec: codec,
TxConfig: tx.NewTxConfig(codec, tx.DefaultSignModes),
Amino: cdc,
}
}
type Account struct {
PrivKey cryptotypes.PrivKey
PubKey cryptotypes.PubKey
Address sdk.AccAddress
ConsKey cryptotypes.PrivKey
}
func (acc Account) Equals(acc2 Account) bool {
return acc.Address.Equals(acc2.Address)
}
func RandomAccounts(r *rand.Rand, n int) []Account {
accs := make([]Account, n)
for i := 0; i < n; i++ {
pkSeed := make([]byte, 15)
r.Read(pkSeed)
accs[i].PrivKey = secp256k1.GenPrivKeyFromSecret(pkSeed)
accs[i].PubKey = accs[i].PrivKey.PubKey()
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
accs[i].ConsKey = ed25519.GenPrivKeyFromSecret(pkSeed)
}
return accs
}
func createRandomTx(txCfg client.TxConfig, account Account, nonce, numberMsgs uint64) (authsigning.Tx, error) {
msgs := make([]sdk.Msg, numberMsgs)
for i := 0; i < int(numberMsgs); i++ {
msgs[i] = &banktypes.MsgSend{
FromAddress: account.Address.String(),
ToAddress: account.Address.String(),
}
}
txBuilder := txCfg.NewTxBuilder()
if err := txBuilder.SetMsgs(msgs...); err != nil {
return nil, err
}
sigV2 := signing.SignatureV2{
PubKey: account.PrivKey.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: txCfg.SignModeHandler().DefaultMode(),
Signature: nil,
},
Sequence: nonce,
}
if err := txBuilder.SetSignatures(sigV2); err != nil {
return nil, err
}
return txBuilder.GetTx(), nil
}

View File

@ -26,7 +26,6 @@ var (
// ConsensusVersion defines the current x/auction module consensus version.
const ConsensusVersion = 1
// -------------------- AppModuleBasic -------------------- //
// AppModuleBasic defines the basic application module used by the auction module.
type AppModuleBasic struct {
cdc codec.Codec
@ -70,16 +69,11 @@ func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *r
}
// GetTxCmd returns the root tx command for the auction module.
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return nil
}
func (AppModuleBasic) GetTxCmd() *cobra.Command { return nil }
// GetQueryCmd returns no root query command for the auction module.
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
return nil
}
func (AppModuleBasic) GetQueryCmd() *cobra.Command { return nil }
// -------------------- AppModule -------------------- //
type AppModule struct {
AppModuleBasic
@ -98,7 +92,11 @@ func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, accountKeeper types.Acc
}
}
// RegisterServices registers a the gRPC Query and Msg services for the auciton module.
// ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return ConsensusVersion }
// RegisterServices registers a the gRPC Query and Msg services for the x/auction
// module.
func (am AppModule) RegisterServices(cfg module.Configurator) {
// TODO: Define the gRPC querier service and register it with the auction module configurator
// TODO: Define the gRPC Msg service and register it with the auction module configurator
@ -106,33 +104,24 @@ func (am AppModule) RegisterServices(cfg module.Configurator) {
func (a AppModuleBasic) RegisterRESTRoutes(ctx client.Context, r *mux.Router) {}
// RegisterInvariants registers the invariants of the module. If an invariant deviates from its predicted value, the InvariantRegistry triggers appropriate logic (most often the chain will be halted)
// RegisterInvariants registers the invariants of the module. If an invariant
// deviates from its predicted value, the InvariantRegistry triggers appropriate
// logic (most often the chain will be halted).
func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
// InitGenesis performs the module's genesis initialization for the auction module. It returns no validator updates.
// InitGenesis performs the module's genesis initialization for the auction
// module. It returns no validator updates.
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate {
var genState types.GenesisState
cdc.MustUnmarshalJSON(gs, &genState)
am.keeper.InitGenesis(ctx, genState)
return []abci.ValidatorUpdate{}
}
// ExportGenesis returns the auction module's exported genesis state as raw JSON bytes.
// ExportGenesis returns the auction module's exported genesis state as raw
// JSON bytes.
func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage {
genState := am.keeper.ExportGenesis(ctx)
return cdc.MustMarshalJSON(genState)
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return ConsensusVersion }
// BeginBlock returns the begin blocker for the auction module.
func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} //nolint
// EndBlock returns the end blocker for the auction module. It returns no validator updates.
func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { //nolint
return []abci.ValidatorUpdate{}
}

View File

@ -2,16 +2,27 @@ package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
// AccountKeeper defines the contract required for account APIs.
// BankKeeper defines the expected API contract for the x/auth module.
type AccountKeeper interface {
GetModuleAddress(moduleName string) sdk.AccAddress
}
// BankKeeper defines the contract required for bank APIs.
// BankKeeper defines the expected API contract for the x/bank module.
type BankKeeper interface {
SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
}
// DistributionKeeper defines the expected API contract for the x/distribution
// module.
type DistributionKeeper interface {
GetPreviousProposerConsAddr(ctx sdk.Context) sdk.ConsAddress
}
// StakingKeeper defines the expected API contract for the x/staking module.
type StakingKeeper interface {
ValidatorByConsAddr(sdk.Context, sdk.ConsAddress) stakingtypes.ValidatorI
}

View File

@ -76,19 +76,23 @@ type Params struct {
// max_bundle_size is the maximum number of transactions that can be bundled
// in a single bundle.
MaxBundleSize uint32 `protobuf:"varint,1,opt,name=max_bundle_size,json=maxBundleSize,proto3" json:"max_bundle_size,omitempty"`
// escrow_account_address is the address of the account that will hold the
// funds for the auctions.
// escrow_account_address is the address of the account that will receive a
// portion of the bid proceeds.
EscrowAccountAddress string `protobuf:"bytes,2,opt,name=escrow_account_address,json=escrowAccountAddress,proto3" json:"escrow_account_address,omitempty"`
// reserve_fee specifies the bid floor for the auction.
ReserveFee github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=reserve_fee,json=reserveFee,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"reserve_fee"`
// min_buy_in_fee specifies the fee that the bidder must pay to enter the auction.
// min_buy_in_fee specifies the fee that the bidder must pay to enter the
// auction.
MinBuyInFee github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,4,rep,name=min_buy_in_fee,json=minBuyInFee,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"min_buy_in_fee"`
// min_bid_increment specifies the minimum amount that the next bid must be
// greater than the previous bid.
MinBidIncrement github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,5,rep,name=min_bid_increment,json=minBidIncrement,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"min_bid_increment"`
// front_running_protection specifies whether front running and sandwich attack protection
// is enabled.
// front_running_protection specifies whether front running and sandwich
// attack protection is enabled.
FrontRunningProtection bool `protobuf:"varint,6,opt,name=front_running_protection,json=frontRunningProtection,proto3" json:"front_running_protection,omitempty"`
// proposer_fee defines the portion of the winning bid that goes to the block
// proposer that proposed the block.
ProposerFee github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,7,opt,name=proposer_fee,json=proposerFee,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"proposer_fee"`
}
func (m *Params) Reset() { *m = Params{} }
@ -174,37 +178,40 @@ func init() {
func init() { proto.RegisterFile("pob/auction/v1/genesis.proto", fileDescriptor_9ed8651e43f855a1) }
var fileDescriptor_9ed8651e43f855a1 = []byte{
// 480 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0xb1, 0x6e, 0xd4, 0x30,
0x18, 0xc7, 0x2f, 0xf4, 0x38, 0x81, 0x8f, 0x52, 0x35, 0xaa, 0x4e, 0xa1, 0xa0, 0x34, 0xea, 0x00,
0x51, 0xa5, 0xda, 0xba, 0x02, 0x12, 0x42, 0x2c, 0x77, 0x48, 0xa0, 0x4a, 0x0c, 0x55, 0xba, 0xb1,
0x58, 0x4e, 0xf2, 0x35, 0x58, 0xc5, 0x76, 0x88, 0x9d, 0x70, 0x57, 0xf1, 0x04, 0x4c, 0x3c, 0x06,
0xea, 0xd4, 0xc7, 0xe8, 0xd8, 0x91, 0x09, 0xd0, 0xdd, 0xd0, 0xd7, 0x40, 0xb1, 0x43, 0xe9, 0xc0,
0xda, 0x25, 0x89, 0xfc, 0xfb, 0xec, 0xdf, 0xf7, 0x45, 0x7f, 0xa3, 0x47, 0xa5, 0x4a, 0x09, 0xab,
0x33, 0xc3, 0x95, 0x24, 0xcd, 0x98, 0x14, 0x20, 0x41, 0x73, 0x8d, 0xcb, 0x4a, 0x19, 0xe5, 0x8f,
0xf4, 0x31, 0x2f, 0x05, 0x34, 0xb8, 0x54, 0x29, 0xee, 0xaa, 0x70, 0x33, 0xde, 0xdc, 0x28, 0x54,
0xa1, 0x6c, 0x09, 0x69, 0xbf, 0x5c, 0xf5, 0x66, 0x98, 0x29, 0x2d, 0x94, 0x26, 0x29, 0xd3, 0x40,
0x9a, 0x71, 0x0a, 0x86, 0x8d, 0x49, 0xa6, 0xb8, 0xec, 0xf8, 0x3a, 0x13, 0x5c, 0x2a, 0x62, 0x9f,
0x6e, 0x69, 0xfb, 0x1d, 0xba, 0xf7, 0xd6, 0x19, 0x0f, 0x0d, 0x33, 0xe0, 0xbf, 0x42, 0x83, 0x92,
0x55, 0x4c, 0xe8, 0xc0, 0x8b, 0xbc, 0x78, 0xb8, 0x17, 0xe2, 0xff, 0x77, 0x80, 0x0f, 0x6c, 0xd5,
0xb4, 0x7f, 0xfe, 0x73, 0xab, 0x97, 0x74, 0x7b, 0xb6, 0x4f, 0xfb, 0x68, 0xe0, 0x80, 0xff, 0x18,
0xad, 0x09, 0x36, 0xa3, 0x69, 0x2d, 0xf3, 0x8f, 0x40, 0x35, 0x3f, 0x01, 0x7b, 0xe2, 0x6a, 0xb2,
0x2a, 0xd8, 0x6c, 0x6a, 0x57, 0x0f, 0xf9, 0x09, 0xf8, 0xcf, 0xd0, 0x08, 0x74, 0x56, 0xa9, 0xcf,
0x94, 0x65, 0x99, 0xaa, 0xa5, 0xa1, 0x2c, 0xcf, 0x2b, 0xd0, 0x3a, 0xb8, 0x15, 0x79, 0xf1, 0xdd,
0x64, 0xc3, 0xd1, 0x89, 0x83, 0x13, 0xc7, 0xfc, 0x4f, 0x68, 0x58, 0x81, 0x86, 0xaa, 0x01, 0x7a,
0x04, 0x10, 0xac, 0x44, 0x2b, 0xf1, 0x70, 0xef, 0x01, 0x76, 0xf3, 0xe3, 0x76, 0x7e, 0xdc, 0xcd,
0x8f, 0x5f, 0x2b, 0x2e, 0xa7, 0xcf, 0xdb, 0x36, 0x4f, 0x7f, 0x6d, 0xc5, 0x05, 0x37, 0x1f, 0xea,
0x14, 0x67, 0x4a, 0x90, 0xee, 0x67, 0xb9, 0xd7, 0xae, 0xce, 0x8f, 0x89, 0x99, 0x97, 0xa0, 0xed,
0x06, 0xfd, 0xfd, 0xf2, 0x6c, 0xc7, 0x4b, 0x50, 0x27, 0x79, 0x03, 0xe0, 0xd7, 0xe8, 0xbe, 0xe0,
0x92, 0xa6, 0xf5, 0x9c, 0x72, 0x69, 0xad, 0xfd, 0x1b, 0xb2, 0x0e, 0x05, 0x97, 0xd3, 0x7a, 0xbe,
0x2f, 0x5b, 0xed, 0x17, 0xb4, 0x6e, 0xb5, 0x3c, 0xa7, 0x5c, 0x66, 0x15, 0x08, 0x90, 0x26, 0xb8,
0x7d, 0x43, 0xe6, 0xb5, 0xd6, 0xcc, 0xf3, 0xfd, 0xbf, 0x22, 0xff, 0x05, 0x0a, 0x8e, 0x2a, 0x25,
0x0d, 0xad, 0x6a, 0x29, 0xb9, 0x2c, 0x68, 0x9b, 0x1a, 0xb0, 0x21, 0x08, 0x06, 0x91, 0x17, 0xdf,
0x49, 0x46, 0x96, 0x27, 0x0e, 0x1f, 0x5c, 0xd1, 0x97, 0xd1, 0xd7, 0xcb, 0xb3, 0x9d, 0x87, 0xd7,
0x64, 0xb3, 0xab, 0x94, 0x77, 0xd1, 0x99, 0x9c, 0x2f, 0x42, 0xef, 0x62, 0x11, 0x7a, 0xbf, 0x17,
0xa1, 0xf7, 0x6d, 0x19, 0xf6, 0x2e, 0x96, 0x61, 0xef, 0xc7, 0x32, 0xec, 0xbd, 0x7f, 0x72, 0xad,
0xeb, 0x36, 0x7e, 0xbb, 0x02, 0x1a, 0xd2, 0xde, 0x93, 0x7f, 0x67, 0xd8, 0xd6, 0xd3, 0x81, 0x0d,
0xf1, 0xd3, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x96, 0x16, 0x18, 0xc6, 0x45, 0x03, 0x00, 0x00,
// 517 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0x31, 0x6f, 0xd3, 0x40,
0x14, 0xc7, 0x63, 0x1a, 0x02, 0x5c, 0x5a, 0xaa, 0x5a, 0x55, 0x64, 0x0a, 0x72, 0xa2, 0x0e, 0x25,
0xaa, 0xd4, 0x3b, 0xa5, 0x80, 0x84, 0x10, 0x4b, 0x02, 0x2a, 0xaa, 0xc4, 0x50, 0xdc, 0x8d, 0xc5,
0x3a, 0xdb, 0xaf, 0xe1, 0x54, 0xee, 0xce, 0xdc, 0xd9, 0x26, 0xa9, 0xf8, 0x04, 0x4c, 0x7c, 0x0c,
0xc4, 0xd4, 0x8f, 0xd1, 0xb1, 0x23, 0x62, 0x28, 0x28, 0x19, 0xfa, 0x29, 0x90, 0xd0, 0xdd, 0xb9,
0xa5, 0x03, 0x03, 0x4b, 0x17, 0xdb, 0xba, 0xff, 0xff, 0xde, 0xef, 0xbd, 0xe7, 0xf7, 0xd0, 0x83,
0x5c, 0x26, 0x84, 0x96, 0x69, 0xc1, 0xa4, 0x20, 0xd5, 0x80, 0x8c, 0x41, 0x80, 0x66, 0x1a, 0xe7,
0x4a, 0x16, 0xd2, 0xef, 0xe8, 0x43, 0x96, 0x73, 0xa8, 0x70, 0x2e, 0x13, 0x5c, 0xbb, 0x70, 0x35,
0x58, 0x5b, 0x1d, 0xcb, 0xb1, 0xb4, 0x16, 0x62, 0xbe, 0x9c, 0x7b, 0x2d, 0x4c, 0xa5, 0xe6, 0x52,
0x93, 0x84, 0x6a, 0x20, 0xd5, 0x20, 0x81, 0x82, 0x0e, 0x48, 0x2a, 0x99, 0xa8, 0xf5, 0x15, 0xca,
0x99, 0x90, 0xc4, 0x3e, 0xdd, 0xd1, 0xfa, 0x6b, 0xb4, 0xf8, 0xca, 0x11, 0xf7, 0x0b, 0x5a, 0x80,
0xff, 0x1c, 0xb5, 0x72, 0xaa, 0x28, 0xd7, 0x81, 0xd7, 0xf3, 0xfa, 0xed, 0xed, 0x10, 0xff, 0x3b,
0x03, 0xbc, 0x67, 0x5d, 0xa3, 0xe6, 0xc9, 0x59, 0xb7, 0x11, 0xd5, 0x77, 0xd6, 0x7f, 0x37, 0x51,
0xcb, 0x09, 0xfe, 0x06, 0x5a, 0xe6, 0x74, 0x12, 0x27, 0xa5, 0xc8, 0xde, 0x43, 0xac, 0xd9, 0x11,
0xd8, 0x88, 0x4b, 0xd1, 0x12, 0xa7, 0x93, 0x91, 0x3d, 0xdd, 0x67, 0x47, 0xe0, 0x3f, 0x46, 0x1d,
0xd0, 0xa9, 0x92, 0x1f, 0x63, 0x9a, 0xa6, 0xb2, 0x14, 0x45, 0x4c, 0xb3, 0x4c, 0x81, 0xd6, 0xc1,
0x8d, 0x9e, 0xd7, 0xbf, 0x13, 0xad, 0x3a, 0x75, 0xe8, 0xc4, 0xa1, 0xd3, 0xfc, 0x0f, 0xa8, 0xad,
0x40, 0x83, 0xaa, 0x20, 0x3e, 0x00, 0x08, 0x16, 0x7a, 0x0b, 0xfd, 0xf6, 0xf6, 0x3d, 0xec, 0xea,
0xc7, 0xa6, 0x7e, 0x5c, 0xd7, 0x8f, 0x5f, 0x48, 0x26, 0x46, 0x4f, 0x4c, 0x9a, 0xdf, 0x7e, 0x76,
0xfb, 0x63, 0x56, 0xbc, 0x2b, 0x13, 0x9c, 0x4a, 0x4e, 0xea, 0x66, 0xb9, 0xd7, 0x96, 0xce, 0x0e,
0x49, 0x31, 0xcd, 0x41, 0xdb, 0x0b, 0xfa, 0xeb, 0xf9, 0xf1, 0xa6, 0x17, 0xa1, 0x1a, 0xb2, 0x03,
0xe0, 0x97, 0xe8, 0x2e, 0x67, 0x22, 0x4e, 0xca, 0x69, 0xcc, 0x84, 0xa5, 0x36, 0xaf, 0x89, 0xda,
0xe6, 0x4c, 0x8c, 0xca, 0xe9, 0xae, 0x30, 0xd8, 0x4f, 0x68, 0xc5, 0x62, 0x59, 0x16, 0x33, 0x91,
0x2a, 0xe0, 0x20, 0x8a, 0xe0, 0xe6, 0x35, 0x91, 0x97, 0x0d, 0x99, 0x65, 0xbb, 0x17, 0x20, 0xff,
0x29, 0x0a, 0x0e, 0x94, 0x14, 0x45, 0xac, 0x4a, 0x21, 0x98, 0x18, 0xc7, 0x66, 0x6a, 0xc0, 0x0e,
0x41, 0xd0, 0xea, 0x79, 0xfd, 0xdb, 0x51, 0xc7, 0xea, 0x91, 0x93, 0xf7, 0x2e, 0x55, 0xff, 0x0d,
0x5a, 0xcc, 0x95, 0xcc, 0xa5, 0x06, 0x65, 0x9b, 0x75, 0xcb, 0xfc, 0xcd, 0x11, 0x36, 0x79, 0xfd,
0x38, 0xeb, 0x6e, 0xfc, 0x47, 0x5e, 0x2f, 0x21, 0x8d, 0xda, 0x17, 0x31, 0x76, 0x00, 0x9e, 0xf5,
0x3e, 0x9f, 0x1f, 0x6f, 0xde, 0xbf, 0xe2, 0x9b, 0x5c, 0x2e, 0x4e, 0x3d, 0x8d, 0xc3, 0x93, 0x59,
0xe8, 0x9d, 0xce, 0x42, 0xef, 0xd7, 0x2c, 0xf4, 0xbe, 0xcc, 0xc3, 0xc6, 0xe9, 0x3c, 0x6c, 0x7c,
0x9f, 0x87, 0x8d, 0xb7, 0x0f, 0xaf, 0x00, 0xcd, 0x44, 0x6f, 0x71, 0xa8, 0x88, 0x59, 0xbd, 0xbf,
0x31, 0x2c, 0x35, 0x69, 0xd9, 0xbd, 0x78, 0xf4, 0x27, 0x00, 0x00, 0xff, 0xff, 0x32, 0x3f, 0xb6,
0x9a, 0x98, 0x03, 0x00, 0x00,
}
func (m *GenesisState) Marshal() (dAtA []byte, err error) {
@ -260,6 +267,16 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
{
size := m.ProposerFee.Size()
i -= size
if _, err := m.ProposerFee.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x3a
if m.FrontRunningProtection {
i--
if m.FrontRunningProtection {
@ -383,6 +400,8 @@ func (m *Params) Size() (n int) {
if m.FrontRunningProtection {
n += 2
}
l = m.ProposerFee.Size()
n += 1 + l + sovGenesis(uint64(l))
return n
}
@ -677,6 +696,40 @@ func (m *Params) Unmarshal(dAtA []byte) error {
}
}
m.FrontRunningProtection = bool(v != 0)
case 7:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ProposerFee", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
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 ErrInvalidLengthGenesis
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.ProposerFee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenesis(dAtA[iNdEx:])

View File

@ -116,6 +116,7 @@ func TestMsgUpdateParams(t *testing.T) {
msg: types.MsgUpdateParams{
Authority: sdk.AccAddress([]byte("test")).String(),
Params: types.Params{
ProposerFee: sdk.NewDec(1),
EscrowAccountAddress: sdk.AccAddress([]byte("test")).String(),
},
},

View File

@ -3,6 +3,7 @@ package types
import (
fmt "fmt"
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -13,10 +14,17 @@ var (
DefaultMinBuyInFee = sdk.Coins{}
DefaultMinBidIncrement = sdk.Coins{}
DefaultFrontRunningProtection = true
DefaultProposerFee = sdk.ZeroDec()
)
// NewParams returns a new Params instance with the provided values.
func NewParams(maxBundleSize uint32, escrowAccountAddress string, reserveFee, minBuyInFee, minBidIncrement sdk.Coins, frontRunningProtection bool) Params {
func NewParams(
maxBundleSize uint32,
escrowAccountAddress string,
reserveFee, minBuyInFee, minBidIncrement sdk.Coins,
frontRunningProtection bool,
proposerFee sdk.Dec,
) Params {
return Params{
MaxBundleSize: maxBundleSize,
EscrowAccountAddress: escrowAccountAddress,
@ -24,6 +32,7 @@ func NewParams(maxBundleSize uint32, escrowAccountAddress string, reserveFee, mi
MinBuyInFee: minBuyInFee,
MinBidIncrement: minBidIncrement,
FrontRunningProtection: frontRunningProtection,
ProposerFee: proposerFee,
}
}
@ -36,6 +45,7 @@ func DefaultParams() Params {
DefaultMinBuyInFee,
DefaultMinBidIncrement,
DefaultFrontRunningProtection,
DefaultProposerFee,
)
}
@ -57,10 +67,29 @@ func (p Params) Validate() error {
return fmt.Errorf("invalid minimum bid increment (%s)", err)
}
if err := validateProposerFee(p.ProposerFee); err != nil {
return err
}
return nil
}
// validateEscrowAccountAddress ensures the escrow account address is a valid address (if set).
func validateProposerFee(v sdk.Dec) error {
if v.IsNil() {
return fmt.Errorf("proposer fee cannot be nil: %s", v)
}
if v.IsNegative() {
return fmt.Errorf("proposer fee cannot be negative: %s", v)
}
if v.GT(math.LegacyOneDec()) {
return fmt.Errorf("proposer fee too large: %s", v)
}
return nil
}
// validateEscrowAccountAddress ensures the escrow account address is a valid
// address.
func validateEscrowAccountAddress(account string) error {
// If the escrow account address is set, ensure it is a valid address.
if _, err := sdk.AccAddressFromBech32(account); err != nil {