Scaffolding basic module configurations (#5)

Co-authored-by: Aleksandr Bezobchuk <aleks.bezobchuk@gmail.com>
This commit is contained in:
David Terpay 2023-03-02 16:02:01 -05:00 committed by GitHub
parent 293ee765b9
commit aff1a26da9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 692 additions and 35 deletions

5
go.mod
View File

@ -3,13 +3,16 @@ module github.com/skip-mev/pob
go 1.20
require (
cosmossdk.io/api v0.3.1
cosmossdk.io/errors v1.0.0-beta.7
github.com/cosmos/cosmos-proto v1.0.0-beta.2
github.com/cosmos/cosmos-sdk v0.47.0-rc2.0.20230228000043-54240ec9ab19
github.com/cosmos/gogoproto v1.4.4
github.com/golang/protobuf v1.5.2
github.com/gorilla/mux v1.8.0
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/stretchr/testify v1.8.1
github.com/spf13/cobra v1.6.1
google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44
google.golang.org/grpc v1.53.0
)
@ -86,10 +89,10 @@ require (
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/spf13/afero v1.9.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cobra v1.6.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.14.0 // indirect
github.com/stretchr/testify v1.8.1 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect

8
go.sum
View File

@ -45,7 +45,6 @@ cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w
cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE=
cosmossdk.io/math v1.0.0-beta.6 h1:WF29SiFYNde5eYvqO2kdOM9nYbDb44j3YW5B8M1m9KE=
cosmossdk.io/math v1.0.0-beta.6/go.mod h1:gUVtWwIzfSXqcOT+lBVz2jyjfua8DoBdzRsIyaUAT/8=
cosmossdk.io/tools/rosetta v0.2.1 h1:ddOMatOH+pbxWbrGJKRAawdBkPYLfKXutK9IETnjYxw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
@ -81,8 +80,6 @@ github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
@ -127,7 +124,6 @@ github.com/cosmos/iavl v0.20.0-alpha4 h1:49SZoxNwah5nqbVE1da8BAhenC7HMSVOTZ0XKVh
github.com/cosmos/iavl v0.20.0-alpha4/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A=
github.com/cosmos/ledger-cosmos-go v0.12.1 h1:sMBxza5p/rNK/06nBSNmsI/WDqI0pVJFVNihy1Y984w=
github.com/cosmos/ledger-cosmos-go v0.12.1/go.mod h1:dhO6kj+Y+AHIOgAe4L9HL/6NDdyyth4q238I9yFpD2g=
github.com/cosmos/rosetta-sdk-go v0.10.0 h1:E5RhTruuoA7KTIXUcMicL76cffyeoyvNybzUGSKFTcM=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM=
@ -141,7 +137,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I=
github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o=
github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
@ -269,6 +264,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
@ -304,7 +300,6 @@ github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw
github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
@ -419,7 +414,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/regen-network/gocuke v0.6.2 h1:pHviZ0kKAq2U2hN2q3smKNxct6hS0mGByFMHGnWA97M=

View File

@ -26,7 +26,7 @@ message Params {
(amino.dont_omitempty) = true,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];
// min_buy_in_fee speficies the bid floor for the auction.
// min_buy_in_fee specifies the bid floor for the auction.
repeated cosmos.base.v1beta1.Coin min_buy_in_fee = 4 [
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true,

View File

View File

@ -0,0 +1,25 @@
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/skip-mev/pob/x/auction/types"
)
// InitGenesis initializes the auction module's state from a given genesis state.
func (k Keeper) InitGenesis(ctx sdk.Context, gs types.GenesisState) {
// Set the auction module's parameters.
if err := k.SetParams(ctx, gs.Params); err != nil {
panic(err)
}
}
// ExportGenesis returns a GenesisState for a given context.
func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
// Get the auction module's parameters.
params, err := k.GetParams(ctx)
if err != nil {
panic(err)
}
return types.NewGenesisState(params)
}

View File

@ -0,0 +1,34 @@
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/skip-mev/pob/x/auction/types"
)
var (
_ types.QueryServer = QueryServer{}
)
// QueryServer defines the auction module's gRPC querier service.
type QueryServer struct {
keeper Keeper
}
// NewQueryServer creates a new gRPC query server for the auction module.
func NewQueryServer(keeper Keeper) *QueryServer {
return &QueryServer{keeper: keeper}
}
// Params queries all parameters of the auction module.
func (q QueryServer) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
params, err := q.keeper.GetParams(ctx)
if err != nil {
return nil, err
}
return &types.QueryParamsResponse{Params: params}, nil
}

141
x/auction/keeper/keeper.go Normal file
View File

