Skip to content

Proto schema ​

The canonical schema for flint.spot.v1. Synced from the flint-protos submodule; regenerate SDKs and docs after bumping that submodule.

proto
// Code generated by `make bundle-proto`; DO NOT EDIT.
// Services are grouped first so the RPC surface is easy to scan.

syntax = "proto3";

package flint.spot.v1;

// -- Services --------------------------------------------------------

// -- AuthService (auth/service.proto) --------------------------------------------------------

// Unauthenticated session-token issuance. Keypair tokens last six hours and
// passwordless organization tokens last seven days.
service AuthService {
  // Issues a single-use nonce.
  rpc Challenge(ChallengeRequest) returns (ChallengeResponse);

  // Exchanges a valid signed nonce for a six-hour keypair session.
  rpc Authenticate(AuthenticateRequest) returns (AuthenticateResponse);

  // Invalidate a token before its natural expiration.
  rpc Revoke(RevokeRequest) returns (RevokeResponse);

  // Send a 6-digit passwordless login code to an organization user's email.
  // Requests are limited to one per email per minute.
  rpc RequestLoginCode(RequestLoginCodeRequest) returns (RequestLoginCodeResponse);

  // Exchange a passwordless login code for a 7-day bearer session token.
  rpc VerifyLoginCode(VerifyLoginCodeRequest) returns (VerifyLoginCodeResponse);
}

// -- MarketDataService (market_data/service.proto) --------------------------------------------------------

// Public market data.
service MarketDataService {
  // Multiplexed book and status stream. Subscriptions are fixed at stream start.
  rpc Subscribe(SubscribeRequest) returns (stream MarketDataEvent);

  // Fill stream; an empty pair filter includes every pair.
  rpc SubscribeFills(SubscribeFillsRequest) returns (stream FillEvent);

  // External-aggregator fills for one pair.
  rpc SubscribeExternalFills(SubscribeExternalFillsRequest)
      returns (stream ExternalFillEvent);

  // Per-venue bid/ask feed for one USD-quoted pair.
  rpc SubscribeExternalQuotes(SubscribeExternalQuotesRequest)
      returns (stream ExternalVenueQuoteEvent);

  // One-shot book snapshot.
  rpc GetBook(GetBookRequest) returns (GetBookResponse);

  rpc ListPairs(ListPairsRequest) returns (ListPairsResponse);

  rpc SubscribeMarketSnapshots(SubscribeMarketSnapshotsRequest)
      returns (stream MarketsSnapshotEvent);
}

// -- MakerService (maker/service.proto) --------------------------------------------------------

// Organization-authenticated maker queries and streams. Responses are maker
// scoped except GetDecodedTransaction.
service MakerService {
  rpc SubscribeBalance(SubscribeBalanceRequest) returns (stream MakerBalanceEvent);

  rpc GetBalance(GetBalanceRequest) returns (GetBalanceResponse);

  rpc SubscribeMarketSnapshots(SubscribeMakerMarketSnapshotsRequest)
      returns (stream MakerMarketsSnapshotEvent);

  rpc GetVolumeBreakdown(GetMakerVolumeBreakdownRequest)
      returns (GetMakerVolumeBreakdownResponse);

  rpc GetVolumeSeries(GetMakerVolumeSeriesRequest)
      returns (GetMakerVolumeSeriesResponse);

  rpc GetNavHistory(GetNavHistoryRequest)
      returns (GetNavHistoryResponse);

  // Streams fills where the authenticated maker provided liquidity.
  rpc SubscribeFills(SubscribeMakerFillsRequest) returns (stream MakerFillEvent);

  // Historical liquidity-provider fills, capped at 1,000 rows.
  rpc GetFills(GetMakerFillsRequest) returns (GetMakerFillsResponse);

  // Whole-window markout summary without a row cap.
  rpc GetMarkoutSummary(GetMakerMarkoutSummaryRequest)
      returns (GetMakerMarkoutSummaryResponse);

  rpc GetStats(GetMakerStatsRequest) returns (GetMakerStatsResponse);

  // Historical maker account actions; fills are excluded.
  rpc GetActivity(GetMakerActivityRequest) returns (GetMakerActivityResponse);

  // Decoded Flint transaction; returns NOT_FOUND for unseen or non-Flint signatures.
  rpc GetDecodedTransaction(GetDecodedTransactionRequest)
      returns (GetDecodedTransactionResponse);

  rpc SubscribeQuotes(SubscribeQuotesRequest) returns (stream QuoteUpdate);

  // Recent quote updates by the maker over a time window, newest first.
  rpc ListRecentQuotes(ListRecentQuotesRequest) returns (ListRecentQuotesResponse);

  // Returns NOT_FOUND when the quote is not owned by this maker.
  rpc GetQuote(GetQuoteRequest) returns (GetQuoteResponse);

  rpc ListQuotingAuthorities(ListQuotingAuthoritiesRequest)
      returns (ListQuotingAuthoritiesResponse);

  rpc ListQuoterSessions(ListQuoterSessionsRequest)
      returns (ListQuoterSessionsResponse);

  // Returns stable read-only SDK registry credentials. Demo sessions receive
  // PERMISSION_DENIED.
  rpc GetSdkCredentials(GetSdkCredentialsRequest)
      returns (GetSdkCredentialsResponse);
}

// -- StatsService (stats/service.proto) --------------------------------------------------------

// Public (unauthenticated) aggregate stats about the exchange.
service StatsService {
  rpc GetSummary(GetSummaryRequest) returns (GetSummaryResponse);

  // 1h / 24h / 30d volume + fill count broken down by pair.
  rpc GetVolumeBreakdown(GetVolumeBreakdownRequest) returns (GetVolumeBreakdownResponse);

  rpc GetVolumeSeries(GetVolumeSeriesRequest) returns (GetVolumeSeriesResponse);

  rpc GetAssetTvls(GetAssetTvlsRequest) returns (GetAssetTvlsResponse);
}

// -- NodeService (node/service.proto) --------------------------------------------------------

// Public node identity and endpoint discovery.
service NodeService {
  rpc GetNodeInfo(GetNodeInfoRequest) returns (GetNodeInfoResponse);

  rpc ListNodes(ListNodesRequest) returns (ListNodesResponse);
}

// -- TxService (tx/service.proto) --------------------------------------------------------

