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

syntax = "proto3";

package flint.margin.maker.v1;

// -- auth/service.proto --------------------------------------------------------

// Issues sessions through a signed challenge; TxService requires the token.
service AuthService {
  // Issues a single-use nonce.
  rpc Challenge(ChallengeRequest) returns (ChallengeResponse);

  // Returns UNAUTHENTICATED for missing or expired nonces, invalid signatures,
  // or keys that control no trader account.
  rpc Authenticate(AuthenticateRequest) returns (AuthenticateResponse);

  rpc Revoke(RevokeRequest) returns (RevokeResponse);
}

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

// -- maker/service.proto --------------------------------------------------------

// Session-authenticated maker queries and streams.
service MakerService {
  rpc SubscribeMarketSnapshots(SubscribeMakerMarketSnapshotsRequest) returns (stream MakerMarketsSnapshotEvent);
  rpc SubscribeFills(SubscribeFillsRequest) returns (stream FillEvent);
  rpc GetFills(GetFillsRequest) returns (GetFillsResponse);
  rpc GetVolumeBreakdown(GetMakerVolumeBreakdownRequest) returns (GetMakerVolumeBreakdownResponse);
  rpc GetVolumeSeries(GetMakerVolumeSeriesRequest) returns (GetMakerVolumeSeriesResponse);
  rpc GetMarkoutSummary(GetMakerMarkoutSummaryRequest) returns (GetMakerMarkoutSummaryResponse);
  rpc GetQuotingState(GetQuotingStateRequest) returns (GetQuotingStateResponse);
  rpc SubscribeQuotes(SubscribeQuotesRequest) returns (stream QuoteUpdate);
  rpc ListRecentQuotes(ListRecentQuotesRequest) returns (ListRecentQuotesResponse);
  rpc GetQuote(GetQuoteRequest) returns (GetQuoteResponse);
  rpc GetStats(GetMakerStatsRequest) returns (GetMakerStatsResponse);
  rpc GetActivity(GetMakerActivityRequest) returns (GetMakerActivityResponse);
  rpc GetDecodedTransaction(GetDecodedTransactionRequest) returns (GetDecodedTransactionResponse);
  rpc ListQuotingAuthorities(ListQuotingAuthoritiesRequest) returns (ListQuotingAuthoritiesResponse);
  rpc ListQuoterSessions(ListQuoterSessionsRequest) returns (ListQuoterSessionsResponse);
  rpc GetSdkCredentials(GetSdkCredentialsRequest) returns (GetSdkCredentialsResponse);
}

// -- node/service.proto --------------------------------------------------------

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

  rpc ListNodes(ListNodesRequest) returns (ListNodesResponse);
}

// -- session/service.proto --------------------------------------------------------

// Server sends a Ping every 30s; clients reply immediately with a Pong.
// Requires a keypair session via `authorization: Bearer <token>` metadata.
service SessionService {
  rpc Session(stream SessionRequest) returns (stream SessionResponse);
}

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

// -- tx/service.proto --------------------------------------------------------

// Requires `authorization: Bearer <token>` metadata from AuthService.
service TxService {
  // Returns after acceptance; status transitions 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);
  rpc SubscribeLeaders(SubscribeLeadersRequest) returns (stream LeaderEvent);
}

// -- auth/messages.proto --------------------------------------------------------

message ChallengeRequest {
  // Base58 owner or active TRADE- or QUOTE-delegate public key.
  string pubkey = 1;
}

message ChallengeResponse {
  // Sign `FLINT-MARGIN-AUTH-V1:` followed by this single-use nonce.
  bytes nonce = 1;
  // Server rejects Authenticate after this time.
  Timestamp expires_at = 2;
}

message AuthenticateRequest {
  // Base58 public key.
  string pubkey = 1;
  // Base58 signature over the domain prefix and nonce returned by Challenge.
  string signature = 2;
  // Account to scope the session to. Omit to select the lowest authorized ID.
  TraderId trader_id = 3;
}

message AuthenticateResponse {
  // Send as `authorization: Bearer <session_token>` metadata.
  string session_token = 1;
  // Accounts controlled as owner or active TRADE or QUOTE delegate.
  repeated TraderId trader_ids = 2;
  // The server returns UNAUTHENTICATED after this time.
  Timestamp expires_at = 3;
  // Account selected for this session.
  TraderId trader_id = 4;
}

message RevokeRequest {
  string session_token = 1;
}

message RevokeResponse {}