@ -0,0 +1,141 @@
package keeper
import (
"fmt"
"github.com/cometbft/cometbft/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/skip-mev/pob/x/auction/types"
)
type Keeper struct {
cdc codec.BinaryCodec
storeKey storetypes.StoreKey
bankkeeper types.BankKeeper
// 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 {
// Ensure that the authority address is valid.
if _, err := sdk.AccAddressFromBech32(authority); err != nil {
panic(err)
}
// Ensure that the auction module account exists.
if accountKeeper.GetModuleAddress(types.ModuleName) == nil {
panic("auction module account has not been set")
}
return Keeper{
cdc: cdc,
storeKey: storeKey,
bankkeeper: bankkeeper,
authority: authority,
}
}
// Logger returns an auction module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", "x/"+types.ModuleName)
}
// GetAuthority returns the address that is capable of executing a MsgUpdateParams message.
func (k Keeper) GetAuthority() string {
return k.authority
}
// GetParams returns the auction module's parameters.
func (k Keeper) GetParams(ctx sdk.Context) (types.Params, error) {
store := ctx.KVStore(k.storeKey)
key := types.KeyParams
bz := store.Get(key)
if len(bz) == 0 {
return types.Params{}, fmt.Errorf("no params found for the auction module")
}
params := types.Params{}
if err := params.Unmarshal(bz); err != nil {
return types.Params{}, err
}
return params, nil
}
// SetParams sets the auction module's parameters.
func (k Keeper) SetParams(ctx sdk.Context, params types.Params) error {
store := ctx.KVStore(k.storeKey)
bz, err := params.Marshal()
if err != nil {
return err
}
store.Set(types.KeyParams, bz)
return nil
}
// GetMaxBundleSize returns the maximum number of transactions that can be included in a bundle.
func (k Keeper) GetMaxBundleSize(ctx sdk.Context) (uint32, error) {
params, err := k.GetParams(ctx)
if err != nil {
return 0, err
}
return params.MaxBundleSize, nil
}
// GetEscrowAccount returns the auction module's escrow account.
func (k Keeper) GetEscrowAccount(ctx sdk.Context) (sdk.AccAddress, error) {
params, err := k.GetParams(ctx)
if err != nil {
return nil, err
}
account, err := sdk.AccAddressFromBech32(params.EscrowAccountAddress)
if err != nil {
return nil, err
}
return account, nil
}
// GetReserveFee returns the reserve fee of the auction module.
func (k Keeper) GetReserveFee(ctx sdk.Context) (sdk.Coins, error) {
params, err := k.GetParams(ctx)
if err != nil {
return sdk.NewCoins(), err
}
return params.ReserveFee, nil
}
// GetMinBuyInFee returns the bid floor for an auction.
func (k Keeper) GetMinBuyInFee(ctx sdk.Context) (sdk.Coins, error) {
params, err := k.GetParams(ctx)
if err != nil {
return sdk.NewCoins(), err
}
return params.MinBuyInFee, nil
}
// GetMinBidIncrement returns the minimum bid increment for the auction.
func (k Keeper) GetMinBidIncrement(ctx sdk.Context) (sdk.Coins, error) {
params, err := k.GetParams(ctx)
if err != nil {
return sdk.NewCoins(), err
}
return params.MinBidIncrement, nil
}

View File

@ -0,0 +1,71 @@
package keeper
import (
"context"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/skip-mev/pob/x/auction/types"
)
var (
_ types.MsgServer = MsgServer{}
)
// MsgServer is the wrapper for the auction module's msg service.
type MsgServer struct {
Keeper
}
// NewMsgServerImpl returns an implementation of the auction MsgServer interface.
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.
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)
if err != nil {
return nil, err
}
if uint32(len(msg.Transactions)) > maxBundleSize {
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 {
return nil, err
}
// TODO: figure out how to handle payments to the escrow address.
// Ref: https://github.com/skip-mev/pob/issues/11
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.
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
}
return &types.MsgUpdateParamsResponse{}, nil
}

137
x/auction/module.go Normal file
View File

@ -0,0 +1,137 @@
package auction
import (
"context"
"encoding/json"
"fmt"
"cosmossdk.io/api/tendermint/abci"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/skip-mev/pob/x/auction/keeper"
"github.com/skip-mev/pob/x/auction/types"
"github.com/spf13/cobra"
)
var (
_ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{}
)
// 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
}
// Name returns the auction module's name.
func (AppModuleBasic) Name() string {
return types.ModuleName
}
// RegisterLegacyAminoCodec registers the auction module's types on the given LegacyAmino codec.
func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
types.RegisterLegacyAminoCodec(cdc)
}
// RegisterInterfaces registers the auction module's interface types.
func (AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
types.RegisterInterfaces(registry)
}
// DefaultGenesis returns default genesis state as raw bytes for the auction module.
func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
return cdc.MustMarshalJSON(types.DefaultGenesisState())
}
// ValidateGenesis performs genesis state validation for the auction module.
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error {
var genState types.GenesisState
if err := cdc.UnmarshalJSON(bz, &genState); err != nil {
return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
}
return genState.Validate()
}
// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the auction module.
func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil {
panic(err)
}
}
// GetTxCmd returns the root tx command for the auction module.
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return nil
}
// GetQueryCmd returns no root query command for the auction module.
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
return nil
}
// -------------------- AppModule -------------------- //
type AppModule struct {
AppModuleBasic
keeper keeper.Keeper
accountKeeper types.AccountKeeper
bankKeeper types.BankKeeper
}
// NewAppModule creates a new AppModule object.
func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{cdc: cdc},
keeper: keeper,
accountKeeper: accountKeeper,
bankKeeper: bankKeeper,
}
}
// RegisterServices registers a the gRPC Query and Msg services for the auciton 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
}
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)
func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
// 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.
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) {}
// EndBlock returns the end blocker for the auction module. It returns no validator updates.
func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{}
}

