Skip to content

Proto schema

The canonical schema for sweetspot.v1.MarketData. Synced from sweetspot-server on every commit; CI fails the build if this file diverges from upstream.

// Shared primitives used across every service: ids, solana-level crypto
// primitives, decimal wire format, enums, book level structs, and metadata.
// Every message in this package has `package sweetspot.api.v1;` so that the
// generated Rust module stays flat (`proto::<Type>`) regardless of which .proto
// a type was declared in.

syntax = "proto3";

package sweetspot.api.v1;

// ── Ids ─────────────────────────────────────────────────────────────

message SpotId {
  uint64 id = 1;
}

message MakerId {
  uint64 id = 1;
}

message Pair {
  SpotId base = 1;
  SpotId quote = 2;
}

// ── Solana-level primitives ─────────────────────────────────────────

message Pubkey {
  bytes key = 1;
}

message Signature {
  bytes signature = 1;
}

message Blockhash {
  bytes hash = 1;
}

// ── Decimal ─────────────────────────────────────────────────────────

// Human-readable decimal string (e.g. "155.14"). The client must parse
// with a decimal library that matches rust_decimal semantics.
message Decimal {
  string value = 1;
}

// ── Timestamp ───────────────────────────────────────────────────────

// Unix microseconds since epoch. The single canonical timestamp unit
// across the entire API — events, responses, range queries. Field value
// `0` means "unspecified" (used on optional bounds in range queries and
// on absent event timestamps).
message Timestamp {
  uint64 micros = 1;
}

// ── Enums ───────────────────────────────────────────────────────────

enum FeedLevel {
  FEED_LEVEL_UNSPECIFIED = 0;
  FEED_LEVEL_L1 = 1;
  FEED_LEVEL_L2 = 2;
  FEED_LEVEL_L3 = 3;
}

enum Side {
  SIDE_UNSPECIFIED = 0;
  SIDE_BUY = 1;
  SIDE_SELL = 2;
}

enum HealthState {
  HEALTH_STATE_UNSPECIFIED = 0;
  HEALTH_STATE_HEALTHY = 1;
  HEALTH_STATE_DEGRADED = 2;
  HEALTH_STATE_HALTED = 3;
}

// ── Book levels ─────────────────────────────────────────────────────

message L2Level {
  Decimal price = 1;
  Decimal size = 2;
}

message L3Entry {
  MakerId maker_id = 1;
  Decimal price = 2;
  Decimal size = 3;
}

// ── Subscription descriptor ─────────────────────────────────────────

message PairSubscription {
  Pair pair = 1;
  FeedLevel level = 2;
  // When true, the server emits a full snapshot on every book update and
  // never sends deltas. When false (default), one snapshot on subscribe
  // followed by incremental deltas.
  bool snapshot_only = 3;
}

// ── Per-event metadata ──────────────────────────────────────────────

message PairMetadata {
  uint64 slot = 1;
  Timestamp ts = 2;
  uint64 update_id = 3;
}

// ── Reference / catalog ─────────────────────────────────────────────

message SpotMetadata {
  SpotId id = 1;
  string name = 2;
  Pubkey mint = 3;
  Pubkey program_id = 4;
  uint32 decimals = 5;
  uint32 atoms_per_lots = 6;
}

message SpotAssets {
  repeated SpotMetadata assets = 1;
}

message MakerMarketState {
  SpotId spot_id = 1;
  uint64 order_sequence = 2;
}

// Low-level per-spot balance sample, used by the indexer and by historical
// queries. `MakerBalanceEvent` is the streaming form.
message BalanceUpdate {
  SpotId spot_id = 1;
  MakerId maker_id = 2;
  uint64 atoms = 3;
  uint64 slot = 4;
}

// ── Health / status (cross-cutting) ─────────────────────────────────

message StatusEvent {
  HealthState state = 1;
  // Absent = global scope, present = per-pair.
  Pair pair = 2;
  string reason = 3;
  Timestamp ts = 4;
}

syntax = "proto3";

package sweetspot.api.v1;

import "sweetspot/api/v1/common.proto";