// Keypair-session-authenticated transaction submission and chain-tip feeds.
service TxService {
  // Returns the signature; lifecycle events arrive on SubscribeTxStatus.
  rpc SubmitTx(SubmitTxRequest) returns (SubmitTxResponse);

  rpc SubscribeBlockhash(SubscribeBlockhashRequest) returns (stream BlockhashEvent);
  rpc SubscribeSlots(SubscribeSlotsRequest) returns (stream SlotEvent);
  rpc SubscribeTxStatus(SubscribeTxStatusRequest) returns (stream TxStatusEvent);

  // Replays the current leader lookahead before new entries.
  rpc SubscribeLeaders(SubscribeLeadersRequest) returns (stream LeaderEvent);
}

// -- SpreadProtectService (spread_protect/service.proto) --------------------------------------------------------

// Keypair-session-authenticated advisory spread-protection feed.
service SpreadProtectService {
  // Sends a reset followed by current and future widen windows.
  rpc SubscribeSpreadProtect(SubscribeSpreadProtectRequest) returns (stream SpreadProtectEvent);
}

// -- HistoricalService (historical/service.proto) --------------------------------------------------------

// Session-authenticated historical queries. Maximum range is 30 days;
// unavailable history returns FAILED_PRECONDITION.
service HistoricalService {
  rpc GetFills(GetFillsRequest) returns (GetFillsResponse);
  rpc GetCandles(GetCandlesRequest) returns (GetCandlesResponse);
}

// -- EscalationService (escalation/service.proto) --------------------------------------------------------

// Organization-authenticated escalation to the on-call team.
service EscalationService {
  // Confirms dispatch, not response. Rejects unauthenticated callers and empty messages.
  rpc PageTheTeam(PageTheTeamRequest) returns (PageTheTeamResponse);
}

// -- Messages, events, and shared types ------------------------------

// -- Shared types (common.proto) --------------------------------------------------------

message SpotId {
  uint64 id = 1;
}

message MakerId {
  uint64 id = 1;
}

message Pair {
  reserved 1, 2;
  optional uint64 base_id = 3;
  string base = 4;
  optional uint64 quote_id = 5;
  string quote = 6;
  string label = 7;
}

message Blockhash {
  bytes hash = 1;
}

// Decimal string (e.g. "155.14"), parsed with rust_decimal-compatible semantics.
message Decimal {
  string value = 1;
}

// Unix microseconds since epoch. Zero means unspecified.
message Timestamp {
  uint64 micros = 1;
}

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

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

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

message PairSubscription {
  Pair pair = 1;
  FeedLevel level = 2;
  // True sends only snapshots; false sends an initial snapshot followed by deltas.
  bool snapshot_only = 3;
}

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

message SpotMetadata {
  SpotId id = 1;
  string name = 2;
  // Base58 mint address.
  string mint = 3;
  // Base58 program id.
  string program_id = 4;
  uint32 decimals = 5;
  uint32 atoms_per_lot = 6;
  // Base58 SPL Token / Token-2022 program that owns the mint.
  string token_program = 7;
  // Token logo URL; empty when unavailable.
  string icon = 8;
}

// Absent when the location is unavailable.
message LatLng {
  double lat = 1;
  double lng = 2;
}

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

// -- Auth messages (auth/messages.proto) --------------------------------------------------------

message ChallengeRequest {
  // Base58 pubkey (quoting authority) that will sign the challenge.
  string pubkey = 1;
}

message ChallengeResponse {
  // Sign the ASCII bytes "SWEETSPOT-AUTH-V1:" followed by this single-use nonce.
  bytes nonce = 1;
  // Absolute expiration. Server rejects Authenticate after this moment.
  Timestamp expires_at = 2;
}

message AuthenticateRequest {
  // Base58 pubkey.
  string pubkey = 1;
  // Base58 signature over the domain prefix and nonce returned by Challenge.
  string signature = 2;
  // Required to choose the session scope for a shared quoting key. When absent,
  // shared keys resolve to the lowest maker ID.
  MakerId maker_id = 3;
}

message AuthenticateResponse {
  // Opaque bearer token. Clients pass this back as
  // `authorization: Bearer <session_token>` metadata on all authenticated RPCs.
  string session_token = 1;
  // Resolved maker identity the token speaks for.
  MakerId maker_id = 2;
  // Absolute session expiration. Clients should re-auth before this
  // moment; server will start returning UNAUTHENTICATED once it passes.
  Timestamp expires_at = 3;
}

message RevokeRequest {
  string session_token = 1;
}

message RevokeResponse {}

message RequestLoginCodeRequest {
  string email = 1;
}

message RequestLoginCodeResponse {}

message VerifyLoginCodeRequest {
  string email = 1;
  string code = 2;
}

message VerifyLoginCodeResponse {
  // Opaque bearer token. Clients pass this back as
  // `authorization: Bearer <session_token>` metadata on maker dashboard RPCs.
  string session_token = 1;
  // Optional spot maker identity associated with the organization.
  MakerId maker_id = 2;
  // Absolute session expiration.
  Timestamp expires_at = 3;
  string organization_name = 4;
  // Optional perps maker (trader account) identity.
  MakerId perp_maker_id = 5;
}

// -- Market data events (market_data/events.proto) --------------------------------------------------------

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

// `slot` is per-market: different entries may carry different slots when
// only a subset of markets updated in the most recent envelope.
message MarketSnapshot {
  Pair pair = 1;
  uint64 slot = 2;
  L2Level best_bid = 3;
  L2Level best_ask = 4;
  repeated L2Level bid_depth_levels = 5;
  repeated L2Level ask_depth_levels = 6;
  Decimal last_price = 7;
}

message MarketsSnapshotEvent {
  uint64 slot = 1;
  Timestamp ts = 2;
  repeated MarketSnapshot markets = 3;
}

message FillEvent {
  Pair pair = 1;
  Side side = 2;
  Decimal price = 3;
  Decimal size = 4;
  uint64 slot = 5;
  Timestamp ts = 6;
  // Base58 signature of the transaction the fill was settled in.
  string signature = 7;
}

// External-aggregator trade normalized to a Flint pair. Price is quote per
// base, size is base units, and side is relative to the base.
message ExternalFillEvent {
  Pair pair = 1;
  Side side = 2;
  Decimal price = 3;
  Decimal size = 4;
  uint64 slot = 5;
  Timestamp ts = 6;
  // Base58 signature of the transaction the swap settled in.
  string signature = 7;
  // Aggregator the swap routed through ("jupiter", "okx", "dflow", "titan").
  string source = 8;
}

