Searcher Call Data

The _searcherCallData argument of the FastLane Auction Handler's submitFlashBid and submitFastBid function should be the transaction data necessary for the searcher's smart contract (as specified by _searcherToAddress) to execute as intended.

The easiest way to get the correct _searcherCallData is for the searcher to create a transaction directly to their own smart contract (as if FastLane didn't exist) and extract that transaction's 'data' value.


There are many approaches on how you want to use the _searcherCallData and they're ultimately up to you.

Potential Approaches:

  • Use it to call another function inside your smart contract In this case _searcherCallData is an encoding of yourFunction(yourParams) that you most likely will call inside your fastLaneCall function with address(this).call(_searcherCallData)

  • Only some arguments to be decoded inside an internal function of your smart contract In this case _searcherCallData is an encoding of param1uint, param2string .. and inside fastLaneCall you will do _myInternalFunction(_searcherCallData) and it's up to _myInternalFunction to decode those back in using abi.decode() like (_param1, _param2) = abi.decode(_searcherCallData, (uint, string))

Example:

// Function you want to use later when received 
// as `_searcherCallData in your searcherContract.fastLaneCall()

// Let's assume you already have a function on your searcher contract
// That does the MEV called doMEV and you just want to call it

const ethers = require('ethers');

const searcherAbi = [
    `function doMEV(uint256, string)`,
  ];

const iface = new ethers.utils.Interface(searcherAbi);

// Grab bytes for doMEV(uint256, string)
const searcherCallDataBytes = iface.encodeFunctionData("doMEV", [ethers.utils.parseEther("1.0"), "hello"]);

Then in your searcher contract you will be able to use it in the fastLaneCall(

contract SearcherHelperUseCallDataFunction {
    function fastLaneCall(
            address _sender,
            uint256 _bidAmount,
            bytes calldata _searcherCallData
    ) external payable returns (bool, bytes memory) {
        bool success;
        
        // Use _searcherCallData to call doMEV
        address(this).call(_searcherCallData);
        
        // Repay Relay
        address to = msg.sender;
        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, _bidAmount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
        return (true,bytes("ok"));
    }
    
    function doMEV(uint256 someInt, string memory someString) public {
        // Your usual security checks, you can allow a list of EOAs 
        // that normally call directly this function (when not using the fastlane)
        // And also whitelist it to be called internally when done
        // from fastLaneCall above
        require(msg.sender == address(this), "Oops");
        // do MEV ...
    }
}

If on the other hand

You just want to get access to params

// Params you want to use later when received 
// for _useMevParams(_searcherCallData) in your searcherContract.fastLaneCall()

const ethers = require('ethers');

const abi = ethers.utils.defaultAbiCode;

// https://docs.ethers.io/v5/api/utils/abi/coder/#AbiCoder--methods
const searcherCallDataBytes = abi.encode(["uint","string"],[100,"hello"]);
contract SearcherHelperUseCallDataParams {
    function fastLaneCall(
            address _sender,
            uint256 _bidAmount,
            bytes calldata _searcherCallData
    ) external payable returns (bool, bytes memory) {
        bool success;
        
        // Use _searcherCallData as params
        _useMevParams(_searcherCallData);
        
        // Repay Relay
        address to = msg.sender;
        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, _bidAmount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
        return (true,bytes("ok"));
    }
    
    function _useMevParams(bytes memory _searcherCallData) internal {
        (uint256 someInt, string memory someString) = abi.decode(_searcherCalldata, (uint, string));
         // do MEV ...
    }
}

Last updated