Submission Methods

Types of Submissions

Bundles can be submitted to the FastLane Relay RPC endpoint using JSON-RPC 2.0 over HTTPS and Websocket.

Searchers can send their submissions to the FastLane Relay API by calling the methods pfl_addSearcherBundle for Bundles

More information on the FastLane Relay API and API calls can be found here:

Relay JSON-RPC API

Rate limits (for both HTTP and websocket):

Request/message limit per second: 2

Burst limit: 32

Repeatedly going over the rate limit will result in temporary IP ban, ranging from 3 minutes to 24 hours.

HTTPS

It's recommended that you use HTTP Keep-Alive connections to connect to the RPC endpoint to minimize TLS connection establishment times as it significantly reduces request latency when sending a bundle if the TLS handshake is already complete.

The /ping endpoint is available for establishing a session, you can have a maximum of 2 sessions per IP address, and sessions will persist for a maximum of 15 minutes.

Example:

import axios from 'axios';

// Abstracted function to create the PFL bundle
function createPflBundle(bundleId, opportunityRawTx, solverOpStruct) {
  return {
    id: bundleId,
    jsonrpc: "2.0",
    method: "pfl_addSearcherBundle",
    params: [opportunityRawTx, solverOpStruct]
  };
}

// Helper function to submit the bundle to the Fastlane endpoint
async function submitBundle(bundle) {
  const httpFastlaneEndpoint = "https://polygon-rpc.fastlane.xyz";

  try {
    const response = await axios.post(httpFastlaneEndpoint, bundle, {
      timeout: 1000
    });

    if (response.data.error) {
      console.error(`Error submitting bundle ${bundle.id}`, response.data);
    } else {
      console.log(`Response received for bundle ${bundle.id}`, response.data);
    }
  } catch (error) {
    console.error(`Error submitting bundle ${bundle.id}`, error);
  }
}

// Main function to submit the bundle
async function main() {
  // Define your variables
  const bundleId = 1;
  const opportunityRawTx = "0x..."; // Replace with your actual opportunity raw transaction
  const solverOpStruct = "0x...";   // Replace with your actual solver operation structure

  // Create the PFL bundle
  const pflBundle = createPflBundle(bundleId, opportunityRawTx, solverOpStruct);

  // Submit the bundle to the Fastlane endpoint
  await submitBundle(pflBundle);
}

main().catch(console.error);

Websocket

Ping messages will be sent to your connection every 60 seconds. A pong response must be sent to avoid disconnection. Alternatively, you can send ping messages yourself to the server every minutes and get pong responses.

To keep a websocket connection open and stable on a long term, we highly recommend to send ping messages to the server every minutes, and to answer pong every time the server sends a ping message.

To better track responses (e.g. when sending multiple concurrent requests), it is highly advised to specify a unique id for each new requests, see example below.

Example:

const WebSocket = require('ws');

// Abstracted function to create the PFL bundle with arguments
function createPflBundle(bundleId, opportunityRawTx, solverOpStruct) {
  return {
    id: bundleId,
    jsonrpc: "2.0",
    method: "pfl_addSearcherBundle",
    params: [`${opportunityRawTx}`, `${JSON.stringify(solverOpStruct)}`]
  };
}

// Helper function to submit the bundle to the Fastlane endpoint over WebSocket
async function submitBundle(bundle) {
  const wsFastlaneEndpoint = "wss://beta-rpc.fastlane-labs.xyz/ws";

  return new Promise((resolve, reject) => {
    const ws = new WebSocket(wsFastlaneEndpoint);

    ws.on('open', function open() {
      // Send the bundle as a JSON-RPC request
      ws.send(JSON.stringify(bundle));
    });

    ws.on('message', function incoming(data) {
      const response = JSON.parse(data);
      if (response.error) {
        console.error(`Error submitting bundle ${bundle.id}`, response);
        ws.close();
        reject(response.error);
      } else {
        console.log(`Response received for bundle ${bundle.id}`, response);
        ws.close();
        resolve(response.result);
      }
    });

    ws.on('error', function error(err) {
      console.error(`WebSocket error for bundle ${bundle.id}`, err);
      ws.close();
      reject(err);
    });

    ws.on('close', function close(code, reason) {
      console.log(`WebSocket connection closed: ${code} ${reason}`);
    });
  });
}

// Main function to submit the bundle
async function main() {
  // Define your variables
  const bundleId = 1;
  const opportunityRawTx = "0x..."; // Replace with your actual opportunity raw transaction
  const solverOpStruct = "0x...";   // Replace with your actual solver operation structure

  // Create the PFL bundle
  const pflBundle = createPflBundle(bundleId, opportunityRawTx, solverOpStruct);

  // Submit the bundle to the Fastlane endpoint
  await submitBundle(pflBundle);
}

main().catch(console.error);

Last updated