// Fixed-notional venue quote. Bid and ask use the same base size; price is
// quote per base and the quote asset is the global USD numeraire.
message ExternalVenueQuoteEvent {
  Pair pair = 1;
  string venue = 2;
  // Sell base for quote.
  L2Level bid = 3;
  // Buy base with quote.
  L2Level ask = 4;
  // Server receipt time of the poll that produced this quote.
  Timestamp received_ts = 5;
  // Route labels in route order; empty when unavailable.
  repeated string ask_route = 6;
  repeated string bid_route = 7;
}

// Book and status stream envelope; fills use SubscribeFills.
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;
  }
}

// -- Market data messages (market_data/messages.proto) --------------------------------------------------------

message SubscribeRequest {
  // Pairs to subscribe to with their desired feed level.
  repeated PairSubscription pairs = 1;
}

message SubscribeFillsRequest {
  // Per-pair filter. Empty = fills from every pair.
  repeated Pair pairs = 1;
}

message SubscribeExternalFillsRequest {
  Pair pair = 1;
}

message SubscribeExternalQuotesRequest {
  Pair pair = 1;
}

message GetBookRequest {
  Pair pair = 1;
  FeedLevel level = 2;
}

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

message ListPairsRequest {}

message SubscribeMarketSnapshotsRequest {}

message ListedPair {
  Pair pair = 1;
  SpotMetadata base = 2;
  // Absent until the server observes a fill.
  Decimal last_price = 3;
  SpotMetadata quote = 4;
  // Taker fee rate for this pair, in hundredths of a basis point:
  // 1_000_000 == 100%, so 100 == 1bp == 0.01%.
  uint32 fee_hbps = 5;
}

message ListPairsResponse {
  repeated ListedPair pairs = 1;
}

// -- Maker events (maker/events.proto) --------------------------------------------------------

// Authenticated maker balance observation.
message MakerBalanceEvent {
  MakerId maker_id = 1;
  SpotId spot_id = 2;
  // Token units (e.g. "1.5" SOL); server scales by SpotMetadata.decimals.
  Decimal balance = 3;
  uint64 slot = 4;
  Timestamp ts = 5;
  Decimal notional = 6;
  Decimal soft_max_balance = 7;
}

// Resting quote with zero-indexed L2 depth.
message MakerQuote {
  Decimal price = 1;
  Decimal size = 2;
  uint32 level = 3;
}

// Per-pair market snapshot with the authenticated maker's quotes.
message MakerMarketSnapshot {
  Pair pair = 1;
  uint64 slot = 2;
  L2Level best_bid = 3;
  L2Level best_ask = 4;
  repeated L2Level bid_depth_levels = 5;
  repeated L2Level ask_depth_levels = 6;
  Decimal last_price = 7;
  // Absent when the maker has no order on this side of this pair.
  MakerQuote maker_bid = 8;
  MakerQuote maker_ask = 9;
}

message MakerMarketsSnapshotEvent {
  uint64 slot = 1;
  Timestamp ts = 2;
  repeated MakerMarketSnapshot markets = 3;
}

// Fill where the authenticated maker provided liquidity. Side is the maker's,
// the inverse of the public FillEvent side.
message MakerFillEvent {
  Pair pair = 1;
  MakerId maker_id = 2;
  Side side = 3;
  Decimal price = 4;
  Decimal size = 5;
  uint64 slot = 6;
  Timestamp ts = 7;
  // Base58 signature of the transaction the fill was settled in.
  string signature = 8;
  // Quote-denominated markout prices. Set only by GetFills; each horizon is
  // unset when no price was captured.
  Decimal ref_price_0s = 9;
  Decimal ref_price_1s = 10;
  Decimal ref_price_5s = 11;
  Decimal ref_price_15s = 12;
  Decimal ref_price_30s = 13;
  Decimal notional_usd = 14;
}

// Selects account actions returned by GetActivity. UNSPECIFIED is ignored.
enum MakerActivityType {
  MAKER_ACTIVITY_TYPE_UNSPECIFIED = 0;
  MAKER_ACTIVITY_TYPE_DEPOSIT_WITHDRAW = 1;
  MAKER_ACTIVITY_TYPE_ADD_MARKET = 2;
  MAKER_ACTIVITY_TYPE_MANAGE_MAKER = 3;
  MAKER_ACTIVITY_TYPE_SET_CROSS_SPREAD = 4;
  MAKER_ACTIVITY_TYPE_SET_QUOTING_PARAMS = 5;
}

message MakerActivity {
  uint64 slot = 1;
  Timestamp ts = 2;
  // Base58 transaction signature the action was emitted in.
  string signature = 3;
  reserved 6;
  reserved "create_maker";
  oneof action {
    DepositAction deposit = 4;
    WithdrawAction withdraw = 5;
    AddMarketAction add_market = 7;
    ManageMakerAction manage_maker = 8;
    CrossSpreadAction set_cross_spread = 9;
    QuotingParamsAction set_quoting_params = 10;
  }
}

message DepositAction {
  SpotId spot_id = 1;
  // Token units deposited (server scales by SpotMetadata.decimals).
  Decimal amount = 2;
  // Spot balance after the deposit, token units.
  Decimal balance_after = 3;
}

message WithdrawAction {
  SpotId spot_id = 1;
  // Token units withdrawn (server scales by SpotMetadata.decimals).
  Decimal amount = 2;
  // Spot balance after the withdrawal, token units.
  Decimal balance_after = 3;
}

// Maker market addition. Fields absent from older actions remain unset.
message AddMarketAction {
  SpotId spot_id = 1;
  optional uint32 book_index = 2;
  // Soft balance cap configured for the book, token units.
  Decimal soft_max_balance = 3;
}

// Maker authority change.
message ManageMakerAction {
  enum Kind {
    KIND_UNSPECIFIED = 0;
    ADD_QUOTER = 1;
    REMOVE_QUOTER = 2;
    SET_ADMIN = 3;
    SET_WITHDRAW_AUTHORITY = 4;
  }
  Kind kind = 1;
  // The authority pubkey added, removed, or set (base58).
  string authority = 2;
}

