Subscribe to intents
This is an example of how to subscribe to intents. Anybody can subscribe to intents.
Name: Intents
Intents
is a GRPC stream of all new intents as they are propagated in the BDN.
IntentsRequest
arguments:
Key | Description | Values |
---|---|---|
| address of solver |
|
| Keccak256Hash of the solverAddress bytes |
|
| ECDSA signature of the hash |
|
| dApp address (optional) |
|
IntentsReply
fields (stream message):
Key | Description | Values |
---|---|---|
| ETH address of the DApp that owns the intent |
|
| ETH address of intent sender |
|
| UUID of the intent |
|
| intent |
|
| 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"
)
// gatewayHost is the address of the gateway to which the subscription is being made
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)
// 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))
}
}
func genIntentsRequest() *pb.IntentsRequest {
// Generate an ECDSA key pair using secp256k1 curve
privKey, err := crypto.GenerateKey()
if err != nil {
log.Fatalln("generate key", err)
}
pubKey := privKey.PublicKey // extract the public key
signerAddress := crypto.PubkeyToAddress(pubKey) // the address of the public key
hash := crypto.Keccak256Hash([]byte(signerAddress.String())).Bytes() // need a hash to sign, so we're hashing the payload here
sig, err := crypto.Sign(hash, privKey) // sign the hash
if err != nil {
log.Fatalln("sign privKey", err)
}
// Return the intent request
return &pb.IntentsRequest{
SolverAddress: signerAddress.String(),
Hash: hash,
Signature: sig,
Filters: "dapp_address=0x097399a35cfC20efE5FcD2e9b1d892884DAAd642", // receive intents for only specific dApp address
}
}
// 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
}
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"github.com/ethereum/go-ethereum/crypto"
"github.com/gorilla/websocket"
)
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 := generateIntentsRequest()
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 generateIntentsRequest() []byte {
// Generate an ECDSA key pair using secp256k1 curve
privKey, err := crypto.GenerateKey()
if err != nil {
log.Fatalln("generate key", err)
}
pubKey := privKey.PublicKey // extract the public key
signerAddress := crypto.PubkeyToAddress(pubKey) // the address of the public key
hash := crypto.Keccak256Hash([]byte(signerAddress.String())).Bytes() // need a hash to sign, so we're hashing the payload here
sig, err := crypto.Sign(hash, privKey) // sign the hash
if err != nil {
log.Fatalln("sign privKey", err)
}
m := map[string]interface{}{
"solver_address": signerAddress.String(),
"hash": hash,
"signature": sig,
}
//
// receive intents for only specific dApp address
// m["filters"]="dapp_address=0x097399a35cfC20efE5FcD2e9b1d892884DAAd642"
//
req, err := json.Marshal(m)
if err != nil {
log.Fatalln("marshal", err)
}
return []byte(fmt.Sprintf(`{ "id": "2", "method": "subscribe", "params": [ "userIntentFeed", %s]}`, req))
}
Last updated