1use serde::{Deserialize, Serialize};
4
5use crate::{CapabilityRisk, McpExposure};
6
7pub const PLATFORM_SCHEMA_VERSION: u16 = 2;
8pub const PLATFORM_CONTRACT_VERSION: &str = "2.0";
9pub const PLATFORM_ACTION_GRAPH: &str = include_str!("../fixtures/v2/platform-action-graph.json");
10#[cfg(any(test, feature = "fixtures"))]
11#[doc(hidden)]
12pub const PLATFORM_SERVICE_STATUS_FIXTURE: &str =
13 include_str!("../fixtures/v2/platform-status.json");
14#[cfg(any(test, feature = "fixtures"))]
15#[doc(hidden)]
16pub const PLATFORM_CAPABILITIES_FIXTURE: &str =
17 include_str!("../fixtures/v2/platform-capabilities.json");
18#[cfg(any(test, feature = "fixtures"))]
19#[doc(hidden)]
20pub const PLATFORM_ASSETS_FIXTURE: &str = include_str!("../fixtures/v2/assets.json");
21#[cfg(any(test, feature = "fixtures"))]
22#[doc(hidden)]
23pub const PLATFORM_SWAP_QUOTE_FIXTURE: &str = include_str!("../fixtures/v2/swap-quote.json");
24#[cfg(any(test, feature = "fixtures"))]
25#[doc(hidden)]
26pub const PLATFORM_MARKETS_FIXTURE: &str = include_str!("../fixtures/v2/markets.json");
27#[cfg(any(test, feature = "fixtures"))]
28#[doc(hidden)]
29pub const PLATFORM_BOOK_FIXTURE: &str = include_str!("../fixtures/v2/book.json");
30#[cfg(any(test, feature = "fixtures"))]
31#[doc(hidden)]
32pub const PLATFORM_BBO_FIXTURE: &str = include_str!("../fixtures/v2/bbo.json");
33#[cfg(any(test, feature = "fixtures"))]
34#[doc(hidden)]
35pub const PLATFORM_FEES_FIXTURE: &str = include_str!("../fixtures/v2/fees.json");
36#[cfg(any(test, feature = "fixtures"))]
37#[doc(hidden)]
38pub const PLATFORM_STATUS_FIXTURE: &str = include_str!("../fixtures/v2/status.json");
39#[cfg(any(test, feature = "fixtures"))]
40#[doc(hidden)]
41pub const PLATFORM_CANDLES_FIXTURE: &str = include_str!("../fixtures/v2/candles.json");
42#[cfg(any(test, feature = "fixtures"))]
43#[doc(hidden)]
44pub const PLATFORM_MARK_FIXTURE: &str = include_str!("../fixtures/v2/mark.json");
45#[cfg(any(test, feature = "fixtures"))]
46#[doc(hidden)]
47pub const PLATFORM_EXECUTION_STATUS_FIXTURE: &str =
48 include_str!("../fixtures/v2/execution-status.json");
49#[cfg(any(test, feature = "fixtures"))]
50#[doc(hidden)]
51pub const PLATFORM_TWAPS_FIXTURE: &str = include_str!("../fixtures/v2/twaps.json");
52#[cfg(any(test, feature = "fixtures"))]
53#[doc(hidden)]
54pub const PLATFORM_TWAP_CHALLENGE_FIXTURE: &str =
55 include_str!("../fixtures/v2/twap-challenge.json");
56#[cfg(any(test, feature = "fixtures"))]
57#[doc(hidden)]
58pub const PLATFORM_TWAP_PREPARE_FIXTURE: &str = include_str!("../fixtures/v2/twap-prepare.json");
59#[cfg(any(test, feature = "fixtures"))]
60#[doc(hidden)]
61pub const PLATFORM_TWAP_SUBMIT_FIXTURE: &str = include_str!("../fixtures/v2/twap-submit.json");
62#[cfg(any(test, feature = "fixtures"))]
63#[doc(hidden)]
64pub const PLATFORM_PORTFOLIO_HISTORY_FIXTURE: &str =
65 include_str!("../fixtures/v2/portfolio-history.json");
66#[cfg(any(test, feature = "fixtures"))]
67#[doc(hidden)]
68pub const PLATFORM_PORTFOLIO_FIXTURE: &str = include_str!("../fixtures/v2/portfolio.json");
69#[cfg(any(test, feature = "fixtures"))]
70#[doc(hidden)]
71pub const PLATFORM_REWARDS_FIXTURE: &str = include_str!("../fixtures/v2/rewards.json");
72#[cfg(any(test, feature = "fixtures"))]
73#[doc(hidden)]
74pub const PLATFORM_REFERRALS_FIXTURE: &str = include_str!("../fixtures/v2/referrals.json");
75#[cfg(any(test, feature = "fixtures"))]
76#[doc(hidden)]
77pub const PLATFORM_REFERRAL_LINK_FIXTURE: &str = include_str!("../fixtures/v2/referral-link.json");
78#[cfg(any(test, feature = "fixtures"))]
79#[doc(hidden)]
80pub const PLATFORM_REFERRAL_CLAIM_FIXTURE: &str =
81 include_str!("../fixtures/v2/referral-claim.json");
82#[cfg(any(test, feature = "fixtures"))]
83#[doc(hidden)]
84pub const PLATFORM_VAULT_STATUS_FIXTURE: &str = include_str!("../fixtures/v2/vault-status.json");
85#[cfg(any(test, feature = "fixtures"))]
86#[doc(hidden)]
87pub const PLATFORM_VAULT_PAUSE_PREPARE_FIXTURE: &str =
88 include_str!("../fixtures/v2/vault-pause-prepare.json");
89#[cfg(any(test, feature = "fixtures"))]
90#[doc(hidden)]
91pub const PLATFORM_VAULT_SETUP_PREPARE_FIXTURE: &str =
92 include_str!("../fixtures/v2/vault-setup-prepare.json");
93pub const PLATFORM_VAULT_DELEGATE_PREPARE_FIXTURE: &str =
94 include_str!("../fixtures/v2/vault-delegate-prepare.json");
95pub const PLATFORM_VAULT_POLICY_PREPARE_FIXTURE: &str =
96 include_str!("../fixtures/v2/vault-policy-prepare.json");
97pub const PLATFORM_VAULT_DEPOSIT_PREPARE_FIXTURE: &str =
98 include_str!("../fixtures/v2/vault-deposit-prepare.json");
99pub const PLATFORM_VAULT_WITHDRAW_PREPARE_FIXTURE: &str =
100 include_str!("../fixtures/v2/vault-withdraw-prepare.json");
101pub const PLATFORM_VAULT_SUBMIT_FIXTURE: &str = include_str!("../fixtures/v2/vault-submit.json");
102#[cfg(any(test, feature = "fixtures"))]
103#[doc(hidden)]
104pub const PLATFORM_BUGS_FIXTURE: &str = include_str!("../fixtures/v2/bugs.json");
105#[cfg(any(test, feature = "fixtures"))]
106#[doc(hidden)]
107pub const PLATFORM_BUG_SUBMIT_FIXTURE: &str = include_str!("../fixtures/v2/bug-submit.json");
108#[cfg(any(test, feature = "fixtures"))]
109#[doc(hidden)]
110pub const PLATFORM_TRADES_FIXTURE: &str = include_str!("../fixtures/v2/trades.json");
111#[cfg(any(test, feature = "fixtures"))]
112#[doc(hidden)]
113pub const PLATFORM_ACCOUNT_FIXTURE: &str = include_str!("../fixtures/v2/account.json");
114#[cfg(any(test, feature = "fixtures"))]
115#[doc(hidden)]
116pub const PLATFORM_MAKER_REPUTATION_FIXTURE: &str =
117 include_str!("../fixtures/v2/maker-reputation.json");
118#[cfg(any(test, feature = "fixtures"))]
119#[doc(hidden)]
120pub const PLATFORM_MAKER_STATUS_FIXTURE: &str = include_str!("../fixtures/v2/maker-status.json");
121#[cfg(any(test, feature = "fixtures"))]
122#[doc(hidden)]
123pub const PLATFORM_MAKER_STREAM_FIXTURE: &str = include_str!("../fixtures/v2/maker-stream.json");
124#[cfg(any(test, feature = "fixtures"))]
125#[doc(hidden)]
126pub const PLATFORM_TWAP_STREAM_FIXTURE: &str = include_str!("../fixtures/v2/twap-stream.json");
127#[cfg(any(test, feature = "fixtures"))]
128#[doc(hidden)]
129pub const PLATFORM_EXECUTION_STREAM_FIXTURE: &str =
130 include_str!("../fixtures/v2/execution-stream.json");
131#[cfg(any(test, feature = "fixtures"))]
132#[doc(hidden)]
133pub const PLATFORM_ORDER_CHALLENGE_FIXTURE: &str =
134 include_str!("../fixtures/v2/order-challenge.json");
135#[cfg(any(test, feature = "fixtures"))]
136#[doc(hidden)]
137pub const PLATFORM_ORDER_PREPARE_FIXTURE: &str = include_str!("../fixtures/v2/order-prepare.json");
138#[cfg(any(test, feature = "fixtures"))]
139#[doc(hidden)]
140pub const PLATFORM_ORDER_SUBMIT_FIXTURE: &str = include_str!("../fixtures/v2/order-submit.json");
141#[cfg(any(test, feature = "fixtures"))]
142#[doc(hidden)]
143pub const PLATFORM_ORDER_STATUS_FIXTURE: &str = include_str!("../fixtures/v2/order-status.json");
144
145#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
146#[serde(rename_all = "snake_case")]
147pub enum PermissionSource {
148 ExternalAgentOwner,
149}
150
151#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
152#[serde(rename_all = "snake_case")]
153pub enum SigningLocation {
154 External,
155}
156
157#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
158#[serde(deny_unknown_fields)]
159pub struct PlatformAuthority {
160 pub permission_source: PermissionSource,
161 pub signing_location: SigningLocation,
162 pub accepts_private_keys: bool,
163}
164
165#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
166#[serde(rename_all = "snake_case")]
167pub enum PlatformTransport {
168 Http,
169 Websocket,
170 Mcp,
171}
172
173#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
174#[serde(rename_all = "snake_case")]
175pub enum PlatformMarketState {
176 Active,
177 ReadOnly,
178 QuoteOnly,
179 CancelOnly,
180 Paused,
181 Warming,
182 Degraded,
183 Unavailable,
184}
185
186#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
187#[serde(rename_all = "snake_case")]
188pub enum PlatformOrderState {
189 Created,
190 Accepted,
191 Open,
192 PartiallyFilled,
193 Filled,
194 CancelPending,
195 Cancelled,
196 Expired,
197 Rejected,
198}
199
200#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
201#[serde(rename_all = "snake_case")]
202pub enum PlatformSettlementState {
203 NotApplicable,
204 Pending,
205 Confirmed,
206 Failed,
207}
208
209#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
210#[serde(rename_all = "snake_case")]
211pub enum PlatformPublicErrorCode {
212 InvalidRequest,
213 UnsupportedCapability,
214 MarketUnavailable,
215 MarketWarming,
216 QuoteUnavailable,
217 QuoteExpired,
218 PriceBoundFailed,
219 InsufficientBalance,
220 PolicyRejected,
221 SessionExpired,
222 SequenceConflict,
223 DuplicateClientId,
224 OrderRejected,
225 OrderNotFound,
226 CancelTooLate,
227 SelfTradePrevented,
228 DeadManExpired,
229 RateLimited,
230 TemporarilyUnavailable,
231 SubmissionAmbiguous,
232 SettlementPending,
233 SettlementFailed,
234}
235
236#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
238#[serde(deny_unknown_fields)]
239pub struct ExactAmount {
240 pub asset_id: String,
241 pub atoms: String,
242}
243
244#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
246#[serde(deny_unknown_fields)]
247pub struct SequenceEnvelope {
248 pub stream_id: String,
249 pub sequence: String,
250 pub previous_sequence: Option<String>,
251 pub server_time_ms: u64,
252 #[serde(skip_serializing_if = "Option::is_none")]
253 pub snapshot_id: Option<String>,
254}
255
256#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
257#[serde(deny_unknown_fields)]
258pub struct PageRequest {
259 #[serde(skip_serializing_if = "Option::is_none")]
260 pub cursor: Option<String>,
261 #[serde(skip_serializing_if = "Option::is_none")]
262 pub limit: Option<u32>,
263}
264
265#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
266#[serde(deny_unknown_fields)]
267pub struct PageInfo {
268 pub next_cursor: Option<String>,
269 pub has_more: bool,
270}
271
272#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
273#[serde(deny_unknown_fields)]
274pub struct PublicOperationError {
275 pub code: PlatformPublicErrorCode,
276 pub message: String,
277 pub retryable: bool,
278 #[serde(skip_serializing_if = "Option::is_none")]
279 pub retry_after_ms: Option<u64>,
280 #[serde(skip_serializing_if = "Option::is_none")]
281 pub operation_id: Option<String>,
282}
283
284#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
286#[serde(deny_unknown_fields)]
287pub struct LivePlatformCapability {
288 pub id: String,
289 pub risk: CapabilityRisk,
290 pub required_scope: String,
291 pub transports: Vec<PlatformTransport>,
292 pub mcp_exposure: McpExposure,
293}
294
295#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
297#[serde(deny_unknown_fields)]
298pub struct PlatformDiscoveryResponse {
299 pub schema_version: u16,
300 pub contract_version: String,
301 pub server_time_ms: u64,
302 pub authority: PlatformAuthority,
303 pub capabilities: Vec<LivePlatformCapability>,
304}
305
306#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
307#[serde(rename_all = "snake_case")]
308pub enum PlatformServiceState {
309 Operational,
310 Degraded,
311}
312
313#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
315#[serde(deny_unknown_fields)]
316pub struct PlatformServiceStatusResponse {
317 pub schema_version: u16,
318 pub contract_version: String,
319 pub server_time_ms: u64,
320 pub status: PlatformServiceState,
321 pub available_operations: u32,
322}
323
324#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
325#[serde(rename_all = "snake_case")]
326pub enum PlatformActionKind {
327 Discovery,
328 Read,
329 Prepare,
330 ExternalSignature,
331 Submit,
332 Receipt,
333 Stream,
334}
335
336#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
337#[serde(deny_unknown_fields)]
338pub struct PlatformGraphRelation {
339 pub from: String,
340 pub to: String,
341 pub kind: String,
342}
343
344#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
345#[serde(deny_unknown_fields)]
346pub struct PlatformGraphModule {
347 pub id: String,
348 pub client_property: String,
349 pub capability_ids: Vec<String>,
350}
351
352#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
353#[serde(deny_unknown_fields)]
354pub struct PlatformOperationTransport {
355 pub transport: PlatformTransport,
356 #[serde(skip_serializing_if = "Option::is_none")]
357 pub method: Option<String>,
358 #[serde(skip_serializing_if = "Option::is_none")]
359 pub path: Option<String>,
360 #[serde(skip_serializing_if = "Option::is_none")]
361 pub tool: Option<String>,
362}
363
364#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
365#[serde(deny_unknown_fields)]
366pub struct PlatformOperation {
367 pub id: String,
368 pub capability_id: String,
369 pub kind: PlatformActionKind,
370 pub summary: String,
371 pub transports: Vec<PlatformOperationTransport>,
372 pub available: bool,
373}
374
375#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
376#[serde(deny_unknown_fields)]
377pub struct PlatformWorkflowNode {
378 pub id: String,
379 pub kind: PlatformActionKind,
380 pub capability_id: Option<String>,
381 pub operation_ids: Vec<String>,
382 pub available: bool,
383}
384
385#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
386#[serde(deny_unknown_fields)]
387pub struct PlatformWorkflowEdge {
388 pub from: String,
389 pub to: String,
390 pub condition: String,
391}
392
393#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
394#[serde(deny_unknown_fields)]
395pub struct PlatformWorkflow {
396 pub id: String,
397 pub entry_node: String,
398 pub nodes: Vec<PlatformWorkflowNode>,
399 pub edges: Vec<PlatformWorkflowEdge>,
400}
401
402#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
405#[serde(deny_unknown_fields)]
406pub struct PlatformActionGraphResponse {
407 pub schema_version: u16,
408 pub contract_version: String,
409 pub graph_version: String,
410 pub entry_operation_id: String,
411 pub authority: PlatformAuthority,
412 pub entities: Vec<String>,
413 pub relations: Vec<PlatformGraphRelation>,
414 pub modules: Vec<PlatformGraphModule>,
415 pub operations: Vec<PlatformOperation>,
416 pub workflows: Vec<PlatformWorkflow>,
417}
418
419impl PlatformActionGraphResponse {
420 pub fn foundation() -> Self {
421 serde_json::from_str(PLATFORM_ACTION_GRAPH)
422 .expect("embedded platform action graph must be valid")
423 }
424
425 pub fn project_availability(
428 &mut self,
429 live_capability_ids: &std::collections::BTreeSet<String>,
430 ) {
431 for operation in &mut self.operations {
432 operation.available = live_capability_ids.contains(&operation.capability_id);
433 }
434 for workflow in &mut self.workflows {
435 for node in &mut workflow.nodes {
436 node.available = node
437 .capability_id
438 .as_ref()
439 .is_none_or(|capability_id| live_capability_ids.contains(capability_id));
440 }
441 }
442 }
443}
444
445#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
446#[serde(rename_all = "snake_case")]
447pub enum PlatformNetwork {
448 Solana,
449}
450
451#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
453#[serde(deny_unknown_fields)]
454pub struct PlatformAsset {
455 pub asset_id: String,
456 pub symbol: String,
457 pub name: String,
458 pub decimals: u8,
459 #[serde(skip_serializing_if = "Option::is_none")]
460 pub logo_url: Option<String>,
461 pub network: PlatformNetwork,
462}
463
464#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
465#[serde(deny_unknown_fields)]
466pub struct PlatformAssetsResponse {
467 pub schema_version: u16,
468 pub contract_version: String,
469 pub server_time_ms: u64,
470 pub assets: Vec<PlatformAsset>,
471 pub page: PageInfo,
472}
473
474#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
478#[serde(deny_unknown_fields)]
479pub struct PlatformSwapQuoteRequest {
480 pub input_asset_id: String,
481 pub output_asset_id: String,
482 pub amount_in_atoms: String,
483 #[serde(default)]
484 pub maximum_tolerance_bps: u16,
485}
486
487#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
489#[serde(deny_unknown_fields)]
490pub struct PlatformSwapQuoteResponse {
491 pub schema_version: u16,
492 pub contract_version: String,
493 pub quote_id: String,
494 pub server_time_ms: u64,
495 pub expires_at_ms: u64,
496 pub input_asset_id: String,
497 pub output_asset_id: String,
498 pub amount_in_atoms: String,
499 pub amount_in_consumed_atoms: String,
500 pub amount_out_atoms: String,
501 pub minimum_output_atoms: String,
502 pub input_fee_atoms: String,
503 pub output_fee_atoms: String,
504 pub maximum_tolerance_bps: u16,
505 pub reference_price: String,
506 pub price_impact_pct: String,
507 pub provider: String,
508}
509
510#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
511#[serde(rename_all = "snake_case")]
512pub enum PlatformMarketAction {
513 Quote,
514 ExecuteImmediate,
515 PlaceOrder,
516 ScheduleTwap,
517}
518
519#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
521#[serde(deny_unknown_fields)]
522pub struct PlatformMarket {
523 pub market_id: String,
524 pub label: String,
525 pub base_asset_id: String,
526 pub quote_asset_id: String,
527 pub status: PlatformMarketState,
528 pub available_actions: Vec<PlatformMarketAction>,
529}
530
531#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
532#[serde(deny_unknown_fields)]
533pub struct PlatformMarketsResponse {
534 pub schema_version: u16,
535 pub contract_version: String,
536 pub server_time_ms: u64,
537 pub markets: Vec<PlatformMarket>,
538 pub page: PageInfo,
539}
540
541#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
542#[serde(deny_unknown_fields)]
543pub struct PlatformBookLevel {
544 pub price_atoms: String,
546 pub size_atoms: String,
548}
549
550#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
551#[serde(rename_all = "snake_case")]
552pub enum PlatformBookSide {
553 Bid,
554 Ask,
555}
556
557#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
558#[serde(deny_unknown_fields)]
559pub struct PlatformBookChange {
560 pub side: PlatformBookSide,
561 pub price_atoms: String,
562 pub size_atoms: String,
564}
565
566#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
567#[serde(deny_unknown_fields)]
568pub struct PlatformBookSnapshotResponse {
569 pub schema_version: u16,
570 pub contract_version: String,
571 pub market_id: String,
572 pub stream_id: String,
573 pub sequence: String,
574 pub server_time_ms: u64,
575 pub snapshot_id: String,
576 pub bids: Vec<PlatformBookLevel>,
577 pub asks: Vec<PlatformBookLevel>,
578}
579
580#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
581#[serde(deny_unknown_fields)]
582pub struct PlatformBestBidAskResponse {
583 pub schema_version: u16,
584 pub contract_version: String,
585 pub market_id: String,
586 pub stream_id: String,
587 pub sequence: String,
588 pub server_time_ms: u64,
589 pub best_bid: Option<PlatformBookLevel>,
590 pub best_ask: Option<PlatformBookLevel>,
591}
592
593#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
594#[serde(deny_unknown_fields)]
595pub struct PlatformFeeScheduleResponse {
596 pub schema_version: u16,
597 pub contract_version: String,
598 pub market_id: String,
599 pub server_time_ms: u64,
600 pub passive_maker_fee_bps: u16,
601 pub maximum_immediate_execution_fee_bps: u16,
602 pub book_prices_include_trading_fees: bool,
603 pub exact_fee_returned_by_quote: bool,
604}
605
606#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
607#[serde(deny_unknown_fields)]
608pub struct PlatformMarketStatusResponse {
609 pub schema_version: u16,
610 pub contract_version: String,
611 pub market_id: String,
612 pub server_time_ms: u64,
613 pub status: PlatformMarketState,
614 pub tick_size_atoms: String,
615 pub minimum_order_size_atoms: String,
618}
619
620#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
622#[serde(deny_unknown_fields)]
623pub struct PlatformCandle {
624 pub started_at_ms: u64,
625 pub open_price: String,
626 pub high_price: String,
627 pub low_price: String,
628 pub close_price: String,
629}
630
631#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
632#[serde(deny_unknown_fields)]
633pub struct PlatformCandlesResponse {
634 pub schema_version: u16,
635 pub contract_version: String,
636 pub market_id: String,
637 pub server_time_ms: u64,
638 pub resolution_seconds: u32,
639 pub candles: Vec<PlatformCandle>,
640}
641
642#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
643#[serde(deny_unknown_fields)]
644pub struct PlatformMarkResponse {
645 pub schema_version: u16,
646 pub contract_version: String,
647 pub market_id: String,
648 pub server_time_ms: u64,
649 pub price_atoms_per_base_unit: Option<String>,
650 pub quote_decimals: u8,
651 pub stale: bool,
652 pub age_ms: Option<u64>,
653}
654
655#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
656#[serde(rename_all = "snake_case")]
657pub enum PlatformExecutionState {
658 Prepared,
659 Confirmed,
660}
661
662#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
665#[serde(deny_unknown_fields)]
666pub struct PlatformExecutionStatusResponse {
667 pub schema_version: u16,
668 pub contract_version: String,
669 pub execution_id: String,
670 pub market_id: String,
671 pub status: PlatformExecutionState,
672 pub signature: Option<String>,
673 pub settlement: PlatformSettlementState,
674 pub updated_at_ms: u64,
675}
676
677#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
680#[serde(deny_unknown_fields)]
681pub struct PlatformExecutionRow {
682 pub execution_id: String,
683 pub market_id: String,
684 pub status: PlatformExecutionState,
685 pub signature: Option<String>,
686 pub settlement: PlatformSettlementState,
687 pub updated_at_ms: u64,
688}
689
690#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
693#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
694pub enum PlatformExecutionCommand {
695 Watch { execution_ids: Vec<String> },
696}
697
698#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
706#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
707pub enum PlatformExecutionEvent {
708 ExecutionsSnapshot {
709 schema_version: u16,
710 contract_version: String,
711 market_id: String,
712 stream_id: String,
713 sequence: String,
714 server_time_ms: u64,
715 executions: Vec<PlatformExecutionRow>,
716 unknown_execution_ids: Vec<String>,
717 },
718 ExecutionUpdate {
719 schema_version: u16,
720 contract_version: String,
721 market_id: String,
722 stream_id: String,
723 sequence: String,
724 previous_sequence: String,
725 server_time_ms: u64,
726 execution: PlatformExecutionRow,
727 },
728 ExecutionExpired {
729 schema_version: u16,
730 contract_version: String,
731 market_id: String,
732 stream_id: String,
733 sequence: String,
734 previous_sequence: String,
735 server_time_ms: u64,
736 execution_id: String,
737 },
738 ExecutionUnknown {
739 schema_version: u16,
740 contract_version: String,
741 market_id: String,
742 stream_id: String,
743 sequence: String,
744 previous_sequence: String,
745 server_time_ms: u64,
746 execution_id: String,
747 },
748 Heartbeat {
749 schema_version: u16,
750 contract_version: String,
751 market_id: String,
752 stream_id: String,
753 sequence: String,
754 previous_sequence: String,
755 server_time_ms: u64,
756 },
757}
758
759#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
760#[serde(rename_all = "snake_case")]
761pub enum PlatformTwapState {
762 Active,
763 Completed,
764 Cancelled,
765}
766
767#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
768#[serde(deny_unknown_fields)]
769pub struct PlatformTwapFill {
770 pub fill_id: String,
771 pub size_atoms: String,
772 pub price_atoms: String,
773 pub gross_quote_atoms: String,
774 pub base_fee_atoms: String,
775 pub quote_fee_atoms: String,
776 pub signature: Option<String>,
777 pub observed_at_ms: u64,
778}
779
780#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
781#[serde(deny_unknown_fields)]
782pub struct PlatformTwap {
783 pub twap_id: String,
784 pub side: PlatformTradeSide,
785 pub status: PlatformTwapState,
786 pub slices_total: u16,
787 pub slices_executed: u16,
788 pub interval_slots: u32,
789 pub maximum_tolerance_bps: u16,
790 pub limit_price_atoms: String,
791 pub total_size_atoms: String,
792 pub executed_size_atoms: String,
793 pub gross_quote_executed_atoms: String,
794 pub complete_execution_value: bool,
795 pub created_at_ms: u64,
796 pub completed_at_ms: Option<u64>,
797 pub placed_signature: Option<String>,
798 pub terminal_signature: Option<String>,
799 pub fills: Vec<PlatformTwapFill>,
800}
801
802#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
803#[serde(deny_unknown_fields)]
804pub struct PlatformTwapsResponse {
805 pub schema_version: u16,
806 pub contract_version: String,
807 pub market_id: String,
808 pub wallet_address: String,
809 pub server_time_ms: u64,
810 pub twaps: Vec<PlatformTwap>,
811}
812
813#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
814#[serde(rename_all = "snake_case")]
815pub enum PlatformTwapControlAction {
816 Place,
817 Cancel,
818}
819
820#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
823#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
824pub enum PlatformTwapChallengeRequest {
825 Place {
826 owner_wallet: String,
827 session_public_key: String,
828 side: PlatformTradeSide,
829 total_size_atoms: String,
830 slices_total: u16,
831 maximum_tolerance_bps: u16,
832 interval_slots: u32,
836 limit_price_atoms: String,
837 },
838 Cancel {
839 owner_wallet: String,
840 session_public_key: String,
841 twap_id: String,
842 },
843}
844
845#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
846#[serde(deny_unknown_fields)]
847pub struct PlatformTwapChallengeResponse {
848 pub schema_version: u16,
849 pub contract_version: String,
850 pub challenge_id: String,
851 pub market_id: String,
852 pub action: PlatformTwapControlAction,
853 pub twap_id: String,
854 pub authorization_payload_base64: String,
855 pub server_time_ms: u64,
856 pub expires_at_ms: u64,
857}
858
859#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
861#[serde(deny_unknown_fields)]
862pub struct PlatformTwapPrepareAuthorization {
863 pub challenge_id: String,
864 pub authorization_signature: String,
866}
867
868#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
872#[serde(untagged)]
873pub enum PlatformTwapPrepareRequest {
874 Authorized(PlatformTwapPrepareAuthorization),
875 Direct(PlatformTwapChallengeRequest),
876}
877
878#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
879#[serde(deny_unknown_fields)]
880pub struct PlatformTwapPrepareResponse {
881 pub schema_version: u16,
882 pub contract_version: String,
883 pub twap_control_id: String,
884 pub market_id: String,
885 pub action: PlatformTwapControlAction,
886 pub twap_id: String,
887 pub transaction_base64: String,
890 pub recent_blockhash: String,
891 pub last_valid_block_height: u64,
892 pub expires_at_ms: u64,
893}
894
895#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
896#[serde(deny_unknown_fields)]
897pub struct PlatformTwapSubmitRequest {
898 pub twap_control_id: String,
899 pub signed_transaction_base64: String,
900 pub idempotency_key: String,
901}
902
903#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
904#[serde(deny_unknown_fields)]
905pub struct PlatformTwapSubmitResponse {
906 pub schema_version: u16,
907 pub contract_version: String,
908 pub twap_control_id: String,
909 pub market_id: String,
910 pub action: PlatformTwapControlAction,
911 pub twap_id: String,
912 pub signature: String,
913 pub status: PlatformOrderSubmissionStatus,
914}
915
916#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
923#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
924#[allow(clippy::large_enum_variant)]
925pub enum PlatformTwapEvent {
926 TwapsSnapshot {
927 schema_version: u16,
928 contract_version: String,
929 market_id: String,
930 wallet_address: String,
931 stream_id: String,
932 sequence: String,
933 server_time_ms: u64,
934 twaps: Vec<PlatformTwap>,
935 },
936 TwapUpdate {
937 schema_version: u16,
938 contract_version: String,
939 market_id: String,
940 wallet_address: String,
941 stream_id: String,
942 sequence: String,
943 previous_sequence: String,
944 server_time_ms: u64,
945 twap: PlatformTwap,
946 },
947 Heartbeat {
948 schema_version: u16,
949 contract_version: String,
950 market_id: String,
951 wallet_address: String,
952 stream_id: String,
953 sequence: String,
954 previous_sequence: String,
955 server_time_ms: u64,
956 },
957}
958
959#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
960pub enum PlatformPortfolioHistoryRange {
961 #[serde(rename = "24h")]
962 Day,
963 #[serde(rename = "7d")]
964 Week,
965 #[serde(rename = "30d")]
966 Month,
967}
968
969#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
970#[serde(deny_unknown_fields)]
971pub struct PlatformPortfolioHistoryPoint {
972 pub recorded_at_ms: u64,
973 pub equity_usd_micros: String,
974 pub available_usd_micros: String,
975 pub locked_usd_micros: String,
976 pub market_count: u32,
977}
978
979#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
982#[serde(deny_unknown_fields)]
983pub struct PlatformPortfolioHistoryResponse {
984 pub schema_version: u16,
985 pub contract_version: String,
986 pub wallet_address: String,
987 pub server_time_ms: u64,
988 pub range: PlatformPortfolioHistoryRange,
989 pub points: Vec<PlatformPortfolioHistoryPoint>,
990 pub collecting: bool,
991 pub first_sample_ms: Option<u64>,
992 pub last_sample_ms: Option<u64>,
993}
994
995#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1000#[serde(deny_unknown_fields)]
1001pub struct PlatformPortfolioBalance {
1002 pub asset_id: String,
1003 pub available_atoms: String,
1005 pub locked_atoms: String,
1007 pub total_atoms: String,
1009 pub value_usd_micros: Option<String>,
1011}
1012
1013#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1016#[serde(deny_unknown_fields)]
1017pub struct PlatformPortfolioPosition {
1018 pub market_id: String,
1019 pub base_asset_id: String,
1020 pub quote_asset_id: String,
1021 pub base_available_atoms: String,
1022 pub base_locked_atoms: String,
1023 pub quote_available_atoms: String,
1024 pub quote_locked_atoms: String,
1025}
1026
1027#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1029#[serde(deny_unknown_fields)]
1030pub struct PlatformPortfolioOrder {
1031 pub market_id: String,
1032 pub order_id: String,
1033 pub side: PlatformTradeSide,
1034 pub order_type: PlatformOrderType,
1035 pub state: PlatformOrderState,
1036 pub limit_price_atoms: String,
1037 pub original_size_atoms: String,
1038 pub remaining_size_atoms: String,
1039}
1040
1041#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1043#[serde(deny_unknown_fields)]
1044pub struct PlatformPortfolioFill {
1045 pub market_id: String,
1046 pub fill_id: String,
1047 pub side: PlatformTradeSide,
1048 pub price_atoms: String,
1049 pub size_atoms: String,
1050 pub fee_quote_atoms: String,
1051 pub fee_is_final: bool,
1052 pub settlement: PlatformSettlementState,
1053 pub executed_at_ms: u64,
1054 pub confirmed_at_ms: Option<u64>,
1055 pub transaction_id: Option<String>,
1056 pub realized_pnl_quote_atoms: String,
1057}
1058
1059#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1066#[serde(deny_unknown_fields)]
1067pub struct PlatformPortfolioResponse {
1068 pub schema_version: u16,
1069 pub contract_version: String,
1070 pub wallet_address: String,
1071 pub server_time_ms: u64,
1072 pub observed_at_ms: u64,
1074 pub observed_slot: String,
1076 pub market_count: u32,
1078 pub balances: Vec<PlatformPortfolioBalance>,
1079 pub positions: Vec<PlatformPortfolioPosition>,
1080 pub open_orders: Vec<PlatformPortfolioOrder>,
1082 pub recent_fills: Vec<PlatformPortfolioFill>,
1084 pub unavailable_market_ids: Vec<String>,
1087 pub equity_usd_micros: Option<String>,
1089 pub available_usd_micros: Option<String>,
1091 pub locked_usd_micros: Option<String>,
1093 pub valuation_complete: bool,
1094 pub unpriced_asset_ids: Vec<String>,
1095}
1096
1097#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1098#[serde(rename_all = "snake_case")]
1099pub enum PlatformVaultState {
1100 Absent,
1101 Active,
1102 Paused,
1103}
1104
1105#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1106#[serde(rename_all = "snake_case")]
1107pub enum PlatformVaultSessionState {
1108 Absent,
1109 Active,
1110 Expired,
1111}
1112
1113#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1114#[serde(rename_all = "snake_case")]
1115pub enum PlatformVaultWithdrawalMode {
1116 Unrestricted,
1117 Blocked,
1118 Restricted,
1119}
1120
1121#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1124#[serde(deny_unknown_fields)]
1125pub struct PlatformVaultSpendingLimit {
1126 pub asset_id: String,
1127 pub maximum_per_execution_atoms: Option<String>,
1128}
1129
1130#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1133#[serde(deny_unknown_fields)]
1134pub struct PlatformVaultSessionStatus {
1135 pub session_public_key: String,
1136 pub state: PlatformVaultSessionState,
1137 pub expires_at_ms: Option<u64>,
1138 pub permanent: bool,
1139 pub minimum_interval_seconds: u32,
1140 pub maximum_tolerance_bps: u16,
1141 pub last_execution_at_ms: Option<u64>,
1142 pub market_execution_ready: bool,
1143 pub price_protection_active: bool,
1144 pub spending_limits: Vec<PlatformVaultSpendingLimit>,
1145}
1146
1147#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1148#[serde(deny_unknown_fields)]
1149pub struct PlatformVaultWithdrawalAccess {
1150 pub mode: PlatformVaultWithdrawalMode,
1151 pub allowed_wallet_addresses: Vec<String>,
1152}
1153
1154#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1157#[serde(deny_unknown_fields)]
1158pub struct PlatformVaultStatusResponse {
1159 pub schema_version: u16,
1160 pub contract_version: String,
1161 pub server_time_ms: u64,
1162 pub wallet_address: String,
1163 pub state: PlatformVaultState,
1164 pub session: Option<PlatformVaultSessionStatus>,
1165 pub withdrawal_access: PlatformVaultWithdrawalAccess,
1166}
1167
1168#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1169#[serde(deny_unknown_fields)]
1170pub struct PlatformVaultPausePrepareRequest {
1171 pub wallet_address: String,
1172 pub paused: bool,
1173}
1174
1175#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1178#[serde(deny_unknown_fields)]
1179pub struct PlatformVaultPausePrepareResponse {
1180 pub schema_version: u16,
1181 pub contract_version: String,
1182 pub server_time_ms: u64,
1183 pub wallet_address: String,
1184 pub paused: bool,
1185 pub transaction_base64: String,
1186 pub recent_blockhash: String,
1187 pub owner_signature_required: bool,
1188 pub preparation_id: String,
1192 pub sponsored: bool,
1196 pub submit_by_ms: u64,
1198}
1199
1200#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1201#[serde(rename_all = "snake_case")]
1202pub enum PlatformVaultSetupMode {
1203 Create,
1204 ReplaceSession,
1205}
1206
1207pub const PLATFORM_SESSION_DEFAULT_MINIMUM_INTERVAL_SECONDS: u32 = 1;
1210pub const PLATFORM_SESSION_DEFAULT_MAXIMUM_TOLERANCE_BPS: u16 = 100;
1211pub const PLATFORM_SESSION_MAX_SPENDING_LIMITS: usize = 4;
1213
1214#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1218#[serde(deny_unknown_fields)]
1219pub struct PlatformVaultSetupPrepareRequest {
1220 pub wallet_address: String,
1221 pub session_public_key: String,
1222 #[serde(default)]
1226 pub replace_session_public_key: Option<String>,
1227 #[serde(default)]
1230 pub market_id: Option<String>,
1231 #[serde(default)]
1234 pub expires_at_ms: Option<u64>,
1235 #[serde(default)]
1237 pub minimum_interval_seconds: Option<u32>,
1238 #[serde(default)]
1240 pub maximum_tolerance_bps: Option<u16>,
1241 #[serde(default)]
1244 pub spending_limits: Vec<PlatformVaultSpendingLimit>,
1245}
1246
1247#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1250#[serde(deny_unknown_fields)]
1251pub struct PlatformVaultSetupPrepareResponse {
1252 pub schema_version: u16,
1253 pub contract_version: String,
1254 pub server_time_ms: u64,
1255 pub wallet_address: String,
1256 pub session_public_key: String,
1257 pub replace_session_public_key: Option<String>,
1259 pub market_id: Option<String>,
1261 pub mode: PlatformVaultSetupMode,
1262 pub expires_at_ms: Option<u64>,
1263 pub permanent: bool,
1264 pub minimum_interval_seconds: u32,
1266 pub maximum_tolerance_bps: u16,
1267 pub spending_limits: Vec<PlatformVaultSpendingLimit>,
1268 pub transaction_base64: String,
1269 pub recent_blockhash: String,
1270 pub owner_signature_required: bool,
1271 pub preparation_id: String,
1275 pub sponsored: bool,
1279 pub submit_by_ms: u64,
1281}
1282
1283#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1284#[serde(rename_all = "snake_case")]
1285pub enum PlatformVaultDelegateAction {
1286 Revoke,
1287}
1288
1289#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1290#[serde(deny_unknown_fields)]
1291pub struct PlatformVaultDelegatePrepareRequest {
1292 pub wallet_address: String,
1293 pub session_public_key: String,
1294 pub action: PlatformVaultDelegateAction,
1295}
1296
1297#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1300#[serde(deny_unknown_fields)]
1301pub struct PlatformVaultDelegatePrepareResponse {
1302 pub schema_version: u16,
1303 pub contract_version: String,
1304 pub server_time_ms: u64,
1305 pub wallet_address: String,
1306 pub session_public_key: String,
1307 pub action: PlatformVaultDelegateAction,
1308 pub transaction_base64: String,
1309 pub recent_blockhash: String,
1310 pub owner_signature_required: bool,
1311 pub preparation_id: String,
1315 pub sponsored: bool,
1319 pub submit_by_ms: u64,
1321}
1322
1323#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1324#[serde(deny_unknown_fields)]
1325pub struct PlatformVaultPolicyPrepareRequest {
1326 pub wallet_address: String,
1327 pub withdrawal_access: PlatformVaultWithdrawalAccess,
1328}
1329
1330#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1333#[serde(deny_unknown_fields)]
1334pub struct PlatformVaultPolicyPrepareResponse {
1335 pub schema_version: u16,
1336 pub contract_version: String,
1337 pub server_time_ms: u64,
1338 pub wallet_address: String,
1339 pub withdrawal_access: PlatformVaultWithdrawalAccess,
1340 pub transaction_base64: String,
1341 pub recent_blockhash: String,
1342 pub owner_signature_required: bool,
1343 pub preparation_id: String,
1347 pub sponsored: bool,
1351 pub submit_by_ms: u64,
1353}
1354
1355#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1356#[serde(deny_unknown_fields)]
1357pub struct PlatformVaultDepositPrepareRequest {
1358 pub wallet_address: String,
1359 pub market_id: String,
1360 pub asset_id: String,
1361 pub amount_atoms: String,
1362 #[serde(default)]
1367 pub session_public_key: Option<String>,
1368}
1369
1370#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1373#[serde(deny_unknown_fields)]
1374pub struct PlatformVaultDepositPrepareResponse {
1375 pub schema_version: u16,
1376 pub contract_version: String,
1377 pub server_time_ms: u64,
1378 pub wallet_address: String,
1379 pub market_id: String,
1380 pub asset_id: String,
1381 pub amount_atoms: String,
1382 pub network_cost_atoms: String,
1388 pub session_public_key: Option<String>,
1390 pub registers_session: bool,
1394 pub transaction_base64: String,
1395 pub recent_blockhash: String,
1396 pub owner_signature_required: bool,
1397 pub preparation_id: String,
1401 pub sponsored: bool,
1405 pub submit_by_ms: u64,
1407}
1408
1409#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1410#[serde(deny_unknown_fields)]
1411pub struct PlatformVaultWithdrawPrepareRequest {
1412 pub wallet_address: String,
1413 pub market_id: String,
1414 pub asset_id: String,
1415 pub destination_wallet_address: String,
1416 pub amount_atoms: String,
1417}
1418
1419#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1422#[serde(deny_unknown_fields)]
1423pub struct PlatformVaultWithdrawPrepareResponse {
1424 pub schema_version: u16,
1425 pub contract_version: String,
1426 pub server_time_ms: u64,
1427 pub wallet_address: String,
1428 pub market_id: String,
1429 pub asset_id: String,
1430 pub destination_wallet_address: String,
1431 pub amount_atoms: String,
1432 pub transaction_base64: String,
1433 pub recent_blockhash: String,
1434 pub owner_signature_required: bool,
1435 pub preparation_id: String,
1439 pub sponsored: bool,
1443 pub submit_by_ms: u64,
1445}
1446
1447#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1449#[serde(rename_all = "snake_case")]
1450pub enum PlatformVaultAction {
1451 Setup,
1452 Deposit,
1453 Withdraw,
1454 Delegate,
1455 Policy,
1456 Pause,
1457}
1458
1459#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1460#[serde(rename_all = "snake_case")]
1461pub enum PlatformVaultSubmissionStatus {
1462 Submitted,
1464 Confirmed,
1465 Failed,
1466}
1467
1468#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1473#[serde(deny_unknown_fields)]
1474pub struct PlatformVaultSubmitRequest {
1475 pub preparation_id: String,
1476 pub signed_transaction_base64: String,
1477 pub idempotency_key: String,
1478}
1479
1480#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1482#[serde(deny_unknown_fields)]
1483pub struct PlatformVaultSubmitResponse {
1484 pub schema_version: u16,
1485 pub contract_version: String,
1486 pub preparation_id: String,
1487 pub action: PlatformVaultAction,
1488 pub wallet_address: String,
1489 pub sponsored: bool,
1490 pub signature: String,
1491 pub status: PlatformVaultSubmissionStatus,
1492 pub failure_code: Option<String>,
1494 pub updated_at_ms: u64,
1495}
1496
1497#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1498#[serde(deny_unknown_fields)]
1499pub struct PlatformRewardStanding {
1500 pub rank: u32,
1501 pub wallet_address: String,
1502 pub points: String,
1503}
1504
1505#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1506#[serde(deny_unknown_fields)]
1507pub struct PlatformOwnerRewards {
1508 pub wallet_address: String,
1509 pub rank: Option<u32>,
1510 pub points: String,
1511 pub trading_points: String,
1512 pub making_points: String,
1513 pub bug_points: String,
1514 pub referral_points: String,
1515}
1516
1517#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1518#[serde(deny_unknown_fields)]
1519pub struct PlatformRewardsResponse {
1520 pub schema_version: u16,
1521 pub contract_version: String,
1522 pub server_time_ms: u64,
1523 pub season: String,
1524 pub total_wallets: u32,
1525 pub owner: Option<PlatformOwnerRewards>,
1526 pub standings: Vec<PlatformRewardStanding>,
1527}
1528
1529#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1530#[serde(deny_unknown_fields)]
1531pub struct PlatformReferralsResponse {
1532 pub schema_version: u16,
1533 pub contract_version: String,
1534 pub server_time_ms: u64,
1535 pub wallet_address: String,
1536 pub enabled: bool,
1537 pub cash_rewards_enabled: bool,
1538 pub referral_code: Option<String>,
1539 pub referred_wallets: u32,
1540 pub referral_points: String,
1541 pub referred_by: Option<String>,
1542 pub referral_locked: bool,
1543 pub cash_accrued_atoms: String,
1544 pub cash_paid_atoms: String,
1545 pub cash_claimable_atoms: String,
1546}
1547
1548#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1549#[serde(deny_unknown_fields)]
1550pub struct PlatformReferralLinkRequest {
1551 pub wallet_address: String,
1552 pub referral_code: String,
1553 pub authorization_signature: String,
1554}
1555
1556#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1557#[serde(deny_unknown_fields)]
1558pub struct PlatformReferralLinkResponse {
1559 pub schema_version: u16,
1560 pub contract_version: String,
1561 pub server_time_ms: u64,
1562 pub wallet_address: String,
1563 pub referral_code: String,
1564 pub status: String,
1565}
1566
1567#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1568#[serde(deny_unknown_fields)]
1569pub struct PlatformReferralClaimRequest {
1570 pub wallet_address: String,
1571 pub payout_wallet_address: Option<String>,
1572 pub authorization_signature: String,
1573}
1574
1575#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1576#[serde(deny_unknown_fields)]
1577pub struct PlatformReferralClaimResponse {
1578 pub schema_version: u16,
1579 pub contract_version: String,
1580 pub server_time_ms: u64,
1581 pub wallet_address: String,
1582 pub payout_wallet_address: String,
1583 pub claimable_atoms: String,
1584 pub status: String,
1585}
1586
1587#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1588#[serde(rename_all = "snake_case")]
1589pub enum PlatformBugStatus {
1590 Pending,
1591 Confirmed,
1592 Rejected,
1593}
1594
1595#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1596#[serde(deny_unknown_fields)]
1597pub struct PlatformBugReport {
1598 pub bug_id: String,
1599 pub status: PlatformBugStatus,
1600 pub severity: u8,
1601 pub points: String,
1602 pub created_at_ms: u64,
1603 pub triaged_at_ms: Option<u64>,
1604 pub completed_at_ms: Option<u64>,
1605}
1606
1607#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1608#[serde(deny_unknown_fields)]
1609pub struct PlatformBugsResponse {
1610 pub schema_version: u16,
1611 pub contract_version: String,
1612 pub server_time_ms: u64,
1613 pub wallet_address: String,
1614 pub points: String,
1615 pub confirmed_reports: u32,
1616 pub reports: Vec<PlatformBugReport>,
1617}
1618
1619#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1620#[serde(deny_unknown_fields)]
1621pub struct PlatformBugSubmitRequest {
1622 pub owner_wallet: String,
1623 pub message: String,
1624 pub authorization_signature: String,
1627}
1628
1629#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1630#[serde(deny_unknown_fields)]
1631pub struct PlatformBugSubmitResponse {
1632 pub schema_version: u16,
1633 pub contract_version: String,
1634 pub server_time_ms: u64,
1635 pub bug_id: String,
1636 pub status: PlatformBugStatus,
1637}
1638
1639#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1640#[serde(rename_all = "snake_case")]
1641pub enum PlatformTradeSide {
1642 Buy,
1643 Sell,
1644}
1645
1646#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1647#[serde(deny_unknown_fields)]
1648pub struct PlatformTrade {
1649 pub trade_id: String,
1650 pub side: PlatformTradeSide,
1651 pub price_atoms: String,
1652 pub size_atoms: String,
1653 pub executed_at_ms: u64,
1654}
1655
1656#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1657#[serde(deny_unknown_fields)]
1658pub struct PlatformTradesResponse {
1659 pub schema_version: u16,
1660 pub contract_version: String,
1661 pub market_id: String,
1662 pub server_time_ms: u64,
1663 pub trades: Vec<PlatformTrade>,
1664}
1665
1666#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1667#[serde(rename_all = "snake_case")]
1668pub enum PlatformOrderType {
1669 GoodUntilCancelled,
1670 ImmediateOrCancel,
1671 FillOrKill,
1672 PostOnly,
1673}
1674
1675#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1679#[serde(rename_all = "snake_case")]
1680pub enum PlatformOrderAction {
1681 Place,
1682 Cancel,
1683 CancelAll,
1684 Replace,
1687 Batch,
1690}
1691
1692#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1695#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
1696pub enum PlatformOrderBatchOperation {
1697 Place {
1698 #[serde(default, skip_serializing_if = "Option::is_none")]
1704 account_sequence: Option<String>,
1705 client_order_id: String,
1706 side: PlatformTradeSide,
1707 order_type: PlatformOrderType,
1708 limit_price_atoms: String,
1709 size_atoms: String,
1710 },
1711 Cancel {
1712 order_id: String,
1713 },
1714 Replace {
1715 order_id: String,
1716 #[serde(default, skip_serializing_if = "Option::is_none")]
1717 account_sequence: Option<String>,
1718 client_order_id: String,
1719 side: PlatformTradeSide,
1720 order_type: PlatformOrderType,
1721 limit_price_atoms: String,
1722 size_atoms: String,
1723 },
1724}
1725
1726#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1730#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
1731pub enum PlatformOrderChallengeRequest {
1732 Place {
1733 owner_wallet: String,
1734 session_public_key: String,
1735 #[serde(default, skip_serializing_if = "Option::is_none")]
1739 account_sequence: Option<String>,
1740 client_order_id: String,
1741 side: PlatformTradeSide,
1742 order_type: PlatformOrderType,
1743 limit_price_atoms: String,
1744 size_atoms: String,
1745 },
1746 Cancel {
1747 owner_wallet: String,
1748 session_public_key: String,
1749 order_id: String,
1750 },
1751 CancelAll {
1752 owner_wallet: String,
1753 session_public_key: String,
1754 },
1755 Replace {
1756 owner_wallet: String,
1757 session_public_key: String,
1758 order_id: String,
1759 #[serde(default, skip_serializing_if = "Option::is_none")]
1760 account_sequence: Option<String>,
1761 client_order_id: String,
1762 side: PlatformTradeSide,
1763 order_type: PlatformOrderType,
1764 limit_price_atoms: String,
1765 size_atoms: String,
1766 },
1767 Batch {
1768 owner_wallet: String,
1769 session_public_key: String,
1770 operations: Vec<PlatformOrderBatchOperation>,
1771 },
1772}
1773
1774#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1775#[serde(deny_unknown_fields)]
1776pub struct PlatformOrderChallengeResponse {
1777 pub schema_version: u16,
1778 pub contract_version: String,
1779 pub challenge_id: String,
1780 pub market_id: String,
1781 pub action: PlatformOrderAction,
1782 pub order_ids: Vec<String>,
1786 pub authorization_payload_base64: String,
1787 pub server_time_ms: u64,
1788 pub expires_at_ms: u64,
1789}
1790
1791#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1793#[serde(deny_unknown_fields)]
1794pub struct PlatformOrderPrepareAuthorization {
1795 pub challenge_id: String,
1796 #[serde(default, skip_serializing_if = "Option::is_none")]
1801 pub authorization_signature: Option<String>,
1802}
1803
1804#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1810#[serde(untagged)]
1811pub enum PlatformOrderPrepareRequest {
1812 Authorized(PlatformOrderPrepareAuthorization),
1813 Direct(PlatformOrderChallengeRequest),
1814}
1815
1816#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1817#[serde(deny_unknown_fields)]
1818pub struct PlatformOrderPrepareResponse {
1819 pub schema_version: u16,
1820 pub contract_version: String,
1821 pub order_control_id: String,
1822 pub market_id: String,
1823 pub action: PlatformOrderAction,
1824 pub order_ids: Vec<String>,
1825 pub transaction_base64: String,
1828 pub recent_blockhash: String,
1829 pub last_valid_block_height: u64,
1830 pub expires_at_ms: u64,
1831}
1832
1833#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1834#[serde(deny_unknown_fields)]
1835pub struct PlatformOrderSubmitRequest {
1836 pub order_control_id: String,
1837 pub signed_transaction_base64: String,
1838 pub idempotency_key: String,
1839}
1840
1841#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1842#[serde(rename_all = "snake_case")]
1843pub enum PlatformOrderSubmissionStatus {
1844 Submitted,
1845}
1846
1847#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1848#[serde(deny_unknown_fields)]
1849pub struct PlatformOrderSubmitResponse {
1850 pub schema_version: u16,
1851 pub contract_version: String,
1852 pub order_control_id: String,
1853 pub market_id: String,
1854 pub action: PlatformOrderAction,
1855 pub order_ids: Vec<String>,
1856 pub signature: String,
1857 pub status: PlatformOrderSubmissionStatus,
1858}
1859
1860#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1861#[serde(deny_unknown_fields)]
1862pub struct PlatformOrderStatusRequest {
1863 pub order_control_id: String,
1864 pub idempotency_key: String,
1865}
1866
1867#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1868#[serde(rename_all = "snake_case")]
1869pub enum PlatformOrderControlStatus {
1870 Submitting,
1871 Submitted,
1872 Failed,
1873}
1874
1875#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1876#[serde(deny_unknown_fields)]
1877pub struct PlatformOrderStatusResponse {
1878 pub schema_version: u16,
1879 pub contract_version: String,
1880 pub order_control_id: String,
1881 pub market_id: String,
1882 pub action: PlatformOrderAction,
1883 pub order_ids: Vec<String>,
1884 pub signature: String,
1885 pub status: PlatformOrderControlStatus,
1886 pub failure_code: Option<String>,
1887 pub updated_at_ms: u64,
1888}
1889
1890#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1894#[serde(rename_all = "snake_case")]
1895pub enum PlatformSelfTradePrevention {
1896 CancelTaker,
1897 CancelMaker,
1898 CancelBoth,
1899 SkipOwnLiquidity,
1900}
1901
1902#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1906#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
1907pub enum PlatformOrderCommand {
1908 Probe {
1910 nonce: String,
1911 },
1912 Challenge {
1913 request: PlatformOrderChallengeRequest,
1914 self_trade_prevention: PlatformSelfTradePrevention,
1915 },
1916 Prepare {
1917 request: PlatformOrderPrepareRequest,
1918 },
1919 Submit {
1920 request: PlatformOrderSubmitRequest,
1921 },
1922 Status {
1923 request: PlatformOrderStatusRequest,
1924 },
1925 DeadManArm {
1926 timeout_ms: u64,
1927 request: PlatformOrderSubmitRequest,
1928 },
1929 DeadManStatus,
1930 DeadManHeartbeat,
1931 DeadManDisarm,
1932}
1933
1934#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1941#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
1942pub enum PlatformOrderCommandClientFrame {
1943 Authenticate {
1944 owner_wallet: String,
1945 session_public_key: String,
1946 signature: String,
1948 #[serde(default, skip_serializing_if = "Option::is_none")]
1951 batch_format: Option<PlatformOrderCommandBatchFormat>,
1952 },
1953 Command {
1954 request_id: String,
1955 sequence: String,
1956 command: PlatformOrderCommand,
1957 },
1958}
1959
1960#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1961#[serde(rename_all = "snake_case")]
1962pub enum PlatformOrderCommandBatchFormat {
1963 CompactV1,
1964}
1965
1966#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1970#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
1971pub enum PlatformOrderCommandBatchEvent {
1972 ProbeResult {
1973 request_id: String,
1974 nonce: String,
1975 },
1976 ChallengeResult {
1977 request_id: String,
1978 self_trade_prevention: PlatformSelfTradePrevention,
1979 prevented_order_ids: Vec<String>,
1980 effective_request: PlatformOrderChallengeRequest,
1981 response: PlatformOrderChallengeResponse,
1982 },
1983 PrepareResult {
1984 request_id: String,
1985 response: PlatformOrderPrepareResponse,
1986 },
1987 SubmitResult {
1988 request_id: String,
1989 response: PlatformOrderSubmitResponse,
1990 },
1991 StatusResult {
1992 request_id: String,
1993 response: PlatformOrderStatusResponse,
1994 },
1995 DeadManResult {
1996 request_id: String,
1997 state: PlatformDeadManState,
1998 },
1999 CommandError {
2000 request_id: String,
2001 error: PublicOperationError,
2002 },
2003 Heartbeat,
2004}
2005
2006#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2007#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2008pub enum PlatformOrderCommandServerFrame {
2009 EventBatch {
2010 schema_version: u16,
2011 contract_version: String,
2012 market_id: String,
2013 stream_id: String,
2014 first_sequence: String,
2015 previous_sequence: String,
2016 server_time_ms: u64,
2017 events: Vec<PlatformOrderCommandBatchEvent>,
2018 },
2019}
2020
2021#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2022#[serde(rename_all = "snake_case")]
2023pub enum PlatformDeadManStatus {
2024 Armed,
2025 Triggering,
2026 Triggered,
2027 Disarmed,
2028 Expired,
2029 Failed,
2030}
2031
2032#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2033#[serde(deny_unknown_fields)]
2034pub struct PlatformDeadManState {
2035 pub status: PlatformDeadManStatus,
2036 pub timeout_ms: u64,
2037 pub heartbeat_deadline_ms: u64,
2038 pub order_control_id: Option<String>,
2039 pub signature: Option<String>,
2040 pub failure_code: Option<String>,
2041 pub updated_at_ms: u64,
2042}
2043
2044#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2050#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2051pub enum PlatformOrderCommandEvent {
2052 AuthChallenge {
2053 schema_version: u16,
2054 contract_version: String,
2055 market_id: String,
2056 challenge: String,
2057 server_time_ms: u64,
2058 expires_at_ms: u64,
2059 },
2060 Ready {
2061 schema_version: u16,
2062 contract_version: String,
2063 market_id: String,
2064 stream_id: String,
2065 sequence: String,
2066 server_time_ms: u64,
2067 },
2068 ProbeResult {
2069 schema_version: u16,
2070 contract_version: String,
2071 market_id: String,
2072 stream_id: String,
2073 sequence: String,
2074 previous_sequence: String,
2075 request_id: String,
2076 nonce: String,
2077 server_time_ms: u64,
2078 },
2079 ChallengeResult {
2080 schema_version: u16,
2081 contract_version: String,
2082 market_id: String,
2083 stream_id: String,
2084 sequence: String,
2085 previous_sequence: String,
2086 request_id: String,
2087 self_trade_prevention: PlatformSelfTradePrevention,
2088 prevented_order_ids: Vec<String>,
2089 effective_request: PlatformOrderChallengeRequest,
2090 response: PlatformOrderChallengeResponse,
2091 server_time_ms: u64,
2092 },
2093 PrepareResult {
2094 schema_version: u16,
2095 contract_version: String,
2096 market_id: String,
2097 stream_id: String,
2098 sequence: String,
2099 previous_sequence: String,
2100 request_id: String,
2101 response: PlatformOrderPrepareResponse,
2102 server_time_ms: u64,
2103 },
2104 SubmitResult {
2105 schema_version: u16,
2106 contract_version: String,
2107 market_id: String,
2108 stream_id: String,
2109 sequence: String,
2110 previous_sequence: String,
2111 request_id: String,
2112 response: PlatformOrderSubmitResponse,
2113 server_time_ms: u64,
2114 },
2115 StatusResult {
2116 schema_version: u16,
2117 contract_version: String,
2118 market_id: String,
2119 stream_id: String,
2120 sequence: String,
2121 previous_sequence: String,
2122 request_id: String,
2123 response: PlatformOrderStatusResponse,
2124 server_time_ms: u64,
2125 },
2126 DeadManResult {
2127 schema_version: u16,
2128 contract_version: String,
2129 market_id: String,
2130 stream_id: String,
2131 sequence: String,
2132 previous_sequence: String,
2133 request_id: String,
2134 state: PlatformDeadManState,
2135 server_time_ms: u64,
2136 },
2137 CommandError {
2138 schema_version: u16,
2139 contract_version: String,
2140 market_id: String,
2141 stream_id: String,
2142 sequence: String,
2143 previous_sequence: String,
2144 request_id: String,
2145 error: PublicOperationError,
2146 server_time_ms: u64,
2147 },
2148 Heartbeat {
2149 schema_version: u16,
2150 contract_version: String,
2151 market_id: String,
2152 stream_id: String,
2153 sequence: String,
2154 previous_sequence: String,
2155 server_time_ms: u64,
2156 },
2157}
2158
2159#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2160#[serde(deny_unknown_fields)]
2161pub struct PlatformAccountOrder {
2162 pub order_id: String,
2163 pub side: PlatformTradeSide,
2164 pub order_type: PlatformOrderType,
2165 pub state: PlatformOrderState,
2166 pub limit_price_atoms: String,
2167 pub original_size_atoms: String,
2168 pub remaining_size_atoms: String,
2169}
2170
2171#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2172#[serde(deny_unknown_fields)]
2173pub struct PlatformAccountFill {
2174 pub fill_id: String,
2175 pub side: PlatformTradeSide,
2176 pub price_atoms: String,
2177 pub size_atoms: String,
2178 pub fee_quote_atoms: String,
2179 pub fee_is_final: bool,
2180 pub settlement: PlatformSettlementState,
2181 pub executed_at_ms: u64,
2182 pub confirmed_at_ms: Option<u64>,
2183 pub transaction_id: Option<String>,
2184 pub realized_pnl_quote_atoms: String,
2185}
2186
2187#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2188#[serde(deny_unknown_fields)]
2189pub struct PlatformAccountSnapshotResponse {
2190 pub schema_version: u16,
2191 pub contract_version: String,
2192 pub market_id: String,
2193 pub wallet_address: String,
2194 pub server_time_ms: u64,
2195 pub orders: Vec<PlatformAccountOrder>,
2196 pub fills: Vec<PlatformAccountFill>,
2197}
2198
2199#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2200#[serde(rename_all = "snake_case")]
2201pub enum PlatformMakerReputationTier {
2202 Probation,
2203 Bronze,
2204 Silver,
2205 Gold,
2206 Platinum,
2207}
2208
2209#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2210#[serde(deny_unknown_fields)]
2211pub struct PlatformMakerTierProgress {
2212 pub next_tier: Option<PlatformMakerReputationTier>,
2213 pub reputation_score_required: Option<u16>,
2214 pub reputation_score_remaining: u16,
2215 pub quote_requests_required: Option<String>,
2216 pub quote_requests_remaining: String,
2217 pub stake_atoms_required: Option<String>,
2218 pub stake_atoms_remaining: String,
2219 pub tenure_slots_required: Option<String>,
2220 pub tenure_slots_remaining: String,
2221}
2222
2223#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2227#[serde(deny_unknown_fields)]
2228pub struct PlatformMakerReputationResponse {
2229 pub schema_version: u16,
2230 pub contract_version: String,
2231 pub market_id: String,
2232 pub maker_id: String,
2233 pub wallet_address: String,
2234 pub active: bool,
2235 pub tier: PlatformMakerReputationTier,
2236 pub reputation_score: u16,
2237 pub total_quote_requests: String,
2238 pub successful_fills: String,
2239 pub missed_quote_requests: String,
2240 pub fill_rate_bps: u16,
2241 pub consecutive_misses: u16,
2242 pub lifetime_filled_quote_atoms: String,
2243 pub distinct_counterparties: u16,
2244 pub recent_average_latency_ms: u16,
2245 pub configured_minimum_spread_bps: u16,
2246 pub weighted_average_spread_bps: u16,
2247 pub stake_atoms: String,
2248 pub epoch_start_stake_atoms: String,
2249 pub epoch_slashed_atoms: String,
2250 pub epoch_slashed_bps: u16,
2251 pub lifetime_auto_slashed_atoms: String,
2252 pub registered_slot: String,
2253 pub last_active_slot: String,
2254 pub last_settled_slot: String,
2255 pub revoked_at_slot: Option<String>,
2256 pub tenure_slots: String,
2257 pub signed_quote_stream_eligible: bool,
2258 pub minimum_quote_interval_ms: Option<u16>,
2259 pub tier_progress: PlatformMakerTierProgress,
2260 pub server_time_ms: u64,
2261}
2262
2263#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2264#[serde(rename_all = "snake_case")]
2265pub enum PlatformMakerSide {
2266 Buy,
2267 Sell,
2268}
2269
2270#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2271#[serde(rename_all = "snake_case")]
2272pub enum PlatformOracleHealth {
2273 Fresh,
2274 Stale,
2275 Unknown,
2276}
2277
2278#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2280#[serde(deny_unknown_fields)]
2281pub struct PlatformMakerFirmOrderSummary {
2282 pub resting_orders: u32,
2283 pub bid_orders: u32,
2284 pub ask_orders: u32,
2285 pub bid_size_atoms: String,
2286 pub ask_size_atoms: String,
2287}
2288
2289#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2291#[serde(deny_unknown_fields)]
2292pub struct PlatformMakerSignedQuote {
2293 pub side: PlatformMakerSide,
2294 pub price_atoms: String,
2295 pub size_atoms: String,
2296 pub nonce: String,
2297 pub issued_at_ms: u64,
2298 pub expires_at_ms: u64,
2299}
2300
2301#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2303#[serde(deny_unknown_fields)]
2304pub struct PlatformMakerIntentStatus {
2305 pub active: bool,
2306 pub side: PlatformMakerSide,
2307 pub minimum_price_atoms: String,
2308 pub maximum_price_atoms: String,
2309 pub maximum_fill_size_atoms: String,
2310 pub remaining_fill_size_atoms: String,
2312 pub minimum_spread_bps: u16,
2313 pub stake_atoms: String,
2314}
2315
2316#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2318#[serde(deny_unknown_fields)]
2319pub struct PlatformMakerSignedQuoteLane {
2320 pub eligible: bool,
2321 pub live_quotes: Vec<PlatformMakerSignedQuote>,
2322}
2323
2324#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2325#[serde(deny_unknown_fields)]
2326pub struct PlatformMakerStrandLevel {
2327 pub price_atoms: Option<String>,
2329 pub size_atoms: String,
2330 pub remaining_size_atoms: String,
2331}
2332
2333#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2335#[serde(deny_unknown_fields)]
2336pub struct PlatformMakerStrandStatus {
2337 pub enabled: bool,
2338 pub async_only: bool,
2339 pub expired: bool,
2341 pub mid_price_atoms: String,
2342 pub tick_size_atoms: String,
2343 pub valid_until_slot: Option<String>,
2345 pub bids: Vec<PlatformMakerStrandLevel>,
2346 pub asks: Vec<PlatformMakerStrandLevel>,
2347 pub maximum_exposure_atoms: String,
2348 pub remaining_exposure_atoms: String,
2349}
2350
2351#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2353#[serde(deny_unknown_fields)]
2354pub struct PlatformMakerCurrentStatus {
2355 pub enabled: bool,
2356 pub async_only: bool,
2357 pub expired: bool,
2358 pub half_spread_bps: u16,
2359 pub band_step_bps: u16,
2360 pub maximum_confidence_bps: u16,
2361 pub maximum_oracle_age_seconds: u32,
2362 pub sync_spread_bps: u16,
2363 pub valid_until_slot: Option<String>,
2365 pub bid_depth_atoms: Vec<String>,
2366 pub ask_depth_atoms: Vec<String>,
2367 pub maximum_exposure_atoms: String,
2368 pub remaining_exposure_atoms: String,
2369 pub oracle_health: PlatformOracleHealth,
2371}
2372
2373#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2375#[serde(deny_unknown_fields)]
2376pub struct PlatformMakerDeadManGuard {
2377 pub session_public_key: String,
2378 pub status: PlatformDeadManStatus,
2379 pub timeout_ms: u64,
2380 pub heartbeat_deadline_ms: u64,
2381 pub updated_at_ms: u64,
2382}
2383
2384#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2389#[serde(deny_unknown_fields)]
2390pub struct PlatformMakerStatusResponse {
2391 pub schema_version: u16,
2392 pub contract_version: String,
2393 pub market_id: String,
2394 pub maker_id: String,
2395 pub wallet_address: String,
2396 pub server_time_ms: u64,
2397 pub current_slot: String,
2398 pub firm_orders: PlatformMakerFirmOrderSummary,
2399 pub intent: Option<PlatformMakerIntentStatus>,
2400 pub signed_quotes: PlatformMakerSignedQuoteLane,
2401 pub strands: Vec<PlatformMakerStrandStatus>,
2402 pub currents: Vec<PlatformMakerCurrentStatus>,
2403 pub dead_man_guards: Vec<PlatformMakerDeadManGuard>,
2404 pub active_products: u16,
2407}
2408
2409#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2412#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
2413pub enum PlatformMakerStrandPrepareRequest {
2414 Upsert {
2415 maker_wallet: String,
2416 enabled: bool,
2417 async_only: bool,
2418 sync_spread_ticks: u16,
2419 mid_price_atoms: String,
2420 #[serde(alias = "max_exposure_base_lots")]
2421 max_exposure_base_atoms: String,
2422 bid_offsets_ticks: Vec<u16>,
2423 ask_offsets_ticks: Vec<u16>,
2424 #[serde(alias = "bid_sizes_base_lots")]
2425 bid_sizes_base_atoms: Vec<String>,
2426 #[serde(alias = "ask_sizes_base_lots")]
2427 ask_sizes_base_atoms: Vec<String>,
2428 valid_until_slot: String,
2429 },
2430 Recenter {
2431 maker_wallet: String,
2432 new_mid_price_atoms: String,
2433 valid_until_slot: String,
2434 },
2435 SetEnabled {
2436 maker_wallet: String,
2437 enabled: bool,
2438 },
2439 Cancel {
2440 maker_wallet: String,
2441 },
2442}
2443
2444#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2447#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
2448pub enum PlatformMakerCurrentPrepareRequest {
2449 Upsert {
2450 maker_wallet: String,
2451 enabled: bool,
2452 async_only: bool,
2453 half_spread_bps: u16,
2454 band_step_bps: u16,
2455 max_conf_bps: u16,
2456 max_oracle_dev_bps: u16,
2457 max_oracle_age_secs: u32,
2458 sync_spread_bps: u16,
2459 max_exposure_base_atoms: String,
2460 bid_depth_base_atoms: Vec<String>,
2461 ask_depth_base_atoms: Vec<String>,
2462 valid_until_slot: String,
2463 },
2464 Cancel {
2465 maker_wallet: String,
2466 },
2467}
2468
2469#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2470#[serde(rename_all = "snake_case")]
2471pub enum PlatformMakerControlProduct {
2472 Strand,
2473 Current,
2474}
2475
2476#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2477#[serde(rename_all = "snake_case")]
2478pub enum PlatformMakerControlAction {
2479 StrandUpsert,
2480 StrandRecenter,
2481 StrandSetEnabled,
2482 StrandCancel,
2483 CurrentUpsert,
2484 CurrentCancel,
2485}
2486
2487#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2488#[serde(deny_unknown_fields)]
2489pub struct PlatformMakerControlPrepareResponse {
2490 pub schema_version: u16,
2491 pub contract_version: String,
2492 pub maker_control_id: String,
2493 pub market_id: String,
2494 pub maker_wallet: String,
2495 pub product: PlatformMakerControlProduct,
2496 pub action: PlatformMakerControlAction,
2497 pub transaction_base64: String,
2501 pub recent_blockhash: String,
2502 pub last_valid_block_height: u64,
2503 pub expires_at_ms: u64,
2504}
2505
2506#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2507#[serde(deny_unknown_fields)]
2508pub struct PlatformMakerControlSubmitRequest {
2509 pub maker_control_id: String,
2510 pub signed_transaction_base64: String,
2511 pub idempotency_key: String,
2512}
2513
2514#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2515#[serde(rename_all = "snake_case")]
2516pub enum PlatformMakerControlSubmissionStatus {
2517 Submitted,
2518}
2519
2520#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2521#[serde(deny_unknown_fields)]
2522pub struct PlatformMakerControlSubmitResponse {
2523 pub schema_version: u16,
2524 pub contract_version: String,
2525 pub maker_control_id: String,
2526 pub market_id: String,
2527 pub maker_wallet: String,
2528 pub product: PlatformMakerControlProduct,
2529 pub action: PlatformMakerControlAction,
2530 pub signature: String,
2531 pub status: PlatformMakerControlSubmissionStatus,
2532}
2533
2534#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2536#[serde(rename_all = "snake_case")]
2537pub enum PlatformMakerProduct {
2538 FirmOrder,
2539 Intent,
2540 Strand,
2541 Current,
2542}
2543
2544#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2547#[serde(deny_unknown_fields)]
2548pub struct PlatformMakerFill {
2549 pub fill_id: String,
2550 pub product: PlatformMakerProduct,
2551 pub side: PlatformTradeSide,
2552 pub price_atoms: String,
2553 pub size_atoms: String,
2554 pub fee_quote_atoms: String,
2555 pub fee_is_final: bool,
2556 pub settlement: PlatformSettlementState,
2557 pub executed_at_ms: u64,
2558 pub confirmed_at_ms: Option<u64>,
2559 pub transaction_id: Option<String>,
2560 pub realized_pnl_quote_atoms: String,
2561}
2562
2563#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2569#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2570pub enum PlatformMakerEvent {
2571 AuthChallenge {
2572 schema_version: u16,
2573 contract_version: String,
2574 market_id: String,
2575 wallet_address: String,
2576 challenge: String,
2577 server_time_ms: u64,
2578 expires_at_ms: u64,
2579 },
2580 MakerSnapshot {
2581 schema_version: u16,
2582 contract_version: String,
2583 market_id: String,
2584 wallet_address: String,
2585 stream_id: String,
2586 sequence: String,
2587 server_time_ms: u64,
2588 status: PlatformMakerStatusResponse,
2589 fills: Vec<PlatformMakerFill>,
2590 },
2591 MakerFill {
2592 schema_version: u16,
2593 contract_version: String,
2594 market_id: String,
2595 wallet_address: String,
2596 stream_id: String,
2597 sequence: String,
2598 previous_sequence: String,
2599 server_time_ms: u64,
2600 fill: PlatformMakerFill,
2601 },
2602 MakerStatus {
2603 schema_version: u16,
2604 contract_version: String,
2605 market_id: String,
2606 wallet_address: String,
2607 stream_id: String,
2608 sequence: String,
2609 previous_sequence: String,
2610 server_time_ms: u64,
2611 status: PlatformMakerStatusResponse,
2612 },
2613 Heartbeat {
2614 schema_version: u16,
2615 contract_version: String,
2616 market_id: String,
2617 wallet_address: String,
2618 stream_id: String,
2619 sequence: String,
2620 previous_sequence: String,
2621 server_time_ms: u64,
2622 },
2623}
2624
2625#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2626#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2627pub enum PlatformAccountEvent {
2628 AuthChallenge {
2629 schema_version: u16,
2630 contract_version: String,
2631 market_id: String,
2632 wallet_address: String,
2633 challenge: String,
2634 server_time_ms: u64,
2635 expires_at_ms: u64,
2636 },
2637 AccountSnapshot {
2638 schema_version: u16,
2639 contract_version: String,
2640 market_id: String,
2641 wallet_address: String,
2642 stream_id: String,
2643 sequence: String,
2644 server_time_ms: u64,
2645 orders: Vec<PlatformAccountOrder>,
2646 fills: Vec<PlatformAccountFill>,
2647 },
2648 OrdersSnapshot {
2649 schema_version: u16,
2650 contract_version: String,
2651 market_id: String,
2652 wallet_address: String,
2653 stream_id: String,
2654 sequence: String,
2655 previous_sequence: String,
2656 server_time_ms: u64,
2657 orders: Vec<PlatformAccountOrder>,
2658 },
2659 Fill {
2660 schema_version: u16,
2661 contract_version: String,
2662 market_id: String,
2663 wallet_address: String,
2664 stream_id: String,
2665 sequence: String,
2666 previous_sequence: String,
2667 server_time_ms: u64,
2668 fill: PlatformAccountFill,
2669 },
2670 Heartbeat {
2671 schema_version: u16,
2672 contract_version: String,
2673 market_id: String,
2674 wallet_address: String,
2675 stream_id: String,
2676 sequence: String,
2677 previous_sequence: String,
2678 server_time_ms: u64,
2679 },
2680}
2681
2682#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2683#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2684pub enum PlatformMarketDataEvent {
2685 BookSnapshot {
2686 schema_version: u16,
2687 contract_version: String,
2688 market_id: String,
2689 stream_id: String,
2690 sequence: String,
2691 server_time_ms: u64,
2692 snapshot_id: String,
2693 bids: Vec<PlatformBookLevel>,
2694 asks: Vec<PlatformBookLevel>,
2695 },
2696 BookDelta {
2697 schema_version: u16,
2698 contract_version: String,
2699 market_id: String,
2700 stream_id: String,
2701 sequence: String,
2702 previous_sequence: String,
2703 server_time_ms: u64,
2704 changes: Vec<PlatformBookChange>,
2705 },
2706 BestBidAsk {
2707 schema_version: u16,
2708 contract_version: String,
2709 market_id: String,
2710 stream_id: String,
2711 sequence: String,
2712 server_time_ms: u64,
2713 best_bid: Option<PlatformBookLevel>,
2714 best_ask: Option<PlatformBookLevel>,
2715 },
2716 Trade {
2717 schema_version: u16,
2718 contract_version: String,
2719 market_id: String,
2720 server_time_ms: u64,
2721 trade: PlatformTrade,
2722 },
2723 MarketStatus {
2724 schema_version: u16,
2725 contract_version: String,
2726 market_id: String,
2727 server_time_ms: u64,
2728 status: PlatformMarketState,
2729 },
2730 Heartbeat {
2731 schema_version: u16,
2732 contract_version: String,
2733 market_id: String,
2734 server_time_ms: u64,
2735 },
2736}
2737
2738#[cfg(test)]
2739mod tests {
2740 use super::*;
2741
2742 #[test]
2743 fn public_platform_fixtures_decode_strictly() {
2744 let discovery: PlatformDiscoveryResponse =
2745 serde_json::from_str(PLATFORM_CAPABILITIES_FIXTURE).unwrap();
2746 let service_status: PlatformServiceStatusResponse =
2747 serde_json::from_str(PLATFORM_SERVICE_STATUS_FIXTURE).unwrap();
2748 let graph = PlatformActionGraphResponse::foundation();
2749 let assets: PlatformAssetsResponse = serde_json::from_str(PLATFORM_ASSETS_FIXTURE).unwrap();
2750 let swap_quote: PlatformSwapQuoteResponse =
2751 serde_json::from_str(PLATFORM_SWAP_QUOTE_FIXTURE).unwrap();
2752 let markets: PlatformMarketsResponse =
2753 serde_json::from_str(PLATFORM_MARKETS_FIXTURE).unwrap();
2754 let book: PlatformBookSnapshotResponse =
2755 serde_json::from_str(PLATFORM_BOOK_FIXTURE).unwrap();
2756 let bbo: PlatformBestBidAskResponse = serde_json::from_str(PLATFORM_BBO_FIXTURE).unwrap();
2757 let fees: PlatformFeeScheduleResponse =
2758 serde_json::from_str(PLATFORM_FEES_FIXTURE).unwrap();
2759 let status: PlatformMarketStatusResponse =
2760 serde_json::from_str(PLATFORM_STATUS_FIXTURE).unwrap();
2761 let candles: PlatformCandlesResponse =
2762 serde_json::from_str(PLATFORM_CANDLES_FIXTURE).unwrap();
2763 let mark: PlatformMarkResponse = serde_json::from_str(PLATFORM_MARK_FIXTURE).unwrap();
2764 let execution_status: PlatformExecutionStatusResponse =
2765 serde_json::from_str(PLATFORM_EXECUTION_STATUS_FIXTURE).unwrap();
2766 let twaps: PlatformTwapsResponse = serde_json::from_str(PLATFORM_TWAPS_FIXTURE).unwrap();
2767 let twap_challenge: PlatformTwapChallengeResponse =
2768 serde_json::from_str(PLATFORM_TWAP_CHALLENGE_FIXTURE).unwrap();
2769 let twap_prepare: PlatformTwapPrepareResponse =
2770 serde_json::from_str(PLATFORM_TWAP_PREPARE_FIXTURE).unwrap();
2771 let twap_submit: PlatformTwapSubmitResponse =
2772 serde_json::from_str(PLATFORM_TWAP_SUBMIT_FIXTURE).unwrap();
2773 let portfolio_history: PlatformPortfolioHistoryResponse =
2774 serde_json::from_str(PLATFORM_PORTFOLIO_HISTORY_FIXTURE).unwrap();
2775 let portfolio: PlatformPortfolioResponse =
2776 serde_json::from_str(PLATFORM_PORTFOLIO_FIXTURE).unwrap();
2777 let rewards: PlatformRewardsResponse =
2778 serde_json::from_str(PLATFORM_REWARDS_FIXTURE).unwrap();
2779 let referrals: PlatformReferralsResponse =
2780 serde_json::from_str(PLATFORM_REFERRALS_FIXTURE).unwrap();
2781 let referral_link: PlatformReferralLinkResponse =
2782 serde_json::from_str(PLATFORM_REFERRAL_LINK_FIXTURE).unwrap();
2783 let referral_claim: PlatformReferralClaimResponse =
2784 serde_json::from_str(PLATFORM_REFERRAL_CLAIM_FIXTURE).unwrap();
2785 let vault_status: PlatformVaultStatusResponse =
2786 serde_json::from_str(PLATFORM_VAULT_STATUS_FIXTURE).unwrap();
2787 let vault_pause: PlatformVaultPausePrepareResponse =
2788 serde_json::from_str(PLATFORM_VAULT_PAUSE_PREPARE_FIXTURE).unwrap();
2789 let vault_setup: PlatformVaultSetupPrepareResponse =
2790 serde_json::from_str(PLATFORM_VAULT_SETUP_PREPARE_FIXTURE).unwrap();
2791 let vault_delegate: PlatformVaultDelegatePrepareResponse =
2792 serde_json::from_str(PLATFORM_VAULT_DELEGATE_PREPARE_FIXTURE).unwrap();
2793 let vault_policy: PlatformVaultPolicyPrepareResponse =
2794 serde_json::from_str(PLATFORM_VAULT_POLICY_PREPARE_FIXTURE).unwrap();
2795 let vault_deposit: PlatformVaultDepositPrepareResponse =
2796 serde_json::from_str(PLATFORM_VAULT_DEPOSIT_PREPARE_FIXTURE).unwrap();
2797 let vault_withdraw: PlatformVaultWithdrawPrepareResponse =
2798 serde_json::from_str(PLATFORM_VAULT_WITHDRAW_PREPARE_FIXTURE).unwrap();
2799 let vault_submit: PlatformVaultSubmitResponse =
2800 serde_json::from_str(PLATFORM_VAULT_SUBMIT_FIXTURE).unwrap();
2801 let bugs: PlatformBugsResponse = serde_json::from_str(PLATFORM_BUGS_FIXTURE).unwrap();
2802 let bug_submit: PlatformBugSubmitResponse =
2803 serde_json::from_str(PLATFORM_BUG_SUBMIT_FIXTURE).unwrap();
2804 let trades: PlatformTradesResponse = serde_json::from_str(PLATFORM_TRADES_FIXTURE).unwrap();
2805 let account: PlatformAccountSnapshotResponse =
2806 serde_json::from_str(PLATFORM_ACCOUNT_FIXTURE).unwrap();
2807 let maker_reputation: PlatformMakerReputationResponse =
2808 serde_json::from_str(PLATFORM_MAKER_REPUTATION_FIXTURE).unwrap();
2809 let maker_status: PlatformMakerStatusResponse =
2810 serde_json::from_str(PLATFORM_MAKER_STATUS_FIXTURE).unwrap();
2811 let maker_stream: PlatformMakerEvent =
2812 serde_json::from_str(PLATFORM_MAKER_STREAM_FIXTURE).unwrap();
2813 let twap_stream: PlatformTwapEvent =
2814 serde_json::from_str(PLATFORM_TWAP_STREAM_FIXTURE).unwrap();
2815 let execution_stream: PlatformExecutionEvent =
2816 serde_json::from_str(PLATFORM_EXECUTION_STREAM_FIXTURE).unwrap();
2817 let order_challenge: PlatformOrderChallengeResponse =
2818 serde_json::from_str(PLATFORM_ORDER_CHALLENGE_FIXTURE).unwrap();
2819 let order_prepare: PlatformOrderPrepareResponse =
2820 serde_json::from_str(PLATFORM_ORDER_PREPARE_FIXTURE).unwrap();
2821 let order_submit: PlatformOrderSubmitResponse =
2822 serde_json::from_str(PLATFORM_ORDER_SUBMIT_FIXTURE).unwrap();
2823 let order_status: PlatformOrderStatusResponse =
2824 serde_json::from_str(PLATFORM_ORDER_STATUS_FIXTURE).unwrap();
2825
2826 assert_eq!(discovery.schema_version, PLATFORM_SCHEMA_VERSION);
2827 assert_eq!(service_status.status, PlatformServiceState::Operational);
2828 assert_eq!(service_status.available_operations, 59);
2829 assert_eq!(graph.entry_operation_id, "platform.capabilities.read");
2830 assert_eq!(graph.operations.len(), 69);
2831 assert_eq!(maker_reputation.tier, PlatformMakerReputationTier::Gold);
2832 assert_eq!(maker_status.active_products, 3);
2833 match &maker_stream {
2834 PlatformMakerEvent::MakerSnapshot { status, fills, .. } => {
2835 assert_eq!(status.active_products, maker_status.active_products);
2836 assert_eq!(fills.len(), 1);
2837 assert_eq!(fills[0].product, PlatformMakerProduct::Strand);
2838 }
2839 other => panic!("maker stream fixture must be a snapshot, got {other:?}"),
2840 }
2841 match &twap_stream {
2842 PlatformTwapEvent::TwapsSnapshot {
2843 twaps: streamed, ..
2844 } => {
2845 assert_eq!(streamed, &twaps.twaps);
2846 }
2847 other => panic!("twap stream fixture must be a snapshot, got {other:?}"),
2848 }
2849 match &execution_stream {
2850 PlatformExecutionEvent::ExecutionsSnapshot {
2851 executions,
2852 unknown_execution_ids,
2853 ..
2854 } => {
2855 assert_eq!(executions.len(), 2);
2856 assert_eq!(executions[0].execution_id, execution_status.execution_id);
2857 assert_eq!(unknown_execution_ids.len(), 1);
2858 }
2859 other => panic!("execution stream fixture must be a snapshot, got {other:?}"),
2860 }
2861 assert_eq!(maker_status.strands.len(), 1);
2862 assert_eq!(maker_status.currents.len(), 1);
2863 assert!(maker_status
2864 .intent
2865 .as_ref()
2866 .is_some_and(|intent| intent.active));
2867 assert_eq!(portfolio.balances.len(), 2);
2868 assert_eq!(portfolio.positions.len(), 1);
2869 assert!(portfolio.valuation_complete);
2870 assert_eq!(portfolio.equity_usd_micros.as_deref(), Some("439989500"));
2871 assert!(graph
2872 .operations
2873 .iter()
2874 .any(|operation| operation.id == "twap.place.submit"));
2875 assert!(graph
2876 .operations
2877 .iter()
2878 .any(|operation| operation.id == "twap.cancel.submit"));
2879 assert_eq!(discovery.capabilities.len(), 5);
2880 assert!(!discovery.authority.accepts_private_keys);
2881 assert_eq!(assets.assets.len(), 2);
2882 assert_eq!(swap_quote.input_asset_id, assets.assets[0].asset_id);
2883 assert_eq!(swap_quote.output_asset_id, assets.assets[1].asset_id);
2884 assert_eq!(markets.markets.len(), 1);
2885 assert_eq!(markets.markets[0].base_asset_id, assets.assets[0].asset_id);
2886 assert_eq!(markets.markets[0].quote_asset_id, assets.assets[1].asset_id);
2887 assert_eq!(book.sequence, "42");
2888 assert_eq!(bbo.best_bid.unwrap().price_atoms, "149990000");
2889 assert_eq!(fees.maximum_immediate_execution_fee_bps, 10);
2890 assert_eq!(status.status, PlatformMarketState::Active);
2891 assert_eq!(candles.candles.len(), 2);
2892 assert_eq!(mark.price_atoms_per_base_unit.as_deref(), Some("149995000"));
2893 assert_eq!(execution_status.status, PlatformExecutionState::Confirmed);
2894 assert_eq!(
2895 execution_status.settlement,
2896 PlatformSettlementState::Confirmed
2897 );
2898 assert_eq!(twaps.twaps[0].fills.len(), 1);
2899 assert_eq!(twaps.twaps[0].slices_executed, 2);
2900 assert_eq!(twap_challenge.action, PlatformTwapControlAction::Place);
2901 assert_eq!(twap_prepare.twap_id, twap_challenge.twap_id);
2902 assert_eq!(twap_submit.twap_control_id, twap_prepare.twap_control_id);
2903 assert_eq!(portfolio_history.points.len(), 2);
2904 assert_eq!(rewards.standings.len(), 2);
2905 assert!(referrals.enabled);
2906 assert_eq!(referral_link.status, "pending_first_fill");
2907 assert_eq!(referral_claim.status, "requested");
2908 assert_eq!(vault_status.state, PlatformVaultState::Active);
2909 assert_eq!(
2910 vault_status.session.as_ref().unwrap().state,
2911 PlatformVaultSessionState::Active
2912 );
2913 assert!(vault_pause.paused);
2914 assert!(vault_pause.owner_signature_required);
2915 assert_eq!(vault_setup.mode, PlatformVaultSetupMode::Create);
2916 assert!(vault_setup.permanent);
2917 assert_eq!(vault_delegate.action, PlatformVaultDelegateAction::Revoke);
2918 assert!(vault_delegate.owner_signature_required);
2919 assert_eq!(
2920 vault_policy.withdrawal_access.mode,
2921 PlatformVaultWithdrawalMode::Restricted
2922 );
2923 assert!(vault_policy.owner_signature_required);
2924 assert_eq!(vault_deposit.amount_atoms, "10000000");
2925 assert!(vault_deposit.owner_signature_required);
2926 assert_eq!(vault_withdraw.amount_atoms, "5000000");
2927 assert!(vault_withdraw.owner_signature_required);
2928 assert!(vault_withdraw.sponsored);
2929 assert!(vault_withdraw.preparation_id.starts_with("vp_"));
2930 assert_eq!(vault_submit.action, PlatformVaultAction::Deposit);
2931 assert_eq!(
2932 vault_submit.status,
2933 PlatformVaultSubmissionStatus::Submitted
2934 );
2935 assert!(vault_submit.sponsored);
2936 assert_eq!(vault_submit.failure_code, None);
2937 assert_eq!(bugs.reports[0].status, PlatformBugStatus::Confirmed);
2938 assert_eq!(bug_submit.status, PlatformBugStatus::Pending);
2939 assert_eq!(trades.trades.len(), 1);
2940 assert_eq!(account.orders.len(), 1);
2941 assert_eq!(account.fills.len(), 1);
2942 assert_eq!(order_challenge.action, PlatformOrderAction::Place);
2943 assert_eq!(order_prepare.order_ids, order_challenge.order_ids);
2944 assert_eq!(order_submit.order_ids, order_challenge.order_ids);
2945 assert_eq!(order_status.order_control_id, order_submit.order_control_id);
2946 assert_eq!(order_status.status, PlatformOrderControlStatus::Submitting);
2947 }
2948
2949 #[test]
2950 fn public_platform_response_rejects_unreviewed_fields() {
2951 let mut value: serde_json::Value =
2952 serde_json::from_str(PLATFORM_CAPABILITIES_FIXTURE).unwrap();
2953 value
2954 .as_object_mut()
2955 .unwrap()
2956 .insert("unexpected_field".to_owned(), serde_json::Value::Bool(true));
2957 assert!(serde_json::from_value::<PlatformDiscoveryResponse>(value).is_err());
2958
2959 let mut account_event: serde_json::Value =
2960 serde_json::from_str(PLATFORM_ACCOUNT_FIXTURE).unwrap();
2961 let event = account_event.as_object_mut().unwrap();
2962 event.insert("type".to_owned(), serde_json::json!("account_snapshot"));
2963 event.insert(
2964 "stream_id".to_owned(),
2965 serde_json::json!("account_stream_66666666666666666666666666666666"),
2966 );
2967 event.insert("sequence".to_owned(), serde_json::json!("1"));
2968 event.insert("unexpected_field".to_owned(), serde_json::json!(true));
2969 assert!(serde_json::from_value::<PlatformAccountEvent>(account_event).is_err());
2970 }
2971
2972 #[test]
2973 fn platform_graph_availability_is_projected_from_live_capabilities() {
2974 let mut graph = PlatformActionGraphResponse::foundation();
2975 let live = std::collections::BTreeSet::from([
2976 "platform.discover".to_owned(),
2977 "graphs.read".to_owned(),
2978 "orders.replace".to_owned(),
2979 ]);
2980
2981 graph.project_availability(&live);
2982
2983 for operation in &graph.operations {
2984 assert_eq!(
2985 operation.available,
2986 live.contains(&operation.capability_id),
2987 "operation {} did not follow capability {}",
2988 operation.id,
2989 operation.capability_id,
2990 );
2991 }
2992 assert!(graph
2993 .workflows
2994 .iter()
2995 .flat_map(|workflow| &workflow.nodes)
2996 .filter(|node| node.kind != PlatformActionKind::ExternalSignature)
2997 .all(|node| {
2998 node.available
2999 == node
3000 .capability_id
3001 .as_ref()
3002 .is_some_and(|capability_id| live.contains(capability_id))
3003 }));
3004 assert!(graph
3005 .workflows
3006 .iter()
3007 .flat_map(|workflow| &workflow.nodes)
3008 .filter(|node| node.kind == PlatformActionKind::ExternalSignature)
3009 .all(|node| node.available));
3010 }
3011
3012 #[test]
3013 fn atomic_order_batch_request_is_strict_and_typed() {
3014 let request: PlatformOrderChallengeRequest = serde_json::from_value(serde_json::json!({
3015 "action": "batch",
3016 "owner_wallet": "11111111111111111111111111111111",
3017 "session_public_key": "22222222222222222222222222222222",
3018 "operations": [
3019 {
3020 "action": "cancel",
3021 "order_id": "order_11111111111111111111111111111111"
3022 },
3023 {
3024 "action": "replace",
3025 "order_id": "order_22222222222222222222222222222222",
3026 "account_sequence": "8",
3027 "client_order_id": "replacement-8",
3028 "side": "sell",
3029 "order_type": "post_only",
3030 "limit_price_atoms": "151000000",
3031 "size_atoms": "2000000"
3032 }
3033 ]
3034 }))
3035 .unwrap();
3036 let PlatformOrderChallengeRequest::Batch { operations, .. } = request else {
3037 panic!("expected batch request");
3038 };
3039 assert_eq!(operations.len(), 2);
3040 assert!(matches!(
3041 &operations[1],
3042 PlatformOrderBatchOperation::Replace { account_sequence: Some(sequence), .. }
3043 if sequence == "8"
3044 ));
3045
3046 let place: PlatformOrderChallengeRequest = serde_json::from_value(serde_json::json!({
3050 "action": "place",
3051 "owner_wallet": "11111111111111111111111111111111",
3052 "session_public_key": "22222222222222222222222222222222",
3053 "client_order_id": "first-order",
3054 "side": "buy",
3055 "order_type": "post_only",
3056 "limit_price_atoms": "150000000",
3057 "size_atoms": "1000000"
3058 }))
3059 .unwrap();
3060 assert!(matches!(
3061 place,
3062 PlatformOrderChallengeRequest::Place {
3063 account_sequence: None,
3064 ..
3065 }
3066 ));
3067 assert!(!serde_json::to_string(&place)
3068 .unwrap()
3069 .contains("account_sequence"));
3070
3071 assert!(
3072 serde_json::from_value::<PlatformOrderChallengeRequest>(serde_json::json!({
3073 "action": "batch",
3074 "owner_wallet": "11111111111111111111111111111111",
3075 "session_public_key": "22222222222222222222222222222222",
3076 "operations": [{
3077 "action": "cancel",
3078 "order_id": "order_11111111111111111111111111111111",
3079 "implementation": "hidden"
3080 }]
3081 }))
3082 .is_err()
3083 );
3084 }
3085
3086 #[test]
3087 fn persistent_order_commands_are_strict_and_explicit_about_self_trade_policy() {
3088 let frame: PlatformOrderCommandClientFrame = serde_json::from_value(serde_json::json!({
3089 "type": "command",
3090 "request_id": "agent-1",
3091 "sequence": "1",
3092 "command": {
3093 "type": "challenge",
3094 "self_trade_prevention": "cancel_maker",
3095 "request": {
3096 "action": "cancel_all",
3097 "owner_wallet": "11111111111111111111111111111111",
3098 "session_public_key": "22222222222222222222222222222222"
3099 }
3100 }
3101 }))
3102 .unwrap();
3103 assert!(matches!(
3104 frame,
3105 PlatformOrderCommandClientFrame::Command {
3106 command: PlatformOrderCommand::Challenge {
3107 self_trade_prevention: PlatformSelfTradePrevention::CancelMaker,
3108 ..
3109 },
3110 ..
3111 }
3112 ));
3113 assert!(
3114 serde_json::from_value::<PlatformOrderCommandClientFrame>(serde_json::json!({
3115 "type": "command",
3116 "request_id": "agent-1",
3117 "sequence": "1",
3118 "command": {
3119 "type": "challenge",
3120 "request": {
3121 "action": "cancel_all",
3122 "owner_wallet": "11111111111111111111111111111111",
3123 "session_public_key": "22222222222222222222222222222222"
3124 }
3125 }
3126 }))
3127 .is_err()
3128 );
3129 }
3130
3131 #[test]
3132 fn prepare_requests_accept_a_signed_challenge_or_the_operation_itself() {
3133 let signed: PlatformOrderPrepareRequest = serde_json::from_value(serde_json::json!({
3134 "challenge_id": "oc_0123456789abcdef0123456789abcdef",
3135 "authorization_signature": "1111",
3136 }))
3137 .unwrap();
3138 assert!(matches!(signed, PlatformOrderPrepareRequest::Authorized(_)));
3139 let direct: PlatformOrderPrepareRequest = serde_json::from_value(serde_json::json!({
3140 "action": "cancel_all",
3141 "owner_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3142 "session_public_key": "9Uu7cLBgfMk233BAjMvTS8XJy6KbZK7oQ7NXuCTi3Fg2",
3143 }))
3144 .unwrap();
3145 assert!(matches!(
3146 direct,
3147 PlatformOrderPrepareRequest::Direct(PlatformOrderChallengeRequest::CancelAll { .. })
3148 ));
3149 assert!(
3151 serde_json::from_value::<PlatformOrderPrepareRequest>(serde_json::json!({
3152 "challenge_id": "oc_0123456789abcdef0123456789abcdef",
3153 "authorization_signature": "1111",
3154 "extra": true,
3155 }))
3156 .is_err()
3157 );
3158 let twap: PlatformTwapPrepareRequest = serde_json::from_value(serde_json::json!({
3159 "action": "cancel",
3160 "owner_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3161 "session_public_key": "9Uu7cLBgfMk233BAjMvTS8XJy6KbZK7oQ7NXuCTi3Fg2",
3162 "twap_id": "twap_0123456789abcdef0123456789abcdef",
3163 }))
3164 .unwrap();
3165 assert!(matches!(twap, PlatformTwapPrepareRequest::Direct(_)));
3166 let execution: crate::ExecutionPrepareRequest = serde_json::from_value(serde_json::json!({
3167 "quote_id": "quote_0123456789abcdef0123456789abcdef",
3168 "owner_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3169 "session_public_key": "9Uu7cLBgfMk233BAjMvTS8XJy6KbZK7oQ7NXuCTi3Fg2",
3170 }))
3171 .unwrap();
3172 assert!(matches!(
3173 execution,
3174 crate::ExecutionPrepareRequest::Direct(_)
3175 ));
3176 }
3177
3178 #[test]
3179 fn maker_control_requests_are_tagged_exact_and_amount_safe() {
3180 let strand_upsert: PlatformMakerStrandPrepareRequest =
3181 serde_json::from_value(serde_json::json!({
3182 "action": "upsert",
3183 "maker_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3184 "enabled": true,
3185 "async_only": false,
3186 "sync_spread_ticks": 1,
3187 "mid_price_atoms": "123000000",
3188 "max_exposure_base_atoms": "1000000",
3189 "bid_offsets_ticks": vec![1; 16],
3190 "ask_offsets_ticks": vec![1; 16],
3191 "bid_sizes_base_atoms": vec!["1"; 16],
3192 "ask_sizes_base_atoms": vec!["1"; 16],
3193 "valid_until_slot": "0"
3194 }))
3195 .unwrap();
3196 let serialized = serde_json::to_value(&strand_upsert).unwrap();
3197 assert_eq!(serialized["max_exposure_base_atoms"], "1000000");
3198 assert!(serialized.get("max_exposure_base_lots").is_none());
3199
3200 let legacy_strand: PlatformMakerStrandPrepareRequest =
3203 serde_json::from_value(serde_json::json!({
3204 "action": "upsert",
3205 "maker_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3206 "enabled": true,
3207 "async_only": false,
3208 "sync_spread_ticks": 1,
3209 "mid_price_atoms": "123000000",
3210 "max_exposure_base_lots": "1000000",
3211 "bid_offsets_ticks": vec![1; 16],
3212 "ask_offsets_ticks": vec![1; 16],
3213 "bid_sizes_base_lots": vec!["1"; 16],
3214 "ask_sizes_base_lots": vec!["1"; 16],
3215 "valid_until_slot": "0"
3216 }))
3217 .unwrap();
3218 assert_eq!(serde_json::to_value(legacy_strand).unwrap(), serialized);
3219
3220 let strand: PlatformMakerStrandPrepareRequest = serde_json::from_value(serde_json::json!({
3221 "action": "recenter",
3222 "maker_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3223 "new_mid_price_atoms": "123000000",
3224 "valid_until_slot": "0"
3225 }))
3226 .unwrap();
3227 assert!(matches!(
3228 strand,
3229 PlatformMakerStrandPrepareRequest::Recenter { .. }
3230 ));
3231
3232 let current: PlatformMakerCurrentPrepareRequest =
3233 serde_json::from_value(serde_json::json!({
3234 "action": "cancel",
3235 "maker_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL"
3236 }))
3237 .unwrap();
3238 assert!(matches!(
3239 current,
3240 PlatformMakerCurrentPrepareRequest::Cancel { .. }
3241 ));
3242 assert!(
3243 serde_json::from_value::<PlatformMakerCurrentPrepareRequest>(serde_json::json!({
3244 "action": "cancel",
3245 "maker_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3246 "oracle_price": 123.45
3247 }))
3248 .is_err()
3249 );
3250 }
3251}