// Submitted cross-market spread change; a stale on-chain update may be skipped.
message CrossSpreadAction {
  // The micro book's own market.
  SpotId market_spot = 1;
  // The cross leg the spread applies to.
  SpotId cross_spot = 2;
  // Raw on-chain spread (oracle units); absent means the cross spread was
  // cleared (no cross spread).
  optional uint32 spread = 3;
}

// Submitted quoting-parameter change; a stale on-chain update may be skipped.
message QuotingParamsAction {
  SpotId spot_id = 1;
  // Whether the book is enabled for quoting (`false` = paused).
  bool enabled = 2;
  // Soft balance cap, token units; absent means no cap.
  Decimal soft_max_balance = 3;
}

// -- Stats messages (stats/messages.proto) --------------------------------------------------------

enum StatsWindow {
  STATS_WINDOW_UNSPECIFIED = 0;
  STATS_WINDOW_1H = 1;
  STATS_WINDOW_24H = 2;
  STATS_WINDOW_30D = 3;
}

message WindowStats {
  StatsWindow window = 1;
  Decimal volume_base = 2;
  Decimal volume_quote = 3;
  uint64 fill_count = 4;
  Decimal volume_usd = 5;
}

// Cross-venue totals are USD: base and quote assets differ per pair and do
// not add.
message CrossVenueWindowStats {
  reserved 2;

  StatsWindow window = 1;
  uint64 fill_count = 3;
  // Valued when each fill was ingested, so price moves never restate it.
  // Excludes fills that were ingested unpriced.
  Decimal volume_usd = 4;
}

message PairVolume {
  Pair pair = 1;
  WindowStats one_hour = 2;
  WindowStats twenty_four_hour = 3;
  WindowStats thirty_day = 4;
  Decimal last_price = 5;
}

message GetSummaryRequest {}

message GetSummaryResponse {
  reserved 6, 7;

  uint32 active_pairs = 1;
  uint32 active_makers = 2;

  CrossVenueWindowStats one_hour = 3;
  CrossVenueWindowStats twenty_four_hour = 4;
  CrossVenueWindowStats thirty_day = 5;

  uint64 fill_count_all_time = 8;
  Decimal volume_usd_all_time = 14;

  // Distinct taker accounts in the last 24h.
  uint32 unique_traders_24h = 9;

  // USDC-quoted trades only.
  LargestTrade largest_trade_24h = 10;

  UpdateRate update_rate = 11;
  UpdateRate oracle_update_rate = 12;

  // Sampled periodically, not real-time.
  Decimal total_nav = 13;
}

message LargestTrade {
  Pair pair = 1;
  Decimal size = 2;
  Decimal price = 3;
  Timestamp ts = 4;
  Decimal notional = 5;
}

message GetVolumeBreakdownRequest {
  // Empty = every pair with fills in the last 30d.
  repeated Pair pairs = 1;
}

message GetVolumeBreakdownResponse {
  // Ordered by 24h volume descending.
  repeated PairVolume pairs = 1;
}

message GetVolumeSeriesRequest {
  // Absent = cross-venue aggregate.
  Pair pair = 1;
  // Sets horizon and bucket size: 1H -> 60 x 1m, 24H -> 288 x 5m,
  // 30D -> 720 x 1h.
  StatsWindow window = 2;
}

message VolumeBucket {
  // Bucket start (inclusive).
  Timestamp ts = 1;
  // Per-pair only; absent on a cross-venue request, where `volume_usd`
  // carries the total.
  Decimal volume_base = 2;
  Decimal volume_quote = 3;
  uint64 fill_count = 4;
  Decimal volume_usd = 5;
}

message GetVolumeSeriesResponse {
  // Ordered oldest-first.
  repeated VolumeBucket buckets = 1;
  uint32 bucket_seconds = 2;
}

message GetAssetTvlsRequest {}

message AssetTvl {
  SpotMetadata asset = 1;
  // Token units, not atoms.
  Decimal total_balance = 2;
  uint32 maker_count = 3;
}

message GetAssetTvlsResponse {
  repeated AssetTvl assets = 1;
}

message UpdateRate {
  double per_second_1s = 1;
  double per_second_1m = 2;
  double per_second_5m = 3;
}

// -- Node messages (node/messages.proto) --------------------------------------------------------

message GetNodeInfoRequest {}

message GetNodeInfoResponse {
  // Server build identity.
  string version = 1;
  string git_commit = 2;
  // Schema revision used to build this node.
  string proto_hash = 3;
  string proto_rev = 4;

  // Solana cluster this node is pointed at (e.g. "mainnet-beta").
  string cluster = 5;
  // Deploy region owning this node.
  string region = 6;
  // Base58 program id of the on-chain venue this node serves.
  string program_id = 7;
  // Process start time.
  Timestamp started_at = 8;

  LeaderProximity leader_proximity = 9;

  // Per-process server instance ID.
  string server_instance = 10;

  // Approximate region location; absent when unavailable.
  optional LatLng region_lat_lng = 11;

  // Health of this node only.
  HealthState health = 12;
  // Why `health` is not HEALTH_STATE_HEALTHY. Empty when it is.
  string health_reason = 13;
}

// Observed round-trip distance to block leaders.
message LeaderProximity {
  // Zero means no sample; distance fields are then meaningless.
  uint32 measured = 1;
  uint32 mean_distance_micros = 2;
  uint32 median_distance_micros = 3;
  uint32 p90_distance_micros = 4;
}

message ListNodesRequest {
  // Empty includes every cluster.
  string cluster = 1;
}

message NodeEndpoint {
  // gRPC endpoint, as host:port or URL.
  string endpoint = 1;
  string region = 2;
  // Approximate region location; absent when unavailable.
  optional LatLng region_lat_lng = 3;
  string cluster = 4;
  // True for the endpoint serving this request.
  bool current = 5;
}

message ListNodesResponse {
  // Published endpoints only; entries do not imply current health.
  repeated NodeEndpoint nodes = 1;
}

// -- Maker messages (maker/messages.proto) --------------------------------------------------------

message SubscribeBalanceRequest {
  // Optional per-spot filter. Empty = every spot the authenticated maker
  // has a balance in (base + quote of every pair they quote on).
  repeated SpotId spot_ids = 1;
}

message GetBalanceRequest {
  // Optional per-spot filter; empty = all spots.
  repeated SpotId spot_ids = 1;
}

message GetBalanceResponse {
  repeated MakerBalanceEvent balances = 1;
}