// -- common.proto --------------------------------------------------------

message PerpId {
  uint32 id = 1;
}

// On-chain margin spot-asset id.
message SpotId {
  uint32 id = 1;
}

message TraderId {
  uint64 id = 1;
}

message Blockhash {
  bytes hash = 1;
}

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

// Decimal string parsed with rust_decimal-compatible semantics.
message Decimal {
  string value = 1;
}

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

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

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

// -- maker/events.proto --------------------------------------------------------

enum QuotingStrategy {
  QUOTING_STRATEGY_UNSPECIFIED = 0;
  QUOTING_STRATEGY_ORDER_LIST = 1;
  QUOTING_STRATEGY_SPLINE = 2;
  QUOTING_STRATEGY_DENSITY = 3;
  QUOTING_STRATEGY_RELATIVE_DENSITY = 4;
}

enum QuoteUpdateKind {
  QUOTE_UPDATE_KIND_UNSPECIFIED = 0;
  QUOTE_UPDATE_KIND_KEEP = 1;
  QUOTE_UPDATE_KIND_RESET = 2;
  QUOTE_UPDATE_KIND_ORDER_LIST = 3;
  QUOTE_UPDATE_KIND_SPLINE_FAIR = 4;
  QUOTE_UPDATE_KIND_SPLINE_BANDS = 5;
  QUOTE_UPDATE_KIND_DENSITY_FAIR = 6;
  QUOTE_UPDATE_KIND_DENSITY_BANDS = 7;
  QUOTE_UPDATE_KIND_RELATIVE_DENSITY_BANDS = 8;
}

// One price level on a perp market book.
message PerpL2Level {
  Decimal price = 1;
  Decimal size = 2;
}

// The authenticated trader's resting quote on one side of a perp.
message MakerQuote {
  Decimal price = 1;
  Decimal size = 2;
  uint32 level = 3;
}

// Perp market snapshot with the authenticated trader's best quotes.
message MakerMarketSnapshot {
  PerpId perp_id = 1;
  uint64 slot = 2;
  PerpL2Level best_bid = 3;
  PerpL2Level best_ask = 4;
  repeated PerpL2Level bid_depth_levels = 5;
  repeated PerpL2Level ask_depth_levels = 6;
  Decimal last_price = 7;
  MakerQuote maker_bid = 8;
  MakerQuote maker_ask = 9;
}

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

// Fill where the authenticated trader provided liquidity. Side is the maker's
// direction. Price and size are scaled from the perp's tick and lot grids;
// maker_rebate is denominated in the perp's PnL currency.
message FillEvent {
  PerpId perp_id = 1;
  TraderId trader_id = 2;
  Side side = 3;
  Decimal price = 4;
  Decimal size = 5;
  uint64 slot = 6;
  Timestamp ts = 7;
  string signature = 8;
  Decimal maker_rebate = 9;
  TraderId taker_id = 10;
  // Quote-denominated markout prices. Set only by GetFills; each horizon is
  // unset when no price was captured.
  Decimal ref_price_0s = 11;
  Decimal ref_price_1s = 12;
  Decimal ref_price_5s = 13;
  Decimal ref_price_15s = 14;
  Decimal ref_price_30s = 15;
  Decimal notional_usd = 16;
}

// Latest observed state for one admitted on-chain quoting entry.
message QuotingState {
  PerpId perp_id = 1;
  TraderId trader_id = 2;
  uint32 entry_index = 3;
  // Maximum of the independent streams; use their fields when reconciling writes.
  uint64 sequence = 4;
  bool enabled = 5;
  QuotingStrategy strategy = 6;
  string payload_json = 7;
  uint64 slot = 8;
  Timestamp observed_at = 9;
  uint64 order_sequence = 10;
  optional uint64 fair_sequence = 11;
}

// Submitted quoting intent in a successfully executed transaction.
message QuoteUpdate {
  PerpId perp_id = 1;
  Timestamp block_time = 2;
  uint64 slot = 3;
  string signature = 4;
  uint32 instruction_index = 5;
  // Lookup hint for UpdateQuoting; exact entry index for compact batches.
  uint32 entry_index_hint = 6;
  TraderId trader_id = 7;
  string quoter = 8;
  QuotingStrategy strategy = 9;
  uint64 sequence = 11;
  string payload_json = 12;
  QuoteUpdateKind update_kind = 13;
  // Zero for UpdateQuoting, otherwise the one-based item within a compact batch.
  uint32 update_index = 14;
  // Absent when a partial-success batch does not report individual outcomes.
  optional bool applied = 15;
  // Absent when the update preserves the current enabled flag.
  optional bool enabled_after = 16;
}

enum MakerActivityType {
  MAKER_ACTIVITY_TYPE_UNSPECIFIED = 0;
  MAKER_ACTIVITY_TYPE_COLLATERAL = 1;
  MAKER_ACTIVITY_TYPE_PERP_TRADE = 2;
  MAKER_ACTIVITY_TYPE_QUOTING_UPDATE = 3;
}

// One decoded account or quoting action associated with a trader.
message MakerActivity {
  TraderId trader_id = 1;
  // Unset for collateral-only actions.
  PerpId perp_id = 2;
  uint64 slot = 3;
  Timestamp ts = 4;
  string signature = 5;
  MakerActivityType type = 6;
  // Decoded event detail; fields depend on type.
  string payload_json = 7;
}

enum TransactionStatus {
  TRANSACTION_STATUS_UNSPECIFIED = 0;
  TRANSACTION_STATUS_CONFIRMED = 1;
  TRANSACTION_STATUS_FAILED = 2;
}

enum DecodedEventKind {
  DECODED_EVENT_KIND_UNSPECIFIED = 0;
  DECODED_EVENT_KIND_COLLATERAL = 1;
  DECODED_EVENT_KIND_PERP_TRADE = 2;
  DECODED_EVENT_KIND_PERP_FILL = 3;
  DECODED_EVENT_KIND_QUOTING_UPDATE = 4;
  DECODED_EVENT_KIND_PERP_LIQUIDATED = 5;
  DECODED_EVENT_KIND_FUNDING_UPDATED = 6;
  DECODED_EVENT_KIND_FUNDING_SETTLED = 7;
  DECODED_EVENT_KIND_PERP_CONFIG_UPDATED = 8;
  DECODED_EVENT_KIND_FUNDING_ADVANCED = 9;
  DECODED_EVENT_KIND_PERP_UPDATE_PROPOSED = 10;
  DECODED_EVENT_KIND_PERP_UPDATE_CANCELLED = 11;
}

// Decoded Flint margin-program event. Type-specific data is JSON.
message DecodedEvent {
  DecodedEventKind kind = 1;
  // Trader account touched by the event; unset when venue-global.
  TraderId trader_id = 2;
  // Perp touched by the event; unset for collateral-only actions.
  PerpId perp_id = 3;
  Side side = 4;
  Decimal price = 5;
  Decimal size = 6;
  uint32 instruction_index = 7;
  uint32 event_index = 8;
  string payload_json = 9;
}

// Aggregate of one authority's currently-open sessions for a trader.
message QuotingAuthority {
  TraderId trader_id = 1;
  // Base58 public key that authenticated the sessions.
  string quoter = 2;
  uint32 open_sessions = 3;
  Timestamp last_seen = 4;
  uint64 min_rtt_micros = 5;
  repeated string regions = 6;
  repeated string sdks = 7;
  optional Timestamp last_submitted_at = 8;
  optional Timestamp last_landed_at = 9;
  optional uint64 sol_lamports = 10;
  optional Timestamp sol_balance_as_of = 11;
  uint64 p50_rtt_micros = 12;
  uint64 p99_rtt_micros = 13;
  uint32 rtt_samples = 14;
  repeated QuoterSeriesBucket series = 15;
}

// One currently-open session for a selected trader.
message QuoterSession {
  // Server-minted identifier; never the bearer token itself.
  string session_id = 1;
  TraderId trader_id = 2;
  string quoter = 3;
  Timestamp connected_at = 4;
  Timestamp expires_at = 5;
  Timestamp last_seen = 6;
  string ip = 7;
  string sdk = 8;
  string proto_rev = 9;
  uint64 rtt_micros = 10;
  int64 drift_micros = 11;
  string region = 12;
  string server_instance = 13;
  optional LatLng session_lat_lng = 14;
  optional LatLng server_lat_lng = 15;
  optional Timestamp last_submitted_at = 16;
  optional Timestamp last_landed_at = 17;
}

message QuoterSeriesBucket {
  Timestamp ts = 1;
  uint32 rtt_samples = 2;
  uint64 p50_rtt_micros = 3;
  uint64 p99_rtt_micros = 4;
  uint64 quotes = 5;
  uint64 transactions_sent = 6;
  uint64 transactions_landed = 7;
  uint64 transactions_failed = 8;
  uint32 land_samples = 9;
  uint64 p50_land_micros = 10;
  uint64 p99_land_micros = 11;
}

