title |
---|
For Searchers |
Bundles must only pass basic CheckTx
validation (e.g. nonce, account balance, etc.) in order to be accepted by the auction. This means that bundles that are submitted to the auction may not be entirely valid on-chain since runMsgs
is not executed. Searchers are encouraged to simulate their bundles before submitting them to the auction.
➡️ How do searchers submit bundles to chains that use the Block SDK?
💡 AuctionTx
(auction bid transaction) = sdk.Tx
that includes a single MsgAuctionBid
Searchers submit bundles by broadcasting a AuctionTx
in the same way they broadcast any other transaction. A few important things to note:
- When a
MsgAuctionBid
message is included in a transaction, no othersdk.Msg
can be present. - Interfacing with the auction may be different across
Block SDK
chains. Bidding may involve interacting with a dedicatedAuctionHouse
smart contract instead of including this special message type. In the future, we will link a chain directory here to check on which interface you need, when there are different implementations.
Default Auction Bid Message
type MsgAuctionBid struct {
Bidder string `protobuf:"bytes,1,opt,name=bidder,proto3" json:"bidder,omitempty"`
Bid types.Coin `protobuf:"bytes,3,opt,name=bid,proto3" json:"bid"`
Transactions [][]byte `protobuf:"bytes,4,rep,name=transactions,proto3" json:"transactions,omitempty"`
}
There are three things searchers must specify to participate in an auction:
- The
Transactions
they want executed at the top of block.- Transactions will be executed in the order they are specified in the message.
- Each transactions included must be the raw bytes of the transaction.
- The
Bidder
who is bidding for top of block execution.- This must be the same account that signs the transaction.
- The
Bid
they want to send alongside the bundle.- This should be in the denom configured by the auction parameters (see below)
- The
Timeout
height i.e. until what height the bid is valid for.- This must be added to the transaction when it is being constructed i.e.
txBuilder.SetTimeoutHeight(timeoutHeight)
- This must be added to the transaction when it is being constructed i.e.
Nonce Checking
In general, all bundles must respect nonce ordering of accounts. If a bundle is submitted with an invalid nonce, it will be rejected. The execution of the bundle will always look like the following:
- Auction Transaction (which extracts the bid)
- All transactions in the bundle (in order)
For example, assume the following:
- Searcher has account
A
with noncen
- Searcher wants to submit a bundle with 3 transactions from account
A
The searcher must first sign the AuctionTx
with nonce n + 1
. Then, the searcher must sign the first transaction in the bundle with nonce n + 2
, the second transaction with nonce n + 3
, and the third transaction with nonce n + 4
.
Skipper Bot
User’s can bootstrap their searching bots by utilizing Skip’s own open source Skipper Bot.
Creating an AuctionTx
func createBidTx(
privateKey *secp256k1.PrivKey,
bidder string,
bid sdk.Coin,
bundle [][]byte,
height uint64,
sequenceOffset uint64,
) (sdk.Tx, error) {
msgs := []sdk.Msg{
&buildertypes.MsgAuctionBid{
Bidder: bidder,
Bid: bid,
Transactions: bundle,
},
}
sequenceNum, accountNum := getAccountInfo(privateKey)
txConfig := authtx.NewTxConfig(
codec.NewProtoCodec(codectypes.NewInterfaceRegistry()),
authTx.DefaultSignModes,
)
txBuilder := txConfig.NewTxBuilder()
txBuilder.SetMsgs(msgs...)
...
txBuilder.SetGasLimit(5000000)
txBuilder.SetTimeoutHeight(height)
offsetNonce := sequenceNum + sequenceOffset
signerData := auth.SignerData{
ChainID: CHAIN_ID,
AccountNumber: accountNumber,
Sequence: offsetNonce,
}
sigV2, err = clientTx.SignWithPrivKey(
txConfig.SignModeHandler().DefaultMode(),
signerData,
txBuilder,
privateKey,
txConfig,
offsetNonce,
)
if err != nil {
return nil, err
}
if err = txBuilder.SetSignatures(sigV2); err != nil {
return nil, error
}
return txBuilder.GetTx(), nil
}
⚙️ Auction fees
All auction parameters are accessible though the /block-sdk/x/auction/v1/params
HTTP path on a standard node or gRPC service defined by x/auction
.
In order to participate in an auction, searchers must pay a fee. This fee is paid in the native token of the chain. The fee is determined by the auction parameters, which are set by the chain. The auction parameters are:
MaxBundleSize
: specifies the maximum number of transactions that can be included in a bundle (bundle = an ordered list of transactions). Bundles must be ≤ this number.ReserveFee
: specifies the bid floor to participate in the auction. Bids that are lower than the reserve fee are ignored.MinBidIncrement
: specifies how much greater each subsequent bid must be (as seen by an individual node) in order to be considered. If the bid is lower than thehighest current bid + min bid increment
, the bid is ignored.FrontRunningProtection
: determines whether front-running and sandwich protection is enabled.
If this is set to true, your bundle must follow these guidelines:
- You must put your signed transactions after transactions you didn’t sign
- You can only have at most two unique signers in the bundle
Bundle Examples:
- Valid: [tx1, tx2, tx3] where tx1 is signed by the signer 1 and tx2 and tx3 are signed by the bidder.
- Valid: [tx1, tx2, tx3, tx4] where tx1 - tx4 are signed by the bidder.
- Invalid: [tx1, tx2, tx3] where tx1 and tx3 are signed by the bidder and tx2 is signed by some other signer. (possible sandwich attack)
- Invalid: [tx1, tx2, tx3] where tx1 is signed by the bidder, and tx2, tx3 are signed by some other signer. (possible front-running attack)
Querying auction parameters
func getAuctionParams() (*auctiontypes.Params, error) {
# Replace this URL with the gRPC url of a node
url := "localhost:9090"
# Establish a gRPC connection to query auction parameters
grpcConn, err := grpc.Dial(
url,
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
return nil, err
}
client := auctiontypes.NewQueryClient(grpcConn)
req := &auctiontypes.QueryParamsRequest{}
resp, err := client.Params(context.Background(), req)
return resp.Params
}
🚨 Chains currently using the MEV-Lane
Mainnets
Chain Name | Chain-ID | Block-SDK Version |
---|---|---|
Juno | juno-1 | v1.0.2 |
Persistence | persistence-1 | v1.0.2 |
Initia | NA | v1.0.2 |
Prism | NA | v1.0.2 |
Terra | phoenix-1 | v1.0.2 |
Testnets
Chain Name | Chain-ID | Block-SDK Version |
---|---|---|
Juno | uni-6 | v1.0.2 |