View File

@ -0,0 +1,16 @@
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// AccountKeeper defines the contract required for account APIs.
type AccountKeeper interface {
GetModuleAddress(moduleName string) sdk.AccAddress
}
// BankKeeper defines the contract required for bank APIs.
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
}

View File

@ -0,0 +1,24 @@
package types
// NewGenesisState creates a new GenesisState instance.
func NewGenesisState(params Params) *GenesisState {
return &GenesisState{
Params: params,
}
}
// DefaultGenesisState returns the default GenesisState instance.
func DefaultGenesisState() *GenesisState {
return &GenesisState{
Params: DefaultParams(),
}
}
// Validate performs basic validation of the auction module genesis state.
func (gs GenesisState) Validate() error {
if err := gs.Params.Validate(); err != nil {
return err
}
return nil
}

View File

@ -81,7 +81,7 @@ type Params struct {
EscrowAccountAddress string `protobuf:"bytes,2,opt,name=escrow_account_address,json=escrowAccountAddress,proto3" json:"escrow_account_address,omitempty"`
// reserve_fee specifies a fee that the bidder must pay to enter 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 speficies the bid floor for the auction.
// min_buy_in_fee specifies the bid floor for 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.

24
x/auction/types/keys.go Normal file
View File

@ -0,0 +1,24 @@
package types
const (
// ModuleName is the name of the auction module
ModuleName = "auction"
// StoreKey is the default store key for the auction module
StoreKey = ModuleName
// RouterKey is the message route for the auction module
RouterKey = ModuleName
// QuerierRoute is the querier route for the auction module
QuerierRoute = ModuleName
)
const (
prefixParams = iota + 1
)
var (
// KeyPrefixParams is the store key for the auction module's parameters.
KeyParams = []byte{prefixParams}
)

View File

@ -1,6 +1,8 @@
package types
import (
fmt "fmt"
"cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -48,8 +50,29 @@ func (m MsgAuctionBid) GetSigners() []sdk.AccAddress {
// ValidateBasic does a sanity check on the provided data.
func (m MsgAuctionBid) ValidateBasic() error {
// TODO: Implement validation.
//
// Ref: https://github.com/skip-mev/pob/issues/8
panic("implement me")
if _, err := sdk.AccAddressFromBech32(m.Bidder); err != nil {
return errors.Wrap(err, "invalid bidder address")
}
// Validate the bid.
if m.Bid.IsZero() {
return fmt.Errorf("no bid included")
}
if err := m.Bid.Validate(); err != nil {
return errors.Wrap(err, "invalid bid")
}
// Validate the transactions.
if len(m.Transactions) == 0 {
return fmt.Errorf("no transactions included")
}
for _, tx := range m.Transactions {
if len(tx) == 0 {
return fmt.Errorf("empty transaction included")
}
}
return nil
}

View File

@ -0,0 +1,131 @@
package types_test
import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/skip-mev/pob/x/auction/types"
)
// TestMsgAuctionBid tests the ValidateBasic method of MsgAuctionBid
func TestMsgAuctionBid(t *testing.T) {
cases := []struct {
description string
msg types.MsgAuctionBid
expectPass bool
}{
{
description: "invalid message with empty bidder",
msg: types.MsgAuctionBid{
Bidder: "",
Bid: sdk.NewCoins(),
Transactions: [][]byte{},
},
expectPass: false,
},
{
description: "invalid message with empty bid",
msg: types.MsgAuctionBid{
Bidder: sdk.AccAddress([]byte("test")).String(),
Bid: sdk.NewCoins(),
Transactions: [][]byte{},
},
expectPass: false,
},
{
description: "invalid message with empty transactions",
msg: types.MsgAuctionBid{
Bidder: sdk.AccAddress([]byte("test")).String(),
Bid: sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(100))),
Transactions: [][]byte{},
},
expectPass: false,
},
{
description: "valid message",
msg: types.MsgAuctionBid{
Bidder: sdk.AccAddress([]byte("test")).String(),
Bid: sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(100))),
Transactions: [][]byte{[]byte("test")},
},
expectPass: true,
},
{
description: "valid message with multiple transactions",
msg: types.MsgAuctionBid{
Bidder: sdk.AccAddress([]byte("test")).String(),
Bid: sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(100))),
Transactions: [][]byte{[]byte("test"), []byte("test2")},
},
expectPass: true,
},
{
description: "invalid message with empty transaction in transactions",
msg: types.MsgAuctionBid{
Bidder: sdk.AccAddress([]byte("test")).String(),
Bid: sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(100))),
Transactions: [][]byte{[]byte("test"), []byte("")},
},
expectPass: false,
},
}
for _, tc := range cases {
t.Run(tc.description, func(t *testing.T) {
err := tc.msg.ValidateBasic()
if tc.expectPass {
if err != nil {
t.Errorf("expected no error on %s, got %s", tc.description, err)
}
} else {
if err == nil {
t.Errorf("expected error on %s, got none", tc.description)
}
}
})
}
}
// TestMsgUpdateParams tests the ValidateBasic method of MsgUpdateParams
func TestMsgUpdateParams(t *testing.T) {
cases := []struct {
description string
msg types.MsgUpdateParams
expectPass bool
}{
{
description: "invalid message with empty authority address",
msg: types.MsgUpdateParams{
Authority: "",
Params: types.Params{},
},
},
{
description: "invalid message with invalid params (invalid escrow address)",
msg: types.MsgUpdateParams{
Authority: sdk.AccAddress([]byte("test")).String(),
Params: types.Params{
EscrowAccountAddress: "test",
},
},
expectPass: false,
},
}
for _, tc := range cases {
t.Run(tc.description, func(t *testing.T) {
err := tc.msg.ValidateBasic()
if tc.expectPass {
if err != nil {
t.Errorf("expected no error on %s, got %s", tc.description, err)
}
} else {
if err == nil {
t.Errorf("expected error on %s, got none", tc.description)
}
}
})
}
}

