Scaffolding basic module configurations (#5)
Co-authored-by: Aleksandr Bezobchuk <aleks.bezobchuk@gmail.com>
This commit is contained in:
parent
293ee765b9
commit
aff1a26da9
5
go.mod
5
go.mod
@ -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
8
go.sum
@ -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=
|
||||
|
||||
@ -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,
|
||||
|
||||
25
x/auction/keeper/genesis.go
Normal file
25
x/auction/keeper/genesis.go
Normal 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)
|
||||
}
|
||||
34
x/auction/keeper/grpc_query.go
Normal file
34
x/auction/keeper/grpc_query.go
Normal 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
141
x/auction/keeper/keeper.go
Normal 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
|
||||
}
|
||||
71
x/auction/keeper/msg_server.go
Normal file
71
x/auction/keeper/msg_server.go
Normal 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
137
x/auction/module.go
Normal 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{}
|
||||
}
|
||||
16
x/auction/types/expected_keepers.go
Normal file
16
x/auction/types/expected_keepers.go
Normal 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
|
||||
}
|
||||
24
x/auction/types/genesis.go
Normal file
24
x/auction/types/genesis.go
Normal 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
|
||||
}
|
||||
@ -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
24
x/auction/types/keys.go
Normal 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}
|
||||
)
|
||||
@ -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
|
||||
}
|
||||
|
||||
131
x/auction/types/msgs_test.go
Normal file
131
x/auction/types/msgs_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user