polynode 0.13.7

Rust SDK for the PolyNode API — real-time Polymarket data
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
//! Trading module types.

use serde::{Deserialize, Serialize};

// ── Wallet & Signer ──

/// Signature types matching Polymarket's exchange contracts.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum SignatureType {
    Eoa = 0,
    PolyProxy = 1,
    PolyGnosisSafe = 2,
    /// ERC-1271 signatures for deposit wallets (V2 only).
    Poly1271 = 3,
}

impl SignatureType {
    pub fn as_u8(self) -> u8 {
        self as u8
    }

    pub fn from_u8(v: u8) -> Option<Self> {
        match v {
            0 => Some(Self::Eoa),
            1 => Some(Self::PolyProxy),
            2 => Some(Self::PolyGnosisSafe),
            3 => Some(Self::Poly1271),
            _ => None,
        }
    }
}

impl Default for SignatureType {
    fn default() -> Self {
        Self::PolyGnosisSafe
    }
}

impl std::fmt::Display for SignatureType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Eoa => write!(f, "EOA"),
            Self::PolyProxy => write!(f, "POLY_PROXY"),
            Self::PolyGnosisSafe => write!(f, "POLY_GNOSIS_SAFE"),
            Self::Poly1271 => write!(f, "POLY_1271"),
        }
    }
}

// ── Builder Credentials ──

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BuilderCredentials {
    pub key: String,
    pub secret: String,
    pub passphrase: String,
}

// ── Exchange Version ──

/// Exchange version. V1 is the current live system. V2 is the new system
/// with PolyUSD collateral, different order struct, and different CLOB endpoint.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ExchangeVersion {
    /// V1: USDC.e collateral, domain version "1", clob.polymarket.com
    V1,
    /// V2: PolyUSD collateral, domain version "2", clob.polymarket.com
    V2,
}

impl Default for ExchangeVersion {
    fn default() -> Self {
        Self::V1
    }
}

impl std::fmt::Display for ExchangeVersion {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::V1 => write!(f, "v1"),
            Self::V2 => write!(f, "v2"),
        }
    }
}

// ── Fee Escrow ──

/// Optional fee configuration for per-order fee collection via on-chain escrow.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FeeConfig {
    /// Fee in basis points (e.g. 50 = 0.5% of order notional). 0 = no fee.
    pub fee_bps: u16,
    /// Affiliate address to receive a share of the fee.
    pub affiliate: Option<String>,
    /// Affiliate's share of the fee in basis points (e.g. 3000 = 30% to affiliate).
    pub affiliate_share_bps: Option<u16>,
}

// ── Config ──

#[derive(Debug, Clone)]
pub struct TraderConfig {
    /// polynode API key (for builder attribution via co-signer).
    pub polynode_key: String,
    /// Path to local SQLite database.
    pub db_path: String,
    /// Co-signer URL.
    pub cosigner_url: String,
    /// If true, submit directly to CLOB when co-signer is unreachable.
    pub fallback_direct: bool,
    /// Wallet type for new users.
    pub default_signature_type: SignatureType,
    /// RPC URL for on-chain reads.
    pub rpc_url: String,
    /// Optional builder credentials for co-signer endpoints.
    pub builder_credentials: Option<BuilderCredentials>,
    /// Exchange version: V1 (current) or V2 (PolyUSD + new order struct).
    pub exchange_version: ExchangeVersion,
    /// Fee escrow config. If fee_bps > 0, fees are pulled before each order.
    pub fee_config: Option<FeeConfig>,
}

impl Default for TraderConfig {
    fn default() -> Self {
        Self {
            polynode_key: String::new(),
            db_path: "./polynode-trading.db".into(),
            cosigner_url: super::constants::DEFAULT_COSIGNER.into(),
            fallback_direct: true,
            default_signature_type: SignatureType::PolyGnosisSafe,
            rpc_url: super::constants::DEFAULT_RPC.into(),
            builder_credentials: None,
            exchange_version: ExchangeVersion::V1,
            fee_config: None,
        }
    }
}

// ── CLOB Credentials ──

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClobCredentials {
    pub api_key: String,
    pub api_secret: String,
    pub api_passphrase: String,
}

// ── Onboarding Results ──

#[derive(Debug, Clone, Serialize)]
pub struct ReadyStatus {
    pub wallet: String,
    pub funder_address: String,
    pub signature_type: SignatureType,
    pub safe_deployed: bool,
    pub approvals_set: bool,
    pub credentials_stored: bool,
    pub credentials: ClobCredentials,
    pub actions: Vec<String>,
}

