Resolvers (How to become a resolver)

This guide explains how to become a resolver (Market Maker) in the Omniston protocol and integrate with its gRPC API.

Overview

A resolver is a service that provides token exchange rates and executes trades. To become a resolver, you need to:

  1. Register by obtaining a Soul-Bound Token (SBT)

  2. Connect to the gRPC API

  3. Handle quote requests and trades

Registration Process

Step 1: Generate Keys

First, generate one or more Ed25519 key pairs that will be used for authentication:

For other languages, you can use any standard Ed25519 implementation library available in your preferred programming language

Step 2: Prepare Metadata

Create a JSON document containing:

  • Your resolver name

  • Your public key(s)

Example:

{
  "name": "MyResolver",
  "publicKeys": [
    "b951254b184fae6906a61ab01e37296fbb28961494cacf7befac9f638fcfe40c",
    "9397ddd52a0d6033da4a32e654b4afbddcc5d832575e396c0a6f5b213faa199f"
  ]
}

Step 3: Submit Registration

  1. Your metadata will be stored in an SBT NFT collection

  2. You'll receive your SBT stake address for API authentication

Connecting to the API

Authentication

  1. Create a connection payload:

message ConnectPayload {
  uint64 connect_timestamp = 1;  // Current timestamp in milliseconds
  string stake_address = 2;      // Your SBT stake address
}
  1. Sign the payload:

  • Serialize the ConnectPayload to bytes

  • Sign using your Ed25519 private key

  • Base64 encode the signature

  1. Send a ConnectRequest:

message ConnectRequest {
  bytes payload = 1;    // Serialized ConnectPayload
  bytes public_key = 2; // Your Ed25519 public key
  bytes signature = 3;  // Signature of the payload
}

Example connection request:

{
  "connect": {
    "payload": "CPKnlt2xYxIwRVFDWFNzMnhaMmRoazlUQXh6R3pYcmEyRWJHX1MyU3F5TjhUZmk2Zko4MkVZaVZq",
    "public_key": "TAPsnPvWhlOvxEK19rONv4sueMeQzOzlrrIFUOKsi34=",
    "signature": "us7nMd9wmUOkuPk0otg6dvUojZwj8VcyXU6HD13BDQhVrzV8sKgyXtKze+9+j9FC1Ghxkx7Jo5FIDeE8ljbADQjyp5bdsWMSMEVRQ1hTczJ4WjJkaGs5VEF4ekd6WHJhMkViR19TMlNxeU44VGZpNmZKODJFWWlWag=="
  },
  "seqno": 1
}

Message Flow

The resolver API uses a bidirectional gRPC stream. After connecting:

1. Incoming Events

You'll receive these events from the server:

message ResolverEvent {
  oneof mux {
    uint64 seqno = 1;    // Server-generated event ID
    uint64 reply_to = 2;  // References your request seqno
  }

  oneof event {
    QuoteRequestedEvent quote_requested = 10;
    QuoteRequestCancelledEvent quote_request_cancelled = 11;
    QuoteAcceptedEvent quote_accepted = 20;
    QuoteRejectedEvent quote_rejected = 21;
    QuoteInvalidatedEvent quote_invalidated = 22;
    KeepAlive keep_alive = 100;
  }
}

Key events:

  • QuoteRequestedEvent: New quote request from a trader

  • QuoteRequestCancelledEvent: Trader cancelled their request

  • QuoteAcceptedEvent: Your quote was accepted

  • QuoteRejectedEvent: Your quote was rejected

  • QuoteInvalidatedEvent: Confirmation of quote invalidation

2. Outgoing Requests

You can send these requests to the server:

message ResolverRequest {
  oneof mux {
    uint64 seqno = 1;    // Your request ID
    uint64 reply_to = 2;  // References server event seqno
  }

  oneof request {
    ConnectRequest connect = 10;
    UpdateQuoteRequest update_quote = 11;
    InvalidateQuoteRequest invalidate_quote = 12;
  }
}

Key requests:

  • UpdateQuoteRequest: Provide or update a quote

  • InvalidateQuoteRequest: Cancel a previously provided quote

Quote Flow

1. Receiving Quote Requests

When you receive a QuoteRequestedEvent:

message QuoteRequestedEvent {
  string rfq_id = 1;                      // Quote request ID
  QuoteRequest quote_request = 2;         // The actual request
  uint32 protocol_fee_bps = 3;           // Protocol fee in basis points
  sint64 request_timestamp = 4;          // When request was made
  sint64 quote_validity_timeout = 5;     // How long quote should be valid
  sint64 deposit_settling_delay = 6;     // Min delay before settlement
  sint64 resolve_timeout = 7;            // Max time to complete trade
}

2. Providing Quotes

Respond with an UpdateQuoteRequest:

message UpdateQuoteRequest {
  string rfq_id = 1;                    // From QuoteRequestedEvent
  string offer_units = 2;               // Amount trader pays
  string ask_units = 3;                 // Amount trader receives
  uint64 trade_start_deadline = 4;      // Quote expiration time

  oneof params {
    ResolverSwapParams swap = 20;       // For swap settlement
    ResolverEscrowParams escrow = 21;   // For escrow settlement
    ResolverHtlcParams htlc = 22;       // For HTLC settlement
  }
}

For swap settlement, include route information:

message ResolverSwapParams {
  repeated SwapRoute routes = 1;  // Possible swap paths
}

3. Quote Lifecycle

  1. You receive QuoteRequestedEvent

  2. You send UpdateQuoteRequest

  3. The server validates your quote and responds with:

    • QuoteAcceptedEvent: Your quote was validated and accepted, includes quote_id.

    • QuoteRejectedEvent: Your quote was rejected. The event includes a code field from the QuoteRejectedCode enum. Possible reasons include:

      • UNDEFINED (0) - Uncategorized error

      • INVALID_PARAMETERS (1) - Invalid value of a parameter

      • INVALID_AMOUNTS (2) - Asset amount restrictions don't pass RFQ requirements

      • ROUTE_PROHIBITED (3) - Route uses a prohibited intermediate asset

      • POOL_PROHIBITED (4) - Route uses a unverified or prohibited liquidity pool

      • EMULATION_RESULT_MISMATCH (5) - Transaction emulation produced a result different from the quote

      • INTERNAL_ERROR (101) - Server errors

  4. At any time, you can:

    • Send new UpdateQuoteRequest to update the quote

    • Send InvalidateQuoteRequest to cancel the quote

Best Practices

  1. Sequence Numbers

    • Use monotonically increasing seqno for your requests

    • Match reply_to with event seqno when responding

    • Track request/response correlation using seqno

  2. Quote Management

    • Honor your quotes until trade_start_deadline

    • Invalidate quotes you can't fulfill

    • Include all fees in your quoted amounts

  3. Error Handling

    • Reconnect on connection loss

    • Handle all event types

    • Log rejected quotes for monitoring

  4. Performance

    • Maintain a single gRPC connection

    • Process events asynchronously

    • Buffer outgoing requests

API Endpoint

Connect to: https://omni-grpc.ston.fi

See Also

Last updated