This page gives you the code example of using Intent Network to work with project Aori. We will guide you through the following steps.
Connect to Intent Network Cloud-API
Subscribe to Aori intent stream
Build an Aori solution
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.
Location
Endpoint
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
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:
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
}
More information on these events and their payloads can be seen here: