Skip to main content

Wallet Integration Guide

This guide explains how to integrate VisualSign into your wallet or application.

Architecture Overview

┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│ Wallet │────▶│ Parser Host │────▶│ Enclave │
│ App │ │ (gRPC) │ │ (Parser) │
└─────────────┘ └──────────────┘ └─────────────┘
│ │ │
│ ▼ │
│ ┌──────────────┐ │
└───────────▶│ Verification │◀────────────┘
│ Library │
└──────────────┘

Integration Steps

1. Connect to Parser Service

The parser exposes a gRPC service. You can connect using any gRPC client library.

Proto Definition:

service ParserService {
rpc Parse(ParseRequest) returns (ParseResponse);
}

message ParseRequest {
string unsigned_payload = 1; // Base64 or hex encoded transaction
Chain chain = 2; // CHAIN_ETHEREUM, CHAIN_SOLANA, etc.
ChainMetadata chain_metadata = 3; // Optional chain-specific data
}

2. Parse Transactions

Send raw transactions to the parser:

Go Example:

import (
pb "your-project/parser"
"google.golang.org/grpc"
)

// Connect to parser
conn, err := grpc.Dial("localhost:44020", grpc.WithInsecure())
client := pb.NewParserServiceClient(conn)

// Parse transaction
resp, err := client.Parse(context.Background(), &pb.ParseRequest{
UnsignedPayload: "0xf86c80850...", // Your raw transaction
Chain: pb.Chain_CHAIN_ETHEREUM,
})

// Extract VisualSign JSON
visualSignJSON := resp.ParsedTransaction.Payload.SignablePayload

JavaScript/TypeScript Example:

import { ParserServiceClient } from './generated/parser_grpc_pb';
import { ParseRequest, Chain } from './generated/parser_pb';

const client = new ParserServiceClient('localhost:44020');

const request = new ParseRequest();
request.setUnsignedPayload('0xf86c80850...');
request.setChain(Chain.CHAIN_ETHEREUM);

client.parse(request, (error, response) => {
if (!error) {
const visualSignJSON = response.getParsedTransaction()
.getPayload()
.getSignablePayload();
// Display to user
}
});

3. Verify Attestation

IMPORTANT: Always verify the enclave attestation before trusting the parsed output.

The parser response includes a signature that must be verified:

// Verify the signature
signature := resp.ParsedTransaction.Signature
publicKey := signature.PublicKey
message := signature.Message
sig := signature.Signature

// Verify using P256 ECDSA
valid := verifyP256Signature(publicKey, message, sig)

4. Display to User

Parse the VisualSign JSON and display it in your UI:

const visualSign = JSON.parse(visualSignJSON);

// Display transaction details
console.log(`Transaction: ${visualSign.Title}`);
visualSign.Fields.forEach(field => {
switch(field.Type) {
case 'text_v2':
console.log(`${field.Label}: ${field.TextV2.Text}`);
break;
case 'amount_v2':
console.log(`${field.Label}: ${field.AmountV2.Amount} ${field.AmountV2.Currency}`);
break;
case 'address_v2':
console.log(`${field.Label}: ${field.AddressV2.Address}`);
break;
}
});

Chain-Specific Metadata

Ethereum - ABI Support

For smart contract interactions, provide the ABI:

request := &pb.ParseRequest{
UnsignedPayload: txBytes,
Chain: pb.Chain_CHAIN_ETHEREUM,
ChainMetadata: &pb.ChainMetadata{
Metadata: &pb.ChainMetadata_Ethereum{
Ethereum: &pb.EthereumMetadata{
Abi: &pb.Abi{
Value: contractABI, // JSON ABI string
},
},
},
},
}

Solana - IDL Support

For Anchor programs, provide the IDL:

request := &pb.ParseRequest{
UnsignedPayload: txBytes,
Chain: pb.Chain_CHAIN_SOLANA,
ChainMetadata: &pb.ChainMetadata{
Metadata: &pb.ChainMetadata_Solana{
Solana: &pb.SolanaMetadata{
Idl: &pb.Idl{
Value: anchorIDL, // JSON IDL string
IdlType: pb.SolanaIdlType_SOLANA_IDL_TYPE_ANCHOR,
},
},
},
},
}

Error Handling

The parser may return errors for invalid transactions:

resp, err := client.Parse(ctx, request)
if err != nil {
// Handle gRPC error
status := status.Convert(err)
log.Printf("Parse failed: %v", status.Message())
}

Health Checks

Monitor parser health:

grpcurl -plaintext -d '{"service":""}' \
localhost:44020 grpc.health.v1.Health/Check

Security Considerations

  1. Always verify attestations - Don't trust parsed output without verification
  2. Use TLS in production - Enable TLS for gRPC connections
  3. Validate signatures - Check the P256 signature on all responses
  4. Monitor PCR values - Keep allowlists updated for enclave measurements

Example: Complete Integration

package main

import (
"context"
"encoding/json"
"log"

pb "your-project/parser"
"google.golang.org/grpc"
)

func parseAndDisplayTransaction(rawTx string) error {
// Connect to parser
conn, err := grpc.Dial("localhost:44020", grpc.WithInsecure())
if err != nil {
return err
}
defer conn.Close()

client := pb.NewParserServiceClient(conn)

// Parse transaction
resp, err := client.Parse(context.Background(), &pb.ParseRequest{
UnsignedPayload: rawTx,
Chain: pb.Chain_CHAIN_ETHEREUM,
})
if err != nil {
return err
}

// Verify signature
sig := resp.ParsedTransaction.Signature
if !verifySignature(sig) {
return fmt.Errorf("invalid signature")
}

// Parse VisualSign JSON
var visualSign map[string]interface{}
err = json.Unmarshal([]byte(resp.ParsedTransaction.Payload.SignablePayload), &visualSign)
if err != nil {
return err
}

// Display to user
displayTransaction(visualSign)

return nil
}

Testing

Use the provided test transactions:

Solana:

cargo run --bin parser_cli -- --chain solana -t 'AgAAAAAAAA...'

Ethereum:

cargo run --bin parser_cli -- --chain ethereum -t '0xf86c808504a817c800...'

Support