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,
616}
617
618#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
620#[serde(deny_unknown_fields)]
621pub struct PlatformCandle {
622 pub started_at_ms: u64,
623 pub open_price: String,
624 pub high_price: String,
625 pub low_price: String,
626 pub close_price: String,
627}
628
629#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
630#[serde(deny_unknown_fields)]
631pub struct PlatformCandlesResponse {
632 pub schema_version: u16,
633 pub contract_version: String,
634 pub market_id: String,
635 pub server_time_ms: u64,
636 pub resolution_seconds: u32,
637 pub candles: Vec<PlatformCandle>,
638}
639
640#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
641#[serde(deny_unknown_fields)]
642pub struct PlatformMarkResponse {
643 pub schema_version: u16,
644 pub contract_version: String,
645 pub market_id: String,
646 pub server_time_ms: u64,
647 pub price_atoms_per_base_unit: Option<String>,
648 pub quote_decimals: u8,
649 pub stale: bool,
650 pub age_ms: Option<u64>,
651}
652
653#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
654#[serde(rename_all = "snake_case")]
655pub enum PlatformExecutionState {
656 Prepared,
657 Confirmed,
658}
659
660#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
663#[serde(deny_unknown_fields)]
664pub struct PlatformExecutionStatusResponse {
665 pub schema_version: u16,
666 pub contract_version: String,
667 pub execution_id: String,
668 pub market_id: String,
669 pub status: PlatformExecutionState,
670 pub signature: Option<String>,
671 pub settlement: PlatformSettlementState,
672 pub updated_at_ms: u64,
673}
674
675#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
678#[serde(deny_unknown_fields)]
679pub struct PlatformExecutionRow {
680 pub execution_id: String,
681 pub market_id: String,
682 pub status: PlatformExecutionState,
683 pub signature: Option<String>,
684 pub settlement: PlatformSettlementState,
685 pub updated_at_ms: u64,
686}
687
688#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
691#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
692pub enum PlatformExecutionCommand {
693 Watch { execution_ids: Vec<String> },
694}
695
696#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
704#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
705pub enum PlatformExecutionEvent {
706 ExecutionsSnapshot {
707 schema_version: u16,
708 contract_version: String,
709 market_id: String,
710 stream_id: String,
711 sequence: String,
712 server_time_ms: u64,
713 executions: Vec<PlatformExecutionRow>,
714 unknown_execution_ids: Vec<String>,
715 },
716 ExecutionUpdate {
717 schema_version: u16,
718 contract_version: String,
719 market_id: String,
720 stream_id: String,
721 sequence: String,
722 previous_sequence: String,
723 server_time_ms: u64,
724 execution: PlatformExecutionRow,
725 },
726 ExecutionExpired {
727 schema_version: u16,
728 contract_version: String,
729 market_id: String,
730 stream_id: String,
731 sequence: String,
732 previous_sequence: String,
733 server_time_ms: u64,
734 execution_id: String,
735 },
736 ExecutionUnknown {
737 schema_version: u16,
738 contract_version: String,
739 market_id: String,
740 stream_id: String,
741 sequence: String,
742 previous_sequence: String,
743 server_time_ms: u64,
744 execution_id: String,
745 },
746 Heartbeat {
747 schema_version: u16,
748 contract_version: String,
749 market_id: String,
750 stream_id: String,
751 sequence: String,
752 previous_sequence: String,
753 server_time_ms: u64,
754 },
755}
756
757#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
758#[serde(rename_all = "snake_case")]
759pub enum PlatformTwapState {
760 Active,
761 Completed,
762 Cancelled,
763}
764
765#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
766#[serde(deny_unknown_fields)]
767pub struct PlatformTwapFill {
768 pub fill_id: String,
769 pub size_atoms: String,
770 pub price_atoms: String,
771 pub gross_quote_atoms: String,
772 pub base_fee_atoms: String,
773 pub quote_fee_atoms: String,
774 pub signature: Option<String>,
775 pub observed_at_ms: u64,
776}
777
778#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
779#[serde(deny_unknown_fields)]
780pub struct PlatformTwap {
781 pub twap_id: String,
782 pub side: PlatformTradeSide,
783 pub status: PlatformTwapState,
784 pub slices_total: u16,
785 pub slices_executed: u16,
786 pub interval_slots: u32,
787 pub maximum_tolerance_bps: u16,
788 pub limit_price_atoms: String,
789 pub total_size_atoms: String,
790 pub executed_size_atoms: String,
791 pub gross_quote_executed_atoms: String,
792 pub complete_execution_value: bool,
793 pub created_at_ms: u64,
794 pub completed_at_ms: Option<u64>,
795 pub placed_signature: Option<String>,
796 pub terminal_signature: Option<String>,
797 pub fills: Vec<PlatformTwapFill>,
798}
799
800#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
801#[serde(deny_unknown_fields)]
802pub struct PlatformTwapsResponse {
803 pub schema_version: u16,
804 pub contract_version: String,
805 pub market_id: String,
806 pub wallet_address: String,
807 pub server_time_ms: u64,
808 pub twaps: Vec<PlatformTwap>,
809}
810
811#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
812#[serde(rename_all = "snake_case")]
813pub enum PlatformTwapControlAction {
814 Place,
815 Cancel,
816}
817
818#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
821#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
822pub enum PlatformTwapChallengeRequest {
823 Place {
824 owner_wallet: String,
825 session_public_key: String,
826 side: PlatformTradeSide,
827 total_size_atoms: String,
828 slices_total: u16,
829 maximum_tolerance_bps: u16,
830 interval_slots: u32,
834 limit_price_atoms: String,
835 },
836 Cancel {
837 owner_wallet: String,
838 session_public_key: String,
839 twap_id: String,
840 },
841}
842
843#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
844#[serde(deny_unknown_fields)]
845pub struct PlatformTwapChallengeResponse {
846 pub schema_version: u16,
847 pub contract_version: String,
848 pub challenge_id: String,
849 pub market_id: String,
850 pub action: PlatformTwapControlAction,
851 pub twap_id: String,
852 pub authorization_payload_base64: String,
853 pub server_time_ms: u64,
854 pub expires_at_ms: u64,
855}
856
857#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
859#[serde(deny_unknown_fields)]
860pub struct PlatformTwapPrepareAuthorization {
861 pub challenge_id: String,
862 pub authorization_signature: String,
864}
865
866#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
870#[serde(untagged)]
871pub enum PlatformTwapPrepareRequest {
872 Authorized(PlatformTwapPrepareAuthorization),
873 Direct(PlatformTwapChallengeRequest),
874}
875
876#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
877#[serde(deny_unknown_fields)]
878pub struct PlatformTwapPrepareResponse {
879 pub schema_version: u16,
880 pub contract_version: String,
881 pub twap_control_id: String,
882 pub market_id: String,
883 pub action: PlatformTwapControlAction,
884 pub twap_id: String,
885 pub transaction_base64: String,
888 pub recent_blockhash: String,
889 pub last_valid_block_height: u64,
890 pub expires_at_ms: u64,
891}
892
893#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
894#[serde(deny_unknown_fields)]
895pub struct PlatformTwapSubmitRequest {
896 pub twap_control_id: String,
897 pub signed_transaction_base64: String,
898 pub idempotency_key: String,
899}
900
901#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
902#[serde(deny_unknown_fields)]
903pub struct PlatformTwapSubmitResponse {
904 pub schema_version: u16,
905 pub contract_version: String,
906 pub twap_control_id: String,
907 pub market_id: String,
908 pub action: PlatformTwapControlAction,
909 pub twap_id: String,
910 pub signature: String,
911 pub status: PlatformOrderSubmissionStatus,
912}
913
914#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
921#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
922#[allow(clippy::large_enum_variant)]
923pub enum PlatformTwapEvent {
924 TwapsSnapshot {
925 schema_version: u16,
926 contract_version: String,
927 market_id: String,
928 wallet_address: String,
929 stream_id: String,
930 sequence: String,
931 server_time_ms: u64,
932 twaps: Vec<PlatformTwap>,
933 },
934 TwapUpdate {
935 schema_version: u16,
936 contract_version: String,
937 market_id: String,
938 wallet_address: String,
939 stream_id: String,
940 sequence: String,
941 previous_sequence: String,
942 server_time_ms: u64,
943 twap: PlatformTwap,
944 },
945 Heartbeat {
946 schema_version: u16,
947 contract_version: String,
948 market_id: String,
949 wallet_address: String,
950 stream_id: String,
951 sequence: String,
952 previous_sequence: String,
953 server_time_ms: u64,
954 },
955}
956
957#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
958pub enum PlatformPortfolioHistoryRange {
959 #[serde(rename = "24h")]
960 Day,
961 #[serde(rename = "7d")]
962 Week,
963 #[serde(rename = "30d")]
964 Month,
965}
966
967#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
968#[serde(deny_unknown_fields)]
969pub struct PlatformPortfolioHistoryPoint {
970 pub recorded_at_ms: u64,
971 pub equity_usd_micros: String,
972 pub available_usd_micros: String,
973 pub locked_usd_micros: String,
974 pub market_count: u32,
975}
976
977#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
980#[serde(deny_unknown_fields)]
981pub struct PlatformPortfolioHistoryResponse {
982 pub schema_version: u16,
983 pub contract_version: String,
984 pub wallet_address: String,
985 pub server_time_ms: u64,
986 pub range: PlatformPortfolioHistoryRange,
987 pub points: Vec<PlatformPortfolioHistoryPoint>,
988 pub collecting: bool,
989 pub first_sample_ms: Option<u64>,
990 pub last_sample_ms: Option<u64>,
991}
992
993#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
998#[serde(deny_unknown_fields)]
999pub struct PlatformPortfolioBalance {
1000 pub asset_id: String,
1001 pub available_atoms: String,
1003 pub locked_atoms: String,
1005 pub total_atoms: String,
1007 pub value_usd_micros: Option<String>,
1009}
1010
1011#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1014#[serde(deny_unknown_fields)]
1015pub struct PlatformPortfolioPosition {
1016 pub market_id: String,
1017 pub base_asset_id: String,
1018 pub quote_asset_id: String,
1019 pub base_available_atoms: String,
1020 pub base_locked_atoms: String,
1021 pub quote_available_atoms: String,
1022 pub quote_locked_atoms: String,
1023}
1024
1025#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1027#[serde(deny_unknown_fields)]
1028pub struct PlatformPortfolioOrder {
1029 pub market_id: String,
1030 pub order_id: String,
1031 pub side: PlatformTradeSide,
1032 pub order_type: PlatformOrderType,
1033 pub state: PlatformOrderState,
1034 pub limit_price_atoms: String,
1035 pub original_size_atoms: String,
1036 pub remaining_size_atoms: String,
1037}
1038
1039#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1041#[serde(deny_unknown_fields)]
1042pub struct PlatformPortfolioFill {
1043 pub market_id: String,
1044 pub fill_id: String,
1045 pub side: PlatformTradeSide,
1046 pub price_atoms: String,
1047 pub size_atoms: String,
1048 pub fee_quote_atoms: String,
1049 pub fee_is_final: bool,
1050 pub settlement: PlatformSettlementState,
1051 pub executed_at_ms: u64,
1052 pub confirmed_at_ms: Option<u64>,
1053 pub transaction_id: Option<String>,
1054 pub realized_pnl_quote_atoms: String,
1055}
1056
1057#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1064#[serde(deny_unknown_fields)]
1065pub struct PlatformPortfolioResponse {
1066 pub schema_version: u16,
1067 pub contract_version: String,
1068 pub wallet_address: String,
1069 pub server_time_ms: u64,
1070 pub observed_at_ms: u64,
1072 pub observed_slot: String,
1074 pub market_count: u32,
1076 pub balances: Vec<PlatformPortfolioBalance>,
1077 pub positions: Vec<PlatformPortfolioPosition>,
1078 pub open_orders: Vec<PlatformPortfolioOrder>,
1080 pub recent_fills: Vec<PlatformPortfolioFill>,
1082 pub unavailable_market_ids: Vec<String>,
1085 pub equity_usd_micros: Option<String>,
1087 pub available_usd_micros: Option<String>,
1089 pub locked_usd_micros: Option<String>,
1091 pub valuation_complete: bool,
1092 pub unpriced_asset_ids: Vec<String>,
1093}
1094
1095#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1096#[serde(rename_all = "snake_case")]
1097pub enum PlatformVaultState {
1098 Absent,
1099 Active,
1100 Paused,
1101}
1102
1103#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1104#[serde(rename_all = "snake_case")]
1105pub enum PlatformVaultSessionState {
1106 Absent,
1107 Active,
1108 Expired,
1109}
1110
1111#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1112#[serde(rename_all = "snake_case")]
1113pub enum PlatformVaultWithdrawalMode {
1114 Unrestricted,
1115 Blocked,
1116 Restricted,
1117}
1118
1119#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1122#[serde(deny_unknown_fields)]
1123pub struct PlatformVaultSpendingLimit {
1124 pub asset_id: String,
1125 pub maximum_per_execution_atoms: Option<String>,
1126}
1127
1128#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1131#[serde(deny_unknown_fields)]
1132pub struct PlatformVaultSessionStatus {
1133 pub session_public_key: String,
1134 pub state: PlatformVaultSessionState,
1135 pub expires_at_ms: Option<u64>,
1136 pub permanent: bool,
1137 pub minimum_interval_seconds: u32,
1138 pub maximum_tolerance_bps: u16,
1139 pub last_execution_at_ms: Option<u64>,
1140 pub market_execution_ready: bool,
1141 pub price_protection_active: bool,
1142 pub spending_limits: Vec<PlatformVaultSpendingLimit>,
1143}
1144
1145#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1146#[serde(deny_unknown_fields)]
1147pub struct PlatformVaultWithdrawalAccess {
1148 pub mode: PlatformVaultWithdrawalMode,
1149 pub allowed_wallet_addresses: Vec<String>,
1150}
1151
1152#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1155#[serde(deny_unknown_fields)]
1156pub struct PlatformVaultStatusResponse {
1157 pub schema_version: u16,
1158 pub contract_version: String,
1159 pub server_time_ms: u64,
1160 pub wallet_address: String,
1161 pub state: PlatformVaultState,
1162 pub session: Option<PlatformVaultSessionStatus>,
1163 pub withdrawal_access: PlatformVaultWithdrawalAccess,
1164}
1165
1166#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1167#[serde(deny_unknown_fields)]
1168pub struct PlatformVaultPausePrepareRequest {
1169 pub wallet_address: String,
1170 pub paused: bool,
1171}
1172
1173#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1176#[serde(deny_unknown_fields)]
1177pub struct PlatformVaultPausePrepareResponse {
1178 pub schema_version: u16,
1179 pub contract_version: String,
1180 pub server_time_ms: u64,
1181 pub wallet_address: String,
1182 pub paused: bool,
1183 pub transaction_base64: String,
1184 pub recent_blockhash: String,
1185 pub owner_signature_required: bool,
1186 pub preparation_id: String,
1190 pub sponsored: bool,
1194 pub submit_by_ms: u64,
1196}
1197
1198#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1199#[serde(rename_all = "snake_case")]
1200pub enum PlatformVaultSetupMode {
1201 Create,
1202 ReplaceSession,
1203}
1204
1205pub const PLATFORM_SESSION_DEFAULT_MINIMUM_INTERVAL_SECONDS: u32 = 1;
1208pub const PLATFORM_SESSION_DEFAULT_MAXIMUM_TOLERANCE_BPS: u16 = 100;
1209pub const PLATFORM_SESSION_MAX_SPENDING_LIMITS: usize = 4;
1211
1212#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1216#[serde(deny_unknown_fields)]
1217pub struct PlatformVaultSetupPrepareRequest {
1218 pub wallet_address: String,
1219 pub session_public_key: String,
1220 #[serde(default)]
1223 pub market_id: Option<String>,
1224 #[serde(default)]
1227 pub expires_at_ms: Option<u64>,
1228 #[serde(default)]
1230 pub minimum_interval_seconds: Option<u32>,
1231 #[serde(default)]
1233 pub maximum_tolerance_bps: Option<u16>,
1234 #[serde(default)]
1237 pub spending_limits: Vec<PlatformVaultSpendingLimit>,
1238}
1239
1240#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1243#[serde(deny_unknown_fields)]
1244pub struct PlatformVaultSetupPrepareResponse {
1245 pub schema_version: u16,
1246 pub contract_version: String,
1247 pub server_time_ms: u64,
1248 pub wallet_address: String,
1249 pub session_public_key: String,
1250 pub market_id: Option<String>,
1252 pub mode: PlatformVaultSetupMode,
1253 pub expires_at_ms: Option<u64>,
1254 pub permanent: bool,
1255 pub minimum_interval_seconds: u32,
1257 pub maximum_tolerance_bps: u16,
1258 pub spending_limits: Vec<PlatformVaultSpendingLimit>,
1259 pub transaction_base64: String,
1260 pub recent_blockhash: String,
1261 pub owner_signature_required: bool,
1262 pub preparation_id: String,
1266 pub sponsored: bool,
1270 pub submit_by_ms: u64,
1272}
1273
1274#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1275#[serde(rename_all = "snake_case")]
1276pub enum PlatformVaultDelegateAction {
1277 Revoke,
1278}
1279
1280#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1281#[serde(deny_unknown_fields)]
1282pub struct PlatformVaultDelegatePrepareRequest {
1283 pub wallet_address: String,
1284 pub session_public_key: String,
1285 pub action: PlatformVaultDelegateAction,
1286}
1287
1288#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1291#[serde(deny_unknown_fields)]
1292pub struct PlatformVaultDelegatePrepareResponse {
1293 pub schema_version: u16,
1294 pub contract_version: String,
1295 pub server_time_ms: u64,
1296 pub wallet_address: String,
1297 pub session_public_key: String,
1298 pub action: PlatformVaultDelegateAction,
1299 pub transaction_base64: String,
1300 pub recent_blockhash: String,
1301 pub owner_signature_required: bool,
1302 pub preparation_id: String,
1306 pub sponsored: bool,
1310 pub submit_by_ms: u64,
1312}
1313
1314#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1315#[serde(deny_unknown_fields)]
1316pub struct PlatformVaultPolicyPrepareRequest {
1317 pub wallet_address: String,
1318 pub withdrawal_access: PlatformVaultWithdrawalAccess,
1319}
1320
1321#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1324#[serde(deny_unknown_fields)]
1325pub struct PlatformVaultPolicyPrepareResponse {
1326 pub schema_version: u16,
1327 pub contract_version: String,
1328 pub server_time_ms: u64,
1329 pub wallet_address: String,
1330 pub withdrawal_access: PlatformVaultWithdrawalAccess,
1331 pub transaction_base64: String,
1332 pub recent_blockhash: String,
1333 pub owner_signature_required: bool,
1334 pub preparation_id: String,
1338 pub sponsored: bool,
1342 pub submit_by_ms: u64,
1344}
1345
1346#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1347#[serde(deny_unknown_fields)]
1348pub struct PlatformVaultDepositPrepareRequest {
1349 pub wallet_address: String,
1350 pub market_id: String,
1351 pub asset_id: String,
1352 pub amount_atoms: String,
1353 #[serde(default)]
1358 pub session_public_key: Option<String>,
1359}
1360
1361#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1364#[serde(deny_unknown_fields)]
1365pub struct PlatformVaultDepositPrepareResponse {
1366 pub schema_version: u16,
1367 pub contract_version: String,
1368 pub server_time_ms: u64,
1369 pub wallet_address: String,
1370 pub market_id: String,
1371 pub asset_id: String,
1372 pub amount_atoms: String,
1373 pub network_cost_atoms: String,
1379 pub session_public_key: Option<String>,
1381 pub registers_session: bool,
1385 pub transaction_base64: String,
1386 pub recent_blockhash: String,
1387 pub owner_signature_required: bool,
1388 pub preparation_id: String,
1392 pub sponsored: bool,
1396 pub submit_by_ms: u64,
1398}
1399
1400#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1401#[serde(deny_unknown_fields)]
1402pub struct PlatformVaultWithdrawPrepareRequest {
1403 pub wallet_address: String,
1404 pub market_id: String,
1405 pub asset_id: String,
1406 pub destination_wallet_address: String,
1407 pub amount_atoms: String,
1408}
1409
1410#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1413#[serde(deny_unknown_fields)]
1414pub struct PlatformVaultWithdrawPrepareResponse {
1415 pub schema_version: u16,
1416 pub contract_version: String,
1417 pub server_time_ms: u64,
1418 pub wallet_address: String,
1419 pub market_id: String,
1420 pub asset_id: String,
1421 pub destination_wallet_address: String,
1422 pub amount_atoms: String,
1423 pub transaction_base64: String,
1424 pub recent_blockhash: String,
1425 pub owner_signature_required: bool,
1426 pub preparation_id: String,
1430 pub sponsored: bool,
1434 pub submit_by_ms: u64,
1436}
1437
1438#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1440#[serde(rename_all = "snake_case")]
1441pub enum PlatformVaultAction {
1442 Setup,
1443 Deposit,
1444 Withdraw,
1445 Delegate,
1446 Policy,
1447 Pause,
1448}
1449
1450#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1451#[serde(rename_all = "snake_case")]
1452pub enum PlatformVaultSubmissionStatus {
1453 Submitted,
1455 Confirmed,
1456 Failed,
1457}
1458
1459#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1464#[serde(deny_unknown_fields)]
1465pub struct PlatformVaultSubmitRequest {
1466 pub preparation_id: String,
1467 pub signed_transaction_base64: String,
1468 pub idempotency_key: String,
1469}
1470
1471#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1473#[serde(deny_unknown_fields)]
1474pub struct PlatformVaultSubmitResponse {
1475 pub schema_version: u16,
1476 pub contract_version: String,
1477 pub preparation_id: String,
1478 pub action: PlatformVaultAction,
1479 pub wallet_address: String,
1480 pub sponsored: bool,
1481 pub signature: String,
1482 pub status: PlatformVaultSubmissionStatus,
1483 pub failure_code: Option<String>,
1485 pub updated_at_ms: u64,
1486}
1487
1488#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1489#[serde(deny_unknown_fields)]
1490pub struct PlatformRewardStanding {
1491 pub rank: u32,
1492 pub wallet_address: String,
1493 pub points: String,
1494}
1495
1496#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1497#[serde(deny_unknown_fields)]
1498pub struct PlatformOwnerRewards {
1499 pub wallet_address: String,
1500 pub rank: Option<u32>,
1501 pub points: String,
1502 pub trading_points: String,
1503 pub making_points: String,
1504 pub bug_points: String,
1505 pub referral_points: String,
1506}
1507
1508#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1509#[serde(deny_unknown_fields)]
1510pub struct PlatformRewardsResponse {
1511 pub schema_version: u16,
1512 pub contract_version: String,
1513 pub server_time_ms: u64,
1514 pub season: String,
1515 pub total_wallets: u32,
1516 pub owner: Option<PlatformOwnerRewards>,
1517 pub standings: Vec<PlatformRewardStanding>,
1518}
1519
1520#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1521#[serde(deny_unknown_fields)]
1522pub struct PlatformReferralsResponse {
1523 pub schema_version: u16,
1524 pub contract_version: String,
1525 pub server_time_ms: u64,
1526 pub wallet_address: String,
1527 pub enabled: bool,
1528 pub cash_rewards_enabled: bool,
1529 pub referral_code: Option<String>,
1530 pub referred_wallets: u32,
1531 pub referral_points: String,
1532 pub referred_by: Option<String>,
1533 pub referral_locked: bool,
1534 pub cash_accrued_atoms: String,
1535 pub cash_paid_atoms: String,
1536 pub cash_claimable_atoms: String,
1537}
1538
1539#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1540#[serde(deny_unknown_fields)]
1541pub struct PlatformReferralLinkRequest {
1542 pub wallet_address: String,
1543 pub referral_code: String,
1544 pub authorization_signature: String,
1545}
1546
1547#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1548#[serde(deny_unknown_fields)]
1549pub struct PlatformReferralLinkResponse {
1550 pub schema_version: u16,
1551 pub contract_version: String,
1552 pub server_time_ms: u64,
1553 pub wallet_address: String,
1554 pub referral_code: String,
1555 pub status: String,
1556}
1557
1558#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1559#[serde(deny_unknown_fields)]
1560pub struct PlatformReferralClaimRequest {
1561 pub wallet_address: String,
1562 pub payout_wallet_address: Option<String>,
1563 pub authorization_signature: String,
1564}
1565
1566#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1567#[serde(deny_unknown_fields)]
1568pub struct PlatformReferralClaimResponse {
1569 pub schema_version: u16,
1570 pub contract_version: String,
1571 pub server_time_ms: u64,
1572 pub wallet_address: String,
1573 pub payout_wallet_address: String,
1574 pub claimable_atoms: String,
1575 pub status: String,
1576}
1577
1578#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1579#[serde(rename_all = "snake_case")]
1580pub enum PlatformBugStatus {
1581 Pending,
1582 Confirmed,
1583 Rejected,
1584}
1585
1586#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1587#[serde(deny_unknown_fields)]
1588pub struct PlatformBugReport {
1589 pub bug_id: String,
1590 pub status: PlatformBugStatus,
1591 pub severity: u8,
1592 pub points: String,
1593 pub created_at_ms: u64,
1594 pub triaged_at_ms: Option<u64>,
1595 pub completed_at_ms: Option<u64>,
1596}
1597
1598#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1599#[serde(deny_unknown_fields)]
1600pub struct PlatformBugsResponse {
1601 pub schema_version: u16,
1602 pub contract_version: String,
1603 pub server_time_ms: u64,
1604 pub wallet_address: String,
1605 pub points: String,
1606 pub confirmed_reports: u32,
1607 pub reports: Vec<PlatformBugReport>,
1608}
1609
1610#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1611#[serde(deny_unknown_fields)]
1612pub struct PlatformBugSubmitRequest {
1613 pub owner_wallet: String,
1614 pub message: String,
1615 pub authorization_signature: String,
1618}
1619
1620#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1621#[serde(deny_unknown_fields)]
1622pub struct PlatformBugSubmitResponse {
1623 pub schema_version: u16,
1624 pub contract_version: String,
1625 pub server_time_ms: u64,
1626 pub bug_id: String,
1627 pub status: PlatformBugStatus,
1628}
1629
1630#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1631#[serde(rename_all = "snake_case")]
1632pub enum PlatformTradeSide {
1633 Buy,
1634 Sell,
1635}
1636
1637#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1638#[serde(deny_unknown_fields)]
1639pub struct PlatformTrade {
1640 pub trade_id: String,
1641 pub side: PlatformTradeSide,
1642 pub price_atoms: String,
1643 pub size_atoms: String,
1644 pub executed_at_ms: u64,
1645}
1646
1647#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1648#[serde(deny_unknown_fields)]
1649pub struct PlatformTradesResponse {
1650 pub schema_version: u16,
1651 pub contract_version: String,
1652 pub market_id: String,
1653 pub server_time_ms: u64,
1654 pub trades: Vec<PlatformTrade>,
1655}
1656
1657#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1658#[serde(rename_all = "snake_case")]
1659pub enum PlatformOrderType {
1660 GoodUntilCancelled,
1661 ImmediateOrCancel,
1662 FillOrKill,
1663 PostOnly,
1664}
1665
1666#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1670#[serde(rename_all = "snake_case")]
1671pub enum PlatformOrderAction {
1672 Place,
1673 Cancel,
1674 CancelAll,
1675 Replace,
1678 Batch,
1681}
1682
1683#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1686#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
1687pub enum PlatformOrderBatchOperation {
1688 Place {
1689 #[serde(default, skip_serializing_if = "Option::is_none")]
1695 account_sequence: Option<String>,
1696 client_order_id: String,
1697 side: PlatformTradeSide,
1698 order_type: PlatformOrderType,
1699 limit_price_atoms: String,
1700 size_atoms: String,
1701 },
1702 Cancel {
1703 order_id: String,
1704 },
1705 Replace {
1706 order_id: String,
1707 #[serde(default, skip_serializing_if = "Option::is_none")]
1708 account_sequence: Option<String>,
1709 client_order_id: String,
1710 side: PlatformTradeSide,
1711 order_type: PlatformOrderType,
1712 limit_price_atoms: String,
1713 size_atoms: String,
1714 },
1715}
1716
1717#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1721#[serde(tag = "action", rename_all = "snake_case", deny_unknown_fields)]
1722pub enum PlatformOrderChallengeRequest {
1723 Place {
1724 owner_wallet: String,
1725 session_public_key: String,
1726 #[serde(default, skip_serializing_if = "Option::is_none")]
1730 account_sequence: Option<String>,
1731 client_order_id: String,
1732 side: PlatformTradeSide,
1733 order_type: PlatformOrderType,
1734 limit_price_atoms: String,
1735 size_atoms: String,
1736 },
1737 Cancel {
1738 owner_wallet: String,
1739 session_public_key: String,
1740 order_id: String,
1741 },
1742 CancelAll {
1743 owner_wallet: String,
1744 session_public_key: String,
1745 },
1746 Replace {
1747 owner_wallet: String,
1748 session_public_key: String,
1749 order_id: String,
1750 #[serde(default, skip_serializing_if = "Option::is_none")]
1751 account_sequence: Option<String>,
1752 client_order_id: String,
1753 side: PlatformTradeSide,
1754 order_type: PlatformOrderType,
1755 limit_price_atoms: String,
1756 size_atoms: String,
1757 },
1758 Batch {
1759 owner_wallet: String,
1760 session_public_key: String,
1761 operations: Vec<PlatformOrderBatchOperation>,
1762 },
1763}
1764
1765#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1766#[serde(deny_unknown_fields)]
1767pub struct PlatformOrderChallengeResponse {
1768 pub schema_version: u16,
1769 pub contract_version: String,
1770 pub challenge_id: String,
1771 pub market_id: String,
1772 pub action: PlatformOrderAction,
1773 pub order_ids: Vec<String>,
1777 pub authorization_payload_base64: String,
1778 pub server_time_ms: u64,
1779 pub expires_at_ms: u64,
1780}
1781
1782#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1784#[serde(deny_unknown_fields)]
1785pub struct PlatformOrderPrepareAuthorization {
1786 pub challenge_id: String,
1787 #[serde(default, skip_serializing_if = "Option::is_none")]
1792 pub authorization_signature: Option<String>,
1793}
1794
1795#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1801#[serde(untagged)]
1802pub enum PlatformOrderPrepareRequest {
1803 Authorized(PlatformOrderPrepareAuthorization),
1804 Direct(PlatformOrderChallengeRequest),
1805}
1806
1807#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1808#[serde(deny_unknown_fields)]
1809pub struct PlatformOrderPrepareResponse {
1810 pub schema_version: u16,
1811 pub contract_version: String,
1812 pub order_control_id: String,
1813 pub market_id: String,
1814 pub action: PlatformOrderAction,
1815 pub order_ids: Vec<String>,
1816 pub transaction_base64: String,
1819 pub recent_blockhash: String,
1820 pub last_valid_block_height: u64,
1821 pub expires_at_ms: u64,
1822}
1823
1824#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1825#[serde(deny_unknown_fields)]
1826pub struct PlatformOrderSubmitRequest {
1827 pub order_control_id: String,
1828 pub signed_transaction_base64: String,
1829 pub idempotency_key: String,
1830}
1831
1832#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1833#[serde(rename_all = "snake_case")]
1834pub enum PlatformOrderSubmissionStatus {
1835 Submitted,
1836}
1837
1838#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1839#[serde(deny_unknown_fields)]
1840pub struct PlatformOrderSubmitResponse {
1841 pub schema_version: u16,
1842 pub contract_version: String,
1843 pub order_control_id: String,
1844 pub market_id: String,
1845 pub action: PlatformOrderAction,
1846 pub order_ids: Vec<String>,
1847 pub signature: String,
1848 pub status: PlatformOrderSubmissionStatus,
1849}
1850
1851#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1852#[serde(deny_unknown_fields)]
1853pub struct PlatformOrderStatusRequest {
1854 pub order_control_id: String,
1855 pub idempotency_key: String,
1856}
1857
1858#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1859#[serde(rename_all = "snake_case")]
1860pub enum PlatformOrderControlStatus {
1861 Submitting,
1862 Submitted,
1863 Failed,
1864}
1865
1866#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1867#[serde(deny_unknown_fields)]
1868pub struct PlatformOrderStatusResponse {
1869 pub schema_version: u16,
1870 pub contract_version: String,
1871 pub order_control_id: String,
1872 pub market_id: String,
1873 pub action: PlatformOrderAction,
1874 pub order_ids: Vec<String>,
1875 pub signature: String,
1876 pub status: PlatformOrderControlStatus,
1877 pub failure_code: Option<String>,
1878 pub updated_at_ms: u64,
1879}
1880
1881#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1885#[serde(rename_all = "snake_case")]
1886pub enum PlatformSelfTradePrevention {
1887 CancelTaker,
1888 CancelMaker,
1889 CancelBoth,
1890 SkipOwnLiquidity,
1891}
1892
1893#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1897#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
1898pub enum PlatformOrderCommand {
1899 Probe {
1901 nonce: String,
1902 },
1903 Challenge {
1904 request: PlatformOrderChallengeRequest,
1905 self_trade_prevention: PlatformSelfTradePrevention,
1906 },
1907 Prepare {
1908 request: PlatformOrderPrepareRequest,
1909 },
1910 Submit {
1911 request: PlatformOrderSubmitRequest,
1912 },
1913 Status {
1914 request: PlatformOrderStatusRequest,
1915 },
1916 DeadManArm {
1917 timeout_ms: u64,
1918 request: PlatformOrderSubmitRequest,
1919 },
1920 DeadManStatus,
1921 DeadManHeartbeat,
1922 DeadManDisarm,
1923}
1924
1925#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1932#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
1933pub enum PlatformOrderCommandClientFrame {
1934 Authenticate {
1935 owner_wallet: String,
1936 session_public_key: String,
1937 signature: String,
1939 #[serde(default, skip_serializing_if = "Option::is_none")]
1942 batch_format: Option<PlatformOrderCommandBatchFormat>,
1943 },
1944 Command {
1945 request_id: String,
1946 sequence: String,
1947 command: PlatformOrderCommand,
1948 },
1949}
1950
1951#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1952#[serde(rename_all = "snake_case")]
1953pub enum PlatformOrderCommandBatchFormat {
1954 CompactV1,
1955}
1956
1957#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1961#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
1962pub enum PlatformOrderCommandBatchEvent {
1963 ProbeResult {
1964 request_id: String,
1965 nonce: String,
1966 },
1967 ChallengeResult {
1968 request_id: String,
1969 self_trade_prevention: PlatformSelfTradePrevention,
1970 prevented_order_ids: Vec<String>,
1971 effective_request: PlatformOrderChallengeRequest,
1972 response: PlatformOrderChallengeResponse,
1973 },
1974 PrepareResult {
1975 request_id: String,
1976 response: PlatformOrderPrepareResponse,
1977 },
1978 SubmitResult {
1979 request_id: String,
1980 response: PlatformOrderSubmitResponse,
1981 },
1982 StatusResult {
1983 request_id: String,
1984 response: PlatformOrderStatusResponse,
1985 },
1986 DeadManResult {
1987 request_id: String,
1988 state: PlatformDeadManState,
1989 },
1990 CommandError {
1991 request_id: String,
1992 error: PublicOperationError,
1993 },
1994 Heartbeat,
1995}
1996
1997#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1998#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
1999pub enum PlatformOrderCommandServerFrame {
2000 EventBatch {
2001 schema_version: u16,
2002 contract_version: String,
2003 market_id: String,
2004 stream_id: String,
2005 first_sequence: String,
2006 previous_sequence: String,
2007 server_time_ms: u64,
2008 events: Vec<PlatformOrderCommandBatchEvent>,
2009 },
2010}
2011
2012#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2013#[serde(rename_all = "snake_case")]
2014pub enum PlatformDeadManStatus {
2015 Armed,
2016 Triggering,
2017 Triggered,
2018 Disarmed,
2019 Expired,
2020 Failed,
2021}
2022
2023#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2024#[serde(deny_unknown_fields)]
2025pub struct PlatformDeadManState {
2026 pub status: PlatformDeadManStatus,
2027 pub timeout_ms: u64,
2028 pub heartbeat_deadline_ms: u64,
2029 pub order_control_id: Option<String>,
2030 pub signature: Option<String>,
2031 pub failure_code: Option<String>,
2032 pub updated_at_ms: u64,
2033}
2034
2035#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2041#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2042pub enum PlatformOrderCommandEvent {
2043 AuthChallenge {
2044 schema_version: u16,
2045 contract_version: String,
2046 market_id: String,
2047 challenge: String,
2048 server_time_ms: u64,
2049 expires_at_ms: u64,
2050 },
2051 Ready {
2052 schema_version: u16,
2053 contract_version: String,
2054 market_id: String,
2055 stream_id: String,
2056 sequence: String,
2057 server_time_ms: u64,
2058 },
2059 ProbeResult {
2060 schema_version: u16,
2061 contract_version: String,
2062 market_id: String,
2063 stream_id: String,
2064 sequence: String,
2065 previous_sequence: String,
2066 request_id: String,
2067 nonce: String,
2068 server_time_ms: u64,
2069 },
2070 ChallengeResult {
2071 schema_version: u16,
2072 contract_version: String,
2073 market_id: String,
2074 stream_id: String,
2075 sequence: String,
2076 previous_sequence: String,
2077 request_id: String,
2078 self_trade_prevention: PlatformSelfTradePrevention,
2079 prevented_order_ids: Vec<String>,
2080 effective_request: PlatformOrderChallengeRequest,
2081 response: PlatformOrderChallengeResponse,
2082 server_time_ms: u64,
2083 },
2084 PrepareResult {
2085 schema_version: u16,
2086 contract_version: String,
2087 market_id: String,
2088 stream_id: String,
2089 sequence: String,
2090 previous_sequence: String,
2091 request_id: String,
2092 response: PlatformOrderPrepareResponse,
2093 server_time_ms: u64,
2094 },
2095 SubmitResult {
2096 schema_version: u16,
2097 contract_version: String,
2098 market_id: String,
2099 stream_id: String,
2100 sequence: String,
2101 previous_sequence: String,
2102 request_id: String,
2103 response: PlatformOrderSubmitResponse,
2104 server_time_ms: u64,
2105 },
2106 StatusResult {
2107 schema_version: u16,
2108 contract_version: String,
2109 market_id: String,
2110 stream_id: String,
2111 sequence: String,
2112 previous_sequence: String,
2113 request_id: String,
2114 response: PlatformOrderStatusResponse,
2115 server_time_ms: u64,
2116 },
2117 DeadManResult {
2118 schema_version: u16,
2119 contract_version: String,
2120 market_id: String,
2121 stream_id: String,
2122 sequence: String,
2123 previous_sequence: String,
2124 request_id: String,
2125 state: PlatformDeadManState,
2126 server_time_ms: u64,
2127 },
2128 CommandError {
2129 schema_version: u16,
2130 contract_version: String,
2131 market_id: String,
2132 stream_id: String,
2133 sequence: String,
2134 previous_sequence: String,
2135 request_id: String,
2136 error: PublicOperationError,
2137 server_time_ms: u64,
2138 },
2139 Heartbeat {
2140 schema_version: u16,
2141 contract_version: String,
2142 market_id: String,
2143 stream_id: String,
2144 sequence: String,
2145 previous_sequence: String,
2146 server_time_ms: u64,
2147 },
2148}
2149
2150#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2151#[serde(deny_unknown_fields)]
2152pub struct PlatformAccountOrder {
2153 pub order_id: String,
2154 pub side: PlatformTradeSide,
2155 pub order_type: PlatformOrderType,
2156 pub state: PlatformOrderState,
2157 pub limit_price_atoms: String,
2158 pub original_size_atoms: String,
2159 pub remaining_size_atoms: String,
2160}
2161
2162#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2163#[serde(deny_unknown_fields)]
2164pub struct PlatformAccountFill {
2165 pub fill_id: String,
2166 pub side: PlatformTradeSide,
2167 pub price_atoms: String,
2168 pub size_atoms: String,
2169 pub fee_quote_atoms: String,
2170 pub fee_is_final: bool,
2171 pub settlement: PlatformSettlementState,
2172 pub executed_at_ms: u64,
2173 pub confirmed_at_ms: Option<u64>,
2174 pub transaction_id: Option<String>,
2175 pub realized_pnl_quote_atoms: String,
2176}
2177
2178#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2179#[serde(deny_unknown_fields)]
2180pub struct PlatformAccountSnapshotResponse {
2181 pub schema_version: u16,
2182 pub contract_version: String,
2183 pub market_id: String,
2184 pub wallet_address: String,
2185 pub server_time_ms: u64,
2186 pub orders: Vec<PlatformAccountOrder>,
2187 pub fills: Vec<PlatformAccountFill>,
2188}
2189
2190#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2191#[serde(rename_all = "snake_case")]
2192pub enum PlatformMakerReputationTier {
2193 Probation,
2194 Bronze,
2195 Silver,
2196 Gold,
2197 Platinum,
2198}
2199
2200#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2201#[serde(deny_unknown_fields)]
2202pub struct PlatformMakerTierProgress {
2203 pub next_tier: Option<PlatformMakerReputationTier>,
2204 pub reputation_score_required: Option<u16>,
2205 pub reputation_score_remaining: u16,
2206 pub quote_requests_required: Option<String>,
2207 pub quote_requests_remaining: String,
2208 pub stake_atoms_required: Option<String>,
2209 pub stake_atoms_remaining: String,
2210 pub tenure_slots_required: Option<String>,
2211 pub tenure_slots_remaining: String,
2212}
2213
2214#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2218#[serde(deny_unknown_fields)]
2219pub struct PlatformMakerReputationResponse {
2220 pub schema_version: u16,
2221 pub contract_version: String,
2222 pub market_id: String,
2223 pub maker_id: String,
2224 pub wallet_address: String,
2225 pub active: bool,
2226 pub tier: PlatformMakerReputationTier,
2227 pub reputation_score: u16,
2228 pub total_quote_requests: String,
2229 pub successful_fills: String,
2230 pub missed_quote_requests: String,
2231 pub fill_rate_bps: u16,
2232 pub consecutive_misses: u16,
2233 pub lifetime_filled_quote_atoms: String,
2234 pub distinct_counterparties: u16,
2235 pub recent_average_latency_ms: u16,
2236 pub configured_minimum_spread_bps: u16,
2237 pub weighted_average_spread_bps: u16,
2238 pub stake_atoms: String,
2239 pub epoch_start_stake_atoms: String,
2240 pub epoch_slashed_atoms: String,
2241 pub epoch_slashed_bps: u16,
2242 pub lifetime_auto_slashed_atoms: String,
2243 pub registered_slot: String,
2244 pub last_active_slot: String,
2245 pub last_settled_slot: String,
2246 pub revoked_at_slot: Option<String>,
2247 pub tenure_slots: String,
2248 pub signed_quote_stream_eligible: bool,
2249 pub minimum_quote_interval_ms: Option<u16>,
2250 pub tier_progress: PlatformMakerTierProgress,
2251 pub server_time_ms: u64,
2252}
2253
2254#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2255#[serde(rename_all = "snake_case")]
2256pub enum PlatformMakerSide {
2257 Buy,
2258 Sell,
2259}
2260
2261#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2262#[serde(rename_all = "snake_case")]
2263pub enum PlatformOracleHealth {
2264 Fresh,
2265 Stale,
2266 Unknown,
2267}
2268
2269#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2271#[serde(deny_unknown_fields)]
2272pub struct PlatformMakerFirmOrderSummary {
2273 pub resting_orders: u32,
2274 pub bid_orders: u32,
2275 pub ask_orders: u32,
2276 pub bid_size_atoms: String,
2277 pub ask_size_atoms: String,
2278}
2279
2280#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2282#[serde(deny_unknown_fields)]
2283pub struct PlatformMakerSignedQuote {
2284 pub side: PlatformMakerSide,
2285 pub price_atoms: String,
2286 pub size_atoms: String,
2287 pub nonce: String,
2288 pub issued_at_ms: u64,
2289 pub expires_at_ms: u64,
2290}
2291
2292#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2294#[serde(deny_unknown_fields)]
2295pub struct PlatformMakerIntentStatus {
2296 pub active: bool,
2297 pub side: PlatformMakerSide,
2298 pub minimum_price_atoms: String,
2299 pub maximum_price_atoms: String,
2300 pub maximum_fill_size_atoms: String,
2301 pub remaining_fill_size_atoms: String,
2303 pub minimum_spread_bps: u16,
2304 pub stake_atoms: String,
2305}
2306
2307#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2309#[serde(deny_unknown_fields)]
2310pub struct PlatformMakerSignedQuoteLane {
2311 pub eligible: bool,
2312 pub live_quotes: Vec<PlatformMakerSignedQuote>,
2313}
2314
2315#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2316#[serde(deny_unknown_fields)]
2317pub struct PlatformMakerStrandLevel {
2318 pub price_atoms: Option<String>,
2320 pub size_atoms: String,
2321 pub remaining_size_atoms: String,
2322}
2323
2324#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2326#[serde(deny_unknown_fields)]
2327pub struct PlatformMakerStrandStatus {
2328 pub enabled: bool,
2329 pub async_only: bool,
2330 pub expired: bool,
2332 pub mid_price_atoms: String,
2333 pub tick_size_atoms: String,
2334 pub valid_until_slot: Option<String>,
2336 pub bids: Vec<PlatformMakerStrandLevel>,
2337 pub asks: Vec<PlatformMakerStrandLevel>,
2338 pub maximum_exposure_atoms: String,
2339 pub remaining_exposure_atoms: String,
2340}
2341
2342#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2344#[serde(deny_unknown_fields)]
2345pub struct PlatformMakerCurrentStatus {
2346 pub enabled: bool,
2347 pub async_only: bool,
2348 pub expired: bool,
2349 pub half_spread_bps: u16,
2350 pub band_step_bps: u16,
2351 pub maximum_confidence_bps: u16,
2352 pub maximum_oracle_age_seconds: u32,
2353 pub sync_spread_bps: u16,
2354 pub valid_until_slot: Option<String>,
2356 pub bid_depth_atoms: Vec<String>,
2357 pub ask_depth_atoms: Vec<String>,
2358 pub maximum_exposure_atoms: String,
2359 pub remaining_exposure_atoms: String,
2360 pub oracle_health: PlatformOracleHealth,
2362}
2363
2364#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2366#[serde(deny_unknown_fields)]
2367pub struct PlatformMakerDeadManGuard {
2368 pub session_public_key: String,
2369 pub status: PlatformDeadManStatus,
2370 pub timeout_ms: u64,
2371 pub heartbeat_deadline_ms: u64,
2372 pub updated_at_ms: u64,
2373}
2374
2375#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2380#[serde(deny_unknown_fields)]
2381pub struct PlatformMakerStatusResponse {
2382 pub schema_version: u16,
2383 pub contract_version: String,
2384 pub market_id: String,
2385 pub maker_id: String,
2386 pub wallet_address: String,
2387 pub server_time_ms: u64,
2388 pub current_slot: String,
2389 pub firm_orders: PlatformMakerFirmOrderSummary,
2390 pub intent: Option<PlatformMakerIntentStatus>,
2391 pub signed_quotes: PlatformMakerSignedQuoteLane,
2392 pub strands: Vec<PlatformMakerStrandStatus>,
2393 pub currents: Vec<PlatformMakerCurrentStatus>,
2394 pub dead_man_guards: Vec<PlatformMakerDeadManGuard>,
2395 pub active_products: u16,
2398}
2399
2400#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
2402#[serde(rename_all = "snake_case")]
2403pub enum PlatformMakerProduct {
2404 FirmOrder,
2405 Intent,
2406 Strand,
2407 Current,
2408}
2409
2410#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2413#[serde(deny_unknown_fields)]
2414pub struct PlatformMakerFill {
2415 pub fill_id: String,
2416 pub product: PlatformMakerProduct,
2417 pub side: PlatformTradeSide,
2418 pub price_atoms: String,
2419 pub size_atoms: String,
2420 pub fee_quote_atoms: String,
2421 pub fee_is_final: bool,
2422 pub settlement: PlatformSettlementState,
2423 pub executed_at_ms: u64,
2424 pub confirmed_at_ms: Option<u64>,
2425 pub transaction_id: Option<String>,
2426 pub realized_pnl_quote_atoms: String,
2427}
2428
2429#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2435#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2436pub enum PlatformMakerEvent {
2437 AuthChallenge {
2438 schema_version: u16,
2439 contract_version: String,
2440 market_id: String,
2441 wallet_address: String,
2442 challenge: String,
2443 server_time_ms: u64,
2444 expires_at_ms: u64,
2445 },
2446 MakerSnapshot {
2447 schema_version: u16,
2448 contract_version: String,
2449 market_id: String,
2450 wallet_address: String,
2451 stream_id: String,
2452 sequence: String,
2453 server_time_ms: u64,
2454 status: PlatformMakerStatusResponse,
2455 fills: Vec<PlatformMakerFill>,
2456 },
2457 MakerFill {
2458 schema_version: u16,
2459 contract_version: String,
2460 market_id: String,
2461 wallet_address: String,
2462 stream_id: String,
2463 sequence: String,
2464 previous_sequence: String,
2465 server_time_ms: u64,
2466 fill: PlatformMakerFill,
2467 },
2468 MakerStatus {
2469 schema_version: u16,
2470 contract_version: String,
2471 market_id: String,
2472 wallet_address: String,
2473 stream_id: String,
2474 sequence: String,
2475 previous_sequence: String,
2476 server_time_ms: u64,
2477 status: PlatformMakerStatusResponse,
2478 },
2479 Heartbeat {
2480 schema_version: u16,
2481 contract_version: String,
2482 market_id: String,
2483 wallet_address: String,
2484 stream_id: String,
2485 sequence: String,
2486 previous_sequence: String,
2487 server_time_ms: u64,
2488 },
2489}
2490
2491#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2492#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2493pub enum PlatformAccountEvent {
2494 AuthChallenge {
2495 schema_version: u16,
2496 contract_version: String,
2497 market_id: String,
2498 wallet_address: String,
2499 challenge: String,
2500 server_time_ms: u64,
2501 expires_at_ms: u64,
2502 },
2503 AccountSnapshot {
2504 schema_version: u16,
2505 contract_version: String,
2506 market_id: String,
2507 wallet_address: String,
2508 stream_id: String,
2509 sequence: String,
2510 server_time_ms: u64,
2511 orders: Vec<PlatformAccountOrder>,
2512 fills: Vec<PlatformAccountFill>,
2513 },
2514 OrdersSnapshot {
2515 schema_version: u16,
2516 contract_version: String,
2517 market_id: String,
2518 wallet_address: String,
2519 stream_id: String,
2520 sequence: String,
2521 previous_sequence: String,
2522 server_time_ms: u64,
2523 orders: Vec<PlatformAccountOrder>,
2524 },
2525 Fill {
2526 schema_version: u16,
2527 contract_version: String,
2528 market_id: String,
2529 wallet_address: String,
2530 stream_id: String,
2531 sequence: String,
2532 previous_sequence: String,
2533 server_time_ms: u64,
2534 fill: PlatformAccountFill,
2535 },
2536 Heartbeat {
2537 schema_version: u16,
2538 contract_version: String,
2539 market_id: String,
2540 wallet_address: String,
2541 stream_id: String,
2542 sequence: String,
2543 previous_sequence: String,
2544 server_time_ms: u64,
2545 },
2546}
2547
2548#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
2549#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
2550pub enum PlatformMarketDataEvent {
2551 BookSnapshot {
2552 schema_version: u16,
2553 contract_version: String,
2554 market_id: String,
2555 stream_id: String,
2556 sequence: String,
2557 server_time_ms: u64,
2558 snapshot_id: String,
2559 bids: Vec<PlatformBookLevel>,
2560 asks: Vec<PlatformBookLevel>,
2561 },
2562 BookDelta {
2563 schema_version: u16,
2564 contract_version: String,
2565 market_id: String,
2566 stream_id: String,
2567 sequence: String,
2568 previous_sequence: String,
2569 server_time_ms: u64,
2570 changes: Vec<PlatformBookChange>,
2571 },
2572 BestBidAsk {
2573 schema_version: u16,
2574 contract_version: String,
2575 market_id: String,
2576 stream_id: String,
2577 sequence: String,
2578 server_time_ms: u64,
2579 best_bid: Option<PlatformBookLevel>,
2580 best_ask: Option<PlatformBookLevel>,
2581 },
2582 Trade {
2583 schema_version: u16,
2584 contract_version: String,
2585 market_id: String,
2586 server_time_ms: u64,
2587 trade: PlatformTrade,
2588 },
2589 MarketStatus {
2590 schema_version: u16,
2591 contract_version: String,
2592 market_id: String,
2593 server_time_ms: u64,
2594 status: PlatformMarketState,
2595 },
2596 Heartbeat {
2597 schema_version: u16,
2598 contract_version: String,
2599 market_id: String,
2600 server_time_ms: u64,
2601 },
2602}
2603
2604#[cfg(test)]
2605mod tests {
2606 use super::*;
2607
2608 #[test]
2609 fn public_platform_fixtures_decode_strictly() {
2610 let discovery: PlatformDiscoveryResponse =
2611 serde_json::from_str(PLATFORM_CAPABILITIES_FIXTURE).unwrap();
2612 let service_status: PlatformServiceStatusResponse =
2613 serde_json::from_str(PLATFORM_SERVICE_STATUS_FIXTURE).unwrap();
2614 let graph = PlatformActionGraphResponse::foundation();
2615 let assets: PlatformAssetsResponse = serde_json::from_str(PLATFORM_ASSETS_FIXTURE).unwrap();
2616 let swap_quote: PlatformSwapQuoteResponse =
2617 serde_json::from_str(PLATFORM_SWAP_QUOTE_FIXTURE).unwrap();
2618 let markets: PlatformMarketsResponse =
2619 serde_json::from_str(PLATFORM_MARKETS_FIXTURE).unwrap();
2620 let book: PlatformBookSnapshotResponse =
2621 serde_json::from_str(PLATFORM_BOOK_FIXTURE).unwrap();
2622 let bbo: PlatformBestBidAskResponse = serde_json::from_str(PLATFORM_BBO_FIXTURE).unwrap();
2623 let fees: PlatformFeeScheduleResponse =
2624 serde_json::from_str(PLATFORM_FEES_FIXTURE).unwrap();
2625 let status: PlatformMarketStatusResponse =
2626 serde_json::from_str(PLATFORM_STATUS_FIXTURE).unwrap();
2627 let candles: PlatformCandlesResponse =
2628 serde_json::from_str(PLATFORM_CANDLES_FIXTURE).unwrap();
2629 let mark: PlatformMarkResponse = serde_json::from_str(PLATFORM_MARK_FIXTURE).unwrap();
2630 let execution_status: PlatformExecutionStatusResponse =
2631 serde_json::from_str(PLATFORM_EXECUTION_STATUS_FIXTURE).unwrap();
2632 let twaps: PlatformTwapsResponse = serde_json::from_str(PLATFORM_TWAPS_FIXTURE).unwrap();
2633 let twap_challenge: PlatformTwapChallengeResponse =
2634 serde_json::from_str(PLATFORM_TWAP_CHALLENGE_FIXTURE).unwrap();
2635 let twap_prepare: PlatformTwapPrepareResponse =
2636 serde_json::from_str(PLATFORM_TWAP_PREPARE_FIXTURE).unwrap();
2637 let twap_submit: PlatformTwapSubmitResponse =
2638 serde_json::from_str(PLATFORM_TWAP_SUBMIT_FIXTURE).unwrap();
2639 let portfolio_history: PlatformPortfolioHistoryResponse =
2640 serde_json::from_str(PLATFORM_PORTFOLIO_HISTORY_FIXTURE).unwrap();
2641 let portfolio: PlatformPortfolioResponse =
2642 serde_json::from_str(PLATFORM_PORTFOLIO_FIXTURE).unwrap();
2643 let rewards: PlatformRewardsResponse =
2644 serde_json::from_str(PLATFORM_REWARDS_FIXTURE).unwrap();
2645 let referrals: PlatformReferralsResponse =
2646 serde_json::from_str(PLATFORM_REFERRALS_FIXTURE).unwrap();
2647 let referral_link: PlatformReferralLinkResponse =
2648 serde_json::from_str(PLATFORM_REFERRAL_LINK_FIXTURE).unwrap();
2649 let referral_claim: PlatformReferralClaimResponse =
2650 serde_json::from_str(PLATFORM_REFERRAL_CLAIM_FIXTURE).unwrap();
2651 let vault_status: PlatformVaultStatusResponse =
2652 serde_json::from_str(PLATFORM_VAULT_STATUS_FIXTURE).unwrap();
2653 let vault_pause: PlatformVaultPausePrepareResponse =
2654 serde_json::from_str(PLATFORM_VAULT_PAUSE_PREPARE_FIXTURE).unwrap();
2655 let vault_setup: PlatformVaultSetupPrepareResponse =
2656 serde_json::from_str(PLATFORM_VAULT_SETUP_PREPARE_FIXTURE).unwrap();
2657 let vault_delegate: PlatformVaultDelegatePrepareResponse =
2658 serde_json::from_str(PLATFORM_VAULT_DELEGATE_PREPARE_FIXTURE).unwrap();
2659 let vault_policy: PlatformVaultPolicyPrepareResponse =
2660 serde_json::from_str(PLATFORM_VAULT_POLICY_PREPARE_FIXTURE).unwrap();
2661 let vault_deposit: PlatformVaultDepositPrepareResponse =
2662 serde_json::from_str(PLATFORM_VAULT_DEPOSIT_PREPARE_FIXTURE).unwrap();
2663 let vault_withdraw: PlatformVaultWithdrawPrepareResponse =
2664 serde_json::from_str(PLATFORM_VAULT_WITHDRAW_PREPARE_FIXTURE).unwrap();
2665 let vault_submit: PlatformVaultSubmitResponse =
2666 serde_json::from_str(PLATFORM_VAULT_SUBMIT_FIXTURE).unwrap();
2667 let bugs: PlatformBugsResponse = serde_json::from_str(PLATFORM_BUGS_FIXTURE).unwrap();
2668 let bug_submit: PlatformBugSubmitResponse =
2669 serde_json::from_str(PLATFORM_BUG_SUBMIT_FIXTURE).unwrap();
2670 let trades: PlatformTradesResponse = serde_json::from_str(PLATFORM_TRADES_FIXTURE).unwrap();
2671 let account: PlatformAccountSnapshotResponse =
2672 serde_json::from_str(PLATFORM_ACCOUNT_FIXTURE).unwrap();
2673 let maker_reputation: PlatformMakerReputationResponse =
2674 serde_json::from_str(PLATFORM_MAKER_REPUTATION_FIXTURE).unwrap();
2675 let maker_status: PlatformMakerStatusResponse =
2676 serde_json::from_str(PLATFORM_MAKER_STATUS_FIXTURE).unwrap();
2677 let maker_stream: PlatformMakerEvent =
2678 serde_json::from_str(PLATFORM_MAKER_STREAM_FIXTURE).unwrap();
2679 let twap_stream: PlatformTwapEvent =
2680 serde_json::from_str(PLATFORM_TWAP_STREAM_FIXTURE).unwrap();
2681 let execution_stream: PlatformExecutionEvent =
2682 serde_json::from_str(PLATFORM_EXECUTION_STREAM_FIXTURE).unwrap();
2683 let order_challenge: PlatformOrderChallengeResponse =
2684 serde_json::from_str(PLATFORM_ORDER_CHALLENGE_FIXTURE).unwrap();
2685 let order_prepare: PlatformOrderPrepareResponse =
2686 serde_json::from_str(PLATFORM_ORDER_PREPARE_FIXTURE).unwrap();
2687 let order_submit: PlatformOrderSubmitResponse =
2688 serde_json::from_str(PLATFORM_ORDER_SUBMIT_FIXTURE).unwrap();
2689 let order_status: PlatformOrderStatusResponse =
2690 serde_json::from_str(PLATFORM_ORDER_STATUS_FIXTURE).unwrap();
2691
2692 assert_eq!(discovery.schema_version, PLATFORM_SCHEMA_VERSION);
2693 assert_eq!(service_status.status, PlatformServiceState::Operational);
2694 assert_eq!(service_status.available_operations, 59);
2695 assert_eq!(graph.entry_operation_id, "platform.capabilities.read");
2696 assert_eq!(graph.operations.len(), 67);
2697 assert_eq!(maker_reputation.tier, PlatformMakerReputationTier::Gold);
2698 assert_eq!(maker_status.active_products, 3);
2699 match &maker_stream {
2700 PlatformMakerEvent::MakerSnapshot { status, fills, .. } => {
2701 assert_eq!(status.active_products, maker_status.active_products);
2702 assert_eq!(fills.len(), 1);
2703 assert_eq!(fills[0].product, PlatformMakerProduct::Strand);
2704 }
2705 other => panic!("maker stream fixture must be a snapshot, got {other:?}"),
2706 }
2707 match &twap_stream {
2708 PlatformTwapEvent::TwapsSnapshot {
2709 twaps: streamed, ..
2710 } => {
2711 assert_eq!(streamed, &twaps.twaps);
2712 }
2713 other => panic!("twap stream fixture must be a snapshot, got {other:?}"),
2714 }
2715 match &execution_stream {
2716 PlatformExecutionEvent::ExecutionsSnapshot {
2717 executions,
2718 unknown_execution_ids,
2719 ..
2720 } => {
2721 assert_eq!(executions.len(), 2);
2722 assert_eq!(executions[0].execution_id, execution_status.execution_id);
2723 assert_eq!(unknown_execution_ids.len(), 1);
2724 }
2725 other => panic!("execution stream fixture must be a snapshot, got {other:?}"),
2726 }
2727 assert_eq!(maker_status.strands.len(), 1);
2728 assert_eq!(maker_status.currents.len(), 1);
2729 assert!(maker_status
2730 .intent
2731 .as_ref()
2732 .is_some_and(|intent| intent.active));
2733 assert_eq!(portfolio.balances.len(), 2);
2734 assert_eq!(portfolio.positions.len(), 1);
2735 assert!(portfolio.valuation_complete);
2736 assert_eq!(portfolio.equity_usd_micros.as_deref(), Some("439989500"));
2737 assert!(graph
2738 .operations
2739 .iter()
2740 .any(|operation| operation.id == "twap.place.submit"));
2741 assert!(graph
2742 .operations
2743 .iter()
2744 .any(|operation| operation.id == "twap.cancel.submit"));
2745 assert_eq!(discovery.capabilities.len(), 5);
2746 assert!(!discovery.authority.accepts_private_keys);
2747 assert_eq!(assets.assets.len(), 2);
2748 assert_eq!(swap_quote.input_asset_id, assets.assets[0].asset_id);
2749 assert_eq!(swap_quote.output_asset_id, assets.assets[1].asset_id);
2750 assert_eq!(markets.markets.len(), 1);
2751 assert_eq!(markets.markets[0].base_asset_id, assets.assets[0].asset_id);
2752 assert_eq!(markets.markets[0].quote_asset_id, assets.assets[1].asset_id);
2753 assert_eq!(book.sequence, "42");
2754 assert_eq!(bbo.best_bid.unwrap().price_atoms, "149990000");
2755 assert_eq!(fees.maximum_immediate_execution_fee_bps, 10);
2756 assert_eq!(status.status, PlatformMarketState::Active);
2757 assert_eq!(candles.candles.len(), 2);
2758 assert_eq!(mark.price_atoms_per_base_unit.as_deref(), Some("149995000"));
2759 assert_eq!(execution_status.status, PlatformExecutionState::Confirmed);
2760 assert_eq!(
2761 execution_status.settlement,
2762 PlatformSettlementState::Confirmed
2763 );
2764 assert_eq!(twaps.twaps[0].fills.len(), 1);
2765 assert_eq!(twaps.twaps[0].slices_executed, 2);
2766 assert_eq!(twap_challenge.action, PlatformTwapControlAction::Place);
2767 assert_eq!(twap_prepare.twap_id, twap_challenge.twap_id);
2768 assert_eq!(twap_submit.twap_control_id, twap_prepare.twap_control_id);
2769 assert_eq!(portfolio_history.points.len(), 2);
2770 assert_eq!(rewards.standings.len(), 2);
2771 assert!(referrals.enabled);
2772 assert_eq!(referral_link.status, "pending_first_fill");
2773 assert_eq!(referral_claim.status, "requested");
2774 assert_eq!(vault_status.state, PlatformVaultState::Active);
2775 assert_eq!(
2776 vault_status.session.as_ref().unwrap().state,
2777 PlatformVaultSessionState::Active
2778 );
2779 assert!(vault_pause.paused);
2780 assert!(vault_pause.owner_signature_required);
2781 assert_eq!(vault_setup.mode, PlatformVaultSetupMode::Create);
2782 assert!(vault_setup.permanent);
2783 assert_eq!(vault_delegate.action, PlatformVaultDelegateAction::Revoke);
2784 assert!(vault_delegate.owner_signature_required);
2785 assert_eq!(
2786 vault_policy.withdrawal_access.mode,
2787 PlatformVaultWithdrawalMode::Restricted
2788 );
2789 assert!(vault_policy.owner_signature_required);
2790 assert_eq!(vault_deposit.amount_atoms, "10000000");
2791 assert!(vault_deposit.owner_signature_required);
2792 assert_eq!(vault_withdraw.amount_atoms, "5000000");
2793 assert!(vault_withdraw.owner_signature_required);
2794 assert!(vault_withdraw.sponsored);
2795 assert!(vault_withdraw.preparation_id.starts_with("vp_"));
2796 assert_eq!(vault_submit.action, PlatformVaultAction::Deposit);
2797 assert_eq!(
2798 vault_submit.status,
2799 PlatformVaultSubmissionStatus::Submitted
2800 );
2801 assert!(vault_submit.sponsored);
2802 assert_eq!(vault_submit.failure_code, None);
2803 assert_eq!(bugs.reports[0].status, PlatformBugStatus::Confirmed);
2804 assert_eq!(bug_submit.status, PlatformBugStatus::Pending);
2805 assert_eq!(trades.trades.len(), 1);
2806 assert_eq!(account.orders.len(), 1);
2807 assert_eq!(account.fills.len(), 1);
2808 assert_eq!(order_challenge.action, PlatformOrderAction::Place);
2809 assert_eq!(order_prepare.order_ids, order_challenge.order_ids);
2810 assert_eq!(order_submit.order_ids, order_challenge.order_ids);
2811 assert_eq!(order_status.order_control_id, order_submit.order_control_id);
2812 assert_eq!(order_status.status, PlatformOrderControlStatus::Submitting);
2813 }
2814
2815 #[test]
2816 fn public_platform_response_rejects_unreviewed_fields() {
2817 let mut value: serde_json::Value =
2818 serde_json::from_str(PLATFORM_CAPABILITIES_FIXTURE).unwrap();
2819 value
2820 .as_object_mut()
2821 .unwrap()
2822 .insert("unexpected_field".to_owned(), serde_json::Value::Bool(true));
2823 assert!(serde_json::from_value::<PlatformDiscoveryResponse>(value).is_err());
2824
2825 let mut account_event: serde_json::Value =
2826 serde_json::from_str(PLATFORM_ACCOUNT_FIXTURE).unwrap();
2827 let event = account_event.as_object_mut().unwrap();
2828 event.insert("type".to_owned(), serde_json::json!("account_snapshot"));
2829 event.insert(
2830 "stream_id".to_owned(),
2831 serde_json::json!("account_stream_66666666666666666666666666666666"),
2832 );
2833 event.insert("sequence".to_owned(), serde_json::json!("1"));
2834 event.insert("unexpected_field".to_owned(), serde_json::json!(true));
2835 assert!(serde_json::from_value::<PlatformAccountEvent>(account_event).is_err());
2836 }
2837
2838 #[test]
2839 fn platform_graph_availability_is_projected_from_live_capabilities() {
2840 let mut graph = PlatformActionGraphResponse::foundation();
2841 let live = std::collections::BTreeSet::from([
2842 "platform.discover".to_owned(),
2843 "graphs.read".to_owned(),
2844 "orders.replace".to_owned(),
2845 ]);
2846
2847 graph.project_availability(&live);
2848
2849 for operation in &graph.operations {
2850 assert_eq!(
2851 operation.available,
2852 live.contains(&operation.capability_id),
2853 "operation {} did not follow capability {}",
2854 operation.id,
2855 operation.capability_id,
2856 );
2857 }
2858 assert!(graph
2859 .workflows
2860 .iter()
2861 .flat_map(|workflow| &workflow.nodes)
2862 .filter(|node| node.kind != PlatformActionKind::ExternalSignature)
2863 .all(|node| {
2864 node.available
2865 == node
2866 .capability_id
2867 .as_ref()
2868 .is_some_and(|capability_id| live.contains(capability_id))
2869 }));
2870 assert!(graph
2871 .workflows
2872 .iter()
2873 .flat_map(|workflow| &workflow.nodes)
2874 .filter(|node| node.kind == PlatformActionKind::ExternalSignature)
2875 .all(|node| node.available));
2876 }
2877
2878 #[test]
2879 fn atomic_order_batch_request_is_strict_and_typed() {
2880 let request: PlatformOrderChallengeRequest = serde_json::from_value(serde_json::json!({
2881 "action": "batch",
2882 "owner_wallet": "11111111111111111111111111111111",
2883 "session_public_key": "22222222222222222222222222222222",
2884 "operations": [
2885 {
2886 "action": "cancel",
2887 "order_id": "order_11111111111111111111111111111111"
2888 },
2889 {
2890 "action": "replace",
2891 "order_id": "order_22222222222222222222222222222222",
2892 "account_sequence": "8",
2893 "client_order_id": "replacement-8",
2894 "side": "sell",
2895 "order_type": "post_only",
2896 "limit_price_atoms": "151000000",
2897 "size_atoms": "2000000"
2898 }
2899 ]
2900 }))
2901 .unwrap();
2902 let PlatformOrderChallengeRequest::Batch { operations, .. } = request else {
2903 panic!("expected batch request");
2904 };
2905 assert_eq!(operations.len(), 2);
2906 assert!(matches!(
2907 &operations[1],
2908 PlatformOrderBatchOperation::Replace { account_sequence: Some(sequence), .. }
2909 if sequence == "8"
2910 ));
2911
2912 let place: PlatformOrderChallengeRequest = serde_json::from_value(serde_json::json!({
2916 "action": "place",
2917 "owner_wallet": "11111111111111111111111111111111",
2918 "session_public_key": "22222222222222222222222222222222",
2919 "client_order_id": "first-order",
2920 "side": "buy",
2921 "order_type": "post_only",
2922 "limit_price_atoms": "150000000",
2923 "size_atoms": "1000000"
2924 }))
2925 .unwrap();
2926 assert!(matches!(
2927 place,
2928 PlatformOrderChallengeRequest::Place {
2929 account_sequence: None,
2930 ..
2931 }
2932 ));
2933 assert!(!serde_json::to_string(&place)
2934 .unwrap()
2935 .contains("account_sequence"));
2936
2937 assert!(
2938 serde_json::from_value::<PlatformOrderChallengeRequest>(serde_json::json!({
2939 "action": "batch",
2940 "owner_wallet": "11111111111111111111111111111111",
2941 "session_public_key": "22222222222222222222222222222222",
2942 "operations": [{
2943 "action": "cancel",
2944 "order_id": "order_11111111111111111111111111111111",
2945 "implementation": "hidden"
2946 }]
2947 }))
2948 .is_err()
2949 );
2950 }
2951
2952 #[test]
2953 fn persistent_order_commands_are_strict_and_explicit_about_self_trade_policy() {
2954 let frame: PlatformOrderCommandClientFrame = serde_json::from_value(serde_json::json!({
2955 "type": "command",
2956 "request_id": "agent-1",
2957 "sequence": "1",
2958 "command": {
2959 "type": "challenge",
2960 "self_trade_prevention": "cancel_maker",
2961 "request": {
2962 "action": "cancel_all",
2963 "owner_wallet": "11111111111111111111111111111111",
2964 "session_public_key": "22222222222222222222222222222222"
2965 }
2966 }
2967 }))
2968 .unwrap();
2969 assert!(matches!(
2970 frame,
2971 PlatformOrderCommandClientFrame::Command {
2972 command: PlatformOrderCommand::Challenge {
2973 self_trade_prevention: PlatformSelfTradePrevention::CancelMaker,
2974 ..
2975 },
2976 ..
2977 }
2978 ));
2979 assert!(
2980 serde_json::from_value::<PlatformOrderCommandClientFrame>(serde_json::json!({
2981 "type": "command",
2982 "request_id": "agent-1",
2983 "sequence": "1",
2984 "command": {
2985 "type": "challenge",
2986 "request": {
2987 "action": "cancel_all",
2988 "owner_wallet": "11111111111111111111111111111111",
2989 "session_public_key": "22222222222222222222222222222222"
2990 }
2991 }
2992 }))
2993 .is_err()
2994 );
2995 }
2996
2997 #[test]
2998 fn prepare_requests_accept_a_signed_challenge_or_the_operation_itself() {
2999 let signed: PlatformOrderPrepareRequest = serde_json::from_value(serde_json::json!({
3000 "challenge_id": "oc_0123456789abcdef0123456789abcdef",
3001 "authorization_signature": "1111",
3002 }))
3003 .unwrap();
3004 assert!(matches!(signed, PlatformOrderPrepareRequest::Authorized(_)));
3005 let direct: PlatformOrderPrepareRequest = serde_json::from_value(serde_json::json!({
3006 "action": "cancel_all",
3007 "owner_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3008 "session_public_key": "9Uu7cLBgfMk233BAjMvTS8XJy6KbZK7oQ7NXuCTi3Fg2",
3009 }))
3010 .unwrap();
3011 assert!(matches!(
3012 direct,
3013 PlatformOrderPrepareRequest::Direct(PlatformOrderChallengeRequest::CancelAll { .. })
3014 ));
3015 assert!(
3017 serde_json::from_value::<PlatformOrderPrepareRequest>(serde_json::json!({
3018 "challenge_id": "oc_0123456789abcdef0123456789abcdef",
3019 "authorization_signature": "1111",
3020 "extra": true,
3021 }))
3022 .is_err()
3023 );
3024 let twap: PlatformTwapPrepareRequest = serde_json::from_value(serde_json::json!({
3025 "action": "cancel",
3026 "owner_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3027 "session_public_key": "9Uu7cLBgfMk233BAjMvTS8XJy6KbZK7oQ7NXuCTi3Fg2",
3028 "twap_id": "twap_0123456789abcdef0123456789abcdef",
3029 }))
3030 .unwrap();
3031 assert!(matches!(twap, PlatformTwapPrepareRequest::Direct(_)));
3032 let execution: crate::ExecutionPrepareRequest = serde_json::from_value(serde_json::json!({
3033 "quote_id": "quote_0123456789abcdef0123456789abcdef",
3034 "owner_wallet": "5Ji61Fbeb22Yntgv1hhHeSSLgdEdZchHeM1Tv1MjGhSL",
3035 "session_public_key": "9Uu7cLBgfMk233BAjMvTS8XJy6KbZK7oQ7NXuCTi3Fg2",
3036 }))
3037 .unwrap();
3038 assert!(matches!(
3039 execution,
3040 crate::ExecutionPrepareRequest::Direct(_)
3041 ));
3042 }
3043}