bloXroute Documentation
WebsiteBlogTwitterDiscord
  • Welcome to bloXroute
  • Introduction
    • Why Use bloXroute?
    • Products
    • Create An Account
    • Technical Support
  • SOLANA
    • Trader API
      • Introduction
        • Regions
        • Authorization
        • Rate Limits
        • Tip and Tipping Addresses
      • Quick Start
        • Transaction Submission
        • Front-Running Protection & Transaction Bundle
        • Go SDK
        • Python SDK
        • Typescript SDK
        • Rust SDK
      • API Endpoints
        • Core Endpoints
          • submit
          • submit-paladin
          • submit-batch
          • balance
          • rate-limit
          • transaction
          • priority-fee
          • GetPriorityFeeStream
          • GetBundleTipStream
          • submit-snipe
        • Pump.fun
          • quotes
          • swap
          • swap-sol
          • GetPumpFunNewTokensStream
          • GetPumpFunSwapsStream
          • GetPumpFunAMMSwapsStream
        • Raydium
          • quotes
          • pools
          • pool-reserves
          • swap
          • cpmm-swap
          • clmm-swap
          • route-swap
          • GetPoolReservesStream
          • GetSwapsStream
          • GetNewRaydiumPoolsStream
          • GetNewRaydiumPoolsByTransactionStream
        • Jupiter
          • quotes
          • swap
          • swap-instructions
          • route-swap
        • Openbook
          • markets
          • orderbooks/{market}
          • depth/{market}
          • tickers/{market}
          • open-orders/{market}
          • unsettled/{market}
          • place
          • replace
          • cancel
          • settle
          • GetOrderbooksStream
          • GetTickersStream
      • Best Performance for Landing Transactions
      • Support
        • API Health
        • Contact us
        • Suggestions
        • Wiki
          • Terms & Concepts
          • Resources
    • Optimized Feed Relay (OFR)
      • Transaction Streamer
      • Gateway and OFR Requirements
      • Gateway and OFR Setup
      • Gateway Startup Arguments
      • OFR performance
      • Logging
      • Submitting Transaction
      • Upgrading Gateway
      • Troubleshooting
  • BSC & ETH
    • EVM Blockchain Distribution Network (BDN)
      • How to Connect
      • The bloXroute Gateway
        • Local Gateway
          • Installation and Startup
            • Authentication & Certificates
            • Requirements
            • Supported Clients
            • GitHub repository option
            • Docker container option
            • Startup Script
            • Startup Arguments
          • General Connectivity Troubleshooting
          • Logging
          • Upgrading your Gateway
        • Add Your Gateway as a Trusted Peer to Your Execution Layer Client
        • Connecting Your Gateway with the Consensus Layer
      • IPs & Relays
        • Relays IPs
        • Private Relays
        • Cloud-API IPs
          • ⏩Reducing Latencies using the BDN
    • APIs
      • Authorization
      • Check Transaction Quota
      • Submit a Transaction
        • Raw Transaction Construction
        • Tx-Validation
        • Batch Transaction
      • Private Transactions
        • ETH Private Transactions
        • BSC Private Transactions
      • Transaction Bundles
        • Bundle Simulation
        • Bundle Validation
        • Bundle Submission
          • BSC Bundle Submission
            • List of BSC Validators
          • ETH Bundle Submission
          • Bundle Submission with Gateway
        • Bundle Tracking
          • BSC Bundle-Trace
          • ETH Bundle-Trace
          • ETH Bundle Inclusion Status
        • Bundle Refunds
          • Priority Fee Refund
          • Bundle Refund
          • Latest Bundle Refunds
      • Backrun Arbitrage
        • BackRunMe: Bundle Submission
          • BSC submit arbOnly
          • ETH submit arbOnly
            • blxr_info
            • ETH arbOnly Simulation
      • Token Launch Sniping
      • Other Utilities
        • List of bloXroute Builders
        • List of External Builders
        • Tx-Trace
        • Ping
    • Streams
      • Requirements
      • Subscription limits
      • Working With Streams
        • Creating a Subscription
          • Websocket
          • gRPC
        • Handling the Notification
          • Websocket
          • gRPC
        • Cancelling a Subscription
          • Websocket
          • gRPC
        • Local Node Validation
      • newTxs and pendingTxs
        • Filters
        • Raw TX Reconstruction
      • BackRunMe: arbOnlyMEV
        • ETH arbOnlyMEV
        • BSC arbOnlyMEV
      • transactionStatus
      • txReceipts
      • newBlocks
      • bdnBlocks
      • ethOnBlock
      • MEVBlockValue
      • MEVNextProposerInfo
    • Block Builders and Validators
      • Validator Gateway
      • MEV Relay (For Validators)
      • Block Submission
      • Proposer MEV-Protect
      • Compliance Lists
      • Preconfirmations
    • Protect RPCs
      • ETH Protect RPC
      • ETH Gas Protect RPC
      • BSC Protect RPC
      • SOL Protect RPC
  • Base Network
    • Submit Transactions
    • Streams
      • GetBdnBlockStream
  • TON NETWORK
    • TON Trader API
      • Quick Start
      • Fee Schedule
      • Connection
      • Submit Signed Transaction
  • Resources
    • BDN Explorer
    • Block Explorer
    • Guides
      • Algorithmic Trading
      • Setting Up a Local Gateway
      • Gateway as Web3 Bridge
    • Architecture
      • BDN Architecture
        • Network Components
        • Performance Techniques
          • Block Compression
          • Cut-through Routing
          • Optimized Topology
      • bloXroute Protocol
        • Versioning
        • Message Structure
        • Message Types
    • Contact Us