message SubscribeMakerMarketSnapshotsRequest {}

message GetMakerVolumeBreakdownRequest {
  // Optional pair filter. Empty = every pair the maker has fills in
  // across the largest window (30d).
  repeated Pair pairs = 1;
}

message GetMakerVolumeBreakdownResponse {
  // Ordered by 24h volume descending.
  repeated PairVolume pairs = 1;
}

message SubscribeMakerFillsRequest {
  // Optional per-pair filter. Empty = every pair the authenticated maker
  // gets a fill on.
  repeated Pair pairs = 1;
}

enum MarkoutHorizon {
  MARKOUT_HORIZON_UNSPECIFIED = 0;  // server default: 5s
  MARKOUT_HORIZON_SEC_0 = 1;
  MARKOUT_HORIZON_SEC_1 = 2;
  MARKOUT_HORIZON_SEC_5 = 3;
  MARKOUT_HORIZON_SEC_15 = 4;
  MARKOUT_HORIZON_SEC_30 = 5;
}

enum MakerFillOrder {
  MAKER_FILL_ORDER_UNSPECIFIED = 0;  // same as TIME_DESC
  MAKER_FILL_ORDER_TIME_DESC = 1;
  // Largest absolute USD markout first; fills without one sort last.
  MAKER_FILL_ORDER_ABS_MARKOUT_DESC = 2;
}

message GetMakerFillsRequest {
  // Optional per-pair filter. Empty = every pair the authenticated maker
  // got a fill on.
  repeated Pair pairs = 1;
  // Inclusive lower bound. Unset / zero-micros = server retention window.
  Timestamp start = 2;
  // Exclusive upper bound. Unset / zero-micros = now.
  Timestamp end = 3;
  // Max rows to return. Zero = server default (50). Hard cap 1000.
  uint32 limit = 4;
  // Ordering for the returned page. Unset = TIME_DESC.
  MakerFillOrder order_by = 5;
  // Horizon ABS_MARKOUT_DESC ranks on. Ignored for TIME_DESC.
  MarkoutHorizon markout_horizon = 6;
}

message GetMakerFillsResponse {
  // Ordered per the request's `order_by`; newest-first by default.
  repeated MakerFillEvent fills = 1;
}

// Markout summary over the whole window, without GetFills' row cap.
message GetMakerMarkoutSummaryRequest {
  repeated Pair pairs = 1;
  // Inclusive lower bound. Unset / zero-micros = server retention window.
  Timestamp start = 2;
  // Exclusive upper bound. Unset / zero-micros = now.
  Timestamp end = 3;
  MarkoutHorizon horizon = 4;
}

// Rolling 24-hour window from effective_start.
message MarkoutBucket {
  uint32 index = 1;
  double net = 2;
  double adverse = 3;
  double favorable = 4;
}

message MarkoutMarketRow {
  Pair pair = 1;
  double net = 2;
  double adverse = 3;
  double favorable = 4;
  double volume_usd = 5;
  uint64 fills = 6;
  uint64 fills_with_markout = 7;
  optional double avg_bps = 8;
}

// Histogram bin; unset edges are unbounded.
message MarkoutHistogramBin {
  optional double min = 1;
  optional double max = 2;
  uint64 count = 3;
  double volume_usd = 4;
  double net = 5;
}

message GetMakerMarkoutSummaryResponse {
  double net = 1;
  // Absolute USD of the negative-markout fills only (adverse selection).
  double adverse = 2;
  double favorable = 3;
  // At-ingest USD notional over every priced fill.
  double volume_usd = 4;
  // Every fill in the window, including those behind no USD figure.
  uint64 fills = 5;
  // Fills with both a USD notional and reference price.
  uint64 fills_with_markout = 6;
  // Unpriced fills. Non-zero means USD totals are lower bounds.
  uint64 fills_unpriced = 7;
  uint64 fills_missing_ref = 8;
  optional double avg_bps = 9;
  // Unset, not 0, when no fill carried a markout - matching avg_bps.
  optional double avg_per_fill = 10;
  repeated MarkoutBucket buckets = 11;
  // Descending by `adverse`.
  repeated MarkoutMarketRow markets = 12;
  // Ascending by bps, edges contiguous.
  repeated MarkoutHistogramBin histogram = 13;
  // Actual queried window, clamped to 30-day retention.
  Timestamp effective_start = 14;
  Timestamp effective_end = 15;
}

message GetMakerVolumeSeriesRequest {
  // Optional pair filter. Absent = aggregate across every pair the maker
  // has fills in.
  Pair pair = 1;
  StatsWindow window = 2;
}

message GetMakerVolumeSeriesResponse {
  // Ordered oldest-first.
  repeated VolumeBucket buckets = 1;
  uint32 bucket_seconds = 2;
}

message GetNavHistoryRequest {
  StatsWindow window = 1;
}

message NavPoint {
  Timestamp ts = 1;
  // USD holdings value; unpriced assets are valued at zero.
  Decimal nav_usd = 2;
  // Freshness of prices used for NAV.
  Timestamp price_as_of = 3;
  // Held assets that were priced into `nav_usd`.
  uint32 priced_assets = 4;
  // Assets valued at zero; non-zero means NAV is understated.
  uint32 unpriced_assets = 5;
}

message GetNavHistoryResponse {
  // Ordered oldest-first.
  repeated NavPoint points = 1;
  uint32 bucket_seconds = 2;
}

message GetMakerStatsRequest {}

message GetMakerStatsResponse {
  reserved 2, 3;

  // Echoed from the bearer token so the client can sanity-check the scope.
  MakerId maker_id = 1;

  // Match events where this maker provided liquidity.
  UpdateRate fills = 4;

  // Transactions accepted from this maker by the server's TxService
  // (counts every TX whose initial outcome was `Submitted`).
  UpdateRate transactions_sent = 5;
  // Transactions confirmed on-chain (TxOutcome::Landed).
  UpdateRate transactions_landed = 6;
  // Transactions that failed - rejected pre-submit, expired before landing,
  // or landed with an error.
  UpdateRate transactions_failed = 7;

  // Venue-wide oracle-fair update rate. Same value every maker observes -
  // included so MMs can compare their request rate against oracle volatility.
  UpdateRate oracle_updates = 8;
}

message GetMakerActivityRequest {
  // Inclusive lower bound. Unset / zero-micros = server retention window.
  Timestamp start = 1;
  // Exclusive upper bound. Unset / zero-micros = now.
  Timestamp end = 2;
  // Max rows to return. Zero = server default (50). Hard cap 1000.
  uint32 limit = 3;
  // Optional action-type filter. Empty = all types; unrecognized / UNSPECIFIED
  // entries are ignored, and a filter matching no known type yields no rows.
  repeated MakerActivityType types = 4;
}

message GetMakerActivityResponse {
  // Ordered newest-first.
  repeated MakerActivity activities = 1;
}

// Archived Flint transaction status. FAILED means it landed but reverted.
enum TransactionStatus {
  TRANSACTION_STATUS_UNSPECIFIED = 0;
  TRANSACTION_STATUS_CONFIRMED = 1;
  TRANSACTION_STATUS_FAILED = 2;
}

// Kind of decoded Flint program event.
enum DecodedEventKind {
  DECODED_EVENT_KIND_UNSPECIFIED = 0;
  // Event-backed (1:1 with the on-chain SweetSpotEvent):
  DECODED_EVENT_KIND_MATCH = 1;
  DECODED_EVENT_KIND_TRADE_SETTLEMENT = 2;
  DECODED_EVENT_KIND_CREATE_SPOT = 3;
  DECODED_EVENT_KIND_CREATE_MAKER = 4;
  DECODED_EVENT_KIND_ADD_MICRO_BOOK = 5;
  DECODED_EVENT_KIND_DEPOSIT_WITHDRAW = 6;
  DECODED_EVENT_KIND_CREATE_GLOBAL_ADMIN = 7;
  DECODED_EVENT_KIND_SWAP = 8;
  DECODED_EVENT_KIND_CROSS_CANCEL = 9;
  DECODED_EVENT_KIND_CROSS_FILL = 10;
  DECODED_EVENT_KIND_WITHDRAW_FEES = 11;
  DECODED_EVENT_KIND_SET_GLOBAL_ADMIN = 12;
  // Synthetic (recovered from instruction data, no CPI event):
  DECODED_EVENT_KIND_MANAGE_MAKER = 13;
  DECODED_EVENT_KIND_CROSS_SPREAD_UPDATE = 14;
  DECODED_EVENT_KIND_QUOTING_PARAMS_UPDATE = 15;
}

// Decoded Flint program event. Type-specific data is JSON in payload_json.
message DecodedEvent {
  DecodedEventKind kind = 1;
  // Trading pair the event touches; unset for venue-global events.
  Pair pair = 2;
  // The maker whose liquidity/account the event concerns; unset when not
  // applicable. Deep-links to the maker page.
  MakerId maker_id = 3;
  // The other party, meaning depends on kind: the taker's signer pubkey for a
  // MATCH, the opposing maker for a CROSS_FILL, the mint for a CREATE_SPOT
  // (base58). Unset when not applicable.
  optional string counterparty = 4;
  // Taker side for fills; SIDE_UNSPECIFIED when the event has no side.
  Side side = 5;
  // Fill price and size; absent for non-trading events.
  Decimal price = 6;
  Decimal size = 7;
  // On-chain order id (formatted) when the event references one.
  optional string order_id = 8;
  // Position within the transaction, used to order rows and address the row
  // uniquely (mirrors GetQuote's addressing).
  uint32 instruction_index = 9;
  uint32 event_index = 10;
  // Signing quoting-authority pubkey (base58) for quote-bearing events;
  // populated once the quote-tape join lands (stats iteration), unset until
  // then. Deep-links to quoter detail.
  optional string quoter = 11;
  // Raw decoded SweetSpotEvent as JSON, for type-specific detail rendering.
  string payload_json = 12;
}

// Address a transaction by its base58 signature.
message GetDecodedTransactionRequest {
  string signature = 1;
}

message GetDecodedTransactionResponse {
  // Base58 signature (echoed).
  string signature = 1;
  uint64 slot = 2;
  // Chain (block) time of the transaction.
  Timestamp block_time = 3;
  TransactionStatus status = 4;
  // Transaction fee in lamports. Unset when tx meta was not archived for this
  // transaction (rows indexed before tx-meta capture landed).
  optional uint64 fee_lamports = 5;
  // Decoded Flint-program events, ordered by (instruction_index, event_index).
  repeated DecodedEvent events = 6;
}

message GetSdkCredentialsRequest {}

message GetSdkCredentialsResponse {
  // Plaintext registry token (read-only pull scope). Stable: every call
  // returns the same token, so clients never need to store it.
  string token = 1;
  // Server-assigned token name, e.g. "sdk-maker-12-mainnet".
  string token_name = 2;
  // Cargo sparse-index URL for `[registries.<registry_name>]` in
  // .cargo/config.toml.
  string index_url = 3;
  // Registry name for Cargo.toml / .cargo/config.toml, e.g. "kellnr".
  string registry_name = 4;
  // When the token was first minted.
  Timestamp created_at = 5;
}

// -- Maker admin messages (maker_admin/messages.proto) --------------------------------------------------------

// Aggregate of one quoting authority's currently-open sessions.
message QuotingAuthority {
  // Quoting keypair pubkey (base58) that authenticated the sessions.
  string quoter = 1;
  // Number of open session streams across all instances.
  uint32 open_sessions = 2;
  // Most recent heartbeat seen for any of this authority's sessions.
  Timestamp last_seen = 3;
  // Best (lowest) live round-trip across this authority's sessions, micros.
  // Zero when no session has completed a heartbeat round trip yet.
  uint64 min_rtt_micros = 4;
  // Distinct flint-server regions this authority is connected to.
  repeated string regions = 5;
  // Distinct client SDK build strings observed.
  repeated string sdks = 6;
  // Most recent time a quote (SubmitTx) from this authority was received by the
  // server. Absent if none seen recently.
  optional Timestamp last_submitted_at = 7;
  // Most recent time a tx from this authority's keypair confirmed on-chain.
  // Absent if none landed recently. The gap from `last_submitted_at` shows
  // whether submitted quotes are actually landing.
  optional Timestamp last_landed_at = 8;

  // Fee-payer balance in lamports; absent means unknown.
  optional uint64 sol_lamports = 9;
  // When sol_lamports was read; absent with it.
  optional Timestamp sol_balance_as_of = 10;

  // Five-minute heartbeat RTT percentiles in microseconds; zero when rtt_samples is zero.
  uint64 p50_rtt_micros = 11;
  uint64 p99_rtt_micros = 12;
  // Samples for RTT percentiles; zero makes percentiles meaningless.
  uint32 rtt_samples = 13;

  // Oldest-first buckets, including empty buckets, keyed by authority.
  repeated QuoterSeriesBucket series = 14;
}

