Appearance
Proto schema
The canonical schema for flint.spot.v1. Synced from the flint-protos submodule; regenerate SDKs and docs after bumping that submodule.
- Download bundled
api.proto— every service inflint.spot.v1. - Download
openapi.yaml— OpenAPI 3.1 schema for the gRPC-Web service URLs.
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;
}