Aori Integration Example

This page gives you the code example of using Intent Network to work with project Aori. We will guide you through the following steps.

  1. Connect to Intent Network Cloud-API

  2. Subscribe to Aori intent stream

  3. Build an Aori solution

  4. Submit an Aori solution

Connect to Intent Network without local Gateway

For the fastest access to the Intent Network, using the following WS/gRPC endpoints is recommended.

LocationEndpoint

United States - Virginia

WS: wss://virginia-intents.blxrbdn.com/ws

gRPC: virginia-intents.blxrbdn.com:5005

England - London

WS: wss://uk-intents.blxrbdn.com/ws

gRPC: uk-intents.blxrbdn.com:5005

Germany

WS: wss://germany-intents.blxrbdn.com/ws

gRPC: germany-intents.blxrbdn.com:5005

Singapore

WS: wss://singapore-intents.blxrbdn.com/ws

gRPC: singapore-intents.blxrbdn.com:5005

Subscribe to Aori Intents

You are now able to subscribe to our Intents Streams.

Endpoint Name: Intents

Intents is a gRPC stream of all new intents as they are propagated in the BDN.

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

// gatewayHost is the address of the gateway to which the subscription is being made. Can be changed to cloud-API ip
const gatewayHost = "virginia-intents.blxrbdn.com:5005"

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

	// Subscribe to intents
	stream, err := client.Intents(context.Background(), genIntentsRequest())
	if err != nil {
		log.Fatalln("subscribe to intents", err)
	}

	for {
		fmt.Printf("listening for intents from %s ...\n", gatewayHost)
		// Receive the intent from the stream until the stream is closed
		msg, err := stream.Recv()

		if err != nil {
			log.Fatalln("receive from stream", err)
		}

		fmt.Println("------------------")
		fmt.Println("got intent:"
		fmt.Println("- dapp addr:  ", msg.DappAddress)
		fmt.Println("- sender addr:", msg.SenderAddress)
		fmt.Println("- id:         ", msg.IntentId)
		fmt.Println("- timestamp:  ", msg.Timestamp.String())
		fmt.Println("- intent:     ", hex.EncodeToString(msg.Intent))
	}
}


// blxrCredentials is an implementation of PerRPCCredentials
type blxrCredentials struct {
	authorization string
}

// GetRequestMetadata sets the authorization header
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
}

Aori dApp Address in Intent Network: 0xB1a2f2A4c79C7C7Ba1Ac161ad0BDeCf11350dAa7

Aori posts intents that are identical to the events seen from its event stream.

There are 7 types of events that will be observed when connected:

  • SwapRequested

  • OrderCreated

  • OrderTaken

  • OrderCancelled

  • QuoteRequested

  • OrderToExecute

  • OrderFulfilled

More information on these events and their payloads can be seen here: https://docs.aori.io/docs/services/data-streaming#events

Each of these can be taken as intents for which connected traders/searchers/solvers can react and send back actions that act as solutions.

Build an Aori Solution

As mentioned, solutions in Aori are very much actions that a trader/searcher or solver can perform in reaction to some event.

The payload for actions should follow the JSON-RPC 2.0 specification format:

{
    "id": <request_id>,
    "jsonrpc": "2.0",
    "method": <method_name>,
    "params": [{ ... }]
}

There are several methods corresponding to actions available:

  • aori_makeOrder

  • aori_takeOrder

  • aori_cancelOrder

These methods each have their own parameters, for which the latest parameter payloads can be found here:

The TypeScript and Rust SDK provide helper functions to simplify creating new limit orders and creating matching orders to take an order.

There are two types of flow that a trader / searcher / solver will generally find themselves being aligned with:

Submit an Aori solution

Endpoint Name: SubmitIntentSolution

SubmitIntentSolution is a gRPC method that propagates the solution to the BDN.

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 = "virginia-intents.blxrbdn.com:5005"

// 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 := "2b3...342"

	// 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":"0xe3...b9f","To":"0xa2...4ee","Value":0,"Gas":950000,"MaxFeePerGas":12000000000,"Nonce":42,"Deadline":4850000,"Solver":"0x4...ee02","Control":"0x1...da98","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":"SRJ...AAA","Signature":"QKx...Bw="}`)

	// 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