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)]
1225 pub market_id: Option<String>,
1226 #[serde(default)]
1229 pub expires_at_ms: Option<u64>,
1230 #[serde(default)]
1232 pub minimum_interval_seconds: Option<u32>,
1233 #[serde(default)]
1235 pub maximum_tolerance_bps: Option<u16>,
1236 #[serde(default)]
1239 pub spending_limits: Vec<PlatformVaultSpendingLimit>,
1240}
1241
1242#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1245#[serde(deny_unknown_fields)]
1246pub struct PlatformVaultSetupPrepareResponse {
1247 pub schema_version: u16,
1248 pub contract_version: String,
1249 pub server_time_ms: u64,
1250 pub wallet_address: String,
1251 pub session_public_key: String,
1252 pub market_id: Option<String>,
1254 pub mode: PlatformVaultSetupMode,
1255 pub expires_at_ms: Option<u64>,
1256 pub permanent: bool,
1257 pub minimum_interval_seconds: u32,
1259 pub maximum_tolerance_bps: u16,
1260 pub spending_limits: Vec<PlatformVaultSpendingLimit>,
1261 pub transaction_base64: String,
1262 pub recent_blockhash: String,
1263 pub owner_signature_required: bool,
1264 pub preparation_id: String,
1268 pub sponsored: bool,
1272 pub submit_by_ms: u64,
1274}
1275
1276#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1277#[serde(rename_all = "snake_case")]
1278pub enum PlatformVaultDelegateAction {
1279 Revoke,
1280}
1281
1282#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1283#[serde(deny_unknown_fields)]
1284pub struct PlatformVaultDelegatePrepareRequest {
1285 pub wallet_address: String,
1286 pub session_public_key: String,
1287 pub action: PlatformVaultDelegateAction,
1288}
1289
1290#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1293#[serde(deny_unknown_fields)]
1294pub struct PlatformVaultDelegatePrepareResponse {
1295 pub schema_version: u16,
1296 pub contract_version: String,
1297 pub server_time_ms: u64,
1298 pub wallet_address: String,
1299 pub session_public_key: String,
1300 pub action: PlatformVaultDelegateAction,
1301 pub transaction_base64: String,
1302 pub recent_blockhash: String,
1303 pub owner_signature_required: bool,
1304 pub preparation_id: String,
1308 pub sponsored: bool,
1312 pub submit_by_ms: u64,
1314}
1315
1316#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1317#[serde(deny_unknown_fields)]
1318pub struct PlatformVaultPolicyPrepareRequest {
1319 pub wallet_address: String,
1320 pub withdrawal_access: PlatformVaultWithdrawalAccess,
1321}
1322
1323#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1326#[serde(deny_unknown_fields)]
1327pub struct PlatformVaultPolicyPrepareResponse {
1328 pub schema_version: u16,
1329 pub contract_version: String,
1330 pub server_time_ms: u64,
1331 pub wallet_address: String,
1332 pub withdrawal_access: PlatformVaultWithdrawalAccess,
1333 pub transaction_base64: String,
1334 pub recent_blockhash: String,
1335 pub owner_signature_required: bool,
1336 pub preparation_id: String,
1340 pub sponsored: bool,
1344 pub submit_by_ms: u64,
1346}
1347
1348#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1349#[serde(deny_unknown_fields)]
1350pub struct PlatformVaultDepositPrepareRequest {
1351 pub wallet_address: String,
1352 pub market_id: String,
1353 pub asset_id: String,
1354 pub amount_atoms: String,
1355 #[serde(default)]
1360 pub session_public_key: Option<String>,
1361}
1362
1363#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1366#[serde(deny_unknown_fields)]
1367pub struct PlatformVaultDepositPrepareResponse {
1368 pub schema_version: u16,
1369 pub contract_version: String,
1370 pub server_time_ms: u64,
1371 pub wallet_address: String,
1372 pub market_id: String,
1373 pub asset_id: String,
1374 pub amount_atoms: String,
1375 pub network_cost_atoms: String,
1381 pub session_public_key: Option<String>,
1383 pub registers_session: bool,
1387 pub transaction_base64: String,
1388 pub recent_blockhash: String,
1389 pub owner_signature_required: bool,
1390 pub preparation_id: String,
1394 pub sponsored: bool,
1398 pub submit_by_ms: u64,
1400}
1401
1402#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1403#[serde(deny_unknown_fields)]
1404pub struct PlatformVaultWithdrawPrepareRequest {
1405 pub wallet_address: String,
1406 pub market_id: String,
1407 pub asset_id: String,
1408 pub destination_wallet_address: String,
1409 pub amount_atoms: String,
1410}
1411
1412#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1415#[serde(deny_unknown_fields)]
1416pub struct PlatformVaultWithdrawPrepareResponse {
1417 pub schema_version: u16,
1418 pub contract_version: String,
1419 pub server_time_ms: u64,
1420 pub wallet_address: String,
1421 pub market_id: String,
1422 pub asset_id: String,
1423 pub destination_wallet_address: String,
1424 pub amount_atoms: String,
1425 pub transaction_base64: String,
1426 pub recent_blockhash: String,
1427 pub owner_signature_required: bool,
1428 pub preparation_id: String,
1432 pub sponsored: bool,
1436 pub submit_by_ms: u64,
1438}
1439
1440#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1442#[serde(rename_all = "snake_case")]
1443pub enum PlatformVaultAction {
1444 Setup,
1445 Deposit,
1446 Withdraw,
1447 Delegate,
1448 Policy,
1449 Pause,
1450}
1451
1452#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1453#[serde(rename_all = "snake_case")]
1454pub enum PlatformVaultSubmissionStatus {
1455 Submitted,
1457 Confirmed,
1458 Failed,
1459}
1460
1461#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1466#[serde(deny_unknown_fields)]
1467pub struct PlatformVaultSubmitRequest {
1468 pub preparation_id: String,
1469 pub signed_transaction_base64: String,
1470 pub idempotency_key: String,
1471}
1472
1473#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1475#[serde(deny_unknown_fields)]
1476pub struct PlatformVaultSubmitResponse {
1477 pub schema_version: u16,
1478 pub contract_version: String,
1479 pub preparation_id: String,
1480 pub action: PlatformVaultAction,
1481 pub wallet_address: String,
1482 pub sponsored: bool,
1483 pub signature: String,
1484 pub status: PlatformVaultSubmissionStatus,
1485 pub failure_code: Option<String>,
1487 pub updated_at_ms: u64,
1488}
1489
1490#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1491#[serde(deny_unknown_fields)]
1492pub struct PlatformRewardStanding {
1493 pub rank: u32,
1494 pub wallet_address: String,
1495 pub points: String,
1496}
1497
1498#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1499#[serde(deny_unknown_fields)]
1500pub struct PlatformOwnerRewards {
1501 pub wallet_address: String,
1502 pub rank: Option<u32>,
1503 pub points: String,
1504 pub trading_points: String,
1505 pub making_points: String,
1506 pub bug_points: String,
1507 pub referral_points: String,
1508}
1509
1510#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1511#[serde(deny_unknown_fields)]
1512pub struct PlatformRewardsResponse {
1513 pub schema_version: u16,
1514 pub contract_version: String,
1515 pub server_time_ms: u64,
1516 pub season: String,
1517 pub total_wallets: u32,
1518 pub owner: Option<PlatformOwnerRewards>,
1519 pub standings: Vec<PlatformRewardStanding>,
1520}
1521
1522#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1523#[serde(deny_unknown_fields)]
1524pub struct PlatformReferralsResponse {
1525 pub schema_version: u16,
1526 pub contract_version: String,
1527 pub server_time_ms: u64,
1528 pub wallet_address: String,
1529 pub enabled: bool,
1530 pub cash_rewards_enabled: bool,
1531 pub referral_code: Option<String>,
1532 pub referred_wallets: u32,
1533 pub referral_points: String,
1534 pub referred_by: Option<String>,
1535 pub referral_locked: bool,
1536 pub cash_accrued_atoms: String,
1537 pub cash_paid_atoms: String,
1538 pub cash_claimable_atoms: String,
1539}
1540
1541#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1542#[serde(deny_unknown_fields)]
1543pub struct PlatformReferralLinkRequest {
1544 pub wallet_address: String,
1545 pub referral_code: String,
1546 pub authorization_signature: String,
1547}
1548
1549#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1550#[serde(deny_unknown_fields)]
1551pub struct PlatformReferralLinkResponse {
1552 pub schema_version: u16,
1553 pub contract_version: String,
1554 pub server_time_ms: u64,
1555 pub wallet_address: String,
1556 pub referral_code: String,
1557 pub status: String,
1558}
1559
1560#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1561#[serde(deny_unknown_fields)]
1562pub struct PlatformReferralClaimRequest {
1563 pub wallet_address: String,
1564 pub payout_wallet_address: Option<String>,
1565 pub authorization_signature: String,
1566}
1567
1568#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1569#[serde(deny_unknown_fields)]
1570pub struct PlatformReferralClaimResponse {
1571 pub schema_version: u16,
1572 pub contract_version: String,
1573 pub server_time_ms: u64,
1574 pub wallet_address: String,
1575 pub payout_wallet_address: String,
1576 pub claimable_atoms: String,
1577 pub status: String,
1578}
1579
1580#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1581#[serde(rename_all = "snake_case")]
1582pub enum PlatformBugStatus {
1583 Pending,
1584 Confirmed,
1585 Rejected,
1586}
1587
1588#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1589#[serde(deny_unknown_fields)]
1590pub struct PlatformBugReport {
1591 pub bug_id: String,
1592 pub status: PlatformBugStatus,
1593 pub severity: u8,
1594 pub points: String,
1595 pub created_at_ms: u64,
1596 pub triaged_at_ms: Option<u64>,
1597 pub completed_at_ms: Option<u64>,
1598}
1599
1600#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1601#[serde(deny_unknown_fields)]
1602pub struct PlatformBugsResponse {
1603 pub schema_version: u16,
1604 pub contract_version: String,
1605 pub server_time_ms: u64,
1606 pub wallet_address: String,
1607 pub points: String,
1608 pub confirmed_reports: u32,
1609 pub reports: Vec<PlatformBugReport>,
1610}
1611
1612#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1613#[serde(deny_unknown_fields)]
1614pub struct PlatformBugSubmitRequest {
1615 pub owner_wallet: String,
1616 pub message: String,
1617 pub authorization_signature: String,
1620}
1621
1622#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1623#[serde(deny_unknown_fields)]
1624pub struct PlatformBugSubmitResponse {
1625 pub schema_version: u16,
1626 pub contract_version: String,
1627 pub server_time_ms: u64,
1628 pub bug_id: String,
1629 pub status: PlatformBugStatus,
1630}
1631
1632#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1633#[serde(rename_all = "snake_case")]
1634pub enum PlatformTradeSide {
1635 Buy,
1636 Sell,
1637}
1638
1639#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1640#[serde(deny_unknown_fields)]
1641pub struct PlatformTrade {
1642 pub trade_id: String,
1643 pub side: PlatformTradeSide,
1644 pub price_atoms: String,
1645 pub size_atoms: String,
1646 pub executed_at_ms: u64,
1647}
1648
1649#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1650#[serde(deny_unknown_fields)]
1651pub struct PlatformTradesResponse {
1652 pub schema_version: u16,
1653 pub contract_version: String,
1654 pub market_id: String,
1655 pub server_time_ms: u64,
1656 pub trades: Vec<PlatformTrade>,
1657}
1658
1659#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1660#[serde(rename_all = "snake_case")]
1661pub enum PlatformOrderType {
1662 GoodUntilCancelled,
1663 ImmediateOrCancel,
1664 FillOrKill,
1665 PostOnly,
1666}
1667
1668#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1672#[serde(rename_all = "snake_case")]
1673pub enum PlatformOrderAction {
1674 Place,
1675 Cancel,
1676 CancelAll,
1677 Replace,
1680 Batch,
1683}
1684
1685#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1688#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
1689pub enum PlatformOrderBatchOperation {
1690 Place {
1691 #[serde(default, skip_serializing_if = "Option::is_none")]
1697 account_sequence: Option<String>,
1698 client_order_id: String,
1699 side: PlatformTradeSide,
1700 order_type: PlatformOrderType,
1701 limit_price_atoms: String,
1702 size_atoms: String,
1703 },
1704 Cancel {
1705 order_id: String,
1706 },
1707 Replace {
1708 order_id: String,
1709 #[serde(default, skip_serializing_if = "Option::is_none")]
1710 account_sequence: Option<String>,
1711 client_order_id: String,
1712 side: PlatformTradeSide,
1713 order_type: PlatformOrderType,
1714 limit_price_atoms: String,
1715 size_atoms: String,
1716 },
1717}
1718
1719#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1723#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
1724pub enum PlatformOrderChallengeRequest {
1725 Place {
1726 owner_wallet: String,
1727 session_public_key: String,
1728 #[serde(default, skip_serializing_if = "Option::is_none")]
1732 account_sequence: Option<String>,
1733 client_order_id: String,
1734 side: PlatformTradeSide,
1735 order_type: PlatformOrderType,
1736 limit_price_atoms: String,
1737 size_atoms: String,
1738 },
1739 Cancel {
1740 owner_wallet: String,
1741 session_public_key: String,
1742 order_id: String,
1743 },
1744 CancelAll {
1745 owner_wallet: String,
1746 session_public_key: String,
1747 },
1748 Replace {
1749 owner_wallet: String,
1750 session_public_key: String,
1751 order_id: String,
1752 #[serde(default, skip_serializing_if = "Option::is_none")]
1753 account_sequence: Option<String>,
1754 client_order_id: String,
1755 side: PlatformTradeSide,
1756 order_type: PlatformOrderType,
1757 limit_price_atoms: String,
1758 size_atoms: String,
1759 },
1760 Batch {
1761 owner_wallet: String,
1762 session_public_key: String,
1763 operations: Vec<PlatformOrderBatchOperation>,
1764 },
1765}
1766
1767#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1768#[serde(deny_unknown_fields)]
1769pub struct PlatformOrderChallengeResponse {
1770 pub schema_version: u16,
1771 pub contract_version: String,
1772 pub challenge_id: String,
1773 pub market_id: String,
1774 pub action: PlatformOrderAction,
1775 pub order_ids: Vec<String>,
1779 pub authorization_payload_base64: String,
1780 pub server_time_ms: u64,
1781 pub expires_at_ms: u64,
1782}
1783
1784#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1786#[serde(deny_unknown_fields)]
1787pub struct PlatformOrderPrepareAuthorization {
1788 pub challenge_id: String,
1789 #[serde(default, skip_serializing_if = "Option::is_none")]
1794 pub authorization_signature: Option<String>,
1795}
1796
1797#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1803#[serde(untagged)]
1804pub enum PlatformOrderPrepareRequest {
1805 Authorized(PlatformOrderPrepareAuthorization),
1806 Direct(PlatformOrderChallengeRequest),
1807}
1808
1809#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1810#[serde(deny_unknown_fields)]
1811pub struct PlatformOrderPrepareResponse {
1812 pub schema_version: u16,
1813 pub contract_version: String,
1814 pub order_control_id: String,
1815 pub market_id: String,
1816 pub action: PlatformOrderAction,
1817 pub order_ids: Vec<String>,
1818 pub transaction_base64: String,
1821 pub recent_blockhash: String,
1822 pub last_valid_block_height: u64,
1823 pub expires_at_ms: u64,
1824}
1825
1826#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1827#[serde(deny_unknown_fields)]
1828pub struct PlatformOrderSubmitRequest {
1829 pub order_control_id: String,
1830 pub signed_transaction_base64: String,
1831 pub idempotency_key: String,
1832}
1833
1834#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1835#[serde(rename_all = "snake_case")]
1836pub enum PlatformOrderSubmissionStatus {
1837 Submitted,
1838}
1839
1840#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1841#[serde(deny_unknown_fields)]
1842pub struct PlatformOrderSubmitResponse {
1843 pub schema_version: u16,
1844 pub contract_version: String,
1845 pub order_control_id: String,
1846 pub market_id: String,
1847 pub action: PlatformOrderAction,
1848 pub order_ids: Vec<String>,
1849 pub signature: String,
1850 pub status: PlatformOrderSubmissionStatus,
1851}
1852
1853#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1854#[serde(deny_unknown_fields)]
1855pub struct PlatformOrderStatusRequest {
1856 pub order_control_id: String,
1857 pub idempotency_key: String,
1858}
1859
1860#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1861#[serde(rename_all = "snake_case")]
1862pub enum PlatformOrderControlStatus {
1863 Submitting,
1864 Submitted,
1865 Failed,
1866}
1867
1868#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1869#[serde(deny_unknown_fields)]
1870pub struct PlatformOrderStatusResponse {
1871 pub schema_version: u16,
1872 pub contract_version: String,
1873 pub order_control_id: String,
1874 pub market_id: String,
1875 pub action: PlatformOrderAction,
1876 pub order_ids: Vec<String>,
1877 pub signature: String,
1878 pub status: PlatformOrderControlStatus,
1879 pub failure_code: Option<String>,
1880 pub updated_at_ms: u64,
1881}
1882
1883#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1887#[serde(rename_all = "snake_case")]
1888pub enum PlatformSelfTradePrevention {
1889 CancelTaker,
1890 CancelMaker,
1891 CancelBoth,
1892 SkipOwnLiquidity,
1893}
1894
1895#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1899#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
1900pub enum PlatformOrderCommand {
1901 Probe {
1903 nonce: String,
1904 },
1905 Challenge {
1906 request: PlatformOrderChallengeRequest,
1907 self_trade_prevention: PlatformSelfTradePrevention,
1908 },
1909 Prepare {
1910 request: PlatformOrderPrepareRequest,
1911 },
1912 Submit {
1913 request: PlatformOrderSubmitRequest,
1914 },
1915 Status {
1916 request: PlatformOrderStatusRequest,
1917 },
1918 DeadManArm {
1919 timeout_ms: u64,
1920 request: PlatformOrderSubmitRequest,
1921 },
1922 DeadManStatus,
1923 DeadManHeartbeat,
1924 DeadManDisarm,
1925}
1926
1927#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1934#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
1935pub enum PlatformOrderCommandClientFrame {
1936 Authenticate {
1937 owner_wallet: String,
1938 session_public_key: String,
1939 signature: String,
1941 #[serde(default, skip_serializing_if = "Option::is_none")]
1944 batch_format: Option<PlatformOrderCommandBatchFormat>,
1945 },
1946 Command {
1947 request_id: String,
1948 sequence: String,
1949 command: PlatformOrderCommand,
1950 },
1951}
1952
1953#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1954#[serde(rename_all = "snake_case")]
1955pub enum PlatformOrderCommandBatchFormat {
1956 CompactV1,
1957}
1958
1959#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1963#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
1964pub enum PlatformOrderCommandBatchEvent {
1965 ProbeResult {
1966 request_id: String,
1967 nonce: String,
1968 },
1969 ChallengeResult {
1970 request_id: String,
1971 self_trade_prevention: PlatformSelfTradePrevention,
1972 prevented_order_ids: Vec<String>,
1973 effective_request: PlatformOrderChallengeRequest,
1974 response: PlatformOrderChallengeResponse,
1975 },
1976 PrepareResult {
1977 request_id: String,
1978 response: PlatformOrderPrepareResponse,
1979 },
1980 SubmitResult {
1981 request_id: String,
1982 response: PlatformOrderSubmitResponse,
1983 },
1984 StatusResult {
1985 request_id: String,
1986 response: PlatformOrderStatusResponse,
1987 },
1988 DeadManResult {
1989 request_id: String,
1990 state: PlatformDeadManState,
1991 },
1992 CommandError {
1993 request_id: String,
1994 error: PublicOperationError,
1995 },
1996 Heartbeat,
1997}
1998
1999#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2000#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2001pub enum PlatformOrderCommandServerFrame {
2002 EventBatch {
2003 schema_version: u16,
2004 contract_version: String,
2005 market_id: String,
2006 stream_id: String,
2007 first_sequence: String,
2008 previous_sequence: String,
2009 server_time_ms: u64,
2010 events: Vec<PlatformOrderCommandBatchEvent>,
2011 },
2012}
2013
2014#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2015#[serde(rename_all = "snake_case")]
2016pub enum PlatformDeadManStatus {
2017 Armed,
2018 Triggering,
2019 Triggered,
2020 Disarmed,
2021 Expired,
2022 Failed,
2023}
2024
2025#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2026#[serde(deny_unknown_fields)]
2027pub struct PlatformDeadManState {
2028 pub status: PlatformDeadManStatus,
2029 pub timeout_ms: u64,
2030 pub heartbeat_deadline_ms: u64,
2031 pub order_control_id: Option<String>,
2032 pub signature: Option<String>,
2033 pub failure_code: Option<String>,
2034 pub updated_at_ms: u64,
2035}
2036
2037#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2043#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2044pub enum PlatformOrderCommandEvent {
2045 AuthChallenge {
2046 schema_version: u16,
2047 contract_version: String,
2048 market_id: String,
2049 challenge: String,
2050 server_time_ms: u64,
2051 expires_at_ms: u64,
2052 },
2053 Ready {
2054 schema_version: u16,
2055 contract_version: String,
2056 market_id: String,
2057 stream_id: String,
2058 sequence: String,
2059 server_time_ms: u64,
2060 },
2061 ProbeResult {
2062 schema_version: u16,
2063 contract_version: String,
2064 market_id: String,
2065 stream_id: String,
2066 sequence: String,
2067 previous_sequence: String,
2068 request_id: String,
2069 nonce: String,
2070 server_time_ms: u64,
2071 },
2072 ChallengeResult {
2073 schema_version: u16,
2074 contract_version: String,
2075 market_id: String,
2076 stream_id: String,
2077 sequence: String,
2078 previous_sequence: String,
2079 request_id: String,
2080 self_trade_prevention: PlatformSelfTradePrevention,
2081 prevented_order_ids: Vec<String>,
2082 effective_request: PlatformOrderChallengeRequest,
2083 response: PlatformOrderChallengeResponse,
2084 server_time_ms: u64,
2085 },
2086 PrepareResult {
2087 schema_version: u16,
2088 contract_version: String,
2089 market_id: String,
2090 stream_id: String,
2091 sequence: String,
2092 previous_sequence: String,
2093 request_id: String,
2094 response: PlatformOrderPrepareResponse,
2095 server_time_ms: u64,
2096 },
2097 SubmitResult {
2098 schema_version: u16,
2099 contract_version: String,
2100 market_id: String,
2101 stream_id: String,
2102 sequence: String,
2103 previous_sequence: String,
2104 request_id: String,
2105 response: PlatformOrderSubmitResponse,
2106 server_time_ms: u64,
2107 },
2108 StatusResult {
2109 schema_version: u16,
2110 contract_version: String,
2111 market_id: String,
2112 stream_id: String,
2113 sequence: String,
2114 previous_sequence: String,
2115 request_id: String,
2116 response: PlatformOrderStatusResponse,
2117 server_time_ms: u64,
2118 },
2119 DeadManResult {
2120 schema_version: u16,
2121 contract_version: String,
2122 market_id: String,
2123 stream_id: String,
2124 sequence: String,
2125 previous_sequence: String,
2126 request_id: String,
2127 state: PlatformDeadManState,
2128 server_time_ms: u64,
2129 },
2130 CommandError {
2131 schema_version: u16,
2132 contract_version: String,
2133 market_id: String,
2134 stream_id: String,
2135 sequence: String,
2136 previous_sequence: String,
2137 request_id: String,
2138 error: PublicOperationError,
2139 server_time_ms: u64,
2140 },
2141 Heartbeat {
2142 schema_version: u16,
2143 contract_version: String,
2144 market_id: String,
2145 stream_id: String,
2146 sequence: String,
2147 previous_sequence: String,
2148 server_time_ms: u64,
2149 },
2150}
2151
2152#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2153#[serde(deny_unknown_fields)]
2154pub struct PlatformAccountOrder {
2155 pub order_id: String,
2156 pub side: PlatformTradeSide,
2157 pub order_type: PlatformOrderType,
2158 pub state: PlatformOrderState,
2159 pub limit_price_atoms: String,
2160 pub original_size_atoms: String,
2161 pub remaining_size_atoms: String,
2162}
2163
2164#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2165#[serde(deny_unknown_fields)]
2166pub struct PlatformAccountFill {
2167 pub fill_id: String,
2168 pub side: PlatformTradeSide,
2169 pub price_atoms: String,
2170 pub size_atoms: String,
2171 pub fee_quote_atoms: String,
2172 pub fee_is_final: bool,
2173 pub settlement: PlatformSettlementState,
2174 pub executed_at_ms: u64,
2175 pub confirmed_at_ms: Option<u64>,
2176 pub transaction_id: Option<String>,
2177 pub realized_pnl_quote_atoms: String,
2178}
2179
2180#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2181#[serde(deny_unknown_fields)]
2182pub struct PlatformAccountSnapshotResponse {
2183 pub schema_version: u16,
2184 pub contract_version: String,
2185 pub market_id: String,
2186 pub wallet_address: String,
2187 pub server_time_ms: u64,
2188 pub orders: Vec<PlatformAccountOrder>,
2189 pub fills: Vec<PlatformAccountFill>,
2190}
2191
2192#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2193#[serde(rename_all = "snake_case")]
2194pub enum PlatformMakerReputationTier {
2195 Probation,
2196 Bronze,
2197 Silver,
2198 Gold,
2199 Platinum,
2200}
2201
2202#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2203#[serde(deny_unknown_fields)]
2204pub struct PlatformMakerTierProgress {
2205 pub next_tier: Option<PlatformMakerReputationTier>,
2206 pub reputation_score_required: Option<u16>,
2207 pub reputation_score_remaining: u16,
2208 pub quote_requests_required: Option<String>,
2209 pub quote_requests_remaining: String,
2210 pub stake_atoms_required: Option<String>,
2211 pub stake_atoms_remaining: String,
2212 pub tenure_slots_required: Option<String>,
2213 pub tenure_slots_remaining: String,
2214}
2215
2216#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2220#[serde(deny_unknown_fields)]
2221pub struct PlatformMakerReputationResponse {
2222 pub schema_version: u16,
2223 pub contract_version: String,
2224 pub market_id: String,
2225 pub maker_id: String,
2226 pub wallet_address: String,
2227 pub active: bool,
2228 pub tier: PlatformMakerReputationTier,
2229 pub reputation_score: u16,
2230 pub total_quote_requests: String,
2231 pub successful_fills: String,
2232 pub missed_quote_requests: String,
2233 pub fill_rate_bps: u16,
2234 pub consecutive_misses: u16,
2235 pub lifetime_filled_quote_atoms: String,
2236 pub distinct_counterparties: u16,
2237 pub recent_average_latency_ms: u16,
2238 pub configured_minimum_spread_bps: u16,
2239 pub weighted_average_spread_bps: u16,
2240 pub stake_atoms: String,
2241 pub epoch_start_stake_atoms: String,
2242 pub epoch_slashed_atoms: String,
2243 pub epoch_slashed_bps: u16,
2244 pub lifetime_auto_slashed_atoms: String,
2245 pub registered_slot: String,
2246 pub last_active_slot: String,
2247 pub last_settled_slot: String,
2248 pub revoked_at_slot: Option<String>,
2249 pub tenure_slots: String,
2250 pub signed_quote_stream_eligible: bool,
2251 pub minimum_quote_interval_ms: Option<u16>,
2252 pub tier_progress: PlatformMakerTierProgress,
2253 pub server_time_ms: u64,
2254}
2255
2256#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2257#[serde(rename_all = "snake_case")]
2258pub enum PlatformMakerSide {
2259 Buy,
2260 Sell,
2261}
2262
2263#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2264#[serde(rename_all = "snake_case")]
2265pub enum PlatformOracleHealth {
2266 Fresh,
2267 Stale,
2268 Unknown,
2269}
2270
2271#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2273#[serde(deny_unknown_fields)]
2274pub struct PlatformMakerFirmOrderSummary {
2275 pub resting_orders: u32,
2276 pub bid_orders: u32,
2277 pub ask_orders: u32,
2278 pub bid_size_atoms: String,
2279 pub ask_size_atoms: String,
2280}
2281
2282#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2284#[serde(deny_unknown_fields)]
2285pub struct PlatformMakerSignedQuote {
2286 pub side: PlatformMakerSide,
2287 pub price_atoms: String,
2288 pub size_atoms: String,
2289 pub nonce: String,
2290 pub issued_at_ms: u64,
2291 pub expires_at_ms: u64,
2292}
2293
2294#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2296#[serde(deny_unknown_fields)]
2297pub struct PlatformMakerIntentStatus {
2298 pub active: bool,
2299 pub side: PlatformMakerSide,
2300 pub minimum_price_atoms: String,
2301 pub maximum_price_atoms: String,
2302 pub maximum_fill_size_atoms: String,
2303 pub remaining_fill_size_atoms: String,
2305 pub minimum_spread_bps: u16,
2306 pub stake_atoms: String,
2307}
2308
2309#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2311#[serde(deny_unknown_fields)]
2312pub struct PlatformMakerSignedQuoteLane {
2313 pub eligible: bool,
2314 pub live_quotes: Vec<PlatformMakerSignedQuote>,
2315}
2316
2317#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2318#[serde(deny_unknown_fields)]
2319pub struct PlatformMakerStrandLevel {
2320 pub price_atoms: Option<String>,
2322 pub size_atoms: String,
2323 pub remaining_size_atoms: String,
2324}
2325
2326#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2328#[serde(deny_unknown_fields)]
2329pub struct PlatformMakerStrandStatus {
2330 pub enabled: bool,
2331 pub async_only: bool,
2332 pub expired: bool,
2334 pub mid_price_atoms: String,
2335 pub tick_size_atoms: String,
2336 pub valid_until_slot: Option<String>,
2338 pub bids: Vec<PlatformMakerStrandLevel>,
2339 pub asks: Vec<PlatformMakerStrandLevel>,
2340 pub maximum_exposure_atoms: String,
2341 pub remaining_exposure_atoms: String,
2342}
2343
2344#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2346#[serde(deny_unknown_fields)]
2347pub struct PlatformMakerCurrentStatus {
2348 pub enabled: bool,
2349 pub async_only: bool,
2350 pub expired: bool,
2351 pub half_spread_bps: u16,
2352 pub band_step_bps: u16,
2353 pub maximum_confidence_bps: u16,
2354 pub maximum_oracle_age_seconds: u32,
2355 pub sync_spread_bps: u16,
2356 pub valid_until_slot: Option<String>,
2358 pub bid_depth_atoms: Vec<String>,
2359 pub ask_depth_atoms: Vec<String>,
2360 pub maximum_exposure_atoms: String,
2361 pub remaining_exposure_atoms: String,
2362 pub oracle_health: PlatformOracleHealth,
2364}
2365
2366#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2368#[serde(deny_unknown_fields)]
2369pub struct PlatformMakerDeadManGuard {
2370 pub session_public_key: String,
2371 pub status: PlatformDeadManStatus,
2372 pub timeout_ms: u64,
2373 pub heartbeat_deadline_ms: u64,
2374 pub updated_at_ms: u64,
2375}
2376
2377#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2382#[serde(deny_unknown_fields)]
2383pub struct PlatformMakerStatusResponse {
2384 pub schema_version: u16,
2385 pub contract_version: String,
2386 pub market_id: String,
2387 pub maker_id: String,
2388 pub wallet_address: String,
2389 pub server_time_ms: u64,
2390 pub current_slot: String,
2391 pub firm_orders: PlatformMakerFirmOrderSummary,
2392 pub intent: Option<PlatformMakerIntentStatus>,
2393 pub signed_quotes: PlatformMakerSignedQuoteLane,
2394 pub strands: Vec<PlatformMakerStrandStatus>,
2395 pub currents: Vec<PlatformMakerCurrentStatus>,
2396 pub dead_man_guards: Vec<PlatformMakerDeadManGuard>,
2397 pub active_products: u16,
2400}
2401
2402#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2405#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
2406pub enum PlatformMakerStrandPrepareRequest {
2407 Upsert {
2408 maker_wallet: String,
2409 enabled: bool,
2410 async_only: bool,
2411 sync_spread_ticks: u16,
2412 mid_price_atoms: String,
2413 #[serde(alias = "max_exposure_base_lots")]
2414 max_exposure_base_atoms: String,
2415 bid_offsets_ticks: Vec<u16>,
2416 ask_offsets_ticks: Vec<u16>,
2417 #[serde(alias = "bid_sizes_base_lots")]
2418 bid_sizes_base_atoms: Vec<String>,
2419 #[serde(alias = "ask_sizes_base_lots")]
2420 ask_sizes_base_atoms: Vec<String>,
2421 valid_until_slot: String,
2422 },
2423 Recenter {
2424 maker_wallet: String,
2425 new_mid_price_atoms: String,
2426 valid_until_slot: String,
2427 },
2428 SetEnabled {
2429 maker_wallet: String,
2430 enabled: bool,
2431 },
2432 Cancel {
2433 maker_wallet: String,
2434 },
2435}
2436
2437#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2440#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
2441pub enum PlatformMakerCurrentPrepareRequest {
2442 Upsert {
2443 maker_wallet: String,
2444 enabled: bool,
2445 async_only: bool,
2446 half_spread_bps: u16,
2447 band_step_bps: u16,
2448 max_conf_bps: u16,
2449 max_oracle_dev_bps: u16,
2450 max_oracle_age_secs: u32,
2451 sync_spread_bps: u16,
2452 max_exposure_base_atoms: String,
2453 bid_depth_base_atoms: Vec<String>,
2454 ask_depth_base_atoms: Vec<String>,
2455 valid_until_slot: String,
2456 },
2457 Cancel {
2458 maker_wallet: String,
2459 },
2460}
2461
2462#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2463#[serde(rename_all = "snake_case")]
2464pub enum PlatformMakerControlProduct {
2465 Strand,
2466 Current,
2467}
2468
2469#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2470#[serde(rename_all = "snake_case")]
2471pub enum PlatformMakerControlAction {
2472 StrandUpsert,
2473 StrandRecenter,
2474 StrandSetEnabled,
2475 StrandCancel,
2476 CurrentUpsert,
2477 CurrentCancel,
2478}
2479
2480#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2481#[serde(deny_unknown_fields)]
2482pub struct PlatformMakerControlPrepareResponse {
2483 pub schema_version: u16,
2484 pub contract_version: String,
2485 pub maker_control_id: String,
2486 pub market_id: String,
2487 pub maker_wallet: String,
2488 pub product: PlatformMakerControlProduct,
2489 pub action: PlatformMakerControlAction,
2490 pub transaction_base64: String,
2494 pub recent_blockhash: String,
2495 pub last_valid_block_height: u64,
2496 pub expires_at_ms: u64,
2497}
2498
2499#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2500#[serde(deny_unknown_fields)]
2501pub struct PlatformMakerControlSubmitRequest {
2502 pub maker_control_id: String,
2503 pub signed_transaction_base64: String,
2504 pub idempotency_key: String,
2505}
2506
2507#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2508#[serde(rename_all = "snake_case")]
2509pub enum PlatformMakerControlSubmissionStatus {
2510 Submitted,
2511}
2512
2513#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2514#[serde(deny_unknown_fields)]
2515pub struct PlatformMakerControlSubmitResponse {
2516 pub schema_version: u16,
2517 pub contract_version: String,
2518 pub maker_control_id: String,
2519 pub market_id: String,
2520 pub maker_wallet: String,
2521 pub product: PlatformMakerControlProduct,
2522 pub action: PlatformMakerControlAction,
2523 pub signature: String,
2524 pub status: PlatformMakerControlSubmissionStatus,
2525}
2526
2527#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2529#[serde(rename_all = "snake_case")]
2530pub enum PlatformMakerProduct {
2531 FirmOrder,
2532 Intent,
2533 Strand,
2534 Current,
2535}
2536
2537#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2540#[serde(deny_unknown_fields)]
2541pub struct PlatformMakerFill {
2542 pub fill_id: String,
2543 pub product: PlatformMakerProduct,
2544 pub side: PlatformTradeSide,
2545 pub price_atoms: String,
2546 pub size_atoms: String,
2547 pub fee_quote_atoms: String,
2548 pub fee_is_final: bool,
2549 pub settlement: PlatformSettlementState,
2550 pub executed_at_ms: u64,
2551 pub confirmed_at_ms: Option<u64>,
2552 pub transaction_id: Option<String>,
2553 pub realized_pnl_quote_atoms: String,
2554}
2555
2556#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2562#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2563pub enum PlatformMakerEvent {
2564 AuthChallenge {
2565 schema_version: u16,
2566 contract_version: String,
2567 market_id: String,
2568 wallet_address: String,
2569 challenge: String,
2570 server_time_ms: u64,
2571 expires_at_ms: u64,
2572 },
2573 MakerSnapshot {
2574 schema_version: u16,
2575 contract_version: String,
2576 market_id: String,
2577 wallet_address: String,
2578 stream_id: String,
2579 sequence: String,
2580 server_time_ms: u64,
2581 status: PlatformMakerStatusResponse,
2582 fills: Vec<PlatformMakerFill>,
2583 },
2584 MakerFill {
2585 schema_version: u16,
2586 contract_version: String,
2587 market_id: String,
2588 wallet_address: String,
2589 stream_id: String,
2590 sequence: String,
2591 previous_sequence: String,
2592 server_time_ms: u64,
2593 fill: PlatformMakerFill,
2594 },
2595 MakerStatus {
2596 schema_version: u16,
2597 contract_version: String,
2598 market_id: String,
2599 wallet_address: String,
2600 stream_id: String,
2601 sequence: String,
2602 previous_sequence: String,
2603 server_time_ms: u64,
2604 status: PlatformMakerStatusResponse,
2605 },
2606 Heartbeat {
2607 schema_version: u16,
2608 contract_version: String,
2609 market_id: String,
2610 wallet_address: String,
2611 stream_id: String,
2612 sequence: String,
2613 previous_sequence: String,
2614 server_time_ms: u64,
2615 },
2616}
2617
2618#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2619#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2620pub enum PlatformAccountEvent {
2621 AuthChallenge {
2622 schema_version: u16,
2623 contract_version: String,
2624 market_id: String,
2625 wallet_address: String,
2626 challenge: String,
2627 server_time_ms: u64,
2628 expires_at_ms: u64,
2629 },
2630 AccountSnapshot {
2631 schema_version: u16,
2632 contract_version: String,
2633 market_id: String,
2634 wallet_address: String,
2635 stream_id: String,
2636 sequence: String,
2637 server_time_ms: u64,
2638 orders: Vec<PlatformAccountOrder>,
2639 fills: Vec<PlatformAccountFill>,
2640 },
2641 OrdersSnapshot {
2642 schema_version: u16,
2643 contract_version: String,
2644 market_id: String,
2645 wallet_address: String,
2646 stream_id: String,
2647 sequence: String,
2648 previous_sequence: String,
2649 server_time_ms: u64,
2650 orders: Vec<PlatformAccountOrder>,
2651 },
2652 Fill {
2653 schema_version: u16,
2654 contract_version: String,
2655 market_id: String,
2656 wallet_address: String,
2657 stream_id: String,
2658 sequence: String,
2659 previous_sequence: String,
2660 server_time_ms: u64,
2661 fill: PlatformAccountFill,
2662 },
2663 Heartbeat {
2664 schema_version: u16,
2665 contract_version: String,
2666 market_id: String,
2667 wallet_address: String,
2668 stream_id: String,
2669 sequence: String,
2670 previous_sequence: String,
2671 server_time_ms: u64,
2672 },
2673}
2674
2675#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2676#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2677pub enum PlatformMarketDataEvent {
2678 BookSnapshot {
2679 schema_version: u16,
2680 contract_version: String,
2681 market_id: String,
2682 stream_id: String,
2683 sequence: String,
2684 server_time_ms: u64,
2685 snapshot_id: String,
2686 bids: Vec<PlatformBookLevel>,
2687 asks: Vec<PlatformBookLevel>,
2688 },
2689 BookDelta {
2690 schema_version: u16,
2691 contract_version: String,
2692 market_id: String,
2693 stream_id: String,
2694 sequence: String,
2695 previous_sequence: String,
2696 server_time_ms: u64,
2697 changes: Vec<PlatformBookChange>,
2698 },
2699 BestBidAsk {
2700 schema_version: u16,
2701 contract_version: String,
2702 market_id: String,
2703 stream_id: String,
2704 sequence: String,
2705 server_time_ms: u64,
2706 best_bid: Option<PlatformBookLevel>,
2707 best_ask: Option<PlatformBookLevel>,
2708 },
2709 Trade {
2710 schema_version: u16,
2711 contract_version: String,
2712 market_id: String,
2713 server_time_ms: u64,
2714 trade: PlatformTrade,
2715 },
2716 MarketStatus {
2717 schema_version: u16,
2718 contract_version: String,
2719 market_id: String,
2720 server_time_ms: u64,
2721 status: PlatformMarketState,
2722 },
2723 Heartbeat {
2724 schema_version: u16,
2725 contract_version: String,
2726 market_id: String,
2727 server_time_ms: u64,
2728 },
2729}
2730
2731#[cfg(test)]
2732mod tests {
2733 use super::*;
2734
2735 #[test]
2736 fn public_platform_fixtures_decode_strictly() {
2737 let discovery: PlatformDiscoveryResponse =
2738 serde_json::from_str(PLATFORM_CAPABILITIES_FIXTURE).unwrap();
2739 let service_status: PlatformServiceStatusResponse =
2740 serde_json::from_str(PLATFORM_SERVICE_STATUS_FIXTURE).unwrap();
2741 let graph = PlatformActionGraphResponse::foundation();
2742 let assets: PlatformAssetsResponse = serde_json::from_str(PLATFORM_ASSETS_FIXTURE).unwrap();
2743 let swap_quote: PlatformSwapQuoteResponse =
2744 serde_json::from_str(PLATFORM_SWAP_QUOTE_FIXTURE).unwrap();
2745 let markets: PlatformMarketsResponse =
2746 serde_json::from_str(PLATFORM_MARKETS_FIXTURE).unwrap();
2747 let book: PlatformBookSnapshotResponse =
2748 serde_json::from_str(PLATFORM_BOOK_FIXTURE).unwrap();
2749 let bbo: PlatformBestBidAskResponse = serde_json::from_str(PLATFORM_BBO_FIXTURE).unwrap();
2750 let fees: PlatformFeeScheduleResponse =
2751 serde_json::from_str(PLATFORM_FEES_FIXTURE).unwrap();
2752 let status: PlatformMarketStatusResponse =
2753 serde_json::from_str(PLATFORM_STATUS_FIXTURE).unwrap();
2754 let candles: PlatformCandlesResponse =
2755 serde_json::from_str(PLATFORM_CANDLES_FIXTURE).unwrap();
2756 let mark: PlatformMarkResponse = serde_json::from_str(PLATFORM_MARK_FIXTURE).unwrap();
2757 let execution_status: PlatformExecutionStatusResponse =
2758 serde_json::from_str(PLATFORM_EXECUTION_STATUS_FIXTURE).unwrap();
2759 let twaps: PlatformTwapsResponse = serde_json::from_str(PLATFORM_TWAPS_FIXTURE).unwrap();
2760 let twap_challenge: PlatformTwapChallengeResponse =
2761 serde_json::from_str(PLATFORM_TWAP_CHALLENGE_FIXTURE).unwrap();
2762 let twap_prepare: PlatformTwapPrepareResponse =
2763 serde_json::from_str(PLATFORM_TWAP_PREPARE_FIXTURE).unwrap();
2764 let twap_submit: PlatformTwapSubmitResponse =
2765 serde_json::from_str(PLATFORM_TWAP_SUBMIT_FIXTURE).unwrap();
2766 let portfolio_history: PlatformPortfolioHistoryResponse =
2767 serde_json::from_str(PLATFORM_PORTFOLIO_HISTORY_FIXTURE).unwrap();
2768 let portfolio: PlatformPortfolioResponse =
2769 serde_json::from_str(PLATFORM_PORTFOLIO_FIXTURE).unwrap();
2770 let rewards: PlatformRewardsResponse =
2771 serde_json::from_str(PLATFORM_REWARDS_FIXTURE).unwrap();
2772 let referrals: PlatformReferralsResponse =
2773 serde_json::from_str(PLATFORM_REFERRALS_FIXTURE).unwrap();
2774 let referral_link: PlatformReferralLinkResponse =
2775 serde_json::from_str(PLATFORM_REFERRAL_LINK_FIXTURE).unwrap();
2776 let referral_claim: PlatformReferralClaimResponse =
2777 serde_json::from_str(PLATFORM_REFERRAL_CLAIM_FIXTURE).unwrap();
2778 let vault_status: PlatformVaultStatusResponse =
2779 serde_json::from_str(PLATFORM_VAULT_STATUS_FIXTURE).unwrap();
2780 let vault_pause: PlatformVaultPausePrepareResponse =
2781 serde_json::from_str(PLATFORM_VAULT_PAUSE_PREPARE_FIXTURE).unwrap();
2782 let vault_setup: PlatformVaultSetupPrepareResponse =
2783 serde_json::from_str(PLATFORM_VAULT_SETUP_PREPARE_FIXTURE).unwrap();
2784 let vault_delegate: PlatformVaultDelegatePrepareResponse =
2785 serde_json::from_str(PLATFORM_VAULT_DELEGATE_PREPARE_FIXTURE).unwrap();
2786 let vault_policy: PlatformVaultPolicyPrepareResponse =
2787 serde_json::from_str(PLATFORM_VAULT_POLICY_PREPARE_FIXTURE).unwrap();
2788 let vault_deposit: PlatformVaultDepositPrepareResponse =
2789 serde_json::from_str(PLATFORM_VAULT_DEPOSIT_PREPARE_FIXTURE).unwrap();
2790 let vault_withdraw: PlatformVaultWithdrawPrepareResponse =
2791 serde_json::from_str(PLATFORM_VAULT_WITHDRAW_PREPARE_FIXTURE).unwrap();
2792 let vault_submit: PlatformVaultSubmitResponse =
2793 serde_json::from_str(PLATFORM_VAULT_SUBMIT_FIXTURE).unwrap();
2794 let bugs: PlatformBugsResponse = serde_json::from_str(PLATFORM_BUGS_FIXTURE).unwrap();
2795 let bug_submit: PlatformBugSubmitResponse =
2796 serde_json::from_str(PLATFORM_BUG_SUBMIT_FIXTURE).unwrap();
2797 let trades: PlatformTradesResponse = serde_json::from_str(PLATFORM_TRADES_FIXTURE).unwrap();
2798 let account: PlatformAccountSnapshotResponse =
2799 serde_json::from_str(PLATFORM_ACCOUNT_FIXTURE).unwrap();
2800 let maker_reputation: PlatformMakerReputationResponse =
2801 serde_json::from_str(PLATFORM_MAKER_REPUTATION_FIXTURE).unwrap();
2802 let maker_status: PlatformMakerStatusResponse =
2803 serde_json::from_str(PLATFORM_MAKER_STATUS_FIXTURE).unwrap();
2804 let maker_stream: PlatformMakerEvent =
2805 serde_json::from_str(PLATFORM_MAKER_STREAM_FIXTURE).unwrap();
2806 let twap_stream: PlatformTwapEvent =
2807 serde_json::from_str(PLATFORM_TWAP_STREAM_FIXTURE).unwrap();
2808 let execution_stream: PlatformExecutionEvent =
2809 serde_json::from_str(PLATFORM_EXECUTION_STREAM_FIXTURE).unwrap();
2810 let order_challenge: PlatformOrderChallengeResponse =
2811 serde_json::from_str(PLATFORM_ORDER_CHALLENGE_FIXTURE).unwrap();
2812 let order_prepare: PlatformOrderPrepareResponse =
2813 serde_json::from_str(PLATFORM_ORDER_PREPARE_FIXTURE).unwrap();
2814 let order_submit: PlatformOrderSubmitResponse =
2815 serde_json::from_str(PLATFORM_ORDER_SUBMIT_FIXTURE).unwrap();
2816 let order_status: PlatformOrderStatusResponse =
2817 serde_json::from_str(PLATFORM_ORDER_STATUS_FIXTURE).unwrap();
2818
2819 assert_eq!(discovery.schema_version, PLATFORM_SCHEMA_VERSION);
2820 assert_eq!(service_status.status, PlatformServiceState::Operational);
2821 assert_eq!(service_status.available_operations, 59);
2822 assert_eq!(graph.entry_operation_id, "platform.capabilities.read");
2823 assert_eq!(graph.operations.len(), 69);
2824 assert_eq!(maker_reputation.tier, PlatformMakerReputationTier::Gold);
2825 assert_eq!(maker_status.active_products, 3);
2826 match &maker_stream {
2827 PlatformMakerEvent::MakerSnapshot { status, fills, .. } => {
2828 assert_eq!(status.active_products, maker_status.active_products);
2829 assert_eq!(fills.len(), 1);
2830 assert_eq!(fills[0].product, PlatformMakerProduct::Strand);
2831 }
2832 other => panic!("maker stream fixture must be a snapshot, got {other:?}"),
2833 }
2834 match &twap_stream {
2835 PlatformTwapEvent::TwapsSnapshot {
2836 twaps: streamed, ..
2837 } => {
2838 assert_eq!(streamed, &twaps.twaps);
2839 }
2840 other => panic!("twap stream fixture must be a snapshot, got {other:?}"),
2841 }
2842 match &execution_stream {
2843 PlatformExecutionEvent::ExecutionsSnapshot {
2844 executions,
2845 unknown_execution_ids,
2846 ..
2847 } => {
2848 assert_eq!(executions.len(), 2);
2849 assert_eq!(executions[0].execution_id, execution_status.execution_id);
2850 assert_eq!(unknown_execution_ids.len(), 1);
2851 }
2852 other => panic!("execution stream fixture must be a snapshot, got {other:?}"),
2853 }
2854 assert_eq!(maker_status.strands.len(), 1);
2855 assert_eq!(maker_status.currents.len(), 1);
2856 assert!(maker_status
2857 .intent
2858 .as_ref()
2859 .is_some_and(|intent| intent.active));
2860 assert_eq!(portfolio.balances.len(), 2);
2861 assert_eq!(portfolio.positions.len(), 1);
2862 assert!(portfolio.valuation_complete);
2863 assert_eq!(portfolio.equity_usd_micros.as_deref(), Some("439989500"));
2864 assert!(graph
2865 .operations
2866 .iter()
2867 .any(|operation| operation.id == "twap.place.submit"));
2868 assert!(graph
2869 .operations
2870 .iter()
2871 .any(|operation| operation.id == "twap.cancel.submit"));
2872 assert_eq!(discovery.capabilities.len(), 5);
2873 assert!(!discovery.authority.accepts_private_keys);
2874 assert_eq!(assets.assets.len(), 2);
2875 assert_eq!(swap_quote.input_asset_id, assets.assets[0].asset_id);
2876 assert_eq!(swap_quote.output_asset_id, assets.assets[1].asset_id);
2877 assert_eq!(markets.markets.len(), 1);
2878 assert_eq!(markets.markets[0].base_asset_id, assets.assets[0].asset_id);
2879 assert_eq!(markets.markets[0].quote_asset_id, assets.assets[1].asset_id);
2880 assert_eq!(book.sequence, "42");
2881 assert_eq!(bbo.best_bid.unwrap().price_atoms, "149990000");
2882 assert_eq!(fees.maximum_immediate_execution_fee_bps, 10);
2883 assert_eq!(status.status, PlatformMarketState::Active);
2884 assert_eq!(candles.candles.len(), 2);
2885 assert_eq!(mark.price_atoms_per_base_unit.as_deref(), Some("149995000"));
2886 assert_eq!(execution_status.status, PlatformExecutionState::Confirmed);
2887 assert_eq!(
2888 execution_status.settlement,
2889 PlatformSettlementState::Confirmed
2890 );
2891 assert_eq!(twaps.twaps[0].fills.len(), 1);
2892 assert_eq!(twaps.twaps[0].slices_executed, 2);
2893 assert_eq!(twap_challenge.action, PlatformTwapControlAction::Place);
2894 assert_eq!(twap_prepare.twap_id, twap_challenge.twap_id);
2895 assert_eq!(twap_submit.twap_control_id, twap_prepare.twap_control_id);
2896 assert_eq!(portfolio_history.points.len(), 2);
2897 assert_eq!(rewards.standings.len(), 2);
2898 assert!(referrals.enabled);
2899 assert_eq!(referral_link.status, "pending_first_fill");
2900 assert_eq!(referral_claim.status, "requested");
2901 assert_eq!(vault_status.state, PlatformVaultState::Active);
2902 assert_eq!(
2903 vault_status.session.as_ref().unwrap().state,
2904 PlatformVaultSessionState::Active
2905 );
2906 assert!(vault_pause.paused);
2907 assert!(vault_pause.owner_signature_required);
2908 assert_eq!(vault_setup.mode, PlatformVaultSetupMode::Create);
2909 assert!(vault_setup.permanent);
2910 assert_eq!(vault_delegate.action, PlatformVaultDelegateAction::Revoke);
2911 assert!(vault_delegate.owner_signature_required);
2912 assert_eq!(
2913 vault_policy.withdrawal_access.mode,
2914 PlatformVaultWithdrawalMode::Restricted
2915 );
2916 assert!(vault_policy.owner_signature_required);
2917 assert_eq!(vault_deposit.amount_atoms, "10000000");
2918 assert!(vault_deposit.owner_signature_required);
2919 assert_eq!(vault_withdraw.amount_atoms, "5000000");
2920 assert!(vault_withdraw.owner_signature_required);
2921 assert!(vault_withdraw.sponsored);
2922 assert!(vault_withdraw.preparation_id.starts_with("vp_"));
2923 assert_eq!(vault_submit.action, PlatformVaultAction::Deposit);
2924 assert_eq!(
2925 vault_submit.status,
2926 PlatformVaultSubmissionStatus::Submitted
2927 );
2928 assert!(vault_submit.sponsored);
2929 assert_eq!(vault_submit.failure_code, None);
2930 assert_eq!(bugs.reports[0].status, PlatformBugStatus::Confirmed);
2931 assert_eq!(bug_submit.status, PlatformBugStatus::Pending);
2932 assert_eq!(trades.trades.len(), 1);
2933 assert_eq!(account.orders.len(), 1);
2934 assert_eq!(account.fills.len(), 1);
2935 assert_eq!(order_challenge.action, PlatformOrderAction::Place);
2936 assert_eq!(order_prepare.order_ids, order_challenge.order_ids);
2937 assert_eq!(order_submit.order_ids, order_challenge.order_ids);
2938 assert_eq!(order_status.order_control_id, order_submit.order_control_id);
2939 assert_eq!(order_status.status, PlatformOrderControlStatus::Submitting);
2940 }
2941
2942 #[test]
2943 fn public_platform_response_rejects_unreviewed_fields() {
2944 let mut value: serde_json::Value =
2945 serde_json::from_str(PLATFORM_CAPABILITIES_FIXTURE).unwrap();
2946 value
2947 .as_object_mut()
2948 .unwrap()
2949 .insert("unexpected_field".to_owned(), serde_json::Value::Bool(true));
2950 assert!(serde_json::from_value::<PlatformDiscoveryResponse>(value).is_err());
2951
2952 let mut account_event: serde_json::Value =
2953 serde_json::from_str(PLATFORM_ACCOUNT_FIXTURE).unwrap();
2954 let event = account_event.as_object_mut().unwrap();
2955 event.insert("type".to_owned(), serde_json::json!("account_snapshot"));
2956 event.insert(
2957 "stream_id".to_owned(),
2958 serde_json::json!("account_stream_66666666666666666666666666666666"),
2959 );
2960 event.insert("sequence".to_owned(), serde_json::json!("1"));
2961 event.insert("unexpected_field".to_owned(), serde_json::json!(true));
2962 assert!(serde_json::from_value::<PlatformAccountEvent>(account_event).is_err());
2963 }
2964
2965 #[test]
2966 fn platform_graph_availability_is_projected_from_live_capabilities() {
2967 let mut graph = PlatformActionGraphResponse::foundation();
2968 let live = std::collections::BTreeSet::from([
2969 "platform.discover".to_owned(),
2970 "graphs.read".to_owned(),
2971 "orders.replace".to_owned(),
2972 ]);
2973
2974 graph.project_availability(&live);
2975
2976 for operation in &graph.operations {
2977 assert_eq!(
2978 operation.available,
2979 live.contains(&operation.capability_id),
2980 "operation {} did not follow capability {}",
2981 operation.id,
2982 operation.capability_id,
2983 );
2984 }
2985 assert!(graph
2986 .workflows
2987 .iter()
2988 .flat_map(|workflow| &workflow.nodes)
2989 .filter(|node| node.kind != PlatformActionKind::ExternalSignature)
2990 .all(|node| {
2991 node.available
2992 == node
2993 .capability_id
2994 .as_ref()
2995 .is_some_and(|capability_id| live.contains(capability_id))
2996 }));
2997 assert!(graph
2998 .workflows
2999 .iter()
3000 .flat_map(|workflow| &workflow.nodes)
3001 .filter(|node| node.kind == PlatformActionKind::ExternalSignature)
3002 .all(|node| node.available));
3003 }
3004
3005 #[test]
3006 fn atomic_order_batch_request_is_strict_and_typed() {
3007 let request: PlatformOrderChallengeRequest = serde_json::from_value(serde_json::json!({
3008 "action": "batch",
3009 "owner_wallet": "11111111111111111111111111111111",
3010 "session_public_key": "22222222222222222222222222222222",
3011 "operations": [
3012 {
3013 "action": "cancel",
3014 "order_id": "order_11111111111111111111111111111111"
3015 },
3016 {
3017 "action": "replace",
3018 "order_id": "order_22222222222222222222222222222222",
3019 "account_sequence": "8",
3020 "client_order_id": "replacement-8",
3021 "side": "sell",
3022 "order_type": "post_only",
3023 "limit_price_atoms": "151000000",
3024 "size_atoms": "2000000"
3025 }
3026 ]
3027 }))
3028 .unwrap();
3029 let PlatformOrderChallengeRequest::Batch { operations, .. } = request else {
3030 panic!("expected batch request");
3031 };
3032 assert_eq!(operations.len(), 2);
3033 assert!(matches!(
3034 &operations[1],
3035 PlatformOrderBatchOperation::Replace { account_sequence: Some(sequence), .. }
3036 if sequence == "8"
3037 ));
3038
3039 let place: PlatformOrderChallengeRequest = serde_json::from_value(serde_json::json!({
3043 "action": "place",
3044 "owner_wallet": "11111111111111111111111111111111",
3045 "session_public_key": "22222222222222222222222222222222",
3046 "client_order_id": "first-order",
3047 "side": "buy",
3048 "order_type": "post_only",
3049 "limit_price_atoms": "150000000",
3050 "size_atoms": "1000000"
3051 }))
3052 .unwrap();
3053 assert!(matches!(
3054 place,
3055 PlatformOrderChallengeRequest::Place {
3056 account_sequence: None,
3057 ..
3058 }
3059 ));
3060 assert!(!serde_json::to_string(&place)
3061 .unwrap()
3062 .contains("account_sequence"));
3063
3064 assert!(
3065 serde_json::from_value::<PlatformOrderChallengeRequest>(serde_json::json!({
3066 "action": "batch",
3067 "owner_wallet": "11111111111111111111111111111111",
3068 "session_public_key": "22222222222222222222222222222222",
3069 "operations": [{
3070 "action": "cancel",
3071 "order_id": "order_11111111111111111111111111111111",
3072 "implementation": "hidden"
3073 }]
3074 }))
3075 .is_err()
3076 );
3077 }
3078
3079 #[test]
3080 fn persistent_order_commands_are_strict_and_explicit_about_self_trade_policy() {
3081 let frame: PlatformOrderCommandClientFrame = serde_json::from_value(serde_json::json!({
3082 "type": "command",
3083 "request_id": "agent-1",
3084 "sequence": "1",
3085 "command": {
3086 "type": "challenge",
3087 "self_trade_prevention": "cancel_maker",
3088 "request": {
3089 "action": "cancel_all",
3090 "owner_wallet": "11111111111111111111111111111111",
3091 "session_public_key": "22222222222222222222222222222222"
3092 }
3093 }
3094 }))
3095 .unwrap();
3096 assert!(matches!(
3097 frame,
3098 PlatformOrderCommandClientFrame::Command {
3099 command: PlatformOrderCommand::Challenge {
3100 self_trade_prevention: PlatformSelfTradePrevention::CancelMaker,
3101 ..
3102 },
3103 ..
3104 }
3105 ));
3106 assert!(
3107 serde_json::from_value::<PlatformOrderCommandClientFrame>(serde_json::json!({
3108 "type": "command",
3109 "request_id": "agent-1",
3110 "sequence": "1",
3111 "command": {
3112 "type": "challenge",
3113 "request": {
3114 "action": "cancel_all",
3115 "owner_wallet": "11111111111111111111111111111111",
3116 "session_public_key": "22222222222222222222222222222222"
3117 }
3118 }
3119 }))
3120 .is_err()
3121 );
3122 }
3123
3124 #[test]
3125 fn prepare_requests_accept_a_signed_challenge_or_the_operation_itself() {
3126 let signed: PlatformOrderPrepareRequest = serde_json::from_value(serde_json::json!({
3127 "challenge_id": "oc_0123456789abcdef0123456789abcdef",
3128 "authorization_signature": "1111",
3129 }))
3130 .unwrap();
3131 assert!(matches!(signed, PlatformOrderPrepareRequest::Authorized(_)));
3132 let direct: PlatformOrderPrepareRequest = serde_json::from_value(serde_json::json!({
3133 "action": "cancel_all",
3134 "owner_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3135 "session_public_key": "9Uu7cLBgfMk233BAjMvTS8XJy6KbZK7oQ7NXuCTi3Fg2",
3136 }))
3137 .unwrap();
3138 assert!(matches!(
3139 direct,
3140 PlatformOrderPrepareRequest::Direct(PlatformOrderChallengeRequest::CancelAll { .. })
3141 ));
3142 assert!(
3144 serde_json::from_value::<PlatformOrderPrepareRequest>(serde_json::json!({
3145 "challenge_id": "oc_0123456789abcdef0123456789abcdef",
3146 "authorization_signature": "1111",
3147 "extra": true,
3148 }))
3149 .is_err()
3150 );
3151 let twap: PlatformTwapPrepareRequest = serde_json::from_value(serde_json::json!({
3152 "action": "cancel",
3153 "owner_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3154 "session_public_key": "9Uu7cLBgfMk233BAjMvTS8XJy6KbZK7oQ7NXuCTi3Fg2",
3155 "twap_id": "twap_0123456789abcdef0123456789abcdef",
3156 }))
3157 .unwrap();
3158 assert!(matches!(twap, PlatformTwapPrepareRequest::Direct(_)));
3159 let execution: crate::ExecutionPrepareRequest = serde_json::from_value(serde_json::json!({
3160 "quote_id": "quote_0123456789abcdef0123456789abcdef",
3161 "owner_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3162 "session_public_key": "9Uu7cLBgfMk233BAjMvTS8XJy6KbZK7oQ7NXuCTi3Fg2",
3163 }))
3164 .unwrap();
3165 assert!(matches!(
3166 execution,
3167 crate::ExecutionPrepareRequest::Direct(_)
3168 ));
3169 }
3170
3171 #[test]
3172 fn maker_control_requests_are_tagged_exact_and_amount_safe() {
3173 let strand_upsert: PlatformMakerStrandPrepareRequest =
3174 serde_json::from_value(serde_json::json!({
3175 "action": "upsert",
3176 "maker_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3177 "enabled": true,
3178 "async_only": false,
3179 "sync_spread_ticks": 1,
3180 "mid_price_atoms": "123000000",
3181 "max_exposure_base_atoms": "1000000",
3182 "bid_offsets_ticks": vec![1; 16],
3183 "ask_offsets_ticks": vec![1; 16],
3184 "bid_sizes_base_atoms": vec!["1"; 16],
3185 "ask_sizes_base_atoms": vec!["1"; 16],
3186 "valid_until_slot": "0"
3187 }))
3188 .unwrap();
3189 let serialized = serde_json::to_value(&strand_upsert).unwrap();
3190 assert_eq!(serialized["max_exposure_base_atoms"], "1000000");
3191 assert!(serialized.get("max_exposure_base_lots").is_none());
3192
3193 let legacy_strand: PlatformMakerStrandPrepareRequest =
3196 serde_json::from_value(serde_json::json!({
3197 "action": "upsert",
3198 "maker_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3199 "enabled": true,
3200 "async_only": false,
3201 "sync_spread_ticks": 1,
3202 "mid_price_atoms": "123000000",
3203 "max_exposure_base_lots": "1000000",
3204 "bid_offsets_ticks": vec![1; 16],
3205 "ask_offsets_ticks": vec![1; 16],
3206 "bid_sizes_base_lots": vec!["1"; 16],
3207 "ask_sizes_base_lots": vec!["1"; 16],
3208 "valid_until_slot": "0"
3209 }))
3210 .unwrap();
3211 assert_eq!(serde_json::to_value(legacy_strand).unwrap(), serialized);
3212
3213 let strand: PlatformMakerStrandPrepareRequest = serde_json::from_value(serde_json::json!({
3214 "action": "recenter",
3215 "maker_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3216 "new_mid_price_atoms": "123000000",
3217 "valid_until_slot": "0"
3218 }))
3219 .unwrap();
3220 assert!(matches!(
3221 strand,
3222 PlatformMakerStrandPrepareRequest::Recenter { .. }
3223 ));
3224
3225 let current: PlatformMakerCurrentPrepareRequest =
3226 serde_json::from_value(serde_json::json!({
3227 "action": "cancel",
3228 "maker_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL"
3229 }))
3230 .unwrap();
3231 assert!(matches!(
3232 current,
3233 PlatformMakerCurrentPrepareRequest::Cancel { .. }
3234 ));
3235 assert!(
3236 serde_json::from_value::<PlatformMakerCurrentPrepareRequest>(serde_json::json!({
3237 "action": "cancel",
3238 "maker_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3239 "oracle_price": 123.45
3240 }))
3241 .is_err()
3242 );
3243 }
3244}