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);
}