FastLane Searcher transactions are calls to the FastLane Auction Handler's submitFlashBid function, which then calls the fastLaneCall function in the searcher's own contract.
_bidAmount (type uint256): The amount in wei that the searcher is bidding.
_oppTxHash (type bytes32): The hash of the opportunity-creating transaction included in the searcher's bundle.
_searcherToAddress (type address): The address of the searcher’s smart contract (or proxy contract, if applicable).
_searcherCallData (type bytes): The data used to call the searcher’s smart contract.
Example:
const { ethers } =require('ethers');const { utils } = ethers;constabi=require('./FastLaneAuctionHandlerAbi.json');constPRIVATE_KEY="0xMyPrivateKey";// Using alchemy here as demo but most likely you will use// ethers.providers.JsonRpcProvider(); or httpProvider// For tapping into your own rpc for speed// This is just a mean to get an oppTx and oppTxRawconstprovider=newethers.providers.AlchemyProvider("matic","alchemy-token");constsigner=newethers.Wallet(PRIVATE_KEY);constbidAmount=100000;constoppTxHash="0x1fc0f032a4957c0001989c984f732a06c388472bf08b4c8fb13d8bf8db32004a";// Your contract,// Implementing `fastLaneCall(address,uint256,bytes) external payable returns (bool, bytes)`constsearcherContract="0xeA26974363EC1dBc132C99cF9A29273B17254aE3";// FastLane Current ContractconstauctionHandler="0xf5DF545113DeE4DF10f8149090Aa737dDC05070a";// Assuming as a searcher I intend to use _searcherCallDataBytes// when received on my searcher contract `fastLaneCall(` callback// to then trigger searcherContract.doMEV(uint256,string);// See: Searcher Call Data section of the docs for more informationsconstsearcherAbi= [`function doMEV(uint256, string)`, ];constiface=newethers.utils.Interface(searcherAbi);// Grab bytes for doMEV(uint256, string)constsearcherCallDataBytes=iface.encodeFunctionData("doMEV", [ethers.utils.parseEther("1.0"),"hello"]);constAuctionHandlerContract=newethers.Contract(auctionHandler, abi, signer);asyncfunctioncreateBundle() {constoppTx=awaitprovider.getTransaction(oppTxHash);constsignedOppTx=getRawTransaction(oppTx);consttx=awaitAuctionHandlerContract.populateTransaction.submitFlashBid( bidAmount, oppTxHash, searcherContract, searcherCallDataBytes, { type:oppTx.type,// Legacy here for `oppTxHash` gasLimit:utils.hexlify(500000),// Need these for type2:// maxPriorityFeePerGas: oppTx.maxPriorityFeePerGas,// maxFeePerGas: oppTx.maxFeePerGas, gasPrice:oppTx.gasPrice, value:ethers.utils.parseEther("2.0") // Sending along 2MATIC, you could send bidAmount and return it aswell });tx.chainId =137;constsignedSearcherTx=awaitsigner.signTransaction(tx);console.log("Precomputed searcherTxHash:",ethers.utils.keccak256(signedSearcherTx));constbundle= [ signedOppTx, signedSearcherTx ];console.log(bundle);return bundle;}functiongetRawTransaction(tx) {functionaddKey(accum, key) {if (tx[key]) { accum[key] = tx[key]; }return accum; }// Extract the relevant parts of the transaction and signature const txFields = "accessList chainId data gasPrice gasLimit maxFeePerGas maxPriorityFeePerGas nonce to type value".split(" ");
constsigFields="v r s".split(" ");// Seriailze the signed transactionconstraw=utils.serializeTransaction(txFields.reduce(addKey, { }),sigFields.reduce(addKey, { }));// Double check things went wellif (utils.keccak256(raw) !==tx.hash) { thrownewError("serializing failed!"); }return raw;}createBundle();
Please see Full Example section on how to target your own transaction instead of one from a provider.