pax-api 2.0.0__tar.gz → 2.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pax-api
3
- Version: 2.0.0
3
+ Version: 2.2.0
4
4
  Summary: Official Python SDK for the PredictAsiaX Trader Track API — Web3-native prediction markets
5
5
  Author-email: PredictAsiaX <support@predictasiax.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pax-api"
7
- version = "2.0.0"
7
+ version = "2.2.0"
8
8
  description = "Official Python SDK for the PredictAsiaX Trader Track API — Web3-native prediction markets"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -26,7 +26,7 @@ caps), not a separate host. Same prefix, same URL — promote to production by
26
26
  upgrading the key's tier.
27
27
  """
28
28
 
29
- __version__ = "2.0.0"
29
+ __version__ = "2.2.0"
30
30
 
31
31
  from pax_api.client import PaxClient # noqa: E402
32
32
  from pax_api.ws_client import PaxWSClient # noqa: E402
@@ -25,7 +25,7 @@ from pax_api.auth import sign_request
25
25
  from pax_api.errors import PaxError, build_error
26
26
  from pax_api.retry import run_with_retry
27
27
 
28
- __version__ = "2.0.0" # keep in sync with __init__.py + pyproject.toml
28
+ __version__ = "2.2.0" # keep in sync with __init__.py + pyproject.toml
29
29
 
30
30
 
31
31
  # v2: sandbox is a tier on the key, not a separate host. All env aliases
@@ -285,6 +285,59 @@ class PaxClient:
285
285
  """Cancel an open order."""
286
286
  return self._request("DELETE", f"/v1/orders/{order_id}")
287
287
 
288
+ def place_orders_batch(self, orders: List[Dict[str, Any]]) -> Dict[str, Any]:
289
+ """POST /v1/orders/batch — place up to 25 orders in one request (v2.1+).
290
+
291
+ Each order dict uses server field names (market_id / outcome_id / side /
292
+ order_type / size / price / client_order_id). Response contains a
293
+ ``results`` array with one entry per input plus a ``summary`` — one
294
+ bad order does not fail the whole batch, inspect ``results[i].ok``.
295
+ Batch cap is env-tunable server-side (BATCH_ORDERS_MAX default 25);
296
+ exceeding returns ``413 BATCH_TOO_LARGE``.
297
+ """
298
+ return self._request("POST", "/v1/orders/batch", json_body={"orders": orders})
299
+
300
+ def cancel_orders_batch(self, order_ids: List[str]) -> Dict[str, Any]:
301
+ """DELETE /v1/orders/batch — cancel up to 50 orders in one request (v2.1+).
302
+
303
+ Response mirrors ``place_orders_batch`` shape. Batch cap env-tunable
304
+ (BATCH_CANCEL_MAX default 50).
305
+ """
306
+ return self._request("DELETE", "/v1/orders/batch", json_body={"orderIds": order_ids})
307
+
308
+ def estimate_fees(self, *, size: str, price: str,
309
+ market_id: Optional[str] = None,
310
+ side: Optional[str] = None,
311
+ action: Optional[str] = None,
312
+ vip_discount: Optional[float] = None,
313
+ sharp_multiplier: Optional[float] = None,
314
+ is_mint_taker: bool = False,
315
+ is_amm_maker: bool = False,
316
+ acquisition_builder_id: Optional[str] = None,
317
+ execution_builder_id: Optional[str] = None,
318
+ operator_id: Optional[str] = None,
319
+ market_creator_id: Optional[str] = None) -> Dict[str, Any]:
320
+ """GET /v1/fees/estimate — pre-trade 5-actor split preview (v2.1+).
321
+
322
+ Returns the same ``fee`` block shape as post-trade responses (splits +
323
+ attribution + breakdown + ledger_preview). Powered server-side by
324
+ ``lib/fiveActorFees`` — env-tunable bps flow through automatically.
325
+ Polymarket has no equivalent endpoint.
326
+ """
327
+ params: Dict[str, Any] = {"size": str(size), "price": str(price)}
328
+ if market_id is not None: params["market_id"] = market_id
329
+ if side is not None: params["side"] = side
330
+ if action is not None: params["action"] = action
331
+ if vip_discount is not None: params["vip_discount"] = str(vip_discount)
332
+ if sharp_multiplier is not None: params["sharp_multiplier"] = str(sharp_multiplier)
333
+ if is_mint_taker: params["is_mint_taker"] = "1"
334
+ if is_amm_maker: params["is_amm_maker"] = "1"
335
+ if acquisition_builder_id is not None: params["acquisition_builder_id"] = acquisition_builder_id
336
+ if execution_builder_id is not None: params["execution_builder_id"] = execution_builder_id
337
+ if operator_id is not None: params["operator_id"] = operator_id
338
+ if market_creator_id is not None: params["market_creator_id"] = market_creator_id
339
+ return self._request("GET", "/v1/fees/estimate", params=params)
340
+
288
341
  def create_market(self, template_id: str, params: Dict[str, Any],
289
342
  creator_metadata: Optional[Dict[str, Any]] = None,
290
343
  idempotency_key: Optional[str] = None) -> Dict[str, Any]:
@@ -334,6 +387,49 @@ class PaxClient:
334
387
  if description is not None: body["description"] = description
335
388
  return self._request("POST", "/v1/apply", json_body=body)
336
389
 
390
+ # ── Public audit verifier (v2.2+, no-auth read-only) ────────────────────
391
+ def audit_status(self) -> Dict[str, Any]:
392
+ """GET /v1/audit/status — event/batch counts + latest anchor lag."""
393
+ return self._request("GET", "/v1/audit/status")
394
+
395
+ def audit_latest_batch(self) -> Dict[str, Any]:
396
+ """GET /v1/audit/batches/latest — most recent Merkle batch metadata."""
397
+ return self._request("GET", "/v1/audit/batches/latest")
398
+
399
+ def audit_batch(self, batch_num: int) -> Dict[str, Any]:
400
+ """GET /v1/audit/batches/{num} — inspect any batch by batch_num."""
401
+ return self._request("GET", f"/v1/audit/batches/{int(batch_num)}")
402
+
403
+ def audit_event(self, seq: int) -> Dict[str, Any]:
404
+ """GET /v1/audit/events/{seq} — inspect a single hash-chained event."""
405
+ return self._request("GET", f"/v1/audit/events/{int(seq)}")
406
+
407
+ def audit_proof(self, seq: int) -> Dict[str, Any]:
408
+ """GET /v1/audit/proof/{seq} — Merkle inclusion proof for an event.
409
+
410
+ Returns ``merkle_proof`` (sibling hashes) that proves the event is in
411
+ its batch's ``merkle_root``. Use ``verify_merkle_proof()`` to verify.
412
+ """
413
+ return self._request("GET", f"/v1/audit/proof/{int(seq)}")
414
+
415
+ def audit_anchor(self, batch_num: int) -> Dict[str, Any]:
416
+ """GET /v1/audit/anchor/{num} — resolve batch → external anchor URL."""
417
+ return self._request("GET", f"/v1/audit/anchor/{int(batch_num)}")
418
+
419
+ @staticmethod
420
+ def verify_merkle_proof(leaf: str, root: str, proof: List[str]) -> bool:
421
+ """Verify a Merkle inclusion proof locally — no PAX call needed.
422
+
423
+ Mirrors OpenZeppelin sorted-pair sha256 (identical to server-side
424
+ batcher + on-chain Solidity ``MerkleProof.verify``).
425
+ """
426
+ import hashlib
427
+ h = leaf
428
+ for sibling in proof:
429
+ a, b = (h, sibling) if h < sibling else (sibling, h)
430
+ h = hashlib.sha256((a + b).encode("ascii")).hexdigest()
431
+ return h == root
432
+
337
433
  def get_application(self, application_code: str) -> Dict[str, Any]:
338
434
  """GET /v1/apply/{code} — check application review status."""
339
435
  return self._request("GET", f"/v1/apply/{application_code}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pax-api
3
- Version: 2.0.0
3
+ Version: 2.2.0
4
4
  Summary: Official Python SDK for the PredictAsiaX Trader Track API — Web3-native prediction markets
5
5
  Author-email: PredictAsiaX <support@predictasiax.com>
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes