diff --git a/SPEC.md b/SPEC.md new file mode 100644 index 00000000..d71156c2 --- /dev/null +++ b/SPEC.md @@ -0,0 +1,311 @@ + +# 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. + +### Configuration + +The `AuctionMempool` mempool implementation accepts a `AuctionFactory` +interface that allows the mempool to be generic across many Cosmos SDK +applications, such that it allows the ability for the application developer to +define their business logic in terms of how to perform things such as the following: + +* Getting tx signers +* Getting bundled tx signers +* Retrieving bid information + + +```go +// AuctionFactory defines the interface for processing auction transactions. +// It is a wrapper around all of the functionality that each application chain +// must implement in order for auction processing to work. +type AuctionFactory 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) (*AuctionBidInfo, error) +} +``` + +### 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 ]; +} +```