Powered by GitBook
On this page
  1. BSC & ETH
  2. Intent Network
  3. Examples

Submit solution

This example demonstrates how to submit a solution to an intent using the bloXroute Gateway gRPC API.

Name: SubmitIntentSolution

SubmitIntentSolution is a GRPC method that propagates the solution to the BDN. SubmitIntentSolutionRequest arguments:

Key
Description
Values

solverAddress

ETH address of the intent solver

string

intentId

UUID of the intent to solve

string

intentSolution

solution payload for the intent

byte[]

hash

Keccak256Hash of the solution payload

byte[]

signature

ECDSA signature of the hash

byte[]

SubmitIntentSolutionReply fields:

Key
Description
Values

solutionId

UUID of the solution

string

first_seen

timestamp when the solution was first seen in BDN.

google.protobuf.Timestamp

Examples

package main

import (
	"context"
	"encoding/hex"
	"fmt"
	"log"

	pb "github.com/bloXroute-Labs/gateway/v2/protobuf"

	"github.com/ethereum/go-ethereum/crypto"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
)

// intentID is the ID of the intent to which the solution is being submitted.
// replace with the actual intent ID.
const intentID = "<INTENT-ID>"

// gatewayHost is the address of the gateway to which the solution is being submitted
const gatewayHost = "127.0.0.1:5001"

// authHeader is the authorization header of your BloxRoute Account
const authHeader = "<YOUR-AUTHORIZATION-HEADER>"

func main() {
	// this will use localhost CA to verify the certificate
	creds := credentials.NewClientTLSFromCert(nil, "")	

	// Dial the gateway
	conn, err := grpc.Dial(gatewayHost,
		grpc.WithTransportCredentials(creds),
		grpc.WithPerRPCCredentials(blxrCredentials{authorization: authHeader}))

	if err != nil {
		log.Fatalln("dial grpc", err)
	}

	// Create a client
	client := pb.NewGatewayClient(conn)

	// Generate the solution
	solution := genIntentSolution(intentID)

	// Submit the solution
	resp, err := client.SubmitIntentSolution(context.Background(), solution)
	if err != nil {
		log.Fatalln(err)
	}

	fmt.Printf("done submitting the solution to %s\nsolver address: %s\nsolution id: %s\n", gatewayHost, solution.SolverAddress, resp.SolutionId)
}

func genIntentSolution(intentID string) *pb.SubmitIntentSolutionRequest {
	// The sample private key of the solver
	solverPrivateKeyHex := "2b36f5c0317c13e6326e9d2e2ae39badec9d030ba44bc889318e4fa5412ad342"

	// The solution is to be submitted as a byte slice.
	// This is a sample solution, and you should replace it with your solution.
	solutionBytes := []byte(`{"From":"0xe34f7d4a8b5b9e5d5f4d6392b4c328e2d1a2bd9f","To":"0xa24dcbb439bfb3c37ad6cce12c92427b0358cb4ee","Value":0,"Gas":950000,"MaxFeePerGas":12000000000,"Nonce":42,"Deadline":4850000,"Solver":"0x4e2f4cb6458c1c08b55a6c362f4abf818279ee02","Control":"0x1de2276df50bd8bceefb353c1a5520bc0fecda98","UserOpHash":[52,201,174,29,78,191,148,66,213,171,223,60,212,140,236,131,174,50,90,5,197,241,205,163,228,26,79,98,140,156,72,182],"BidToken":"0x0000000000000000000000000000000000000001","BidAmount":150000000000000,"Data":"SRJ0xQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAJ6tEZqZDFXPFuIOdvTCoIJnhSWMAAAAAAAAAAAAAAAAfmECoXVr1vx0XYvklva3cQgH5hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqHvuU4AAAAAAAAAAAAAAAAAA//mXZ4LUbMBWMNH266sYsjJNaxQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI4byb8EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","Signature":"QKx9m3wSuO2bx2QOMyGweMaaXozxq5p6rc9VkpJg6pYRAKFq+diLTG8AEeYoscYpfSTGWCGHBJuQLvV/Q/fvuBw="}`)

	// Decode the hex string to a byte slice
	solverPrivateKeyBytes, err := hex.DecodeString(solverPrivateKeyHex)
	if err != nil {
		log.Fatalf("invalid hex string: %v", err)
	}

	// Use the Ethereum crypto package to create an ECDSA private key
	solverPrivateKey, err := crypto.ToECDSA(solverPrivateKeyBytes)
	if err != nil {
		log.Fatalf("failed to create private key: %v", err)
	}

	// Sign the solution with the private key
	solutionHash := crypto.Keccak256Hash(solutionBytes).Bytes()     // need a hash to sign, so we're hashing the payload here
	solutionSig, err := crypto.Sign(solutionHash, solverPrivateKey) // signing the hash
	if err != nil {
		log.Fatalln("could not sign the message", err)
	}

	// Extract the address of the solver
	solverAddress := crypto.PubkeyToAddress(solverPrivateKey.PublicKey).String()

	// Return the solution request
	return &pb.SubmitIntentSolutionRequest{
		SolverAddress:  solverAddress,
		IntentId:       intentID,
		IntentSolution: solutionBytes,
		Hash:           solutionHash,
		Signature:      solutionSig,
	}
}

// blxrCredentials is a struct that implements the PerRPCCredentials interface
type blxrCredentials struct {
	authorization string
}

// GetRequestMetadata is a method of the PerRPCCredentials interface
func (bc blxrCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
	return map[string]string{
		"authorization": bc.authorization,
	}, nil
}

// RequireTransportSecurity is a method of the PerRPCCredentials interface
func (bc blxrCredentials) RequireTransportSecurity() bool {
	return false
}
package main

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"log"
	"net/http"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/gorilla/websocket"
)

// intentID is the ID of the intent to which the solution is being submitted.
// replace with the actual intent ID.
const intentID = "<INTENT-ID>"

