mev

package
v2.1.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 2, 2024 License: Apache-2.0 Imports: 9 Imported by: 10

README ΒΆ

πŸ—οΈ MEV Lane Setup

πŸ“¦ Dependencies

The Block SDK is built on top of the Cosmos SDK. The Block SDK is currently compatible with Cosmos SDK versions greater than or equal to v0.47.0.

πŸ“₯ Installation

To install the Block SDK, run the following command:

$ go install github.com/skip-mev/block-sdk

πŸ“š Usage

Note: Please visit app.go to see a sample base app set up.

  1. This guide assumes you have already set up the Block SDK (and the default lane)
  2. You will need to instantiate the x/auction module into your application. This module is responsible for processing auction transactions and distributing revenue to the auction house. The x/auction module is also responsible for ensuring the validity of auction transactions. The x/auction module should not exist on its own. This is the most intensive part of the set up process.
  3. Next, add the MEV lane into the lane object on your app.go. The first lane is the highest priority lane and the last lane is the lowest priority lane. Since the MEV lane is meant to auction off the top of the block, it should be the highest priority lane. The default lane should follow.
  4. You will also need to create a PrepareProposalHandler and a ProcessProposalHandler that will be responsible for preparing and processing proposals respectively. Configure the order of the lanes in the PrepareProposalHandler and ProcessProposalHandler to match the order of the lanes in the LanedMempool.

