Polygon FastLane
  • What is Polygon FastLane?
    • Overview
    • Design Principles
    • Components
    • Component Diagram
  • Getting Started as a Validator
    • Getting Started as a Validator
    • Connecting to a FastLane Sentry Node
      • Finding Your Enode Address & Peer ID
      • Adding FastLane as a Static Peer
    • Patching Your Sentry Nodes With The FastLane Patch
      • Installing from source
        • Patch Download
        • Patch Installation
      • Installing from packages
  • Withdrawing Validator Revenue
    • Validator Vault
      • Connect an Eligible Wallet
      • Revenue Redemption (withdrawal)
  • Searcher Guides
    • Getting Started as a Searcher
      • Solver Call Data
      • Submission Methods
      • Migration Guide for Searchers
    • Bundles (Backruns)
      • Bundle Format
      • Bid Submission
      • Bundle Requirements
      • Full Example
      • Subscribe Events
    • 4337 Bundles Integration Guide
      • Overview
      • How it works
      • RPC Reference
      • Examples
    • Searcher Contract Integration
      • Safety Considerations
      • atlasSolverCall
      • Direct Implementation
      • Proxy Implementation
      • Solver Concepts
      • Altas Bonding Concept
      • Bond atlETH
      • Estimating Solver Gas Charges
    • Addresses & Endpoints
    • Helpers
    • Common Mistakes
    • Atlas SDK's
  • Tools and Analytics
    • FastLane Bundle Explorer
      • Features Overview
      • Key Components
      • Usage Example
      • Error Codes & Troubleshooting
  • Key Concepts
    • Transaction Encoding
  • INFRASTRUCTURE
    • Health Status Endpoint
  • Reference
    • Relay JSON-RPC API
    • Relay REST API
    • Glossary of Terms
Powered by GitBook
On this page
  • Types of Submissions
  • HTTPS
  • Websocket
  1. Searcher Guides
  2. Getting Started as a Searcher

Submission Methods

PreviousSolver Call DataNextMigration Guide for Searchers

Last updated 6 months ago

Types of Submissions

can be submitted to the using JSON-RPC 2.0 over HTTPS and Websocket.

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

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

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);
import asyncio
import aiohttp
import json

# Asynchronous function to test the connection to the Fastlane endpoint
async def ping_fastlane():
    http_fastlane_ping_endpoint = "https://polygon-rpc.fastlane.xyz/ping"
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(http_fastlane_ping_endpoint, timeout=10) as response:
                if response.status == 200:
                    text = await response.text()
                    print("Ping successful:", text)
                else:
                    print("Ping failed with status code:", response.status)
    except aiohttp.ClientError as e:
        print("Ping failed:", e)
    except asyncio.TimeoutError:
        print("Ping failed: Request timed out")

# Function to create the PFL bundle with specified arguments
def create_pfl_bundle(bundle_id, opportunity_raw_tx, solver_op_struct):
    return {
        "id": bundle_id,
        "jsonrpc": "2.0",
        "method": "submitBundle",
        "params": [opportunity_raw_tx, solver_op_struct]
    }

# Asynchronous function to submit the bundle to the Fastlane endpoint
async def submit_bundle(bundle):
    http_fastlane_endpoint = "https://polygon-rpc.fastlane.xyz"
    try:
        async with aiohttp.ClientSession() as session:
            async with session.post(http_fastlane_endpoint, json=bundle, timeout=10) as response:
                response.raise_for_status()  # Raise an error for bad HTTP status codes
                response_data = await response.json()
                if 'error' in response_data:
                    print(f"Error submitting bundle {bundle['id']}: {response_data['error']}")
                else:
                    print(f"Response received for bundle {bundle['id']}: {response_data['result']}")
    except aiohttp.ClientResponseError as http_err:
        print(f"HTTP error occurred while submitting bundle {bundle['id']}: {http_err}")
    except aiohttp.ClientError as client_err:
        print(f"Client error occurred while submitting bundle {bundle['id']}: {client_err}")
    except asyncio.TimeoutError:
        print(f"Error submitting bundle {bundle['id']}: Request timed out")
    except json.JSONDecodeError as json_err:
        print(f"JSON decode error for bundle {bundle['id']}: {json_err}")

# Asynchronous main function to test connection and submit the bundle
async def main():
    # Test the connection to the Fastlane endpoint
    await ping_fastlane()
    
    # Wait until you're ready to send a bundle, refreshing session as necessary
    # You might include a delay or a condition here if needed
    
    # Define your variables
    bundle_id = 1
    opportunity_raw_tx = "0x..."  # Replace with your actual opportunity raw transaction
    solver_op_struct = "0x..."    # Replace with your actual solver operation structure
    
    # Create the PFL bundle with the specified arguments
    pfl_bundle = create_pfl_bundle(bundle_id, opportunity_raw_tx, solver_op_struct)
    
    # Submit the bundle to the Fastlane endpoint
    await submit_bundle(pfl_bundle)

if __name__ == "__main__":
    asyncio.run(main())

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);
import asyncio
import websockets
import json

# Function to create the PFL bundle with arguments
def create_pfl_bundle(bundleId, opportunityRawTx, solverOpStruct):
    return {
        "id": bundleId,
        "jsonrpc": "2.0",
        "method": "pfl_addSearcherBundle",  # Ensure the method name matches the JS version
        "params": [
            f"{opportunityRawTx}",                   # Convert opportunityRawTx to string
            f"{json.dumps(solverOpStruct)}"          # Serialize solverOpStruct to JSON string
        ]
    }

# Helper function to submit the bundle via WebSocket
async def submit_bundle(bundle):
    websocket_endpoint = "wss://polygon-rpc.fastlane.xyz"
    try:
        async with websockets.connect(websocket_endpoint) as websocket:
            await websocket.send(json.dumps(bundle))
            response = await websocket.recv()
            response_data = json.loads(response)
            if 'error' in response_data:
                print(f"Error submitting bundle {bundle['id']}:", response_data['error'])
            else:
                print(f"Response received for bundle {bundle['id']}:", response_data['result'])
    except Exception as e:
        print(f"Error submitting bundle {bundle['id']}:", e)

# Main function to submit the bundle
async def main():
    # Wait until you're ready to send a bundle, refreshing session as necessary
    # You might want to include some delay or conditions here
    
    # Define your variables
    bundleId = 1
    opportunityRawTx = "0x..."  # Replace with your actual opportunity raw transaction
    solverOpStruct = "0x..."    # Replace with your actual solver operation structure
    
    # Create the PFL bundle with the specified arguments
    pfl_bundle = create_pfl_bundle(bundleId, opportunityRawTx, solverOpStruct)
    
    # Submit the bundle to the Fastlane endpoint
    await submit_bundle(pfl_bundle)

if __name__ == "__main__":
    asyncio.run(main())

Bundles
FastLane Relay RPC endpoint
Relay JSON-RPC API
pfl_addSearcherBundle