// One currently-open session stream.
message QuoterSession {
  // Per-stream id minted by the server at connect.
  string session_id = 1;
  // Quoting keypair pubkey (base58).
  string quoter = 2;
  Timestamp connected_at = 3;
  // Most recent heartbeat round trip for this session.
  Timestamp last_seen = 4;
  // Peer IP as seen by the server (proxy-forwarded first hop when present).
  string ip = 5;
  string sdk = 6;
  string proto_rev = 7;
  // Latest heartbeat round-trip time, micros (0 before the first round trip).
  uint64 rtt_micros = 8;
  // Latest estimated client clock drift, micros (signed; 0 if unknown).
  int64 drift_micros = 9;
  // flint-server deploy region that owns this stream.
  string region = 10;
  // Per-process id of the flint-server instance that owns this stream.
  string server_instance = 11;
  // Approximate quoter location; absent when unavailable.
  optional LatLng session_lat_lng = 12;
  // Approximate server location; absent when unavailable.
  optional LatLng server_lat_lng = 13;
  // Most recent time this session's quoter submitted a quote (SubmitTx) to the
  // server. Per quoter key, so all of a quoter's sessions share the value.
  optional Timestamp last_submitted_at = 14;
  // Most recent time a tx from this session's quoter keypair confirmed
  // on-chain. Per quoter key. The gap from `last_submitted_at` shows whether
  // submitted quotes are landing.
  optional Timestamp last_landed_at = 15;
}

message ListQuotingAuthoritiesRequest {
  // Optional authority filter; empty includes every authority.
  string quoter = 1;
}

message ListQuotingAuthoritiesResponse {
  // Ordered by open-session count, descending.
  repeated QuotingAuthority authorities = 1;

  // Series bucket width; use series_start and series_end for the horizon.
  uint32 bucket_seconds = 2;
  // `series_start` inclusive, `series_end` exclusive.
  Timestamp series_start = 3;
  Timestamp series_end = 4;
}

message ListQuoterSessionsRequest {
  // Optional: restrict to a single quoting authority (pubkey). Empty returns
  // all of the caller's open sessions.
  string quoter = 1;
}

message ListQuoterSessionsResponse {
  // Ordered most-recently-seen first.
  repeated QuoterSession sessions = 1;
}

// One bucket of a quoting authority's activity.
message QuoterSeriesBucket {
  // Bucket start (inclusive).
  Timestamp ts = 1;

  // Heartbeat samples; zero makes RTT percentiles meaningless.
  uint32 rtt_samples = 2;
  uint64 p50_rtt_micros = 3;
  uint64 p99_rtt_micros = 4;

  // Quote updates received, one per quoted leg.
  uint64 quotes = 5;

  // Transaction outcomes are bucketed by observation time, not submission.
  uint64 transactions_sent = 6;
  // Confirmed on-chain.
  uint64 transactions_landed = 7;
  // Rejected pre-submit, expired before landing, or landed with an error.
  uint64 transactions_failed = 8;

  // Landings used for submit-to-land percentiles; zero makes them meaningless.
  uint32 land_samples = 9;
  uint64 p50_land_micros = 10;
  uint64 p99_land_micros = 11;
}

// -- Tx events (tx/events.proto) --------------------------------------------------------

message BlockhashEvent {
  Blockhash blockhash = 1;
  // Server's current priority-fee recommendation (microlamports per CU)
  // sampled from recent landed txs. Zero = no recommendation yet.
  uint64 recommended_cu_price = 2;
  Timestamp ts = 3;
  // Solana lastValidBlockHeight; zero before the height clock is ready.
  uint64 last_valid_block_height = 4;
}

message SlotEvent {
  uint64 slot = 1;
  Timestamp ts = 2;
}

// Upcoming leader and its TPU endpoint. Events are idempotent by start_slot,
// expire after end_slot, and updates for the same start_slot replace prior data.
message LeaderEvent {
  // Inclusive first slot of this leader's window.
  uint64 start_slot = 1;
  // Inclusive last slot of the leader window.
  uint64 end_slot = 2;
  // TPU address from validator gossip.
  string tpu_ip = 3;
  // QUIC TPU port; zero means direct QUIC send is unavailable.
  uint32 tpu_quic_port = 4;
  // Server send time, for client-side latency attribution. Not policy.
  Timestamp ts = 5;
}

// Server accepted the transaction for submission.
message TxAckEvent {
  // Base58 transaction signature.
  string signature = 1;
  Timestamp ts = 2;
}

// Observed at processed commitment; not confirmed or finalized.
message TxLandedEvent {
  // Base58 transaction signature.
  string signature = 1;
  uint64 slot = 2;
  Timestamp ts = 3;
}

// Validation, submission, on-chain failure, or expiry. Expiry alone does not prove non-execution.
message TxFailedEvent {
  // Base58 transaction signature.
  string signature = 1;
  string reason = 2;
  Timestamp ts = 3;
}

message TxStatusEvent {
  oneof kind {
    TxAckEvent ack = 1;
    TxLandedEvent landed = 2;
    TxFailedEvent failed = 3;
  }
}

// -- Tx messages (tx/messages.proto) --------------------------------------------------------

// Submit a fully signed Solana transaction.
message SubmitTxRequest {
  // Serialized legacy or v0 signed transaction.
  bytes transaction = 1;
  // Client send time for latency telemetry only. Omit or use zero if unavailable.
  Timestamp client_sent_at = 2;
}

message SubmitTxResponse {
  // Base58 signature for correlating status events.
  string signature = 1;
  // Server wall-clock timestamp the submission was accepted for queueing.
  Timestamp ts = 2;
  // Server reply time. Subtract ts for server handling time without clock skew.
  Timestamp server_replied_at = 3;
}

message GetSponsoredPayersRequest {}

message GetSponsoredPayersResponse {
  // Base58 fee-payer pubkeys.
  repeated string payers = 1;
}

message SubscribeBlockhashRequest {}

message SubscribeSlotsRequest {}

message SubscribeLeadersRequest {}