NOTE: This example walks through setting up the MEV and Default lanes.

  1. Import the necessary dependencies into your application. This includes the Block SDK proposal handlers + mempool, keeper, auction types, and auction module. This tutorial will go into more detail into each of the dependencies.

    import (
     ...
     "github.com/skip-mev/block-sdk/abci"
     "github.com/skip-mev/block-sdk/lanes/mev"
     "github.com/skip-mev/block-sdk/lanes/base"
     auctionmodule "github.com/skip-mev/block-sdk/x/auction"
     auctionkeeper "github.com/skip-mev/block-sdk/x/auction/keeper"
     auctiontypes "github.com/skip-mev/block-sdk/x/auction/types"
     auctionante "github.com/skip-mev/block-sdk/x/auction/ante"
      ...
    )
    
  2. Add your module to the the AppModuleBasic manager. This manager is in charge of setting up basic, non-dependent module elements such as codec registration and genesis verification. This will register the special MsgAuctionBid message. When users want to bid for top of block execution, they will submit a transaction - which we call an auction transaction - that includes a single MsgAuctionBid. We prevent any other messages from being included in auction transaction to prevent malicious behavior - such as front running or sandwiching.

    var (
      ModuleBasics = module.NewBasicManager(
        ...
        auctionmodule.AppModuleBasic{},
      )
      ...
    )
    
  3. The auction Keeper is MEV lane's gateway to processing special MsgAuctionBid messages that allow users to participate in the top of block auction, distribute revenue to the auction house, and ensure the validity of auction transactions.

    a. First add the keeper to the app's struct definition. We also want to add MEV lane's custom checkTx handler to the app's struct definition. This will allow us to override the default checkTx handler to process bid transactions before they are inserted into the LanedMempool. NOTE: The custom handler is required as otherwise the auction can be held hostage by a malicious users.

    type App struct {
    ...
    // auctionkeeper is the keeper that handles processing auction transactions
    auctionkeeper         auctionkeeper.Keeper
    
    // Custom checkTx handler
    checkTxHandler mev.CheckTx
    }
    

    b. Add the auction module to the list of module account permissions. This will instantiate the auction module account on genesis.

    maccPerms = map[string][]string{
    auction.ModuleName: nil,
    ...
    }
    

    c. Instantiate the Block SDK's LanedMempool with the application's desired lanes.

    // 1. Create the lanes.
    //
    // NOTE: The lanes are ordered by priority. The first lane is the
    // highest priority
    // lane and the last lane is the lowest priority lane. Top of block 
    // lane allows transactions to bid for inclusion at the top of the next block.
    //
    // For more information on how to utilize the LaneConfig please
    // visit the README in docs.skip.money/chains/lanes/build-your-own-lane#-lane-config.
    //
    // MEV lane hosts an auction at the top of the block.
    mevConfig := base.LaneConfig{
        Logger:        app.Logger(),
        TxEncoder:     app.txConfig.TxEncoder(),
        TxDecoder:     app.txConfig.TxDecoder(),
        MaxBlockSpace: math.LegacyZeroDec(), 
        MaxTxs:        0,
    }
    mevLane := mev.NewMEVLane(
        mevConfig,
        mev.NewDefaultAuctionFactory(app.txConfig.TxDecoder()),
    )
    
    // default lane accepts all other transactions.
    defaultConfig := base.LaneConfig{
        Logger:        app.Logger(),
        TxEncoder:     app.txConfig.TxEncoder(),
        TxDecoder:     app.txConfig.TxDecoder(),
        MaxBlockSpace: math.LegacyZeroDec(),
        MaxTxs:        0,
    }
    defaultLane := base.NewStandardLane(defaultConfig, base.DefaultMatchHandler())
    
    // 2. Set up the relative priority of lanes
    lanes := []block.Lane{
        mevLane,
        defaultLane,
    }
    mempool := block.NewLanedMempool(app.Logger(), true, lanes...)
    app.App.SetMempool(mempool)
    

    d. Add the x/auction module's AuctionDecorator to the ante-handler chain. The AuctionDecorator is an AnteHandler decorator that enforces various chain configurable MEV rules.

    anteDecorators := []sdk.AnteDecorator{
        ante.NewSetUpContextDecorator(), 
        ...
        auctionante.NewAuctionDecorator(
        options.auctionkeeper, 
        options.TxEncoder, 
        options.TOBLane, 
        options.Mempool,
        ),
    }
    
    anteHandler := sdk.ChainAnteDecorators(anteDecorators...)
    app.SetAnteHandler(anteHandler)
    
    // Set the antehandlers on the lanes.
    //
    // NOTE: This step is required as otherwise the lanes will not be able to
    // process auction transactions.
    for _, lane := range lanes {
        lane.SetAnteHandler(anteHandler)
    }
    app.App.SetAnteHandler(anteHandler)
    

    e. Instantiate the auction keeper, store keys, and module manager. Note, be sure to do this after all the required keeper dependencies have been instantiated.

    keys := storetypes.NewKVStoreKeys(
        auctiontypes.StoreKey,
        ...
    )
    
    ...
    app.auctionkeeper := auctionkeeper.NewKeeper(
        appCodec,
        keys[auctiontypes.StoreKey],
        app.AccountKeeper,
        app.BankKeeper,
        app.DistrKeeper,
        app.StakingKeeper,
        authtypes.NewModuleAddress(govv1.ModuleName).String(),
    )
    
    
    app.ModuleManager = module.NewManager(
        auction.NewAppModule(appCodec, app.auctionkeeper),
        ...
    )
    

    f. Configure the proposal/checkTx handlers on base app.

    // Create the proposal handler that will be used to build and validate blocks.
    proposalHandler := abci.NewProposalHandler(
        app.Logger(),
        app.txConfig.TxDecoder(),
        mempool,
    )
    app.App.SetPrepareProposal(proposalHandler.PrepareProposalHandler())
    app.App.SetProcessProposal(proposalHandler.ProcessProposalHandler())
    
    // Set the custom CheckTx handler on BaseApp.
    checkTxHandler := mev.NewCheckTxHandler(
        app.App,
        app.txConfig.TxDecoder(),
        mevLane,
        anteHandler,
    )
    app.SetCheckTx(checkTxHandler.CheckTx())
    
    // CheckTx will check the transaction with the provided checkTxHandler. 
    // We override the default handler so that we can verify transactions 
    // before they are inserted into the mempool. With the CheckTx, we can 
    // verify the bid transaction and all of the bundled transactions
    // before inserting the bid transaction into the mempool.
    func (app *TestApp) CheckTx(req *cometabci.RequestCheckTx) 
        (*cometabci.ResponseCheckTx, error) {
        return app.checkTxHandler(req)
    }
    
    // SetCheckTx sets the checkTxHandler for the app.
    func (app *TestApp) SetCheckTx(handler mev.CheckTx) {
        app.checkTxHandler = handler
    }
    

    g. Finally, update the app's InitGenesis order.

    genesisModuleOrder := []string{
        auctiontypes.ModuleName,
        ...,
    }
    

