use serde::{Deserialize, Serialize};
use crate::{CapabilityRisk, McpExposure};
pub const PLATFORM_SCHEMA_VERSION: u16 = 2;
pub const PLATFORM_CONTRACT_VERSION: &str = "2.0";
pub const PLATFORM_ACTION_GRAPH: &str = include_str!("../fixtures/v2/platform-action-graph.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_SERVICE_STATUS_FIXTURE: &str =
include_str!("../fixtures/v2/platform-status.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_CAPABILITIES_FIXTURE: &str =
include_str!("../fixtures/v2/platform-capabilities.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_ASSETS_FIXTURE: &str = include_str!("../fixtures/v2/assets.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_SWAP_QUOTE_FIXTURE: &str = include_str!("../fixtures/v2/swap-quote.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_MARKETS_FIXTURE: &str = include_str!("../fixtures/v2/markets.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_BOOK_FIXTURE: &str = include_str!("../fixtures/v2/book.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_BBO_FIXTURE: &str = include_str!("../fixtures/v2/bbo.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_FEES_FIXTURE: &str = include_str!("../fixtures/v2/fees.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_STATUS_FIXTURE: &str = include_str!("../fixtures/v2/status.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_CANDLES_FIXTURE: &str = include_str!("../fixtures/v2/candles.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_MARK_FIXTURE: &str = include_str!("../fixtures/v2/mark.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_EXECUTION_STATUS_FIXTURE: &str =
include_str!("../fixtures/v2/execution-status.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_TWAPS_FIXTURE: &str = include_str!("../fixtures/v2/twaps.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_TWAP_CHALLENGE_FIXTURE: &str =
include_str!("../fixtures/v2/twap-challenge.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_TWAP_PREPARE_FIXTURE: &str = include_str!("../fixtures/v2/twap-prepare.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_TWAP_SUBMIT_FIXTURE: &str = include_str!("../fixtures/v2/twap-submit.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_PORTFOLIO_HISTORY_FIXTURE: &str =
include_str!("../fixtures/v2/portfolio-history.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_PORTFOLIO_FIXTURE: &str = include_str!("../fixtures/v2/portfolio.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_REWARDS_FIXTURE: &str = include_str!("../fixtures/v2/rewards.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_REFERRALS_FIXTURE: &str = include_str!("../fixtures/v2/referrals.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_REFERRAL_LINK_FIXTURE: &str = include_str!("../fixtures/v2/referral-link.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_REFERRAL_CLAIM_FIXTURE: &str =
include_str!("../fixtures/v2/referral-claim.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_VAULT_STATUS_FIXTURE: &str = include_str!("../fixtures/v2/vault-status.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_VAULT_PAUSE_PREPARE_FIXTURE: &str =
include_str!("../fixtures/v2/vault-pause-prepare.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_VAULT_SETUP_PREPARE_FIXTURE: &str =
include_str!("../fixtures/v2/vault-setup-prepare.json");
pub const PLATFORM_VAULT_DELEGATE_PREPARE_FIXTURE: &str =
include_str!("../fixtures/v2/vault-delegate-prepare.json");
pub const PLATFORM_VAULT_POLICY_PREPARE_FIXTURE: &str =
include_str!("../fixtures/v2/vault-policy-prepare.json");
pub const PLATFORM_VAULT_DEPOSIT_PREPARE_FIXTURE: &str =
include_str!("../fixtures/v2/vault-deposit-prepare.json");
pub const PLATFORM_VAULT_WITHDRAW_PREPARE_FIXTURE: &str =
include_str!("../fixtures/v2/vault-withdraw-prepare.json");
pub const PLATFORM_VAULT_SUBMIT_FIXTURE: &str = include_str!("../fixtures/v2/vault-submit.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_BUGS_FIXTURE: &str = include_str!("../fixtures/v2/bugs.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_BUG_SUBMIT_FIXTURE: &str = include_str!("../fixtures/v2/bug-submit.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_TRADES_FIXTURE: &str = include_str!("../fixtures/v2/trades.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_ACCOUNT_FIXTURE: &str = include_str!("../fixtures/v2/account.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_MAKER_REPUTATION_FIXTURE: &str =
include_str!("../fixtures/v2/maker-reputation.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_MAKER_STATUS_FIXTURE: &str = include_str!("../fixtures/v2/maker-status.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_MAKER_STREAM_FIXTURE: &str = include_str!("../fixtures/v2/maker-stream.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_TWAP_STREAM_FIXTURE: &str = include_str!("../fixtures/v2/twap-stream.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_EXECUTION_STREAM_FIXTURE: &str =
include_str!("../fixtures/v2/execution-stream.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_ORDER_CHALLENGE_FIXTURE: &str =
include_str!("../fixtures/v2/order-challenge.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_ORDER_PREPARE_FIXTURE: &str = include_str!("../fixtures/v2/order-prepare.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_ORDER_SUBMIT_FIXTURE: &str = include_str!("../fixtures/v2/order-submit.json");
#[cfg(any(test, feature = "fixtures"))]
#[doc(hidden)]
pub const PLATFORM_ORDER_STATUS_FIXTURE: &str = include_str!("../fixtures/v2/order-status.json");
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PermissionSource {
ExternalAgentOwner,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum SigningLocation {
External,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformAuthority {
pub permission_source: PermissionSource,
pub signing_location: SigningLocation,
pub accepts_private_keys: bool,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformTransport {
Http,
Websocket,
Mcp,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformMarketState {
Active,
ReadOnly,
QuoteOnly,
CancelOnly,
Paused,
Warming,
Degraded,
Unavailable,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformOrderState {
Created,
Accepted,
Open,
PartiallyFilled,
Filled,
CancelPending,
Cancelled,
Expired,
Rejected,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformSettlementState {
NotApplicable,
Pending,
Confirmed,
Failed,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformPublicErrorCode {
InvalidRequest,
UnsupportedCapability,
MarketUnavailable,
MarketWarming,
QuoteUnavailable,
QuoteExpired,
PriceBoundFailed,
InsufficientBalance,
PolicyRejected,
SessionExpired,
SequenceConflict,
DuplicateClientId,
OrderRejected,
OrderNotFound,
CancelTooLate,
SelfTradePrevented,
DeadManExpired,
RateLimited,
TemporarilyUnavailable,
SubmissionAmbiguous,
SettlementPending,
SettlementFailed,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ExactAmount {
pub asset_id: String,
pub atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct SequenceEnvelope {
pub stream_id: String,
pub sequence: String,
pub previous_sequence: Option<String>,
pub server_time_ms: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub snapshot_id: Option<String>,
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PageRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PageInfo {
pub next_cursor: Option<String>,
pub has_more: bool,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PublicOperationError {
pub code: PlatformPublicErrorCode,
pub message: String,
pub retryable: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub retry_after_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub operation_id: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct LivePlatformCapability {
pub id: String,
pub risk: CapabilityRisk,
pub required_scope: String,
pub transports: Vec<PlatformTransport>,
pub mcp_exposure: McpExposure,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformDiscoveryResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub authority: PlatformAuthority,
pub capabilities: Vec<LivePlatformCapability>,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformServiceState {
Operational,
Degraded,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformServiceStatusResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub status: PlatformServiceState,
pub available_operations: u32,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformActionKind {
Discovery,
Read,
Prepare,
ExternalSignature,
Submit,
Receipt,
Stream,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformGraphRelation {
pub from: String,
pub to: String,
pub kind: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformGraphModule {
pub id: String,
pub client_property: String,
pub capability_ids: Vec<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformOperationTransport {
pub transport: PlatformTransport,
#[serde(skip_serializing_if = "Option::is_none")]
pub method: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformOperation {
pub id: String,
pub capability_id: String,
pub kind: PlatformActionKind,
pub summary: String,
pub transports: Vec<PlatformOperationTransport>,
pub available: bool,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformWorkflowNode {
pub id: String,
pub kind: PlatformActionKind,
pub capability_id: Option<String>,
pub operation_ids: Vec<String>,
pub available: bool,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformWorkflowEdge {
pub from: String,
pub to: String,
pub condition: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformWorkflow {
pub id: String,
pub entry_node: String,
pub nodes: Vec<PlatformWorkflowNode>,
pub edges: Vec<PlatformWorkflowEdge>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformActionGraphResponse {
pub schema_version: u16,
pub contract_version: String,
pub graph_version: String,
pub entry_operation_id: String,
pub authority: PlatformAuthority,
pub entities: Vec<String>,
pub relations: Vec<PlatformGraphRelation>,
pub modules: Vec<PlatformGraphModule>,
pub operations: Vec<PlatformOperation>,
pub workflows: Vec<PlatformWorkflow>,
}
impl PlatformActionGraphResponse {
pub fn foundation() -> Self {
serde_json::from_str(PLATFORM_ACTION_GRAPH)
.expect("embedded platform action graph must be valid")
}
pub fn project_availability(
&mut self,
live_capability_ids: &std::collections::BTreeSet<String>,
) {
for operation in &mut self.operations {
operation.available = live_capability_ids.contains(&operation.capability_id);
}
for workflow in &mut self.workflows {
for node in &mut workflow.nodes {
node.available = node
.capability_id
.as_ref()
.is_none_or(|capability_id| live_capability_ids.contains(capability_id));
}
}
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformNetwork {
Solana,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformAsset {
pub asset_id: String,
pub symbol: String,
pub name: String,
pub decimals: u8,
#[serde(skip_serializing_if = "Option::is_none")]
pub logo_url: Option<String>,
pub network: PlatformNetwork,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformAssetsResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub assets: Vec<PlatformAsset>,
pub page: PageInfo,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformSwapQuoteRequest {
pub input_asset_id: String,
pub output_asset_id: String,
pub amount_in_atoms: String,
#[serde(default)]
pub maximum_tolerance_bps: u16,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformSwapQuoteResponse {
pub schema_version: u16,
pub contract_version: String,
pub quote_id: String,
pub server_time_ms: u64,
pub expires_at_ms: u64,
pub input_asset_id: String,
pub output_asset_id: String,
pub amount_in_atoms: String,
pub amount_in_consumed_atoms: String,
pub amount_out_atoms: String,
pub minimum_output_atoms: String,
pub input_fee_atoms: String,
pub output_fee_atoms: String,
pub maximum_tolerance_bps: u16,
pub reference_price: String,
pub price_impact_pct: String,
pub provider: String,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformMarketAction {
Quote,
ExecuteImmediate,
PlaceOrder,
ScheduleTwap,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMarket {
pub market_id: String,
pub label: String,
pub base_asset_id: String,
pub quote_asset_id: String,
pub status: PlatformMarketState,
pub available_actions: Vec<PlatformMarketAction>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMarketsResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub markets: Vec<PlatformMarket>,
pub page: PageInfo,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformBookLevel {
pub price_atoms: String,
pub size_atoms: String,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformBookSide {
Bid,
Ask,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformBookChange {
pub side: PlatformBookSide,
pub price_atoms: String,
pub size_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformBookSnapshotResponse {
pub schema_version: u16,
pub contract_version: String,
pub market_id: String,
pub stream_id: String,
pub sequence: String,
pub server_time_ms: u64,
pub snapshot_id: String,
pub bids: Vec<PlatformBookLevel>,
pub asks: Vec<PlatformBookLevel>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformBestBidAskResponse {
pub schema_version: u16,
pub contract_version: String,
pub market_id: String,
pub stream_id: String,
pub sequence: String,
pub server_time_ms: u64,
pub best_bid: Option<PlatformBookLevel>,
pub best_ask: Option<PlatformBookLevel>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformFeeScheduleResponse {
pub schema_version: u16,
pub contract_version: String,
pub market_id: String,
pub server_time_ms: u64,
pub passive_maker_fee_bps: u16,
pub maximum_immediate_execution_fee_bps: u16,
pub book_prices_include_trading_fees: bool,
pub exact_fee_returned_by_quote: bool,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMarketStatusResponse {
pub schema_version: u16,
pub contract_version: String,
pub market_id: String,
pub server_time_ms: u64,
pub status: PlatformMarketState,
pub tick_size_atoms: String,
pub minimum_order_size_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformCandle {
pub started_at_ms: u64,
pub open_price: String,
pub high_price: String,
pub low_price: String,
pub close_price: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformCandlesResponse {
pub schema_version: u16,
pub contract_version: String,
pub market_id: String,
pub server_time_ms: u64,
pub resolution_seconds: u32,
pub candles: Vec<PlatformCandle>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMarkResponse {
pub schema_version: u16,
pub contract_version: String,
pub market_id: String,
pub server_time_ms: u64,
pub price_atoms_per_base_unit: Option<String>,
pub quote_decimals: u8,
pub stale: bool,
pub age_ms: Option<u64>,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformExecutionState {
Prepared,
Confirmed,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformExecutionStatusResponse {
pub schema_version: u16,
pub contract_version: String,
pub execution_id: String,
pub market_id: String,
pub status: PlatformExecutionState,
pub signature: Option<String>,
pub settlement: PlatformSettlementState,
pub updated_at_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformExecutionRow {
pub execution_id: String,
pub market_id: String,
pub status: PlatformExecutionState,
pub signature: Option<String>,
pub settlement: PlatformSettlementState,
pub updated_at_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformExecutionCommand {
Watch { execution_ids: Vec<String> },
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformExecutionEvent {
ExecutionsSnapshot {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
server_time_ms: u64,
executions: Vec<PlatformExecutionRow>,
unknown_execution_ids: Vec<String>,
},
ExecutionUpdate {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
execution: PlatformExecutionRow,
},
ExecutionExpired {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
execution_id: String,
},
ExecutionUnknown {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
execution_id: String,
},
Heartbeat {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
},
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformTwapState {
Active,
Completed,
Cancelled,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformTwapFill {
pub fill_id: String,
pub size_atoms: String,
pub price_atoms: String,
pub gross_quote_atoms: String,
pub base_fee_atoms: String,
pub quote_fee_atoms: String,
pub signature: Option<String>,
pub observed_at_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformTwap {
pub twap_id: String,
pub side: PlatformTradeSide,
pub status: PlatformTwapState,
pub slices_total: u16,
pub slices_executed: u16,
pub interval_slots: u32,
pub maximum_tolerance_bps: u16,
pub limit_price_atoms: String,
pub total_size_atoms: String,
pub executed_size_atoms: String,
pub gross_quote_executed_atoms: String,
pub complete_execution_value: bool,
pub created_at_ms: u64,
pub completed_at_ms: Option<u64>,
pub placed_signature: Option<String>,
pub terminal_signature: Option<String>,
pub fills: Vec<PlatformTwapFill>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformTwapsResponse {
pub schema_version: u16,
pub contract_version: String,
pub market_id: String,
pub wallet_address: String,
pub server_time_ms: u64,
pub twaps: Vec<PlatformTwap>,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformTwapControlAction {
Place,
Cancel,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformTwapChallengeRequest {
Place {
owner_wallet: String,
session_public_key: String,
side: PlatformTradeSide,
total_size_atoms: String,
slices_total: u16,
maximum_tolerance_bps: u16,
interval_slots: u32,
limit_price_atoms: String,
},
Cancel {
owner_wallet: String,
session_public_key: String,
twap_id: String,
},
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformTwapChallengeResponse {
pub schema_version: u16,
pub contract_version: String,
pub challenge_id: String,
pub market_id: String,
pub action: PlatformTwapControlAction,
pub twap_id: String,
pub authorization_payload_base64: String,
pub server_time_ms: u64,
pub expires_at_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformTwapPrepareAuthorization {
pub challenge_id: String,
pub authorization_signature: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(untagged)]
pub enum PlatformTwapPrepareRequest {
Authorized(PlatformTwapPrepareAuthorization),
Direct(PlatformTwapChallengeRequest),
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformTwapPrepareResponse {
pub schema_version: u16,
pub contract_version: String,
pub twap_control_id: String,
pub market_id: String,
pub action: PlatformTwapControlAction,
pub twap_id: String,
pub transaction_base64: String,
pub recent_blockhash: String,
pub last_valid_block_height: u64,
pub expires_at_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformTwapSubmitRequest {
pub twap_control_id: String,
pub signed_transaction_base64: String,
pub idempotency_key: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformTwapSubmitResponse {
pub schema_version: u16,
pub contract_version: String,
pub twap_control_id: String,
pub market_id: String,
pub action: PlatformTwapControlAction,
pub twap_id: String,
pub signature: String,
pub status: PlatformOrderSubmissionStatus,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
#[allow(clippy::large_enum_variant)]
pub enum PlatformTwapEvent {
TwapsSnapshot {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
stream_id: String,
sequence: String,
server_time_ms: u64,
twaps: Vec<PlatformTwap>,
},
TwapUpdate {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
twap: PlatformTwap,
},
Heartbeat {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
},
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum PlatformPortfolioHistoryRange {
#[serde(rename = "24h")]
Day,
#[serde(rename = "7d")]
Week,
#[serde(rename = "30d")]
Month,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformPortfolioHistoryPoint {
pub recorded_at_ms: u64,
pub equity_usd_micros: String,
pub available_usd_micros: String,
pub locked_usd_micros: String,
pub market_count: u32,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformPortfolioHistoryResponse {
pub schema_version: u16,
pub contract_version: String,
pub wallet_address: String,
pub server_time_ms: u64,
pub range: PlatformPortfolioHistoryRange,
pub points: Vec<PlatformPortfolioHistoryPoint>,
pub collecting: bool,
pub first_sample_ms: Option<u64>,
pub last_sample_ms: Option<u64>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformPortfolioBalance {
pub asset_id: String,
pub available_atoms: String,
pub locked_atoms: String,
pub total_atoms: String,
pub value_usd_micros: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformPortfolioPosition {
pub market_id: String,
pub base_asset_id: String,
pub quote_asset_id: String,
pub base_available_atoms: String,
pub base_locked_atoms: String,
pub quote_available_atoms: String,
pub quote_locked_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformPortfolioOrder {
pub market_id: String,
pub order_id: String,
pub side: PlatformTradeSide,
pub order_type: PlatformOrderType,
pub state: PlatformOrderState,
pub limit_price_atoms: String,
pub original_size_atoms: String,
pub remaining_size_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformPortfolioFill {
pub market_id: String,
pub fill_id: String,
pub side: PlatformTradeSide,
pub price_atoms: String,
pub size_atoms: String,
pub fee_quote_atoms: String,
pub fee_is_final: bool,
pub settlement: PlatformSettlementState,
pub executed_at_ms: u64,
pub confirmed_at_ms: Option<u64>,
pub transaction_id: Option<String>,
pub realized_pnl_quote_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformPortfolioResponse {
pub schema_version: u16,
pub contract_version: String,
pub wallet_address: String,
pub server_time_ms: u64,
pub observed_at_ms: u64,
pub observed_slot: String,
pub market_count: u32,
pub balances: Vec<PlatformPortfolioBalance>,
pub positions: Vec<PlatformPortfolioPosition>,
pub open_orders: Vec<PlatformPortfolioOrder>,
pub recent_fills: Vec<PlatformPortfolioFill>,
pub unavailable_market_ids: Vec<String>,
pub equity_usd_micros: Option<String>,
pub available_usd_micros: Option<String>,
pub locked_usd_micros: Option<String>,
pub valuation_complete: bool,
pub unpriced_asset_ids: Vec<String>,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformVaultState {
Absent,
Active,
Paused,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformVaultSessionState {
Absent,
Active,
Expired,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformVaultWithdrawalMode {
Unrestricted,
Blocked,
Restricted,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultSpendingLimit {
pub asset_id: String,
pub maximum_per_execution_atoms: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultSessionStatus {
pub session_public_key: String,
pub state: PlatformVaultSessionState,
pub expires_at_ms: Option<u64>,
pub permanent: bool,
pub minimum_interval_seconds: u32,
pub maximum_tolerance_bps: u16,
pub last_execution_at_ms: Option<u64>,
pub market_execution_ready: bool,
pub price_protection_active: bool,
pub spending_limits: Vec<PlatformVaultSpendingLimit>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultWithdrawalAccess {
pub mode: PlatformVaultWithdrawalMode,
pub allowed_wallet_addresses: Vec<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultStatusResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub wallet_address: String,
pub state: PlatformVaultState,
pub session: Option<PlatformVaultSessionStatus>,
pub withdrawal_access: PlatformVaultWithdrawalAccess,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultPausePrepareRequest {
pub wallet_address: String,
pub paused: bool,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultPausePrepareResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub wallet_address: String,
pub paused: bool,
pub transaction_base64: String,
pub recent_blockhash: String,
pub owner_signature_required: bool,
pub preparation_id: String,
pub sponsored: bool,
pub submit_by_ms: u64,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformVaultSetupMode {
Create,
ReplaceSession,
}
pub const PLATFORM_SESSION_DEFAULT_MINIMUM_INTERVAL_SECONDS: u32 = 1;
pub const PLATFORM_SESSION_DEFAULT_MAXIMUM_TOLERANCE_BPS: u16 = 100;
pub const PLATFORM_SESSION_MAX_SPENDING_LIMITS: usize = 4;
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultSetupPrepareRequest {
pub wallet_address: String,
pub session_public_key: String,
#[serde(default)]
pub market_id: Option<String>,
#[serde(default)]
pub expires_at_ms: Option<u64>,
#[serde(default)]
pub minimum_interval_seconds: Option<u32>,
#[serde(default)]
pub maximum_tolerance_bps: Option<u16>,
#[serde(default)]
pub spending_limits: Vec<PlatformVaultSpendingLimit>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultSetupPrepareResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub wallet_address: String,
pub session_public_key: String,
pub market_id: Option<String>,
pub mode: PlatformVaultSetupMode,
pub expires_at_ms: Option<u64>,
pub permanent: bool,
pub minimum_interval_seconds: u32,
pub maximum_tolerance_bps: u16,
pub spending_limits: Vec<PlatformVaultSpendingLimit>,
pub transaction_base64: String,
pub recent_blockhash: String,
pub owner_signature_required: bool,
pub preparation_id: String,
pub sponsored: bool,
pub submit_by_ms: u64,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformVaultDelegateAction {
Revoke,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultDelegatePrepareRequest {
pub wallet_address: String,
pub session_public_key: String,
pub action: PlatformVaultDelegateAction,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultDelegatePrepareResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub wallet_address: String,
pub session_public_key: String,
pub action: PlatformVaultDelegateAction,
pub transaction_base64: String,
pub recent_blockhash: String,
pub owner_signature_required: bool,
pub preparation_id: String,
pub sponsored: bool,
pub submit_by_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultPolicyPrepareRequest {
pub wallet_address: String,
pub withdrawal_access: PlatformVaultWithdrawalAccess,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultPolicyPrepareResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub wallet_address: String,
pub withdrawal_access: PlatformVaultWithdrawalAccess,
pub transaction_base64: String,
pub recent_blockhash: String,
pub owner_signature_required: bool,
pub preparation_id: String,
pub sponsored: bool,
pub submit_by_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultDepositPrepareRequest {
pub wallet_address: String,
pub market_id: String,
pub asset_id: String,
pub amount_atoms: String,
#[serde(default)]
pub session_public_key: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultDepositPrepareResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub wallet_address: String,
pub market_id: String,
pub asset_id: String,
pub amount_atoms: String,
pub network_cost_atoms: String,
pub session_public_key: Option<String>,
pub registers_session: bool,
pub transaction_base64: String,
pub recent_blockhash: String,
pub owner_signature_required: bool,
pub preparation_id: String,
pub sponsored: bool,
pub submit_by_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultWithdrawPrepareRequest {
pub wallet_address: String,
pub market_id: String,
pub asset_id: String,
pub destination_wallet_address: String,
pub amount_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultWithdrawPrepareResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub wallet_address: String,
pub market_id: String,
pub asset_id: String,
pub destination_wallet_address: String,
pub amount_atoms: String,
pub transaction_base64: String,
pub recent_blockhash: String,
pub owner_signature_required: bool,
pub preparation_id: String,
pub sponsored: bool,
pub submit_by_ms: u64,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformVaultAction {
Setup,
Deposit,
Withdraw,
Delegate,
Policy,
Pause,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformVaultSubmissionStatus {
Submitted,
Confirmed,
Failed,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultSubmitRequest {
pub preparation_id: String,
pub signed_transaction_base64: String,
pub idempotency_key: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformVaultSubmitResponse {
pub schema_version: u16,
pub contract_version: String,
pub preparation_id: String,
pub action: PlatformVaultAction,
pub wallet_address: String,
pub sponsored: bool,
pub signature: String,
pub status: PlatformVaultSubmissionStatus,
pub failure_code: Option<String>,
pub updated_at_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformRewardStanding {
pub rank: u32,
pub wallet_address: String,
pub points: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformOwnerRewards {
pub wallet_address: String,
pub rank: Option<u32>,
pub points: String,
pub trading_points: String,
pub making_points: String,
pub bug_points: String,
pub referral_points: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformRewardsResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub season: String,
pub total_wallets: u32,
pub owner: Option<PlatformOwnerRewards>,
pub standings: Vec<PlatformRewardStanding>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformReferralsResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub wallet_address: String,
pub enabled: bool,
pub cash_rewards_enabled: bool,
pub referral_code: Option<String>,
pub referred_wallets: u32,
pub referral_points: String,
pub referred_by: Option<String>,
pub referral_locked: bool,
pub cash_accrued_atoms: String,
pub cash_paid_atoms: String,
pub cash_claimable_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformReferralLinkRequest {
pub wallet_address: String,
pub referral_code: String,
pub authorization_signature: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformReferralLinkResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub wallet_address: String,
pub referral_code: String,
pub status: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformReferralClaimRequest {
pub wallet_address: String,
pub payout_wallet_address: Option<String>,
pub authorization_signature: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformReferralClaimResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub wallet_address: String,
pub payout_wallet_address: String,
pub claimable_atoms: String,
pub status: String,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformBugStatus {
Pending,
Confirmed,
Rejected,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformBugReport {
pub bug_id: String,
pub status: PlatformBugStatus,
pub severity: u8,
pub points: String,
pub created_at_ms: u64,
pub triaged_at_ms: Option<u64>,
pub completed_at_ms: Option<u64>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformBugsResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub wallet_address: String,
pub points: String,
pub confirmed_reports: u32,
pub reports: Vec<PlatformBugReport>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformBugSubmitRequest {
pub owner_wallet: String,
pub message: String,
pub authorization_signature: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformBugSubmitResponse {
pub schema_version: u16,
pub contract_version: String,
pub server_time_ms: u64,
pub bug_id: String,
pub status: PlatformBugStatus,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformTradeSide {
Buy,
Sell,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformTrade {
pub trade_id: String,
pub side: PlatformTradeSide,
pub price_atoms: String,
pub size_atoms: String,
pub executed_at_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformTradesResponse {
pub schema_version: u16,
pub contract_version: String,
pub market_id: String,
pub server_time_ms: u64,
pub trades: Vec<PlatformTrade>,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformOrderType {
GoodUntilCancelled,
ImmediateOrCancel,
FillOrKill,
PostOnly,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformOrderAction {
Place,
Cancel,
CancelAll,
Replace,
Batch,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformOrderBatchOperation {
Place {
#[serde(default, skip_serializing_if = "Option::is_none")]
account_sequence: Option<String>,
client_order_id: String,
side: PlatformTradeSide,
order_type: PlatformOrderType,
limit_price_atoms: String,
size_atoms: String,
},
Cancel {
order_id: String,
},
Replace {
order_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
account_sequence: Option<String>,
client_order_id: String,
side: PlatformTradeSide,
order_type: PlatformOrderType,
limit_price_atoms: String,
size_atoms: String,
},
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformOrderChallengeRequest {
Place {
owner_wallet: String,
session_public_key: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
account_sequence: Option<String>,
client_order_id: String,
side: PlatformTradeSide,
order_type: PlatformOrderType,
limit_price_atoms: String,
size_atoms: String,
},
Cancel {
owner_wallet: String,
session_public_key: String,
order_id: String,
},
CancelAll {
owner_wallet: String,
session_public_key: String,
},
Replace {
owner_wallet: String,
session_public_key: String,
order_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
account_sequence: Option<String>,
client_order_id: String,
side: PlatformTradeSide,
order_type: PlatformOrderType,
limit_price_atoms: String,
size_atoms: String,
},
Batch {
owner_wallet: String,
session_public_key: String,
operations: Vec<PlatformOrderBatchOperation>,
},
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformOrderChallengeResponse {
pub schema_version: u16,
pub contract_version: String,
pub challenge_id: String,
pub market_id: String,
pub action: PlatformOrderAction,
pub order_ids: Vec<String>,
pub authorization_payload_base64: String,
pub server_time_ms: u64,
pub expires_at_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformOrderPrepareAuthorization {
pub challenge_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub authorization_signature: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(untagged)]
pub enum PlatformOrderPrepareRequest {
Authorized(PlatformOrderPrepareAuthorization),
Direct(PlatformOrderChallengeRequest),
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformOrderPrepareResponse {
pub schema_version: u16,
pub contract_version: String,
pub order_control_id: String,
pub market_id: String,
pub action: PlatformOrderAction,
pub order_ids: Vec<String>,
pub transaction_base64: String,
pub recent_blockhash: String,
pub last_valid_block_height: u64,
pub expires_at_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformOrderSubmitRequest {
pub order_control_id: String,
pub signed_transaction_base64: String,
pub idempotency_key: String,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformOrderSubmissionStatus {
Submitted,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformOrderSubmitResponse {
pub schema_version: u16,
pub contract_version: String,
pub order_control_id: String,
pub market_id: String,
pub action: PlatformOrderAction,
pub order_ids: Vec<String>,
pub signature: String,
pub status: PlatformOrderSubmissionStatus,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformOrderStatusRequest {
pub order_control_id: String,
pub idempotency_key: String,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformOrderControlStatus {
Submitting,
Submitted,
Failed,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformOrderStatusResponse {
pub schema_version: u16,
pub contract_version: String,
pub order_control_id: String,
pub market_id: String,
pub action: PlatformOrderAction,
pub order_ids: Vec<String>,
pub signature: String,
pub status: PlatformOrderControlStatus,
pub failure_code: Option<String>,
pub updated_at_ms: u64,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformSelfTradePrevention {
CancelTaker,
CancelMaker,
CancelBoth,
SkipOwnLiquidity,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformOrderCommand {
Probe {
nonce: String,
},
Challenge {
request: PlatformOrderChallengeRequest,
self_trade_prevention: PlatformSelfTradePrevention,
},
Prepare {
request: PlatformOrderPrepareRequest,
},
Submit {
request: PlatformOrderSubmitRequest,
},
Status {
request: PlatformOrderStatusRequest,
},
DeadManArm {
timeout_ms: u64,
request: PlatformOrderSubmitRequest,
},
DeadManStatus,
DeadManHeartbeat,
DeadManDisarm,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformOrderCommandClientFrame {
Authenticate {
owner_wallet: String,
session_public_key: String,
signature: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
batch_format: Option<PlatformOrderCommandBatchFormat>,
},
Command {
request_id: String,
sequence: String,
command: PlatformOrderCommand,
},
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformOrderCommandBatchFormat {
CompactV1,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformOrderCommandBatchEvent {
ProbeResult {
request_id: String,
nonce: String,
},
ChallengeResult {
request_id: String,
self_trade_prevention: PlatformSelfTradePrevention,
prevented_order_ids: Vec<String>,
effective_request: PlatformOrderChallengeRequest,
response: PlatformOrderChallengeResponse,
},
PrepareResult {
request_id: String,
response: PlatformOrderPrepareResponse,
},
SubmitResult {
request_id: String,
response: PlatformOrderSubmitResponse,
},
StatusResult {
request_id: String,
response: PlatformOrderStatusResponse,
},
DeadManResult {
request_id: String,
state: PlatformDeadManState,
},
CommandError {
request_id: String,
error: PublicOperationError,
},
Heartbeat,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformOrderCommandServerFrame {
EventBatch {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
first_sequence: String,
previous_sequence: String,
server_time_ms: u64,
events: Vec<PlatformOrderCommandBatchEvent>,
},
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformDeadManStatus {
Armed,
Triggering,
Triggered,
Disarmed,
Expired,
Failed,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformDeadManState {
pub status: PlatformDeadManStatus,
pub timeout_ms: u64,
pub heartbeat_deadline_ms: u64,
pub order_control_id: Option<String>,
pub signature: Option<String>,
pub failure_code: Option<String>,
pub updated_at_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformOrderCommandEvent {
AuthChallenge {
schema_version: u16,
contract_version: String,
market_id: String,
challenge: String,
server_time_ms: u64,
expires_at_ms: u64,
},
Ready {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
server_time_ms: u64,
},
ProbeResult {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
request_id: String,
nonce: String,
server_time_ms: u64,
},
ChallengeResult {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
request_id: String,
self_trade_prevention: PlatformSelfTradePrevention,
prevented_order_ids: Vec<String>,
effective_request: PlatformOrderChallengeRequest,
response: PlatformOrderChallengeResponse,
server_time_ms: u64,
},
PrepareResult {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
request_id: String,
response: PlatformOrderPrepareResponse,
server_time_ms: u64,
},
SubmitResult {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
request_id: String,
response: PlatformOrderSubmitResponse,
server_time_ms: u64,
},
StatusResult {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
request_id: String,
response: PlatformOrderStatusResponse,
server_time_ms: u64,
},
DeadManResult {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
request_id: String,
state: PlatformDeadManState,
server_time_ms: u64,
},
CommandError {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
request_id: String,
error: PublicOperationError,
server_time_ms: u64,
},
Heartbeat {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
},
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformAccountOrder {
pub order_id: String,
pub side: PlatformTradeSide,
pub order_type: PlatformOrderType,
pub state: PlatformOrderState,
pub limit_price_atoms: String,
pub original_size_atoms: String,
pub remaining_size_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformAccountFill {
pub fill_id: String,
pub side: PlatformTradeSide,
pub price_atoms: String,
pub size_atoms: String,
pub fee_quote_atoms: String,
pub fee_is_final: bool,
pub settlement: PlatformSettlementState,
pub executed_at_ms: u64,
pub confirmed_at_ms: Option<u64>,
pub transaction_id: Option<String>,
pub realized_pnl_quote_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformAccountSnapshotResponse {
pub schema_version: u16,
pub contract_version: String,
pub market_id: String,
pub wallet_address: String,
pub server_time_ms: u64,
pub orders: Vec<PlatformAccountOrder>,
pub fills: Vec<PlatformAccountFill>,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformMakerReputationTier {
Probation,
Bronze,
Silver,
Gold,
Platinum,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMakerTierProgress {
pub next_tier: Option<PlatformMakerReputationTier>,
pub reputation_score_required: Option<u16>,
pub reputation_score_remaining: u16,
pub quote_requests_required: Option<String>,
pub quote_requests_remaining: String,
pub stake_atoms_required: Option<String>,
pub stake_atoms_remaining: String,
pub tenure_slots_required: Option<String>,
pub tenure_slots_remaining: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMakerReputationResponse {
pub schema_version: u16,
pub contract_version: String,
pub market_id: String,
pub maker_id: String,
pub wallet_address: String,
pub active: bool,
pub tier: PlatformMakerReputationTier,
pub reputation_score: u16,
pub total_quote_requests: String,
pub successful_fills: String,
pub missed_quote_requests: String,
pub fill_rate_bps: u16,
pub consecutive_misses: u16,
pub lifetime_filled_quote_atoms: String,
pub distinct_counterparties: u16,
pub recent_average_latency_ms: u16,
pub configured_minimum_spread_bps: u16,
pub weighted_average_spread_bps: u16,
pub stake_atoms: String,
pub epoch_start_stake_atoms: String,
pub epoch_slashed_atoms: String,
pub epoch_slashed_bps: u16,
pub lifetime_auto_slashed_atoms: String,
pub registered_slot: String,
pub last_active_slot: String,
pub last_settled_slot: String,
pub revoked_at_slot: Option<String>,
pub tenure_slots: String,
pub signed_quote_stream_eligible: bool,
pub minimum_quote_interval_ms: Option<u16>,
pub tier_progress: PlatformMakerTierProgress,
pub server_time_ms: u64,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformMakerSide {
Buy,
Sell,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformOracleHealth {
Fresh,
Stale,
Unknown,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMakerFirmOrderSummary {
pub resting_orders: u32,
pub bid_orders: u32,
pub ask_orders: u32,
pub bid_size_atoms: String,
pub ask_size_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMakerSignedQuote {
pub side: PlatformMakerSide,
pub price_atoms: String,
pub size_atoms: String,
pub nonce: String,
pub issued_at_ms: u64,
pub expires_at_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMakerIntentStatus {
pub active: bool,
pub side: PlatformMakerSide,
pub minimum_price_atoms: String,
pub maximum_price_atoms: String,
pub maximum_fill_size_atoms: String,
pub remaining_fill_size_atoms: String,
pub minimum_spread_bps: u16,
pub stake_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMakerSignedQuoteLane {
pub eligible: bool,
pub live_quotes: Vec<PlatformMakerSignedQuote>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMakerStrandLevel {
pub price_atoms: Option<String>,
pub size_atoms: String,
pub remaining_size_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMakerStrandStatus {
pub enabled: bool,
pub async_only: bool,
pub expired: bool,
pub mid_price_atoms: String,
pub tick_size_atoms: String,
pub valid_until_slot: Option<String>,
pub bids: Vec<PlatformMakerStrandLevel>,
pub asks: Vec<PlatformMakerStrandLevel>,
pub maximum_exposure_atoms: String,
pub remaining_exposure_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMakerCurrentStatus {
pub enabled: bool,
pub async_only: bool,
pub expired: bool,
pub half_spread_bps: u16,
pub band_step_bps: u16,
pub maximum_confidence_bps: u16,
pub maximum_oracle_age_seconds: u32,
pub sync_spread_bps: u16,
pub valid_until_slot: Option<String>,
pub bid_depth_atoms: Vec<String>,
pub ask_depth_atoms: Vec<String>,
pub maximum_exposure_atoms: String,
pub remaining_exposure_atoms: String,
pub oracle_health: PlatformOracleHealth,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMakerDeadManGuard {
pub session_public_key: String,
pub status: PlatformDeadManStatus,
pub timeout_ms: u64,
pub heartbeat_deadline_ms: u64,
pub updated_at_ms: u64,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMakerStatusResponse {
pub schema_version: u16,
pub contract_version: String,
pub market_id: String,
pub maker_id: String,
pub wallet_address: String,
pub server_time_ms: u64,
pub current_slot: String,
pub firm_orders: PlatformMakerFirmOrderSummary,
pub intent: Option<PlatformMakerIntentStatus>,
pub signed_quotes: PlatformMakerSignedQuoteLane,
pub strands: Vec<PlatformMakerStrandStatus>,
pub currents: Vec<PlatformMakerCurrentStatus>,
pub dead_man_guards: Vec<PlatformMakerDeadManGuard>,
pub active_products: u16,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformMakerProduct {
FirmOrder,
Intent,
Strand,
Current,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct PlatformMakerFill {
pub fill_id: String,
pub product: PlatformMakerProduct,
pub side: PlatformTradeSide,
pub price_atoms: String,
pub size_atoms: String,
pub fee_quote_atoms: String,
pub fee_is_final: bool,
pub settlement: PlatformSettlementState,
pub executed_at_ms: u64,
pub confirmed_at_ms: Option<u64>,
pub transaction_id: Option<String>,
pub realized_pnl_quote_atoms: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformMakerEvent {
AuthChallenge {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
challenge: String,
server_time_ms: u64,
expires_at_ms: u64,
},
MakerSnapshot {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
stream_id: String,
sequence: String,
server_time_ms: u64,
status: PlatformMakerStatusResponse,
fills: Vec<PlatformMakerFill>,
},
MakerFill {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
fill: PlatformMakerFill,
},
MakerStatus {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
status: PlatformMakerStatusResponse,
},
Heartbeat {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
},
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformAccountEvent {
AuthChallenge {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
challenge: String,
server_time_ms: u64,
expires_at_ms: u64,
},
AccountSnapshot {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
stream_id: String,
sequence: String,
server_time_ms: u64,
orders: Vec<PlatformAccountOrder>,
fills: Vec<PlatformAccountFill>,
},
OrdersSnapshot {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
orders: Vec<PlatformAccountOrder>,
},
Fill {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
fill: PlatformAccountFill,
},
Heartbeat {
schema_version: u16,
contract_version: String,
market_id: String,
wallet_address: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
},
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
pub enum PlatformMarketDataEvent {
BookSnapshot {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
server_time_ms: u64,
snapshot_id: String,
bids: Vec<PlatformBookLevel>,
asks: Vec<PlatformBookLevel>,
},
BookDelta {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
previous_sequence: String,
server_time_ms: u64,
changes: Vec<PlatformBookChange>,
},
BestBidAsk {
schema_version: u16,
contract_version: String,
market_id: String,
stream_id: String,
sequence: String,
server_time_ms: u64,
best_bid: Option<PlatformBookLevel>,
best_ask: Option<PlatformBookLevel>,
},
Trade {
schema_version: u16,
contract_version: String,
market_id: String,
server_time_ms: u64,
trade: PlatformTrade,
},
MarketStatus {
schema_version: u16,
contract_version: String,
market_id: String,
server_time_ms: u64,
status: PlatformMarketState,
},
Heartbeat {
schema_version: u16,
contract_version: String,
market_id: String,
server_time_ms: u64,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn public_platform_fixtures_decode_strictly() {
let discovery: PlatformDiscoveryResponse =
serde_json::from_str(PLATFORM_CAPABILITIES_FIXTURE).unwrap();
let service_status: PlatformServiceStatusResponse =
serde_json::from_str(PLATFORM_SERVICE_STATUS_FIXTURE).unwrap();
let graph = PlatformActionGraphResponse::foundation();
let assets: PlatformAssetsResponse = serde_json::from_str(PLATFORM_ASSETS_FIXTURE).unwrap();
let swap_quote: PlatformSwapQuoteResponse =
serde_json::from_str(PLATFORM_SWAP_QUOTE_FIXTURE).unwrap();
let markets: PlatformMarketsResponse =
serde_json::from_str(PLATFORM_MARKETS_FIXTURE).unwrap();
let book: PlatformBookSnapshotResponse =
serde_json::from_str(PLATFORM_BOOK_FIXTURE).unwrap();
let bbo: PlatformBestBidAskResponse = serde_json::from_str(PLATFORM_BBO_FIXTURE).unwrap();
let fees: PlatformFeeScheduleResponse =
serde_json::from_str(PLATFORM_FEES_FIXTURE).unwrap();
let status: PlatformMarketStatusResponse =
serde_json::from_str(PLATFORM_STATUS_FIXTURE).unwrap();
let candles: PlatformCandlesResponse =
serde_json::from_str(PLATFORM_CANDLES_FIXTURE).unwrap();
let mark: PlatformMarkResponse = serde_json::from_str(PLATFORM_MARK_FIXTURE).unwrap();
let execution_status: PlatformExecutionStatusResponse =
serde_json::from_str(PLATFORM_EXECUTION_STATUS_FIXTURE).unwrap();
let twaps: PlatformTwapsResponse = serde_json::from_str(PLATFORM_TWAPS_FIXTURE).unwrap();
let twap_challenge: PlatformTwapChallengeResponse =
serde_json::from_str(PLATFORM_TWAP_CHALLENGE_FIXTURE).unwrap();
let twap_prepare: PlatformTwapPrepareResponse =
serde_json::from_str(PLATFORM_TWAP_PREPARE_FIXTURE).unwrap();
let twap_submit: PlatformTwapSubmitResponse =
serde_json::from_str(PLATFORM_TWAP_SUBMIT_FIXTURE).unwrap();
let portfolio_history: PlatformPortfolioHistoryResponse =
serde_json::from_str(PLATFORM_PORTFOLIO_HISTORY_FIXTURE).unwrap();
let portfolio: PlatformPortfolioResponse =
serde_json::from_str(PLATFORM_PORTFOLIO_FIXTURE).unwrap();
let rewards: PlatformRewardsResponse =
serde_json::from_str(PLATFORM_REWARDS_FIXTURE).unwrap();
let referrals: PlatformReferralsResponse =
serde_json::from_str(PLATFORM_REFERRALS_FIXTURE).unwrap();
let referral_link: PlatformReferralLinkResponse =
serde_json::from_str(PLATFORM_REFERRAL_LINK_FIXTURE).unwrap();
let referral_claim: PlatformReferralClaimResponse =
serde_json::from_str(PLATFORM_REFERRAL_CLAIM_FIXTURE).unwrap();
let vault_status: PlatformVaultStatusResponse =
serde_json::from_str(PLATFORM_VAULT_STATUS_FIXTURE).unwrap();
let vault_pause: PlatformVaultPausePrepareResponse =
serde_json::from_str(PLATFORM_VAULT_PAUSE_PREPARE_FIXTURE).unwrap();
let vault_setup: PlatformVaultSetupPrepareResponse =
serde_json::from_str(PLATFORM_VAULT_SETUP_PREPARE_FIXTURE).unwrap();
let vault_delegate: PlatformVaultDelegatePrepareResponse =
serde_json::from_str(PLATFORM_VAULT_DELEGATE_PREPARE_FIXTURE).unwrap();
let vault_policy: PlatformVaultPolicyPrepareResponse =
serde_json::from_str(PLATFORM_VAULT_POLICY_PREPARE_FIXTURE).unwrap();
let vault_deposit: PlatformVaultDepositPrepareResponse =
serde_json::from_str(PLATFORM_VAULT_DEPOSIT_PREPARE_FIXTURE).unwrap();
let vault_withdraw: PlatformVaultWithdrawPrepareResponse =
serde_json::from_str(PLATFORM_VAULT_WITHDRAW_PREPARE_FIXTURE).unwrap();
let vault_submit: PlatformVaultSubmitResponse =
serde_json::from_str(PLATFORM_VAULT_SUBMIT_FIXTURE).unwrap();
let bugs: PlatformBugsResponse = serde_json::from_str(PLATFORM_BUGS_FIXTURE).unwrap();
let bug_submit: PlatformBugSubmitResponse =
serde_json::from_str(PLATFORM_BUG_SUBMIT_FIXTURE).unwrap();
let trades: PlatformTradesResponse = serde_json::from_str(PLATFORM_TRADES_FIXTURE).unwrap();
let account: PlatformAccountSnapshotResponse =
serde_json::from_str(PLATFORM_ACCOUNT_FIXTURE).unwrap();
let maker_reputation: PlatformMakerReputationResponse =
serde_json::from_str(PLATFORM_MAKER_REPUTATION_FIXTURE).unwrap();
let maker_status: PlatformMakerStatusResponse =
serde_json::from_str(PLATFORM_MAKER_STATUS_FIXTURE).unwrap();
let maker_stream: PlatformMakerEvent =
serde_json::from_str(PLATFORM_MAKER_STREAM_FIXTURE).unwrap();
let twap_stream: PlatformTwapEvent =
serde_json::from_str(PLATFORM_TWAP_STREAM_FIXTURE).unwrap();
let execution_stream: PlatformExecutionEvent =
serde_json::from_str(PLATFORM_EXECUTION_STREAM_FIXTURE).unwrap();
let order_challenge: PlatformOrderChallengeResponse =
serde_json::from_str(PLATFORM_ORDER_CHALLENGE_FIXTURE).unwrap();
let order_prepare: PlatformOrderPrepareResponse =
serde_json::from_str(PLATFORM_ORDER_PREPARE_FIXTURE).unwrap();
let order_submit: PlatformOrderSubmitResponse =
serde_json::from_str(PLATFORM_ORDER_SUBMIT_FIXTURE).unwrap();
let order_status: PlatformOrderStatusResponse =
serde_json::from_str(PLATFORM_ORDER_STATUS_FIXTURE).unwrap();
assert_eq!(discovery.schema_version, PLATFORM_SCHEMA_VERSION);
assert_eq!(service_status.status, PlatformServiceState::Operational);
assert_eq!(service_status.available_operations, 59);
assert_eq!(graph.entry_operation_id, "platform.capabilities.read");
assert_eq!(graph.operations.len(), 67);
assert_eq!(maker_reputation.tier, PlatformMakerReputationTier::Gold);
assert_eq!(maker_status.active_products, 3);
match &maker_stream {
PlatformMakerEvent::MakerSnapshot { status, fills, .. } => {
assert_eq!(status.active_products, maker_status.active_products);
assert_eq!(fills.len(), 1);
assert_eq!(fills[0].product, PlatformMakerProduct::Strand);
}
other => panic!("maker stream fixture must be a snapshot, got {other:?}"),
}
match &twap_stream {
PlatformTwapEvent::TwapsSnapshot {
twaps: streamed, ..
} => {
assert_eq!(streamed, &twaps.twaps);
}
other => panic!("twap stream fixture must be a snapshot, got {other:?}"),
}
match &execution_stream {
PlatformExecutionEvent::ExecutionsSnapshot {
executions,
unknown_execution_ids,
..
} => {
assert_eq!(executions.len(), 2);
assert_eq!(executions[0].execution_id, execution_status.execution_id);
assert_eq!(unknown_execution_ids.len(), 1);
}
other => panic!("execution stream fixture must be a snapshot, got {other:?}"),
}
assert_eq!(maker_status.strands.len(), 1);
assert_eq!(maker_status.currents.len(), 1);
assert!(maker_status
.intent
.as_ref()
.is_some_and(|intent| intent.active));
assert_eq!(portfolio.balances.len(), 2);
assert_eq!(portfolio.positions.len(), 1);
assert!(portfolio.valuation_complete);
assert_eq!(portfolio.equity_usd_micros.as_deref(), Some("439989500"));
assert!(graph
.operations
.iter()
.any(|operation| operation.id == "twap.place.submit"));
assert!(graph
.operations
.iter()
.any(|operation| operation.id == "twap.cancel.submit"));
assert_eq!(discovery.capabilities.len(), 5);
assert!(!discovery.authority.accepts_private_keys);
assert_eq!(assets.assets.len(), 2);
assert_eq!(swap_quote.input_asset_id, assets.assets[0].asset_id);
assert_eq!(swap_quote.output_asset_id, assets.assets[1].asset_id);
assert_eq!(markets.markets.len(), 1);
assert_eq!(markets.markets[0].base_asset_id, assets.assets[0].asset_id);
assert_eq!(markets.markets[0].quote_asset_id, assets.assets[1].asset_id);
assert_eq!(book.sequence, "42");
assert_eq!(bbo.best_bid.unwrap().price_atoms, "149990000");
assert_eq!(fees.maximum_immediate_execution_fee_bps, 10);
assert_eq!(status.status, PlatformMarketState::Active);
assert_eq!(candles.candles.len(), 2);
assert_eq!(mark.price_atoms_per_base_unit.as_deref(), Some("149995000"));
assert_eq!(execution_status.status, PlatformExecutionState::Confirmed);
assert_eq!(
execution_status.settlement,
PlatformSettlementState::Confirmed
);
assert_eq!(twaps.twaps[0].fills.len(), 1);
assert_eq!(twaps.twaps[0].slices_executed, 2);
assert_eq!(twap_challenge.action, PlatformTwapControlAction::Place);
assert_eq!(twap_prepare.twap_id, twap_challenge.twap_id);
assert_eq!(twap_submit.twap_control_id, twap_prepare.twap_control_id);
assert_eq!(portfolio_history.points.len(), 2);
assert_eq!(rewards.standings.len(), 2);
assert!(referrals.enabled);
assert_eq!(referral_link.status, "pending_first_fill");
assert_eq!(referral_claim.status, "requested");
assert_eq!(vault_status.state, PlatformVaultState::Active);
assert_eq!(
vault_status.session.as_ref().unwrap().state,
PlatformVaultSessionState::Active
);
assert!(vault_pause.paused);
assert!(vault_pause.owner_signature_required);
assert_eq!(vault_setup.mode, PlatformVaultSetupMode::Create);
assert!(vault_setup.permanent);
assert_eq!(vault_delegate.action, PlatformVaultDelegateAction::Revoke);
assert!(vault_delegate.owner_signature_required);
assert_eq!(
vault_policy.withdrawal_access.mode,
PlatformVaultWithdrawalMode::Restricted
);
assert!(vault_policy.owner_signature_required);
assert_eq!(vault_deposit.amount_atoms, "10000000");
assert!(vault_deposit.owner_signature_required);
assert_eq!(vault_withdraw.amount_atoms, "5000000");
assert!(vault_withdraw.owner_signature_required);
assert!(vault_withdraw.sponsored);
assert!(vault_withdraw.preparation_id.starts_with("vp_"));
assert_eq!(vault_submit.action, PlatformVaultAction::Deposit);
assert_eq!(
vault_submit.status,
PlatformVaultSubmissionStatus::Submitted
);
assert!(vault_submit.sponsored);
assert_eq!(vault_submit.failure_code, None);
assert_eq!(bugs.reports[0].status, PlatformBugStatus::Confirmed);
assert_eq!(bug_submit.status, PlatformBugStatus::Pending);
assert_eq!(trades.trades.len(), 1);
assert_eq!(account.orders.len(), 1);
assert_eq!(account.fills.len(), 1);
assert_eq!(order_challenge.action, PlatformOrderAction::Place);
assert_eq!(order_prepare.order_ids, order_challenge.order_ids);
assert_eq!(order_submit.order_ids, order_challenge.order_ids);
assert_eq!(order_status.order_control_id, order_submit.order_control_id);
assert_eq!(order_status.status, PlatformOrderControlStatus::Submitting);
}
#[test]
fn public_platform_response_rejects_unreviewed_fields() {
let mut value: serde_json::Value =
serde_json::from_str(PLATFORM_CAPABILITIES_FIXTURE).unwrap();
value
.as_object_mut()
.unwrap()
.insert("unexpected_field".to_owned(), serde_json::Value::Bool(true));
assert!(serde_json::from_value::<PlatformDiscoveryResponse>(value).is_err());
let mut account_event: serde_json::Value =
serde_json::from_str(PLATFORM_ACCOUNT_FIXTURE).unwrap();
let event = account_event.as_object_mut().unwrap();
event.insert("type".to_owned(), serde_json::json!("account_snapshot"));
event.insert(
"stream_id".to_owned(),
serde_json::json!("account_stream_66666666666666666666666666666666"),
);
event.insert("sequence".to_owned(), serde_json::json!("1"));
event.insert("unexpected_field".to_owned(), serde_json::json!(true));
assert!(serde_json::from_value::<PlatformAccountEvent>(account_event).is_err());
}
#[test]
fn platform_graph_availability_is_projected_from_live_capabilities() {
let mut graph = PlatformActionGraphResponse::foundation();
let live = std::collections::BTreeSet::from([
"platform.discover".to_owned(),
"graphs.read".to_owned(),
"orders.replace".to_owned(),
]);
graph.project_availability(&live);
for operation in &graph.operations {
assert_eq!(
operation.available,
live.contains(&operation.capability_id),
"operation {} did not follow capability {}",
operation.id,
operation.capability_id,
);
}
assert!(graph
.workflows
.iter()
.flat_map(|workflow| &workflow.nodes)
.filter(|node| node.kind != PlatformActionKind::ExternalSignature)
.all(|node| {
node.available
== node
.capability_id
.as_ref()
.is_some_and(|capability_id| live.contains(capability_id))
}));
assert!(graph
.workflows
.iter()
.flat_map(|workflow| &workflow.nodes)
.filter(|node| node.kind == PlatformActionKind::ExternalSignature)
.all(|node| node.available));
}
#[test]
fn atomic_order_batch_request_is_strict_and_typed() {
let request: PlatformOrderChallengeRequest = serde_json::from_value(serde_json::json!({
"action": "batch",
"owner_wallet": "11111111111111111111111111111111",
"session_public_key": "22222222222222222222222222222222",
"operations": [
{
"action": "cancel",
"order_id": "order_11111111111111111111111111111111"
},
{
"action": "replace",
"order_id": "order_22222222222222222222222222222222",
"account_sequence": "8",
"client_order_id": "replacement-8",
"side": "sell",
"order_type": "post_only",
"limit_price_atoms": "151000000",
"size_atoms": "2000000"
}
]
}))
.unwrap();
let PlatformOrderChallengeRequest::Batch { operations, .. } = request else {
panic!("expected batch request");
};
assert_eq!(operations.len(), 2);
assert!(matches!(
&operations[1],
PlatformOrderBatchOperation::Replace { account_sequence: Some(sequence), .. }
if sequence == "8"
));
let place: PlatformOrderChallengeRequest = serde_json::from_value(serde_json::json!({
"action": "place",
"owner_wallet": "11111111111111111111111111111111",
"session_public_key": "22222222222222222222222222222222",
"client_order_id": "first-order",
"side": "buy",
"order_type": "post_only",
"limit_price_atoms": "150000000",
"size_atoms": "1000000"
}))
.unwrap();
assert!(matches!(
place,
PlatformOrderChallengeRequest::Place {
account_sequence: None,
..
}
));
assert!(!serde_json::to_string(&place)
.unwrap()
.contains("account_sequence"));
assert!(
serde_json::from_value::<PlatformOrderChallengeRequest>(serde_json::json!({
"action": "batch",
"owner_wallet": "11111111111111111111111111111111",
"session_public_key": "22222222222222222222222222222222",
"operations": [{
"action": "cancel",
"order_id": "order_11111111111111111111111111111111",
"implementation": "hidden"
}]
}))
.is_err()
);
}
#[test]
fn persistent_order_commands_are_strict_and_explicit_about_self_trade_policy() {
let frame: PlatformOrderCommandClientFrame = serde_json::from_value(serde_json::json!({
"type": "command",
"request_id": "agent-1",
"sequence": "1",
"command": {
"type": "challenge",
"self_trade_prevention": "cancel_maker",
"request": {
"action": "cancel_all",
"owner_wallet": "11111111111111111111111111111111",
"session_public_key": "22222222222222222222222222222222"
}
}
}))
.unwrap();
assert!(matches!(
frame,
PlatformOrderCommandClientFrame::Command {
command: PlatformOrderCommand::Challenge {
self_trade_prevention: PlatformSelfTradePrevention::CancelMaker,
..
},
..
}
));
assert!(
serde_json::from_value::<PlatformOrderCommandClientFrame>(serde_json::json!({
"type": "command",
"request_id": "agent-1",
"sequence": "1",
"command": {
"type": "challenge",
"request": {
"action": "cancel_all",
"owner_wallet": "11111111111111111111111111111111",
"session_public_key": "22222222222222222222222222222222"
}
}
}))
.is_err()
);
}
#[test]
fn prepare_requests_accept_a_signed_challenge_or_the_operation_itself() {
let signed: PlatformOrderPrepareRequest = serde_json::from_value(serde_json::json!({
"challenge_id": "oc_0123456789abcdef0123456789abcdef",
"authorization_signature": "1111",
}))
.unwrap();
assert!(matches!(signed, PlatformOrderPrepareRequest::Authorized(_)));
let direct: PlatformOrderPrepareRequest = serde_json::from_value(serde_json::json!({
"action": "cancel_all",
"owner_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
"session_public_key": "9Uu7cLBgfMk233BAjMvTS8XJy6KbZK7oQ7NXuCTi3Fg2",
}))
.unwrap();
assert!(matches!(
direct,
PlatformOrderPrepareRequest::Direct(PlatformOrderChallengeRequest::CancelAll { .. })
));
assert!(
serde_json::from_value::<PlatformOrderPrepareRequest>(serde_json::json!({
"challenge_id": "oc_0123456789abcdef0123456789abcdef",
"authorization_signature": "1111",
"extra": true,
}))
.is_err()
);
let twap: PlatformTwapPrepareRequest = serde_json::from_value(serde_json::json!({
"action": "cancel",
"owner_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
"session_public_key": "9Uu7cLBgfMk233BAjMvTS8XJy6KbZK7oQ7NXuCTi3Fg2",
"twap_id": "twap_0123456789abcdef0123456789abcdef",
}))
.unwrap();
assert!(matches!(twap, PlatformTwapPrepareRequest::Direct(_)));
let execution: crate::ExecutionPrepareRequest = serde_json::from_value(serde_json::json!({
"quote_id": "quote_0123456789abcdef0123456789abcdef",
"owner_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
"session_public_key": "9Uu7cLBgfMk233BAjMvTS8XJy6KbZK7oQ7NXuCTi3Fg2",
}))
.unwrap();
assert!(matches!(
execution,
crate::ExecutionPrepareRequest::Direct(_)
));
}
}