// Maker-scoped status feed; reconcile after stream gaps.
message SubscribeTxStatusRequest {}

// -- Spread protect events (spread_protect/events.proto) --------------------------------------------------------

// Spread-protection stream event.
message SpreadProtectEvent {
  oneof kind {
    ResetState reset_state = 1;
    WidenWindow widen_window = 2;
  }
}

// Replace the client's local SpreadProtect state.
message ResetState {
  // Baseline multiplier to apply when no widen window is active.
  Decimal default_spread_mult = 1;
}

// Idempotent advisory for an inclusive slot range; expires after end_slot.
message WidenWindow {
  // Inclusive first slot of the window.
  uint64 start_slot = 1;
  // Inclusive last slot of the window.
  uint64 end_slot = 2;
  // Exact decimal multiplier, at least 1.0.
  Decimal spread_mult = 3;
  // Server send time, for client-side latency/attribution. Not policy.
  Timestamp ts = 4;
}

// -- Spread protect messages (spread_protect/messages.proto) --------------------------------------------------------

// Subscribe to the SpreadProtect widen-window feed. No filters: the policy is
// server-side and the same windows apply to every maker.
message SubscribeSpreadProtectRequest {}

// -- Historical messages (historical/messages.proto) --------------------------------------------------------

enum CandleInterval {
  CANDLE_INTERVAL_UNSPECIFIED = 0;
  CANDLE_INTERVAL_1M = 1;
  CANDLE_INTERVAL_5M = 2;
  CANDLE_INTERVAL_15M = 3;
  CANDLE_INTERVAL_30M = 4;
  CANDLE_INTERVAL_1H = 5;
  CANDLE_INTERVAL_4H = 6;
  CANDLE_INTERVAL_1D = 7;
}

message Candle {
  // Candle open time.
  Timestamp ts = 1;
  Decimal open = 2;
  Decimal high = 3;
  Decimal low = 4;
  Decimal close = 5;
  // Base-asset volume over the interval.
  Decimal volume = 6;
}

message GetFillsRequest {
  Pair pair = 1;
  // Inclusive lower bound. Unset / zero-micros = unbounded (server uses
  // its retention window).
  Timestamp start = 2;
  // Exclusive upper bound. Unset / zero-micros = now.
  Timestamp end = 3;
  // Max rows to return. Zero = server default (50). Hard cap 1000.
  uint32 limit = 4;
}

message GetFillsResponse {
  // Ordered newest-first.
  repeated FillEvent fills = 1;
}

message GetCandlesRequest {
  Pair pair = 1;
  CandleInterval interval = 2;
  // Inclusive lower bound.
  Timestamp start = 3;
  // Exclusive upper bound. Unset / zero-micros = now.
  Timestamp end = 4;
}

message GetCandlesResponse {
  // Ordered oldest-first. Hard cap of 10_000 candles per response.
  repeated Candle candles = 1;
}

// -- Escalation messages (escalation/messages.proto) --------------------------------------------------------

message PageTheTeamRequest {
  // Required non-empty message, delivered verbatim to on-call.
  string message = 1;
}

message PageTheTeamResponse {
  // Server-assigned page ID.
  string page_id = 1;
  // When the server accepted the page.
  Timestamp received_at = 2;
}

// -- Quote messages (quote/messages.proto) --------------------------------------------------------

// Determines how to interpret QuoteUpdate.payload_json.
enum QuoteUpdateKind {
  QUOTE_UPDATE_KIND_UNSPECIFIED = 0;
  // payload_json: {bids, asks}.
  QUOTE_UPDATE_KIND_ORDERLIST = 1;
  // payload_json: {risk, buy_orders, sell_orders}.
  QUOTE_UPDATE_KIND_ORACLE_OFFSET = 2;
  // payload_json: {risk, client_order_id, ...}.
  QUOTE_UPDATE_KIND_LINEAR_DISTRIBUTION = 3;
  // payload_json: {last_oracle_slot, oracle_sequence, buy_fair, sell_fair}.
  QUOTE_UPDATE_KIND_ORACLE_FAIR = 4;
  // payload_json: {last_oracle_slot, oracle_sequence, buy_start_price, ...}.
  QUOTE_UPDATE_KIND_LINEAR_FAIR = 5;
}

// On-chain quote update. Strategy-specific data is JSON in payload_json.
message QuoteUpdate {
  uint32 spot_id = 1;
  // Block (chain) time of the quote.
  Timestamp block_time = 2;
  uint64 slot = 3;
  // Transaction signature (base58) that carried the update.
  string signature = 4;
  // Identifies one update within a transaction.
  uint32 instruction_index = 5;
  uint32 leg_index = 6;
  uint32 maker_id = 7;
  // Signing quoting-authority pubkey (base58).
  string quoter = 8;
  QuoteUpdateKind strategy = 9;
  // Always true for fast-fair refreshes.
  bool enabled = 10;
  // Soft inventory cap in atoms; max-uint64 means no cap.
  uint64 soft_max_balance = 11;
  // Strategy-specific detail as JSON (levels / offsets / risk params).
  string payload_json = 12;
}

// Filters apply within the authenticated maker. Fields are OR-within and
// AND-across; empty fields are wildcards.
message SubscribeQuotesRequest {
  reserved 1; // was maker_ids - the RPC is scoped to the authenticated maker
  // Markets (quoting spots) to include; empty = all of the maker's markets.
  repeated uint32 spot_ids = 2;
  // Signing quoter pubkeys (base58) to include; empty = all of the maker's quoters.
  repeated string quoters = 3;
}

// Historical quote query with the stream's filter semantics.
message ListRecentQuotesRequest {
  reserved 1; // was maker_ids - the RPC is scoped to the authenticated maker
  repeated uint32 spot_ids = 2;
  repeated string quoters = 3;
  // Inclusive lower/upper bounds on block time. `0`/absent = unbounded.
  optional Timestamp start = 4;
  optional Timestamp end = 5;
  // Max rows to return. Server clamps to a sane ceiling; 0 = server default.
  uint32 limit = 6;
}

message ListRecentQuotesResponse {
  // Newest first.
  repeated QuoteUpdate quotes = 1;
}

// Exact on-chain identity of one quote update.
message GetQuoteRequest {
  string signature = 1;
  uint32 instruction_index = 2;
  uint32 leg_index = 3;
}

message GetQuoteResponse {
  QuoteUpdate quote = 1;
}

Built on Solana