Params

Note, before building or upgrading the application, make sure to initialize the escrow address in the parameters of the module. The default parameters initialize the escrow address to be the module account address.

Documentation ΒΆ

Index ΒΆ

Constants ΒΆ

View Source
const (
	// LaneName defines the name of the mev lane.
	LaneName = "mev"
)

Variables ΒΆ

This section is empty.

Functions ΒΆ

func GetMsgAuctionBidFromTx ΒΆ

func GetMsgAuctionBidFromTx(tx sdk.Tx) (*auctiontypes.MsgAuctionBid, error)

GetMsgAuctionBidFromTx attempts to retrieve a MsgAuctionBid from an sdk.Tx if one exists. If a MsgAuctionBid does exist and other messages are also present, an error is returned. If no MsgAuctionBid is present, <nil, nil> is returned.

func TxPriority ΒΆ

func TxPriority(config Factory) base.TxPriority[string]

TxPriority returns a TxPriority over mev lane transactions only. It is to be used in the mev index only.

Types ΒΆ

type DefaultAuctionFactory ΒΆ

type DefaultAuctionFactory struct {
	// contains filtered or unexported fields
}

DefaultAuctionFactory defines a default implmentation for the auction factory interface for processing auction transactions.

func (*DefaultAuctionFactory) GetAuctionBidInfo ΒΆ

func (config *DefaultAuctionFactory) GetAuctionBidInfo(tx sdk.Tx) (*types.BidInfo, error)

GetAuctionBidInfo defines a default function that returns the auction bid info from an auction transaction. In the default case, the auction bid info is stored in the MsgAuctionBid message.

func (*DefaultAuctionFactory) GetTimeoutHeight ΒΆ

func (config *DefaultAuctionFactory) GetTimeoutHeight(tx sdk.Tx) (uint64, error)

GetTimeoutHeight returns the timeout height of the transaction.

func (*DefaultAuctionFactory) MatchHandler ΒΆ

func (config *DefaultAuctionFactory) MatchHandler() base.MatchHandler

MatchHandler defines a default function that checks if a transaction matches the mev lane.

func (*DefaultAuctionFactory) WrapBundleTransaction ΒΆ

func (config *DefaultAuctionFactory) WrapBundleTransaction(tx []byte) (sdk.Tx, error)

WrapBundleTransaction defines a default function that wraps a transaction that is included in the bundle into a sdk.Tx. In the default case, the transaction that is included in the bundle will be the raw bytes of an sdk.Tx so we can just decode it.

type Factory ΒΆ

type Factory interface {
	// WrapBundleTransaction defines a function that wraps a bundle transaction into a sdk.Tx. Since
	// this is a potentially expensive operation, we allow each application chain to define how
	// they want to wrap the transaction such that it is only called when necessary (i.e. when the
	// transaction is being considered in the proposal handlers).
	WrapBundleTransaction(tx []byte) (sdk.Tx, error)

	// GetAuctionBidInfo defines a function that returns the bid info from an auction transaction.
	GetAuctionBidInfo(tx sdk.Tx) (*types.BidInfo, error)

	// MatchHandler defines a function that checks if a transaction matches the auction lane.
	MatchHandler() base.MatchHandler
}

Factory defines the interface for processing auction transactions. It is a wrapper around all the functionality that each application chain must implement in order for auction processing to work.