View File

@ -1,37 +1,71 @@
package types
import (
fmt "fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func NewParams(maxBundleSize uint32, escrowAddr string, reserveFee, minBuyInFee, minBidIncr sdk.Coins) Params {
return Params{
MaxBundleSize: maxBundleSize,
EscrowAccountAddress: escrowAddr,
ReserveFee: reserveFee,
MinBuyInFee: minBuyInFee,
MinBidIncrement: minBidIncr,
}
}
// DefaultParams returns default x/auction module parameters.
func DefaultParams() Params {
var (
// TODO: Choose reasonable default values.
//
// Ref: https://github.com/skip-mev/pob/issues/7
DefaultMaxBundleSize uint32 = 0
DefaultEscrowAccountAddress = ""
DefaultReserveFee = sdk.Coins{}
DefaultMinBuyInFee = sdk.Coins{}
DefaultMinBidIncrement = sdk.Coins{}
)
// NewParams returns a new Params instance with the provided values.
func NewParams(maxBundleSize uint32, escrowAccountAddress string, reserveFee, minBuyInFee, minBidIncrement sdk.Coins) Params {
return Params{
MaxBundleSize: 0,
EscrowAccountAddress: "",
ReserveFee: sdk.NewCoins(),
MinBuyInFee: sdk.NewCoins(),
MinBidIncrement: sdk.NewCoins(),
MaxBundleSize: maxBundleSize,
EscrowAccountAddress: escrowAccountAddress,
ReserveFee: reserveFee,
MinBuyInFee: minBuyInFee,
MinBidIncrement: minBidIncrement,
}
}
// DefaultParams returns the default x/auction parameters.
func DefaultParams() Params {
return NewParams(
DefaultMaxBundleSize,
DefaultEscrowAccountAddress,
DefaultReserveFee,
DefaultMinBuyInFee,
DefaultMinBidIncrement,
)
}
// Validate performs basic validation on the parameters.
func (p Params) Validate() error {
// TODO: Implement validation.
//
// Ref: https://github.com/skip-mev/pob/issues/6
panic("not implemented")
if err := validateEscrowAccountAddress(p.EscrowAccountAddress); err != nil {
return err
}
if err := p.ReserveFee.Validate(); err != nil {
return fmt.Errorf("invalid reserve fee (%s)", err)
}
if err := p.MinBuyInFee.Validate(); err != nil {
return fmt.Errorf("invalid minimum buy-in fee (%s)", err)
}
if err := p.MinBidIncrement.Validate(); err != nil {
return fmt.Errorf("invalid minimum bid increment (%s)", err)
}
return nil
}
// validateEscrowAccountAddress ensures the escrow account address is a valid address (if set).
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 {
return fmt.Errorf("invalid escrow account address (%s)", err)
}
return nil
}