#[derive(Debug, Clone, Serialize)]
pub struct LinkResult {
    pub wallet: String,
    pub funder_address: String,
    pub signature_type: SignatureType,
    pub credentials: ClobCredentials,
}

#[derive(Debug, Clone, Serialize)]
pub struct WalletInfo {
    pub wallet: String,
    pub funder_address: String,
    pub signature_type: SignatureType,
    pub credentials: ClobCredentials,
    pub created_at: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WalletExport {
    pub wallet: String,
    pub funder_address: String,
    pub signature_type: SignatureType,
    pub credentials: ClobCredentials,
    pub safe_deployed: bool,
    pub approvals_set: bool,
    pub created_at: f64,
}

// ── Approval / Balance Checks ──

#[derive(Debug, Clone, Serialize)]
pub struct UsdcApprovals {
    pub ctf_exchange: bool,
    pub neg_risk_ctf_exchange: bool,
    pub neg_risk_adapter: bool,
    pub fee_escrow: bool,
}

#[derive(Debug, Clone, Serialize)]
pub struct CtfApprovals {
    pub ctf_exchange: bool,
    pub neg_risk_ctf_exchange: bool,
    pub neg_risk_adapter: bool,
}

#[derive(Debug, Clone, Serialize)]
pub struct ApprovalStatus {
    pub funder_address: String,
    pub usdc: UsdcApprovals,
    pub ctf: CtfApprovals,
    pub all_approved: bool,
}

#[derive(Debug, Clone, Serialize)]
pub struct BalanceInfo {
    pub funder_address: String,
    pub usdc: String,
    pub usdc_raw: String,
    pub matic: String,
}

// ── Trading ──

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum OrderSide {
    #[serde(rename = "BUY")]
    Buy,
    #[serde(rename = "SELL")]
    Sell,
}

impl std::fmt::Display for OrderSide {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Buy => write!(f, "BUY"),
            Self::Sell => write!(f, "SELL"),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum OrderType {
    GTC,
    GTD,
    FOK,
    FAK,
}

impl Default for OrderType {
    fn default() -> Self {
        Self::GTC
    }
}

impl std::fmt::Display for OrderType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::GTC => write!(f, "GTC"),
            Self::GTD => write!(f, "GTD"),
            Self::FOK => write!(f, "FOK"),
            Self::FAK => write!(f, "FAK"),
        }
    }
}

