diff --git a/README.md b/README.md
index 6ef7d94..deab51a 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
Protocol-Owned Builder
+Block SDK 🧱
@@ -9,337 +9,201 @@
[](https://github.com/skip-mev/pob/blob/main/LICENSE)
[](https://github.com/skip-mev/pob)
-Skip Protocol's Protocol-Owned Builder (POB) is a set of Cosmos SDK and ABCI++
-primitives that provide application developers the ability to define how their
-apps construct and validate blocks on-chain in a transparent, enforceable way,
-such as giving complete control to the protocol to recapture, control, and
-redistribute MEV.
+## 📖 Overview
-Skip's POB provides developers with a set of a few core primitives:
+The Block SDK is a framework for building smarter blocks. The Block SDK is built
+harnessing the power of ABCI++ which is a new ABCI implementation that allows
+for more complex and expressive applications to be built on top of the Cosmos SDK.
+The process of building and verifiying proposals can be broken down into two
+distinct parts:
-* `BlockBuster`: BlockBuster is a generalized block-building and mempool SDK
- that allows developers to define how their applications construct and validate blocks
- on-chain in a transparent, enforceable way. At its core, BlockBuster is an app-side mempool + set
- of proposal handlers (`PrepareProposal`/`ProcessProposal`) that allow developers to configure
- modular lanes of transactions in their blocks with distinct validation/ordering logic. For more
- information, see the [BlockBuster README](/block/README.md).
-* `x/builder`: This Cosmos SDK module gives applications the ability to process
- MEV bundled transactions in addition to having the ability to define how searchers
- and block proposers are rewarded. In addition, the module defines a `AuctionDecorator`,
- which is an AnteHandler decorator that enforces various chain configurable MEV
- rules.
+1. Preparing a proposal during `PrepareProposal`.
+2. Processing a proposal during `ProcessProposal`.
-## Releases
+The Block SDK provides a framework for building and verifying proposals by
+segmenting a single block into multiple lanes. Each lane can be responsible for
+proposing and verifying specific types of transaction. The Block SDK provides
+a default implementation of a lane that can be used to build and verify proposals
+similar to how they are built and verified in the Cosmos SDK today while also
+providing a framework for building more complex lanes that can be used to build
+and verify much more complex proposals.
-### Release Compatibility Matrix
+## 🤔 How does it work
-| POB Version | Cosmos SDK |
-| :---------: | :--------: |
-| v1.x.x | v0.47.x |
-| v1.x.x | v0.48.x |
-| v1.x.x | v0.49.x |
-| v1.x.x | v0.50.x |
+### 🔁 Transaction Lifecycle
-## Install
+The best way to understand how lanes work is to first understand the lifecycle
+of a transaction. A transaction begins its lifecycle when it is first signed and
+broadcasted to a chain. After it is broadcasted to a validator, it will be checked
+in `CheckTx` by the base application. If the transaction is valid, it will be
+inserted into the applications mempool.
-```shell
-$ go install github.com/skip-mev/pob
+The transaction then waits in the mempool until a new block needs to be proposed.
+When a new block needs to be proposed, the application will call `PrepareProposal`
+(which is a new ABCI++ addition) to request a new block from the current
+proposer. The proposer will look at what transactions currently waiting to
+be included in a block by looking at their mempool. The proposer will then
+iteratively select transactions until the block is full. The proposer will then
+send the block to other validators in the network.
+
+When a validator receives a proposed block, the validator will first want to
+verify the contents of the block before signing off on it. The validator will
+call `ProcessProposal` to verify the contents of the block. If the block is
+valid, the validator will sign off on the block and broadcast their vote to the
+network. If the block is invalid, the validator will reject the block. Once a
+block is accepted by the network, it is committed and the transactions that
+were included in the block are removed from the validator's mempool (as they no
+longer need to be considered).
+
+### 🛣️ Lane Lifecycle
+
+After a transaction is verified in `CheckTx`, it will attempt to be inserted
+into the `LanedMempool`. A `LanedMempool` is composed of several distinct `Lanes`
+that have the ability to store their own transactions. The `LanedMempool` will
+insert the transaction into all lanes that will accept it. The criteria for
+whether a lane will accept a transaction is defined by the lane's
+`MatchHandler`. The default implementation of a `MatchHandler` will accept all transactions.
+
+
+When a new block is proposed, the `PrepareProposalHandler` will iteratively call
+`PrepareLane` on each lane (in the order in which they are defined in the
+`LanedMempool`). The `PrepareLane` method is anaolgous to `PrepareProposal`. Calling
+`PrepareLane` on a lane will trigger the lane to reap transactions from its mempool
+and add them to the proposal (given they are valid respecting the verification rules
+of the lane).
+
+When proposals need to be verified in `ProcessProposal`, the `ProcessProposalHandler`
+defined in `abci/abci.go` will call `ProcessLane` on each lane in the same order
+as they were called in the `PrepareProposalHandler`. Each subsequent call to
+`ProcessLane` will filter out transactions that belong to previous lanes. A given
+lane's `ProcessLane` will only verify transactions that belong to that lane.
+
+> **Scenario**
+>
+> Let's say we have a `LanedMempool` composed of two lanes: `LaneA` and `LaneB`.
+> `LaneA` is defined first in the `LanedMempool` and `LaneB` is defined second.
+> `LaneA` contains transactions `Tx1` and `Tx2` and `LaneB` contains transactions
+> `Tx3` and `Tx4`.
+
+
+When a new block needs to be proposed, the `PrepareProposalHandler` will call
+`PrepareLane` on `LaneA` first and `LaneB` second. When `PrepareLane` is called
+on `LaneA`, `LaneA` will reap transactions from its mempool and add them to the
+proposal. Same applies for `LaneB`. Say `LaneA` reaps transactions `Tx1` and `Tx2`
+and `LaneB` reaps transactions `Tx3` and `Tx4`. This gives us a proposal composed
+of the following:
+
+* `Tx1`, `Tx2`, `Tx3`, `Tx4`
+
+When the `ProcessProposalHandler` is called, it will call `ProcessLane` on `LaneA`
+with the proposal composed of `Tx1`, `Tx2`, `Tx3`, and `Tx4`. `LaneA` will then
+verify `Tx1` and `Tx2` and return the remaining transactions - `Tx3` and `Tx4`.
+The `ProcessProposalHandler` will then call `ProcessLane` on `LaneB` with the
+remaining transactions - `Tx3` and `Tx4`. `LaneB` will then verify `Tx3` and `Tx4`
+and return no remaining transactions.
+
+## 🏗️ Setup
+
+> **Note**
+>
+> For a more in depth example of how to use the Block SDK, check out our
+> example application in `block-sdk/tests/app/app.go`.
+
+### 📦 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:
+
+```bash
+go get github.com/skip-mev/block-sdk/abci
```
-## Setup
+### 📚 Usage
->This set up guide will walk you through the process of setting up a POB application. In particular, we will configure an application with the following features:
->
->* Top of block lane (auction lane). This will create an auction lane where users can bid to have their
-> transactions executed at the top of the block.
->* Free lane. This will create a free lane where users can submit transactions that will be executed
-> for free (no fees).
->* Default lane. This will create a default lane where users can submit transactions that will be executed
-> with the default app logic.
->* Builder module that pairs with the auction lane to process auction transactions and distribute revenue
-> to the auction house.
->
-> To build your own custom BlockBuster Lane, please see the [BlockBuster README](/block/README.md).
+First determine the set of lanes that you want to use in your application. The available
+lanes can be found in our **Lane App Store** in `block-sdk/lanes`. In your base
+application, you will need to create a `LanedMempool` composed of the lanes that
+you want to use. You will also need to create a `PrepareProposalHandler` and a
+`ProcessProposalHandler` that will be responsible for preparing and processing
+proposals respectively.
-1. Import the necessary dependencies into your application. This includes the
- block proposal handlers +mempool, keeper, builder types, and builder module. This
- tutorial will go into more detail into each of the dependencies.
+```golang
+// 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 block-sdk/block/base.
+//
+// MEV lane hosts an action at the top of the block.
+mevConfig := constructor.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()),
+)
- ```go
- import (
- ...
- "github.com/skip-mev/pob/block"
- "github.com/skip-mev/pob/block/abci"
- "github.com/skip-mev/pob/block/lanes/mev"
- "github.com/skip-mev/pob/block/lanes/base"
- "github.com/skip-mev/pob/block/lanes/free"
- buildermodule "github.com/skip-mev/pob/x/builder"
- builderkeeper "github.com/skip-mev/pob/x/builder/keeper"
- ...
- )
- ```
+// Free lane allows transactions to be included in the next block for free.
+freeConfig := constructor.LaneConfig{
+ Logger: app.Logger(),
+ TxEncoder: app.txConfig.TxEncoder(),
+ TxDecoder: app.txConfig.TxDecoder(),
+ MaxBlockSpace: math.LegacyZeroDec(),
+ MaxTxs: 0,
+}
+freeLane := free.NewFreeLane(
+ freeConfig,
+ constructor.DefaultTxPriority(),
+ free.DefaultMatchHandler(),
+)
-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 MEV 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.
+// Default lane accepts all other transactions.
+defaultConfig := constructor.LaneConfig{
+ Logger: app.Logger(),
+ TxEncoder: app.txConfig.TxEncoder(),
+ TxDecoder: app.txConfig.TxDecoder(),
+ MaxBlockSpace: math.LegacyZeroDec(),
+ MaxTxs: 0,
+}
+defaultLane := base.NewStandardLane(defaultConfig)
- ```go
- var (
- ModuleBasics = module.NewBasicManager(
- ...
- buildermodule.AppModuleBasic{},
- )
- ...
- )
- ```
+// Set the lanes into the mempool.
+lanes := []block.Lane{
+ mevLane,
+ freeLane,
+ defaultLane,
+}
+mempool := block.NewLanedMempool(app.Logger(), true, lanes...)
+app.App.SetMempool(mempool)
-3. The builder `Keeper` is POB's gateway to processing special `MsgAuctionBid`
- messages that allow users to participate in the MEV 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 POB'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 mempool.
- NOTE: The custom handler is required as otherwise the auction can be held hostage by a malicious
- users.
+anteHandler := NewAnteHandler(options)
- ```go
- type App struct {
- ...
- // BuilderKeeper is the keeper that handles processing auction transactions
- BuilderKeeper builderkeeper.Keeper
+// Set the lane ante handlers on the lanes.
+for _, lane := range lanes {
+ lane.SetAnteHandler(anteHandler)
+}
+app.App.SetAnteHandler(anteHandler)
- // Custom checkTx handler
- checkTxHandler abci.CheckTx
- }
- ```
+// Set the abci handlers on base app
+proposalHandler := abci.NewProposalHandler(
+ app.Logger(),
+ app.TxConfig().TxDecoder(),
+ lanes,
+)
+app.App.SetPrepareProposal(proposalHandler.PrepareProposalHandler())
+app.App.SetProcessProposal(proposalHandler.ProcessProposalHandler())
+```
- b. Add the builder module to the list of module account permissions. This will
- instantiate the builder module account on genesis.
-
- ```go
- maccPerms = map[string][]string{
- builder.ModuleName: nil,
- ...
- }
- ```
-
- c. Instantiate the block mempool with the application's desired lanes.
-
- ```go
- // Set the block mempool into the app.
- // 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.
- //
- // block.BaseLaneConfig is utilized for basic encoding/decoding of transactions.
- tobConfig := block.BaseLaneConfig{
- Logger: app.Logger(),
- TxEncoder: app.txConfig.TxEncoder(),
- TxDecoder: app.txConfig.TxDecoder(),
- // the desired portion of total block space to be reserved for the lane. a value of 0
- // indicates that the lane can use all available block space.
- MaxBlockSpace: sdk.ZeroDec(),
- }
- tobLane := auction.NewMEVLane(
- tobConfig,
- // the maximum number of transactions that the mempool can store. a value of 0 indicates
- // that the mempool can store an unlimited number of transactions.
- 0,
- // AuctionFactory is responsible for determining what is an auction bid transaction and
- // how to extract the bid information from the transaction. There is a default implementation
- // that can be used or application developers can implement their own.
- auction.NewDefaultAuctionFactory(app.txConfig.TxDecoder()),
- )
-
- // Free lane allows transactions to be included in the next block for free.
- freeConfig := block.BaseLaneConfig{
- Logger: app.Logger(),
- TxEncoder: app.txConfig.TxEncoder(),
- TxDecoder: app.txConfig.TxDecoder(),
- MaxBlockSpace: sdk.ZeroDec(),
- // IgnoreList is a list of lanes that if a transaction should be included in, it will be
- // ignored by the lane. For example, if a transaction should belong to the tob lane, it
- // will be ignored by the free lane.
- IgnoreList: []block.Lane{
- tobLane,
- },
- }
- freeLane := free.NewFreeLane(
- freeConfig,
- free.NewDefaultFreeFactory(app.txConfig.TxDecoder()),
- )
-
- // Default lane accepts all other transactions.
- defaultConfig := block.BaseLaneConfig{
- Logger: app.Logger(),
- TxEncoder: app.txConfig.TxEncoder(),
- TxDecoder: app.txConfig.TxDecoder(),
- MaxBlockSpace: sdk.ZeroDec(),
- IgnoreList: []block.Lane{
- tobLane,
- freeLane,
- },
- }
- defaultLane := base.NewStandardLane(defaultConfig)
-
- // Set the lanes into the mempool.
- lanes := []block.Lane{
- tobLane,
- freeLane,
- defaultLane,
- }
- mempool := block.NewMempool(lanes...)
- app.App.SetMempool(mempool)
- ```
-
- d. Instantiate the antehandler chain for the application with awareness of the
- block mempool. This will allow the application to verify the validity
- of a transaction respecting the desired logic of a given lane. In this walkthrough,
- we want the `FeeDecorator` to be ignored for all transactions that should belong to the
- free lane. Additionally, we want to add the `x/builder` module's `AuctionDecorator` to the
- ante-handler chain. The `AuctionDecorator` is an AnteHandler decorator that enforces various
- chain configurable MEV rules.
-
- ```go
- import (
- ...
- "github.com/skip-mev/pob/block"
- "github.com/skip-mev/pob/block/utils"
- builderante "github.com/skip-mev/pob/x/builder/ante"
- ...
- )
-
- anteDecorators := []sdk.AnteDecorator{
- ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
- ...
- // The IgnoreDecorator allows for certain decorators to be ignored for certain transactions. In
- // this case, we want to ignore the FeeDecorator for all transactions that should belong to the
- // free lane.
- utils.NewIgnoreDecorator(
- ante.NewDeductFeeDecorator(
- options.BaseOptions.AccountKeeper,
- options.BaseOptions.BankKeeper,
- options.BaseOptions.FeegrantKeeper,
- options.BaseOptions.TxFeeChecker,
- ),
- options.FreeLane,
- ),
- ...
- builderante.NewBuilderDecorator(options.BuilderKeeper, options.TxEncoder, options.MEVLane, options.Mempool),
- }
-
- anteHandler := sdk.ChainAnteDecorators(anteDecorators...)
- app.SetAnteHandler(anteHandler)
-
- // Set the antehandlers on the lanes.
- for _, lane := range lanes {
- lane.SetAnteHandler(anteHandler)
- }
- app.App.SetAnteHandler(anteHandler)
- ```
-
- e. Instantiate the builder keeper, store keys, and module manager. Note, be
- sure to do this after all the required keeper dependencies have been instantiated.
-
- ```go
- keys := storetypes.NewKVStoreKeys(
- buildertypes.StoreKey,
- ...
- )
-
- ...
- app.BuilderKeeper := builderkeeper.NewKeeper(
- appCodec,
- keys[buildertypes.StoreKey],
- app.AccountKeeper,
- app.BankKeeper,
- app.DistrKeeper,
- app.StakingKeeper,
- authtypes.NewModuleAddress(govv1.ModuleName).String(),
- )
-
-
- app.ModuleManager = module.NewManager(
- builder.NewAppModule(appCodec, app.BuilderKeeper),
- ...
- )
- ```
-
- e. With Cosmos SDK version 0.47.0, the process of building blocks has been
- updated and moved from the consensus layer, CometBFT, to the application layer.
- When a new block is requested, the proposer for that height will utilize the
- `PrepareProposal` handler to build a block while the `ProcessProposal` handler
- will verify the contents of the block proposal by all validators. The
- combination of the `BlockBuster` mempool + `PrepareProposal`/`ProcessProposal`
- handlers allows the application to verifiably build valid blocks with
- mev block space reserved for auctions and partial block for free transactions.
- Additionally, we override the `BaseApp`'s `CheckTx` handler with our own custom
- `CheckTx` handler that will be responsible for checking the validity of transactions.
- We override the `CheckTx` handler so that we can verify auction transactions before they are
- inserted into the mempool. With the POB `CheckTx`, we can verify the auction
- transaction and all of the bundled transactions before inserting the auction
- transaction into the mempool. This is important because we otherwise there may be
- discrepencies between the auction transaction and the bundled transactions
- are validated in `CheckTx` and `PrepareProposal` such that the auction can be
- griefed. All other transactions will be executed with base app's `CheckTx`.
-
- ```go
-
- // 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 := abci.NewCheckTxHandler(
- app.App,
- app.txConfig.TxDecoder(),
- tobLane,
- anteHandler,
- app.ChainID(),
- )
- app.SetCheckTx(checkTxHandler.CheckTx())
- ...
-
- // CheckTx will check the transaction with the provided checkTxHandler. We override the default
- // handler so that we can verify bid transactions before they are inserted into the mempool.
- // With the POB 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 {
- return app.checkTxHandler(req)
- }
-
- // SetCheckTx sets the checkTxHandler for the app.
- func (app *TestApp) SetCheckTx(handler abci.CheckTx) {
- app.checkTxHandler = handler
- }
- ```
-
- f. Finally, update the app's `InitGenesis` order and ante-handler chain.
-
- ```go
- genesisModuleOrder := []string{
- buildertypes.ModuleName,
- ...,
- }
- ```
-
-## Params
-
-Note, before building or upgrading the application, make sure to initialize the
-escrow address for POB in the parameters of the module. The default parameters
-initialize the escrow address to be the module account address. The escrow address
-will be the address that is receiving a portion of auction house revenue alongside the proposer (or custom rewards providers).