// -- maker/messages.proto --------------------------------------------------------

message SubscribeMakerMarketSnapshotsRequest {
  // Empty selects every perp admitted for the session's trader.
  repeated PerpId perp_ids = 1;
}

message SubscribeFillsRequest {
  repeated PerpId perp_ids = 1;
}

message GetFillsRequest {
  repeated PerpId perp_ids = 1;
  Timestamp start = 2;
  Timestamp end = 3;
  uint32 limit = 4;
  string cursor = 5;
  MakerFillOrder order_by = 6;
  // Horizon used by ABS_MARKOUT_DESC; ignored for TIME_DESC.
  MarkoutHorizon markout_horizon = 7;
}

message GetFillsResponse {
  repeated FillEvent fills = 1;
  string next_cursor = 2;
}

// Per-trader maker volume, split by rolling window.
message GetMakerVolumeBreakdownRequest {
  // Empty selects every perp where the session's trader has maker fills.
  repeated PerpId perp_ids = 1;
}

message VolumeWindow {
  // Notional in USD, counted once for each matched long/short pair.
  Decimal volume_usd = 1;
  uint64 fill_count = 2;
}

message PerpVolume {
  PerpId perp_id = 1;
  VolumeWindow one_hour = 2;
  VolumeWindow twenty_four_hour = 3;
  VolumeWindow thirty_day = 4;
  // Most recent observed fill price.
  Decimal last_price = 5;
}

message GetMakerVolumeBreakdownResponse {
  // Ordered by 24-hour USD volume descending.
  repeated PerpVolume perps = 1;
}

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

message GetMakerVolumeSeriesRequest {
  // Unset aggregates every perp where the session's trader has maker fills.
  PerpId perp_id = 1;
  StatsWindow window = 2;
}

message VolumeBucket {
  Timestamp ts = 1;
  Decimal volume_usd = 2;
  uint64 fill_count = 3;
}

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

enum MarkoutHorizon {
  MARKOUT_HORIZON_UNSPECIFIED = 0;
  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;
  MAKER_FILL_ORDER_TIME_DESC = 1;
  // Largest absolute USD markout first; fills without one sort last.
  MAKER_FILL_ORDER_ABS_MARKOUT_DESC = 2;
}

// Whole-window markout summary, without GetFills' page limit.
message GetMakerMarkoutSummaryRequest {
  repeated PerpId perp_ids = 1;
  // Inclusive lower bound; unset selects the server retention window.
  Timestamp start = 2;
  // Exclusive upper bound; unset selects now.
  Timestamp end = 3;
  MarkoutHorizon horizon = 4;
}

message MarkoutBucket {
  uint32 index = 1;
  double net = 2;
  double adverse = 3;
  double favorable = 4;
}

message MarkoutPerpRow {
  PerpId perp_id = 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;
}

message MarkoutHistogramBin {
  // Unset edges are unbounded.
  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 value of negative-markout fills.
  double adverse = 2;
  double favorable = 3;
  double volume_usd = 4;
  uint64 fills = 5;
  uint64 fills_with_markout = 6;
  // Non-zero means USD totals are lower bounds.
  uint64 fills_unpriced = 7;
  uint64 fills_missing_ref = 8;
  optional double avg_bps = 9;
  optional double avg_per_fill = 10;
  repeated MarkoutBucket buckets = 11;
  // Ordered by adverse selection descending.
  repeated MarkoutPerpRow perps = 12;
  repeated MarkoutHistogramBin histogram = 13;
  // Actual queried window after retention clamping.
  Timestamp effective_start = 14;
  Timestamp effective_end = 15;
}

message GetQuotingStateRequest {
  repeated PerpId perp_ids = 1;
}

message GetQuotingStateResponse {
  repeated QuotingState entries = 1;
}

message SubscribeQuotesRequest {
  reserved 1;
  repeated PerpId perp_ids = 2;
  repeated string quoters = 3;
}

message ListRecentQuotesRequest {
  reserved 1;
  repeated PerpId perp_ids = 2;
  repeated string quoters = 3;
  optional Timestamp start = 4;
  optional Timestamp end = 5;
  uint32 limit = 6;
  string cursor = 7;
}

message ListRecentQuotesResponse {
  repeated QuoteUpdate quotes = 1;
  string next_cursor = 2;
}

