Submitting Transaction

This endpoint is used to broadcast a signed transaction

How OFR Handles Transaction Propagation

When you submit a transaction to the OFR endpoint, bloXroute’s infrastructure determines the current Solana leader and forwards the transaction to the Trader API instance that is geographically closest to that leader. This dynamic routing reduces latency and increases the probability of successful inclusion on-chain.

This behavior is fully abstracted away from the user. You do not need to manually manage or track leader locations—OFR handles that for you.

To maximize reliability and minimize latency, we recommend submitting each transaction to:

This dual submission approach ensures both localized propagation from your own infrastructure and optimized propagation through OFR’s leader-aware routing.

Gateway setup

The two flags required at gateway startup for transaction submission are: -run-http-server and -http-port :

docker run --name bxgateway-solana -d \
  --network=host bloxroute/solana-gateway:latest \
  -auth-header=[AuthHeader] \
  -run-http-server \
  -http-port=8080 \
  -ofr-host=ny.solana-v2.blxrbdn.com \
  -port=18888

Additionally, gateway can be started with the -tx-submission-only flag. This will launch the gateway in a dormant mode in which no shreds are sent nor received from OFR, effectively turning it into a local transaction submission API only.

Request

Method:

POST ./submit

Example

The Solana Gateway, connecting to the bloXroute Optimized Feed Relay (OFR), should run with http server flags, and more details about flags can be found here.

package main

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"github.com/gagliardetto/solana-go"
	"github.com/gagliardetto/solana-go/rpc"
	"io"
	"net/http"
)

func createJsonReq(solanaTx *solana.Transaction, frp, fbe, useStakedRPCs bool) ([]byte, error) {
	txBase64, err := solanaTx.ToBase64()
	if err != nil {
		return nil, err
	}

	txBytes, err := rpc.DataBytesOrJSONFromBase64(txBase64)
	if err != nil {
		return nil, err
	}

	twm := rpc.TransactionWithMeta{
		Transaction: txBytes,
	}

	txWithMeta, err := twm.GetTransaction()
	if err != nil {
		return nil, err
	}

	txData, err := txWithMeta.MarshalBinary()
	if err != nil {
		return nil, err
	}

	var jsonStr = []byte(fmt.Sprintf(`{"transaction": {"content": "%v"}, "frontRunningProtection": %v, "useStakedRPCs": %v, "fastBestEffort": %v}`,
		base64.StdEncoding.EncodeToString(txData), frp, useStakedRPCs, fbe))
	return jsonStr, nil
}

func main() {
	// create your solana tx
	solanaTx := &solana.Transaction{
		Signatures: nil,
		Message:    solana.Message{},
	}
	//endpoint for solana gw to submit tx
	url := "http://127.0.0.1:8080/submit"
	jsonStr, err := createJsonReq(solanaTx, false, false, false)
	if err != nil {
		fmt.Println(err)
		return
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	if err != nil {
		fmt.Println(err)
		return
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "<AUTH_HEADER>")

	httpClient := http.DefaultClient
	resp, err := httpClient.Do(req)
	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(fmt.Sprintf("read response body: %s", err))
	}
	fmt.Println(string(body))
}

Last updated