// ── AuthService messages ────────────────────────────────────────────
//
// Session-token flow:
//   1. Client calls `AuthService.Challenge(pubkey)` → server returns a
//      single-use nonce bound to that pubkey with a short TTL.
//   2. Client signs AUTH_DOMAIN_PREFIX || nonce with the pubkey's keypair.
//   3. Client calls `AuthService.Authenticate(pubkey, signature)` → server
//      verifies the signature covers the outstanding nonce, maps pubkey to
//      maker_id via MakerRegistry, and returns a bearer `session_token`.
//   4. Client attaches `authorization: Bearer <session_token>` metadata on
//      every subsequent RPC to BalanceService / TxService (MarketDataService
//      is public — no token required).

message ChallengeRequest {
  Pubkey pubkey = 1;
}

message ChallengeResponse {
  bytes nonce = 1;
  Timestamp expires_at = 2;
}

message AuthenticateRequest {
  Pubkey pubkey = 1;
  Signature signature = 2;
}

message AuthenticateResponse {
  string session_token = 1;
  MakerId maker_id = 2;
  Timestamp expires_at = 3;
}

message RevokeRequest {
  string session_token = 1;
}

message RevokeResponse {}

service AuthService {
  rpc Challenge(ChallengeRequest) returns (ChallengeResponse);
  rpc Authenticate(AuthenticateRequest) returns (AuthenticateResponse);
  rpc Revoke(RevokeRequest) returns (RevokeResponse);
}

syntax = "proto3";

package sweetspot.api.v1;

import "sweetspot/api/v1/common.proto";

// ── Book events ─────────────────────────────────────────────────────

message L1Event {
  Pair pair = 1;
  PairMetadata metadata = 2;
  L2Level bid = 3;
  L2Level ask = 4;
}

message L2SnapshotEvent {
  Pair pair = 1;
  PairMetadata metadata = 2;
  repeated L2Level bids = 3;
  repeated L2Level asks = 4;
}

message L2UpdateEvent {
  Pair pair = 1;
  PairMetadata metadata = 2;
  repeated L2Level bids = 3;
  repeated L2Level asks = 4;
}

message L3SnapshotEvent {
  Pair pair = 1;
  PairMetadata metadata = 2;
  repeated L3Entry bids = 3;
  repeated L3Entry asks = 4;
}

message L3UpdateEvent {
  Pair pair = 1;
  PairMetadata metadata = 2;
  repeated L3Entry bids = 3;
  repeated L3Entry asks = 4;
}

message FillEvent {
  Pair pair = 1;
  Side side = 2;
  Decimal price = 3;
  Decimal size = 4;
  uint64 slot = 5;
  Timestamp ts = 6;
}

message MarketDataEvent {
  oneof kind {
    L1Event l1 = 1;
    L2SnapshotEvent l2_snapshot = 2;
    L2UpdateEvent l2_update = 3;
    L3SnapshotEvent l3_snapshot = 4;
    L3UpdateEvent l3_update = 5;
    StatusEvent status = 6;
  }
}

// ── Service request / response ─────────────────────────────────────

message SubscribeRequest {
  repeated PairSubscription pairs = 1;
}

message SubscribeFillsRequest {
  repeated Pair pairs = 1;
}

message GetBookRequest {
  Pair pair = 1;
  // Only FEED_LEVEL_L2 and FEED_LEVEL_L3 are valid.
  FeedLevel level = 2;
}

message GetBookResponse {
  oneof snapshot {
    L2SnapshotEvent l2 = 1;
    L3SnapshotEvent l3 = 2;
  }
}

message ListPairsRequest {}

message ListPairsResponse {
  repeated Pair pairs = 1;
  repeated SpotMetadata spots = 2;
}

// Public (unauthenticated) market data. Streaming RPCs are also exposed via
// the websocket feed for browser clients where gRPC streaming is awkward.
service MarketDataService {
  rpc Subscribe(SubscribeRequest) returns (stream MarketDataEvent);
  rpc SubscribeFills(SubscribeFillsRequest) returns (stream FillEvent);
  rpc GetBook(GetBookRequest) returns (GetBookResponse);
  rpc ListPairs(ListPairsRequest) returns (ListPairsResponse);
}

Apache 2.0