UNPKG

flashbot-sdk

Version:

A simple wrapper for the Flashbots API with TypeScript support and latest ethers.js compatibility.

165 lines (163 loc) 4.88 kB
// core/flashbot.ts import { id } from "ethers"; // constants/types.ts var Relays; ((Relays2) => { Relays2["MAINNET"] = "https://relay.flashbots.net"; Relays2["SEPOLIA"] = "https://relay-sepolia.flashbots.net"; Relays2["GOERLI"] = "https://relay-goerli.flashbots.net"; })(Relays ||= {}); var Methods; ((Methods2) => { Methods2["GET_USER_STATS_V2"] = "flashbots_getUserStatsV2"; Methods2["GET_BUNDLE_STATS_V2"] = "flashbots_getBundleStatsV2"; Methods2["SEND_PRIVATE_TRANSACTION"] = "eth_sendPrivateTransaction"; Methods2["SEND_PRIVATE_RAW_TRANSACTION"] = "eth_sendPrivateRawTransaction"; Methods2["CANCEL_BUNDLE"] = "eth_cancelBundle"; Methods2["CALL_BUNDLE"] = "eth_callBundle"; Methods2["SEND_BUNDLE"] = "eth_sendBundle"; })(Methods ||= {}); // core/flashbot.ts class Flashbot { relay; provider; user; defaultBody = { jsonrpc: "2.0", id: 1 }; constructor(relay, user, provider) { if (!user?.provider) throw new Error("User must have a provider"); this.relay = relay; this.user = user; this.provider = provider; } async getSignature(body) { return `${this.user.address}:${await this.user.signMessage(id(JSON.stringify(body)))}`; } calculateEffectiveGas(baseFee, maxPriority) { const effectiveGas = Number(baseFee) + Number(maxPriority); return BigInt(effectiveGas); } async getUserStats(params) { const body = { ...this.defaultBody, method: "flashbots_getUserStatsV2" /* GET_USER_STATS_V2 */, params }; const res = await fetch(`${this.relay}`, { method: "POST", body: JSON.stringify(body), headers: { "Content-Type": "application/json", "X-Flashbots-Signature": `${await this.getSignature(body)}` } }); if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); const data = await res.json(); if (data.error) throw new Error(data.error); if (data.message) throw new Error(data.message); return data; } async simulate(params) { const body = { ...this.defaultBody, method: "eth_callBundle" /* CALL_BUNDLE */, params }; const res = await fetch(`${this.relay}`, { method: "POST", body: JSON.stringify(body), headers: { "Content-Type": "application/json", "X-Flashbots-Signature": `${await this.getSignature(body)}` } }); if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); const data = await res.json(); if (data.error) throw new Error(data.error.message); return { simulationResult: data.result, send: () => this.sendBundle(params) }; } async sendBundle(params) { const body = { ...this.defaultBody, method: "eth_sendBundle" /* SEND_BUNDLE */, params }; const res = await fetch(`${this.relay}`, { method: "POST", body: JSON.stringify(body), headers: { "Content-Type": "application/json", "X-Flashbots-Signature": `${await this.getSignature(body)}` } }); if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); const data = await res.json(); if (data.error) throw new Error(data.error.message); return data; } async getBundleStatsV2(params) { const body = { ...this.defaultBody, method: "flashbots_getBundleStatsV2" /* GET_BUNDLE_STATS_V2 */, params }; const res = await fetch(`${this.relay}`, { method: "POST", body: JSON.stringify(body), headers: { "Content-Type": "application/json", "X-Flashbots-Signature": `${await this.getSignature(body)}` } }); if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); const data = await res.json(); return data; } async waitForInclusion(targetBlock, hashes) { return new Promise((resolve, reject) => { const blockHandler = async (blockNum) => { const tx = await this.provider.getBlock(blockNum); if (!tx?.transactions || tx.transactions.length === 0) return; const transactions = tx.transactions.map((tx2) => tx2); if (transactions.some((tx2) => hashes.includes(tx2))) { this.provider.removeListener("block", blockHandler); resolve({ status: "success", blockNumber: blockNum, transactions: transactions.filter((tx2) => hashes.includes(tx2)) }); } if (blockNum >= targetBlock) { this.provider.removeListener("block", blockHandler); resolve({ status: "passed", blockNumber: blockNum, transactions: [] }); } }; this.provider.on("block", blockHandler); }); } } var flashbot_default = Flashbot; export { Relays, Methods, flashbot_default as Flashbot };