diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index bcaff7f..398c785 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -24,3 +24,14 @@ jobs:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
version: latest
only-new-issues: true
+ lint-markdown:
+ name: Lint markdown
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v3
+
+ - name: Lint markdown
+ uses: avto-dev/markdown-lint@v1
+ with:
+ args: "**/*.md"
diff --git a/.markdownlint.json b/.markdownlint.json
new file mode 100644
index 0000000..d5eabd2
--- /dev/null
+++ b/.markdownlint.json
@@ -0,0 +1,12 @@
+{
+ "default": true,
+ "MD004": { "style": "asterisk" },
+ "MD007": { "indent": 4 },
+ "MD024": { "siblings_only": true },
+ "MD025": false,
+ "MD033": false,
+ "MD034": false,
+ "MD014": false,
+ "no-hard-tabs": false,
+ "whitespace": false
+}
diff --git a/.markdownlintignore b/.markdownlintignore
new file mode 100644
index 0000000..0205a42
--- /dev/null
+++ b/.markdownlintignore
@@ -0,0 +1,18 @@
+{
+ "default": true,
+ "MD004": {
+ "style": "asterisk"
+ },
+ "MD007": {
+ "indent": 4
+ },
+ "MD013": false,
+ "MD024": {
+ "siblings_only": true
+ },
+ "MD025": false,
+ "MD033": false,
+ "MD034": false,
+ "no-hard-tabs": false,
+ "whitespace": false
+}
diff --git a/Makefile b/Makefile
index dbb1a2b..93da6c8 100644
--- a/Makefile
+++ b/Makefile
@@ -47,3 +47,26 @@ proto-update-deps:
$(DOCKER) run --rm -v $(CURDIR)/proto:/workspace --workdir /workspace $(protoImageName) buf mod update
.PHONY: proto-all proto-gen proto-format proto-lint proto-check-breaking proto-update-deps
+
+###############################################################################
+### Linting ###
+###############################################################################
+
+golangci_lint_cmd=golangci-lint
+golangci_version=v1.51.2
+
+lint:
+ @echo "--> Running linter"
+ @go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(golangci_version)
+ @golangci-lint run
+
+lint-fix:
+ @echo "--> Running linter"
+ @go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(golangci_version)
+ @golangci-lint run --fix
+
+lint-markdown:
+ @echo "--> Running markdown linter"
+ @markdownlint **/*.md
+
+.PHONY: lint lint-fix lint-markdown
diff --git a/README.md b/README.md
index 26d62fa..78f534f 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+
Protocol-Owned Builder
[](https://www.repostatus.org/#wip)
@@ -146,7 +147,8 @@ $ go install github.com/skip-mev/pob
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
+ 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 `AuctionMempool`, `PrepareProposal` and `ProcessProposal`
handlers allows the application to verifiably build valid blocks with
diff --git a/spec.md b/spec.md
new file mode 100644
index 0000000..30a11be
--- /dev/null
+++ b/spec.md
@@ -0,0 +1,281 @@
+
+# POB Specification
+
+## Abstract
+
+The `x/builder` module is a Cosmos SDK module that allows Cosmos chains to host
+top-of-block auctions directly in-protocol with auction revenue (MEV) being
+redistributed according to the preferences of the chain. The `x/builder` module
+introduces a new `MsgAuctionBid` message that allows users to submit a bid
+alongside an ordered list of transactions, i.e. a **bundle**, that they want
+executed at top-of-block before any other transactions are executed for that
+block. The `x/builder` module works alongside the `AuctionMempool` such that:
+
+* Auctions are held directly in the `AuctionMempool`, where a winner is determined
+ when the proposer proposes a new block in `PrepareProposal`.
+* `x/builder` provides the necessary validation of auction bids and subsequent
+ state transitions to extract bids.
+
+## Concepts
+
+### Miner Extractable Value (MEV)
+
+MEV refers to the potential profit that miners, or validators in a Proof-of-Stake
+system, can make by strategically ordering, selecting, or even censoring
+transactions in the blocks they produce. MEV can be classified into "good MEV"
+and "bad MEV" based on the effects it has on the blockchain ecosystem and its
+users. It's important to note that these classifications are subjective and may
+vary depending on one's perspective.
+
+**Good MEV** refers to the value that validators can extract while contributing
+positively to the blockchain ecosystem. This typically includes activities that
+enhance network efficiency, maintain fairness, and align incentives with the
+intended use of the system. Examples of good MEV include:
+
+* **Back-running**: Validators can place their own transactions immediately
+ after a profitable transaction, capitalizing on the changes caused by the
+ preceding transaction.
+* **Arbitrage**: By exploiting price differences across decentralized exchanges
+ or other DeFi platforms, validators help maintain more consistent price levels
+ across the ecosystem, ultimately contributing to its stability.
+* **Liquidations**: In DeFi platforms, when users' collateral falls below a
+ specific threshold, validators can liquidate these positions, thereby maintaining
+ the overall health of the platform and protecting its users from insolvency risks.
+
+**Bad MEV** refers to the value that validators can extract through activities
+that harm the blockchain ecosystem, lead to unfair advantages, or exploit users.
+Examples of bad MEV include:
+
+* **Front-running**: Validators can observe pending transactions in the mempool
+ (the pool of unconfirmed transactions) and insert their own transactions ahead
+ of them. This can be particularly profitable in decentralized finance (DeFi)
+ applications, where a validator could front-run a large trade to take advantage
+ of price movements.
+* **Sandwich attacks**: Validators can surround a user's transaction with their
+ own transactions, effectively manipulating the market price for their benefit.
+* **Censorship**: Validators can selectively exclude certain transactions from
+ blocks to benefit their own transactions or to extract higher fees from users.
+
+MEV is a topic of concern in the blockchain community because it can lead to
+unfair advantages for validators, reduced trust in the system, and a potential
+concentration of power. Various approaches have been proposed to mitigate MEV,
+such as proposer-builder separation (described below) and transparent and fair
+transaction ordering mechanisms at the protocol-level (`POB`) to make MEV
+extraction more incentive aligned with the users and blockchain ecosystem.
+
+### Proposer Builder Separation (PBS)
+
+Proposer-builder separation is a concept in the design of blockchain protocols,
+specifically in the context of transaction ordering within a block. In traditional
+blockchain systems, validators perform two main tasks: they create new blocks
+(acting as proposers) and determine the ordering of transactions within those
+blocks (acting as builders).
+
+
+**Proposers**: They are responsible for creating and broadcasting new blocks,
+just like in traditional blockchain systems. *However, they no longer determine
+the ordering of transactions within those blocks*.
+
+**Builders**: They have the exclusive role of determining the order of transactions
+within a block - can be full or partial block. Builders submit their proposed
+transaction orderings to an auction mechanism, which selects the winning template
+based on predefined criteria, e.g. highest bid.
+
+This dual role can lead to potential issues, such as front-running and other
+manipulations that benefit the miners/builders themselves.
+
+* *Increased complexity*: Introducing PBS adds an extra layer of complexity to
+ the blockchain protocol. Designing, implementing, and maintaining an auction
+ mechanism for transaction ordering requires additional resources and may
+ introduce new vulnerabilities or points of failure in the system.
+* *Centralization risks*: With PBS, there's a risk that a few dominant builders
+ may emerge, leading to centralization of transaction ordering. This centralization
+ could result in a lack of diversity in transaction ordering algorithms and an
+ increased potential for collusion or manipulation by the dominant builders.
+* *Incentive misalignments*: The bidding process may create perverse incentives
+ for builders. For example, builders may be incentivized to include only high-fee
+ transactions to maximize their profits, potentially leading to a neglect of
+ lower-fee transactions. Additionally, builders may be incentivized to build
+ blocks that include **bad-MEV** strategies because they are more profitable.
+
+## Specification
+
+### Mempool
+
+As the lifeblood of blockchains, mempools serve as the intermediary space for
+pending transactions, playing a vital role in transaction management, fee markets,
+and network health. With ABCI++, mempools can be defined at the application layer
+instead of the consensus layer (CometBFT). This means applications can define
+their own mempools that have their own custom verification, block building, and
+state transition logic. Adding on, these changes make it such that blocks are
+built (`PrepareProposal`) and verified (`ProcessProposal`) directly in the
+application layer.
+
+The `x/builder` module implements an application-side mempool, `AuctionMempool`,
+that implements the `sdk.Mempool` interface. The mempool is composed of two
+primary indexes, a global index that contains all non-auction transactions and
+an index that only contains auction transactions, i.e. transactions with a single
+`MsgAuctionBid` message. Both indexes order transactions based on priority respecting
+the sender's sequence number. The global index prioritizes transactions based on
+`ctx.Priority()` and the auction index prioritizes transactions based on the
+bid.
+
+### PrepareProposal
+
+After the proposer of the next block has been selected, the CometBFT client will
+call `PrepareProposal` to build the next block. The block will be built in two
+stages. First, it will host the auction and include the winning bidder's bundle
+as the first set of transactions for the block, i.e. it will select the bid
+transaction itself along with automatically including all the bundled transactions
+in the specified order they appear in the bid's `transactions` field.
+
+The auction currently supports only a single winner. Selecting the auction winner
+involves a greedy search for a valid auction transaction starting from highest
+paying bid, respecting user nonce, in the `AuctionMempool`. The `x/builder`'s
+ante handler is responsible for verifying the auction transaction based on the
+criteria described below (see **Ante Handler**).
+
+Then, it will build the rest of the block by reaping and validating the transactions
+in the global index. The second portion of block building iterates from highest
+to lowest priority transactions in the global index and adds them to the proposal
+if they are valid. If the proposer comes across a transaction that was already
+included in the top of block, it will be ignored.
+
+### ProcessProposal
+
+After the proposer proposes a block of transactions for the next block, the
+block will be verified by other nodes in the network in `ProcessProposal`. If
+there is an auction transaction in the proposal, it must be the first transaction
+in the proposal and all bundled transactions must follow the auction transaction
+in the exact order we would expect them to be seen. If this fails, the proposal
+is rejected. If this passes, the validator will then run `CheckTx` on all of the
+transactions in the block in the order in which they were provided in the proposal.
+
+### Ante Handler
+
+When users want to bid for the rights for top-of-block execution they will submit
+a normal `sdk.Tx` transaction with a single `MsgAuctionBid`. The ante handler is
+responsible for verification of this transaction. The ante handler will verify that:
+
+1. The auction transaction specifies a timeout height where the bid is no longer
+ considered valid. Note, it is REQUIRED that all bid transactions include a
+ height timeout.
+2. The auction transaction includes less than `MaxBundleSize` transactions in
+ its bundle.
+3. The auction transaction includes only a SINGLE `MsgAuctionBid` message. We
+ enforce that no other messages are included to prevent front-running.
+4. Enforce that the user has sufficient funds to pay the bid they entered while
+ covering all relevant auction fees.
+5. Enforce that the transaction's min bid increment greater than the local highest
+ bid in the mempool.
+6. Enforce that the bundle of transactions the bidder provided does not front-run
+ or sandwich (if enabled).
+
+Note, the process of selecting auction winners occurs in a greedy manner. In
+`PrepareProposal`, the `AuctionMempool` will iterate from largest to smallest
+bidding transaction until it finds the first valid bid transaction.
+
+### State
+
+The `x/builder` module stores the following state objects:
+
+```protobuf
+message Params {
+ option (amino.name) = "cosmos-sdk/x/builder/Params";
+
+ // max_bundle_size is the maximum number of transactions that can be bundled
+ // in a single bundle.
+ uint32 max_bundle_size = 1;
+
+ // escrow_account_address is the address of the account that will receive a
+ // portion of the bid proceeds.
+ string escrow_account_address = 2;
+
+ // reserve_fee specifies the bid floor for the auction.
+ cosmos.base.v1beta1.Coin reserve_fee = 3
+ [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
+
+ // min_buy_in_fee specifies the fee that the bidder must pay to enter the
+ // auction.
+ cosmos.base.v1beta1.Coin min_buy_in_fee = 4
+ [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
+
+ // min_bid_increment specifies the minimum amount that the next bid must be
+ // greater than the previous bid.
+ cosmos.base.v1beta1.Coin min_bid_increment = 5
+ [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
+
+ // front_running_protection specifies whether front running and sandwich
+ // attack protection is enabled.
+ bool front_running_protection = 6;
+
+ // proposer_fee defines the portion of the winning bid that goes to the block
+ // proposer that proposed the block.
+ string proposer_fee = 7 [
+ (gogoproto.nullable) = false,
+ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec"
+ ];
+}
+```
+
+## Messages
+
+### MsgAuctionBid
+
+POB defines a new Cosmos SDK `Message`, `MsgAuctionBid`, that allows users to
+create an auction bid and participate in a top-of-block auction. The `MsgAuctionBid`
+message defines a bidder and a series of embedded transactions, i.e. the bundle.
+
+```protobuf
+message MsgAuctionBid {
+ option (cosmos.msg.v1.signer) = "bidder";
+ option (amino.name) = "pob/x/builder/MsgAuctionBid";
+
+ option (gogoproto.equal) = false;
+
+ // bidder is the address of the account that is submitting a bid to the
+ // auction.
+ string bidder = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
+ // bid is the amount of coins that the bidder is bidding to participate in the
+ // auction.
+ cosmos.base.v1beta1.Coin bid = 3
+ [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
+ // transactions are the bytes of the transactions that the bidder wants to
+ // bundle together.
+ repeated bytes transactions = 4;
+}
+```
+
+Note, the `transactions` may or may not exist in a node's application mempool. If
+a transaction containing a single `MsgAuctionBid` wins the auction, the block
+proposal will automatically include the `MsgAuctionBid` transaction along with
+injecting all the bundled transactions such that they are executed in the same
+order after the `MsgAuctionBid` transaction.
+
+When processing a `MsgAuctionBid`, the `x/builder` module will perform two primary
+actions:
+
+1. Ensure the bid is valid per the module's parameters and configuration.
+2. Extract fee payments from the bidder's account and escrow them to the module's
+ escrow account and the proposer that included the winning bid in the block
+ proposal.
+
+### MsgUpdateParams
+
+The `MsgUpdateParams` message allows for an authority, typically the `x/gov`
+module account, to update the `x/builder`'s parameters.
+
+```protobuf
+message MsgUpdateParams {
+ option (cosmos.msg.v1.signer) = "authority";
+ option (amino.name) = "pob/x/builder/MsgUpdateParams";
+
+ option (gogoproto.equal) = false;
+
+ // authority is the address of the account that is authorized to update the
+ // x/builder module parameters.
+ string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
+ // params is the new parameters for the x/builder module.
+ Params params = 2 [ (gogoproto.nullable) = false ];
+}
+```