func NewDefaultAuctionFactory ΒΆ

func NewDefaultAuctionFactory(txDecoder sdk.TxDecoder, extractor signer_extraction.Adapter) Factory

NewDefaultAuctionFactory returns a default auction factory interface implementation.

type MEVLane ΒΆ

type MEVLane struct {
	*base.BaseLane

	// Factory defines the API/functionality which is responsible for determining
	// if a transaction is a bid transaction and how to extract relevant
	// information from the transaction (bid, timeout, bidder, etc.).
	Factory
}

MEVLane defines a MEV (Maximal Extracted Value) auction lane. The MEV auction lane hosts transactions that want to bid for inclusion at the top of the next block. The MEV auction lane stores bid transactions that are sorted by their bid price. The highest valid bid transaction is selected for inclusion in the next block. The bundled transactions of the selected bid transaction are also included in the next block.

func NewMEVLane ΒΆ

func NewMEVLane(
	cfg base.LaneConfig,
	factory Factory,
	matchHandler base.MatchHandler,
) *MEVLane

NewMEVLane returns a new TOB lane.

func (*MEVLane) GetTopAuctionTx ΒΆ

func (l *MEVLane) GetTopAuctionTx(ctx context.Context) sdk.Tx

GetTopAuctionTx returns the highest bidding transaction in the auction mempool. This is primarily a helper function for the x/auction module.

type ProposalHandler ΒΆ

type ProposalHandler struct {
	// contains filtered or unexported fields
}

Implements the MEV lane's PrepareLaneHandler and ProcessLaneHandler.

func NewProposalHandler ΒΆ

func NewProposalHandler(lane *base.BaseLane, factory Factory) *ProposalHandler

NewProposalHandler returns a new mev proposal handler.

func (*ProposalHandler) PrepareLaneHandler ΒΆ

func (h *ProposalHandler) PrepareLaneHandler() base.PrepareLaneHandler

PrepareLaneHandler will attempt to select the highest bid transaction that is valid and whose bundled transactions are valid and include them in the proposal. It will return no transactions if no valid bids are found. If any of the bids are invalid, it will return them and will only remove the bids and not the bundled transactions.

func (*ProposalHandler) ProcessLaneHandler ΒΆ

func (h *ProposalHandler) ProcessLaneHandler() base.ProcessLaneHandler

ProcessLaneHandler will ensure that block proposals that include transactions from the mev lane are valid. In particular, the invariant checks that we perform are:

  1. If the first transaction does not match the lane, no other MEV transactions should be included in the proposal.
  2. The bid transaction must be valid.
  3. The bundled transactions must be valid.
  4. The bundled transactions must match the transactions in the block proposal in the same order they were defined in the bid transaction.
  5. The bundled transactions must not be bid transactions.

func (*ProposalHandler) VerifyBidBasic ΒΆ

func (h *ProposalHandler) VerifyBidBasic(
	ctx sdk.Context,
	bidTx sdk.Tx,
	proposal proposals.Proposal,
	limit proposals.LaneLimits,
) ([]sdk.Tx, error)

VerifyBidBasic will verify that the bid transaction and all of its bundled transactions respect the basic invariants of the lane (e.g. size, gas limit).

func (*ProposalHandler) VerifyBidTx ΒΆ

func (h *ProposalHandler) VerifyBidTx(ctx sdk.Context, bidTx sdk.Tx, bundle []sdk.Tx) error

VerifyBidTx will verify that the bid transaction and all of its bundled transactions are valid.

type TxWithTimeoutHeight ΒΆ

type TxWithTimeoutHeight interface {
	sdk.Tx

	GetTimeoutHeight() uint64
}

TxWithTimeoutHeight is used to extract timeouts from sdk.Tx transactions. In the case where, timeouts are explicitly set on the sdk.Tx, we can use this interface to extract the timeout.

Directories ΒΆ

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL