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:

KeyDescriptionValues

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:

KeyDescriptionValues

solutionId

UUID of the solution

string

first_seen

timestamp when the solution was first seen in BDN.

google.protobuf.Timestamp

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/insecure"
)

// 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() {
	// Dial the gateway
	conn, err := grpc.Dial(gatewayHost,
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		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
}

Last updated