message GetQuoteRequest {
  string signature = 1;
  uint32 instruction_index = 2;
  uint32 update_index = 3;
}

message GetQuoteResponse {
  QuoteUpdate quote = 1;
}

// Historical actions performed by the session's selected trader.
message GetMakerActivityRequest {
  Timestamp start = 1;
  Timestamp end = 2;
  // Zero uses the server default; maximum 1000.
  uint32 limit = 3;
  repeated MakerActivityType types = 4;
}

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

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

message GetDecodedTransactionResponse {
  string signature = 1;
  uint64 slot = 2;
  Timestamp block_time = 3;
  TransactionStatus status = 4;
  // Unset when transaction metadata was not archived.
  optional uint64 fee_lamports = 5;
  // Ordered by instruction_index, then event_index.
  repeated DecodedEvent events = 6;
}

message ListQuotingAuthoritiesRequest {
  // Empty includes every authority observed for the selected trader.
  string quoter = 1;
}

message ListQuotingAuthoritiesResponse {
  // Ordered by open session count descending.
  repeated QuotingAuthority authorities = 1;
  uint32 bucket_seconds = 2;
  Timestamp series_start = 3;
  Timestamp series_end = 4;
}

message ListQuoterSessionsRequest {
  // Empty includes every session observed for the selected trader.
  string quoter = 1;
}

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

message GetSdkCredentialsRequest {}

message GetSdkCredentialsResponse {
  // Plaintext read-only registry token. Repeated calls return the same token.
  string token = 1;
  string token_name = 2;
  string index_url = 3;
  string registry_name = 4;
  Timestamp created_at = 5;
}

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

message GetMakerStatsRequest {}

message GetMakerStatsResponse {
  TraderId trader_id = 1;
  reserved 2, 3;
  UpdateRate fills = 4;
  UpdateRate transactions_sent = 5;
  UpdateRate transactions_landed = 6;
  UpdateRate transactions_failed = 7;
  UpdateRate oracle_updates = 8;
  UpdateRate quote_updates = 9;
}

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

// -- session/messages.proto --------------------------------------------------------

message SessionResponse {
  oneof message {
    Ping ping = 1;
  }
}

message SessionRequest {
  oneof message {
    Pong pong = 1;
  }
}

// Server liveness probe; clients echo seq in an immediate Pong.
message Ping {
  // Server wall-clock at send time.
  Timestamp local_time = 1;
  // Per-stream correlation nonce.
  uint64 seq = 2;
}

// Client reply to a `Ping`, sent immediately on receipt.
message Pong {
  // Client wall-clock at reply time; used to estimate clock drift.
  Timestamp local_time = 1;
  // Echo of the originating `Ping.seq`.
  uint64 seq = 2;
}

// -- 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.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 {}

// -- tx/events.proto --------------------------------------------------------

message BlockhashEvent {
  Blockhash blockhash = 1;
  // Priority-fee recommendation in microlamports per CU; zero is unavailable.
  uint64 recommended_cu_price = 2;
  Timestamp ts = 3;
  // Solana lastValidBlockHeight; zero is unavailable.
  uint64 last_valid_block_height = 4;
}

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

message LeaderEvent {
  uint64 start_slot = 1;
  uint64 end_slot = 2;
  string tpu_ip = 3;
  uint32 tpu_quic_port = 4;
  Timestamp ts = 5;
}

// Accepted for submission; not confirmation.
message TxAckEvent {
  string signature = 1;
  Timestamp ts = 2;
}

// Observed at Processed commitment with no error.
message TxLandedEvent {
  string signature = 1;
  uint64 slot = 2;
  Timestamp ts = 3;
}

// Reverted after landing or timed out before landing.
message TxFailedEvent {
  string signature = 1;
  string reason = 2;
  Timestamp ts = 3;
}

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

// -- tx/messages.proto --------------------------------------------------------

message SubmitTxRequest {
  // Fully signed legacy or v0 transaction. The authenticated key must be a
  // required static signer. The selected trader scopes status attribution;
  // the server does not infer transaction account ownership.
  bytes transaction = 1;
  // Client send time for latency telemetry only.
  Timestamp client_sent_at = 2;
}

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

message SubscribeBlockhashRequest {}

message SubscribeSlotsRequest {}

message SubscribeLeadersRequest {}

// Streams status transitions attributed to this session's selected trader.
message SubscribeTxStatusRequest {}