func main() {
	dialer := websocket.DefaultDialer
	// Add the following lines if you work with IP instead of DNS
	// tlsConfig := &tls.Config{
	// 	Certificates:       []tls.Certificate{cert},
	// 	InsecureSkipVerify: true,
	// }
	// dialer.TLSClientConfig = tlsConfig

	req := genIntentSolution(intentID)

	wsSubscriber, _, err := dialer.Dial("wss://virginia.eth.blxrbdn.com/ws", http.Header{"Authorization": []string{"YOUR-AUTHORIZATION-HEADER"}})
	if err != nil {
		fmt.Println(err)
		return
	}

	err = wsSubscriber.WriteMessage(websocket.TextMessage, req)
	if err != nil {
		fmt.Println(err)
		return
	}

	for {
		_, nextNotification, err := wsSubscriber.ReadMessage()
		if err != nil {
			fmt.Println(err)
		}
		fmt.Println(string(nextNotification)) // or process it generally
	}
}

func genIntentSolution(intentID string) []byte {
	// The sample private key of the solver
	solverPrivateKeyHex := "2b36f5c0317c13e6326e9d2e2ae39badec9d030ba44bc889318e4fa5412ad342"

	// The solution is to be submitted as a byte slice.
	// This is a sample solution, and you should replace it with your solution.
	solutionBytes := []byte(`{"From":"0xe34f7d4a8b5b9e5d5f4d6392b4c328e2d1a2bd9f","To":"0xa24dcbb439bfb3c37ad6cce12c92427b0358cb4ee","Value":0,"Gas":950000,"MaxFeePerGas":12000000000,"Nonce":42,"Deadline":4850000,"Solver":"0x4e2f4cb6458c1c08b55a6c362f4abf818279ee02","Control":"0x1de2276df50bd8bceefb353c1a5520bc0fecda98","UserOpHash":[52,201,174,29,78,191,148,66,213,171,223,60,212,140,236,131,174,50,90,5,197,241,205,163,228,26,79,98,140,156,72,182],"BidToken":"0x0000000000000000000000000000000000000001","BidAmount":150000000000000,"Data":"SRJ0xQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAJ6tEZqZDFXPFuIOdvTCoIJnhSWMAAAAAAAAAAAAAAAAfmECoXVr1vx0XYvklva3cQgH5hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqHvuU4AAAAAAAAAAAAAAAAAA//mXZ4LUbMBWMNH266sYsjJNaxQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI4byb8EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","Signature":"QKx9m3wSuO2bx2QOMyGweMaaXozxq5p6rc9VkpJg6pYRAKFq+diLTG8AEeYoscYpfSTGWCGHBJuQLvV/Q/fvuBw="}`)

	// Decode the hex string to a byte slice
	solverPrivateKeyBytes, err := hex.DecodeString(solverPrivateKeyHex)
	if err != nil {
		log.Fatalf("invalid hex string: %v", err)
	}

	// Use the Ethereum crypto package to create an ECDSA private key
	solverPrivateKey, err := crypto.ToECDSA(solverPrivateKeyBytes)
	if err != nil {
		log.Fatalf("failed to create private key: %v", err)
	}

	// Sign the solution with the private key
	solutionHash := crypto.Keccak256Hash(solutionBytes).Bytes()     // need a hash to sign, so we're hashing the payload here
	solutionSig, err := crypto.Sign(solutionHash, solverPrivateKey) // signing the hash
	if err != nil {
		log.Fatalln("could not sign the message", err)
	}

	// Extract the address of the solver
	solverAddress := crypto.PubkeyToAddress(solverPrivateKey.PublicKey).String()

	m := map[string]interface{}{
		"solver_address":  solverAddress,
		"intent_id":       intentID,
		"intent_solution": solutionBytes,
		"hash":            solutionHash,
		"signature":       solutionSig,
	}

	req, err := json.Marshal(m)
	if err != nil {
		log.Fatalln("marshal", err)
	}

	return []byte(fmt.Sprintf(`{"id": "1", "method": "blxr_submit_intent_solution", "params": %s}`, req))
}