[Suspended] MEV Bundle RPC Endpoint
Blocknative's MEV Bundle RPC Endpoint follows the standards of builders in the ecosystem to allow searchers to quickly start sending bundles to the Blocknative Builder.
The Blocknative Auction endpoint was suspended on September 27, 2023 at 8am PST.
Bundles you submit to the Blocknative auction gateway will return a 503 error code. Please remove the Blocknative endpoint from your configuration.
Searchers can interact with the RPC endpoints :
Mainnet:
https://api.blocknative.com/v1/auction
Goerli:https://api.blocknative.com/v1/auction?network=goerli
The API provides JSON-RPC methods for interfacing with Blocknative builders, which are documented below:
To send your bundles to the Blocknative builders, you can use eth_sendBundle with the following payload format:
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_sendBundle",
"params": [
{
txs, // Array[String], A list of signed transactions to execute in an atomic bundle
blockNumber, // String, a hex encoded block number for which this bundle is valid on
minTimestamp, // (Optional) Number, the minimum timestamp for which this bundle is valid, in seconds since the unix epoch
maxTimestamp, // (Optional) Number, the maximum timestamp for which this bundle is valid, in seconds since the unix epoch
revertingTxHashes, // (Optional) Array[String], A list of tx hashes that are allowed to revert
uuid, // (Optional) String, a unique identifier of the bundle. This field can be used for bundle replacement and bundle cancellation
refundPercent, // (Optional) Number, the percentage (from 0 to 99) of the ETH reward of the last transaction, or the transaction specified by refundIndex, that should be refunded back to the ‘refundRecipient’
refundIndex, // (Optional) Number, the index of the transaction of which the ETH reward should be refunded. Default, last transaction in the bundle
refundRecipient, // (Optional) Address, the address that will receive the ETH refund. Default, sender of the first transaction in the bundle
}
]
}
In order to use
eth_cancelBundle
or bundle replacement the Uuid
must be set when submitting the bundleexample request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_sendBundle",
"params": [
{
"txs": ["0x123abc...", "0x456def..."],
"blockNumber": "0xb63dcd",
"minTimestamp": 0,
"maxTimestamp": 1615920932
}
]
}
example response:
{
"jsonrpc": "2.0",
"id": "123",
"result": {
"bundleHash": "0x2228f5d8954ce31dc1601a8ba264dbd401bf1428388ce88238932815c5d6f23f"
}
}
To replace a bundle, send the new bundle via
eth_sendBundle
with the same uuid
as the bundle you want to replace. Your previous bundle will be canceled and replaced with the new bundle - this is faster than canceling and resubmitting.To prevent a previously submitted bundle from being included on-chain
eth_cancelBundle
should be called with the UUID
of the target bundle.example request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_cancelBundle",
"params": [
{
uuid, // UUID of the previously submitted bundle
}
]
}
example response:
The response is empty/null
To simulate a bundle against a specific block number, including simulating a bundle at the top of the next block, you can use
eth_callBundle
with the following payload format:{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_callBundle",
"params": [
{
txs, // Array[String], A list of signed transactions to execute in an atomic bundle
blockNumber, // String, a hex encoded block number for which this bundle is valid on
stateBlockNumber, // String, either a hex encoded number or a block tag for which state to base this simulation on. Can use "latest"
timestamp, // (Optional) Number, the timestamp to use for this bundle simulation, in seconds since the unix epoch
}
]
}
example request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_callBundle",
"params": [
{
"txs": ["0x123abc...", "0x456def..."],
"blockNumber": "0xb63dcd",
"stateBlockNumber": "latest",
"timestamp": 1615920932
}
]
}
example response:
{
"jsonrpc": "2.0",
"id": "123",
"result": {
"bundleGasPrice": "476190476193",
"bundleHash": "0x73b1e258c7a42fd0230b2fd05529c5d4b6fcb66c227783f8bece8aeacdd1db2e",
"coinbaseDiff": "20000000000126000",
"ethSentToCoinbase": "20000000000000000",
"gasFees": "126000",
"results": [
{
"coinbaseDiff": "10000000000063000",
"ethSentToCoinbase": "10000000000000000",
"fromAddress": "0x02A727155aeF8609c9f7F2179b2a1f560B39F5A0",
"gasFees": "63000",
"gasPrice": "476190476193",
"gasUsed": 21000,
"toAddress": "0x73625f59CAdc5009Cb458B751b3E7b6b48C06f2C",
"txHash": "0x669b4704a7d993a946cdd6e2f95233f308ce0c4649d2e04944e8299efcaa098a",
"value": "0x"
},
{
"coinbaseDiff": "10000000000063000",
"ethSentToCoinbase": "10000000000000000",
"fromAddress": "0x02A727155aeF8609c9f7F2179b2a1f560B39F5A0",
"gasFees": "63000",
"gasPrice": "476190476193",
"gasUsed": 21000,
"toAddress": "0x73625f59CAdc5009Cb458B751b3E7b6b48C06f2C",
"txHash": "0xa839ee83465657cac01adc1d50d96c1b586ed498120a84a64749c0034b4f19fa",
"value": "0x"
}
],
"stateBlockNumber": 5221585,
"totalGasUsed": 42000
}
}
To authenticate your request, Blocknative endpoints require you to sign the payload and include the signed payload in the
X-Flashbots-Signature
or X-Auction-Signature
header of your request:Using
X-Flashbots-Signature
curl -X POST -H "Content-Type: application/json" -H "X-Flashbots-Signature: 0x1234:0xabcd" --data '{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}' <https://api.blocknative.com/v1/auction>
Using
X-Auction-Signature
curl -X POST -H "Content-Type: application/json" -H "X-Auction-Signature: 0x1234:0xabcd" --data '{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}' <https://api.blocknative.com/v1/auction>
Note: both
X-Auction-Signature
and x-auction-signature
will work, this is case insensitive.Any valid Ethereum key can be used to sign the payload. The Ethereum address associated with this key will be used by Blocknative to keep track of your requests over time and provide user statistics. You can change the key you use at any time.
Here's an example using ethers.js:
ether.js
web3.py
Go
import { Wallet, utils } from "ethers";
const privateKey = "0x1234";
const wallet = new Wallet(privateKey);
const body =
'{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}';
const signature = wallet.address + ":" + wallet.signMessage(utils.id(body));
from web3 import Web3
from eth_account import Account, messages
body = '{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}'
message = messages.encode_defunct(text=Web3.keccak(text=body).hex())
signature = Account.from_key(private_key).address + ':' + Account.sign_message(message, private_key).signature.hex()
body := `{"jsonrpc":"2.0","method":"eth_sendBundle","params":[{see above}],"id":1}`
hashedBody := crypto.Keccak256Hash([]byte(body)).Hex()
sig, err := crypto.Sign(accounts.TextHash([]byte(hashedBody)), privKey)
signature := crypto.PubkeyToAddress(privKey.PublicKey).Hex() + ":" + hexutil.Encode(sig)