Flashbots Matchmaker
Client library for Flashbots MEV-share
Matchmaker.
Based on prospective API docs.
quickstart
Install from npm:
yarn add @flashbots/matchmaker-ts
npm i @flashbots/matchmaker-ts
Alternatively, clone the library & build from source:
git clone https://github.com/flashbots/matchmaker-ts
cd matchmaker-ts
yarn install && yarn build
yarn add ../matchmaker-ts
use matchmaker in your project
:warning: Variables denoted in ALL_CAPS
are placeholders; the code does not compile. examples/ contains compilable demos.
In your project:
import { Wallet, JsonRpcProvider } from "ethers"
import Matchmaker, {
BundleParams,
HintPreferences,
IPendingBundle,
IPendingTransaction,
TransactionOptions
} from "@flashbots/matchmaker-ts"
const provider = new JsonRpcProvider(RPC_URL)
const authSigner = new Wallet(FB_REPUTATION_PRIVATE_KEY, provider)
The Matchmaker
class has built-in initializers for networks supported by Flashbots.
Connect to Ethereum Mainnet
const matchmaker = Matchmaker.useEthereumMainnet(authSigner)
Connect to Ethereum Goerli
const matchmaker = Matchmaker.useEthereumGoerli(authSigner)
Connect with an Ethers Provider or Chain ID
Networks supported by Flashbots have presets built-in. If it's more convenient, you can instantiate a Matchmaker using a chainId
(or a ethers.js Network
object, which has a chainId
param).
import { JsonRpcProvider, Wallet } from "ethers"
const provider = new JsonRpcProvider("http://localhost:8545", {chainId: 5, name: "goerli"})
const authSigner = new Wallet("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")
.connect(provider)
const matchmaker = Matchmaker.fromNetwork(authSigner, provider._network)
const matchmaker = Matchmaker.fromNetwork(authSigner, {chainId: 5})
Connect to a custom network
To use custom network parameters, you can instantiate a new Matchmaker directly. This example is what the client uses to connect to mainnet:
const matchmaker = new Matchmaker(authSigner, {
name: "mainnet",
chainId: 1,
streamUrl: "https://mev-share.flashbots.net",
apiUrl: "https://relay.flashbots.net"
})
See MatchmakerNetwork for more details.
examples
Source code
:information_source: Examples require a .env
file (or that you populate your environment directly with the appropriate variables).
cd src/examples
cp .env.example .env
vim .env
send a tx with hints
This example sends a transaction to the Flashbots Goerli Matchmaker from the account specified by SENDER_PRIVATE_KEY with a hex-encoded string as calldata.
yarn example.tx
backrun a pending tx
This example watches the mev-share streaming endpoint for pending mev-share transactions and attempts to backrun them all. The example runs until a backrun has been included on-chain.
yarn example.backrun
Usage
See src/api/interfaces.ts for interface definitions.
on
Use on
to start listening for events on mev-share. The function registers the provided callback to be called when a new event is detected.
const handler = matchmaker.on("transaction", (tx: IPendingTransaction) => {
})
handler.close()
sendTransaction
Sends a private transaction to the Flashbots Matchmaker with specified hint parameters.
const wallet = new Wallet(PRIVATE_KEY)
const tx = {
to: "0xfb000000387627910184cc42fc92995913806333",
value: BigInt(1e13 * 275),
data: "0x646f637320626179626565652121",
gasLimit: 42000,
maxFeePerGas: BigInt(1e9) * BigInt(42),
maxPriorityFeePerGas: BigInt(1e9) * BigInt(2),
chainId: 5,
type: 2,
}
const shareTxParams: TransactionOptions = {
hints: {
logs: true,
calldata: false,
functionSelector: true,
contractAddress: true,
},
maxBlockNumber: undefined,
builders: ["flashbots"]
}
const signedTx = await wallet.signTransaction(tx)
await matchmaker.sendTransaction(SIGNED_TX, shareTxParams)
sendBundle
Sends a bundle; an array of transactions with parameters to specify conditions for inclusion and MEV kickbacks. Transactions are placed in the body
parameter with wrappers to indicate whether they're a new signed transaction or a pending transaction from the event stream.
See MEV-Share Docs for detailed descriptions of these parameters.
const bundleParams: BundleParams = {
inclusion: {
block: TARGET_BLOCK,
},
body: [
{hash: TX_HASH_FROM_EVENT_STREAM},
{tx: SIGNED_TX, canRevert: false},
],
validity: {
refund: [
{address: SEARCHER_ADDRESS, percent: 10}
]
},
privacy: {
hints: {
calldata: false,
logs: false,
functionSelector: true,
contractAddress: true,
},
}
}
await matchmaker.sendBundle(bundleParams)
simulateBundle
Simulates a bundle. Accepts options to modify block header for simulation.
const bundle: BundleParams = {
inclusion: {
block: TARGET_BLOCK,
maxBlock: TARGET_BLOCK + 3,
},
body: [
{hash: "0xTARGET_TX_HASH"},
{tx: "0xSIGNED_BACKRUN_TX", canRevert: false}
],
}
const simBundleOptions: SimBundleOptions = {
parentBlock: TARGET_BLOCK - 1,
blockNumber: TARGET_BLOCK,
}
const simResult = await matchmaker.simulateBundle(bundle, simBundleOptions)
This example uses the state of parentBlock
, but overrides the state's blockNumber
value. Setting more fields in SimBundleOptions
is useful when testing smart contracts which have specific criteria that must be met, like the block being a certain number, or a specific timestamp having passed.