#[derive(Debug, Clone)]
pub struct OrderParams {
    pub token_id: String,
    pub side: OrderSide,
    pub price: f64,
    pub size: f64,
    pub order_type: OrderType,
    pub expiration: Option<u64>,
    pub post_only: bool,
    /// Per-order fee override. If set, overrides config-level fee_config for this order.
    pub fee_config: Option<FeeConfig>,
    /// V2 builder attribution bytes32. Mint at polymarket.com/settings?tab=builder.
    /// Defaults to zero (no attribution). Ignored on V1.
    pub builder: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OrderResult {
    pub success: bool,
    pub order_id: Option<String>,
    pub status: Option<String>,
    pub error: Option<String>,
    pub making_amount: Option<String>,
    pub taking_amount: Option<String>,
    /// Fee escrow transaction hash, if a fee was pulled for this order.
    pub fee_escrow_tx_hash: Option<String>,
    /// Fee amount in USDC (human-readable, e.g. "0.05").
    pub fee_amount: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CancelResult {
    pub canceled: Vec<String>,
    pub not_canceled: std::collections::HashMap<String, String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OpenOrder {
    pub id: String,
    pub market: String,
    #[serde(rename = "assetId")]
    pub asset_id: String,
    pub side: String,
    pub price: String,
    #[serde(rename = "originalSize")]
    pub original_size: String,
    #[serde(rename = "sizeMatched")]
    pub size_matched: String,
    pub status: String,
    #[serde(rename = "createdAt")]
    pub created_at: String,
    #[serde(rename = "orderType")]
    pub order_type: String,
}

// ── Position Management (split/merge/convert) ──

/// Parameters for splitting USDC into YES + NO outcome tokens.
#[derive(Debug, Clone)]
pub struct SplitParams {
    /// Market condition ID.
    pub condition_id: String,
    /// Amount in USDC (e.g. 100.0 = $100). SDK handles 6-decimal conversion.
    pub amount: f64,
}

/// Parameters for merging YES + NO outcome tokens back into USDC.
#[derive(Debug, Clone)]
pub struct MergeParams {
    /// Market condition ID.
    pub condition_id: String,
    /// Amount in USDC (e.g. 100.0 = $100).
    pub amount: f64,
}

/// Parameters for converting NO positions on selected outcomes into USDC + YES on complementary outcomes.
/// Only works on neg-risk multi-outcome markets.
#[derive(Debug, Clone)]
pub struct ConvertParams {
    /// Neg-risk market group ID (negRiskMarketID from market data).
    pub market_id: String,
    /// Outcome indices to convert (e.g. vec![0, 1]).
    pub outcome_indices: Vec<u32>,
    /// Amount per outcome in USDC (e.g. 100.0 = $100).
    pub amount: f64,
}

/// A pre-built transaction ready for submission to the Polymarket relayer or directly on-chain.
#[derive(Debug, Clone, Serialize)]
pub struct TransactionRequest {
    /// Contract address to call.
    pub to: String,
    /// ABI-encoded calldata (hex string with 0x prefix).
    pub data: String,
    /// ETH value (always "0" for these operations).
    pub value: String,
}

/// Result of a position management operation.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PositionResult {
    pub success: bool,
    pub tx_hash: Option<String>,
    pub error: Option<String>,
}

// ── Market Metadata ──

#[derive(Debug, Clone)]
pub struct MarketMeta {
    pub token_id: String,
    pub tick_size: String,
    pub fee_rate_bps: i32,
    pub neg_risk: bool,
    pub fetched_at: f64,
}

// ── Order History (local) ──

#[derive(Debug, Clone, Serialize)]
pub struct OrderHistoryRow {
    pub id: i64,
    pub wallet_address: String,
    pub order_id: Option<String>,
    pub token_id: String,
    pub side: String,
    pub price: f64,
    pub size: f64,
    pub order_type: String,
    pub status: String,
    pub error_msg: Option<String>,
    pub response_json: Option<String>,
    pub created_at: f64,
    pub fee_amount_raw: Option<String>,
    pub escrow_order_id: Option<String>,
    pub fee_escrow_tx_hash: Option<String>,
}

#[derive(Debug, Clone, Default)]
pub struct HistoryParams {
    pub limit: Option<u32>,
    pub offset: Option<u32>,
    pub token_id: Option<String>,
    pub side: Option<OrderSide>,
}

// ── Stored Credentials ──

#[derive(Debug, Clone)]
pub struct StoredCredentials {
    pub wallet_address: String,
    pub funder_address: Option<String>,
    pub api_key: String,
    pub api_secret: String,
    pub api_passphrase: String,
    pub signature_type: SignatureType,
    pub safe_deployed: bool,
    pub approvals_set: bool,
    pub created_at: f64,
    pub updated_at: f64,
}

// ── Co-signer ──

#[derive(Debug, Clone, Serialize)]
pub struct CosignerRequest {
    pub method: String,
    pub path: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub body: Option<String>,
    pub headers: std::collections::HashMap<String, String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub builder_credentials: Option<BuilderCredentials>,
    /// Fee escrow authorization. If set, cosigner calls pullFee before forwarding order.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub fee_auth: Option<FeeAuthRequest>,
    /// CLOB host override for direct submission (V1 vs V2).
    /// Not serialized to cosigner — only used by send_direct fallback.
    #[serde(skip)]
    pub clob_host: Option<String>,
}

// ── Fee Auth (for cosigner) ──

#[derive(Debug, Clone, Serialize)]
pub struct FeeAuthRequest {
    pub escrow_order_id: String,
    pub payer: String,
    pub signer: String,
    pub fee_amount: String,
    pub deadline: u64,
    pub nonce: u64,
    pub signature: String,
    pub affiliate: String,
    pub affiliate_share_bps: u16,
    /// V2-routing hint for the cosigner. Set when exchange_version == V2 so the
    /// cosigner picks the V2 FeeEscrow operator; omitted for V1 (preserves
    /// backwards compatibility with V1 customers).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub escrow_contract: Option<String>,
}

// ── EIP-712 ──

#[derive(Debug, Clone, Serialize)]
pub struct Eip712Payload {
    pub domain: serde_json::Value,
    pub types: serde_json::Value,
    pub primary_type: String,
    pub message: serde_json::Value,
}