polynode 0.10.3__tar.gz → 0.10.4__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.
Files changed (45) hide show
  1. {polynode-0.10.3 → polynode-0.10.4}/PKG-INFO +1 -1
  2. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/relayer.py +121 -2
  3. {polynode-0.10.3 → polynode-0.10.4}/pyproject.toml +1 -1
  4. {polynode-0.10.3 → polynode-0.10.4}/.gitignore +0 -0
  5. {polynode-0.10.3 → polynode-0.10.4}/README.md +0 -0
  6. {polynode-0.10.3 → polynode-0.10.4}/polynode/__init__.py +0 -0
  7. {polynode-0.10.3 → polynode-0.10.4}/polynode/_version.py +0 -0
  8. {polynode-0.10.3 → polynode-0.10.4}/polynode/cache/__init__.py +0 -0
  9. {polynode-0.10.3 → polynode-0.10.4}/polynode/client.py +0 -0
  10. {polynode-0.10.3 → polynode-0.10.4}/polynode/engine.py +0 -0
  11. {polynode-0.10.3 → polynode-0.10.4}/polynode/errors.py +0 -0
  12. {polynode-0.10.3 → polynode-0.10.4}/polynode/orderbook.py +0 -0
  13. {polynode-0.10.3 → polynode-0.10.4}/polynode/orderbook_state.py +0 -0
  14. {polynode-0.10.3 → polynode-0.10.4}/polynode/redemption_watcher.py +0 -0
  15. {polynode-0.10.3 → polynode-0.10.4}/polynode/short_form.py +0 -0
  16. {polynode-0.10.3 → polynode-0.10.4}/polynode/subscription.py +0 -0
  17. {polynode-0.10.3 → polynode-0.10.4}/polynode/testing.py +0 -0
  18. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/V2_ORDER_FLOW.md +0 -0
  19. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/__init__.py +0 -0
  20. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/clob_api.py +0 -0
  21. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/constants.py +0 -0
  22. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/cosigner.py +0 -0
  23. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/eip712.py +0 -0
  24. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/escrow.py +0 -0
  25. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/onboarding.py +0 -0
  26. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/position_management.py +0 -0
  27. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/privy.py +0 -0
  28. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/signer.py +0 -0
  29. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/sqlite_backend.py +0 -0
  30. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/trader.py +0 -0
  31. {polynode-0.10.3 → polynode-0.10.4}/polynode/trading/types.py +0 -0
  32. {polynode-0.10.3 → polynode-0.10.4}/polynode/types/__init__.py +0 -0
  33. {polynode-0.10.3 → polynode-0.10.4}/polynode/types/enums.py +0 -0
  34. {polynode-0.10.3 → polynode-0.10.4}/polynode/types/events.py +0 -0
  35. {polynode-0.10.3 → polynode-0.10.4}/polynode/types/orderbook.py +0 -0
  36. {polynode-0.10.3 → polynode-0.10.4}/polynode/types/rest.py +0 -0
  37. {polynode-0.10.3 → polynode-0.10.4}/polynode/types/short_form.py +0 -0
  38. {polynode-0.10.3 → polynode-0.10.4}/polynode/types/ws.py +0 -0
  39. {polynode-0.10.3 → polynode-0.10.4}/polynode/ws.py +0 -0
  40. {polynode-0.10.3 → polynode-0.10.4}/tests/__init__.py +0 -0
  41. {polynode-0.10.3 → polynode-0.10.4}/tests/conftest.py +0 -0
  42. {polynode-0.10.3 → polynode-0.10.4}/tests/test_client.py +0 -0
  43. {polynode-0.10.3 → polynode-0.10.4}/tests/test_orderbook.py +0 -0
  44. {polynode-0.10.3 → polynode-0.10.4}/tests/test_trading.py +0 -0
  45. {polynode-0.10.3 → polynode-0.10.4}/tests/test_types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polynode
3
- Version: 0.10.3
3
+ Version: 0.10.4
4
4
  Summary: Python SDK for the PolyNode real-time prediction market data platform
5
5
  Project-URL: Homepage, https://polynode.dev
6
6
  Project-URL: Documentation, https://docs.polynode.dev
@@ -25,8 +25,8 @@ from typing import Any
25
25
 
26
26
  import httpx
27
27
 
28
- from .constants import CHAIN_ID, RELAYER_HOST, SAFE_FACTORY, SAFE_MULTISEND
29
- from .onboarding import derive_safe_address
28
+ from .constants import CHAIN_ID, RELAYER_HOST, SAFE_FACTORY, SAFE_MULTISEND, CTF, DEPOSIT_WALLET_FACTORY
29
+ from .onboarding import derive_safe_address, derive_deposit_wallet_address
30
30
 
31
31
 
32
32
  @dataclass
@@ -301,3 +301,122 @@ class RelayClient:
301
301
  if state in ("STATE_FAILED", "STATE_REVERTED"):
302
302
  raise RuntimeError(f"tx {tx_id} failed on-chain: state={state} hash={row.get('transactionHash')}")
303
303
  raise RuntimeError(f"tx {tx_id} timed out waiting for mined state")
304
+
305
+ async def _poll_tx(self, tx_id: str) -> str:
306
+ """Poll relayer transaction until mined/confirmed/failed."""
307
+ for _ in range(45):
308
+ await asyncio.sleep(2)
309
+ async with httpx.AsyncClient(timeout=10.0) as client:
310
+ r = await client.get(f"{self.relayer_url}/transaction", params={"id": tx_id})
311
+ if not r.is_success:
312
+ continue
313
+ rows = r.json()
314
+ row = rows[0] if isinstance(rows, list) else rows
315
+ state = row.get("state", "")
316
+ if state in ("STATE_MINED", "STATE_CONFIRMED"):
317
+ return row["transactionHash"]
318
+ if state in ("STATE_FAILED", "STATE_REVERTED"):
319
+ raise RuntimeError(f"tx {tx_id} failed: {state}")
320
+ raise RuntimeError(f"tx {tx_id} timed out")
321
+
322
+ async def _submit_with_auth(self, body: dict) -> str:
323
+ """Submit to relayer with builder HMAC headers, poll until confirmed."""
324
+ body_str = json.dumps(body, separators=(",", ":"))
325
+ headers = _build_hmac_headers(self.builder_creds, "POST", "/submit", body_str)
326
+ headers["Content-Type"] = "application/json"
327
+ async with httpx.AsyncClient(timeout=30.0) as client:
328
+ r = await client.post(f"{self.relayer_url}/submit", content=body_str, headers=headers)
329
+ if not r.is_success:
330
+ raise RuntimeError(f"relayer /submit {r.status_code}: {r.text}")
331
+ resp = r.json()
332
+ tx_id = resp["transactionID"]
333
+ return await self._poll_tx(tx_id)
334
+
335
+ async def deploy_deposit_wallet(self, eoa_address: str) -> str:
336
+ """Deploy a deposit wallet for an EOA via the relayer (gasless)."""
337
+ body = {
338
+ "type": "WALLET-CREATE",
339
+ "from": eoa_address,
340
+ "to": DEPOSIT_WALLET_FACTORY,
341
+ }
342
+ return await self._submit_with_auth(body)
343
+
344
+ async def set_deposit_wallet_approvals(
345
+ self, signer_pk: str, eoa_address: str, wallet_address: str,
346
+ ) -> str:
347
+ """Set token approvals for a deposit wallet via EIP-712 batch + relayer (gasless)."""
348
+ try:
349
+ from eth_account import Account
350
+ from eth_abi import encode
351
+ except ImportError:
352
+ raise ImportError("eth-account and eth-abi required for deposit wallet approvals")
353
+
354
+ from .constants import V2_SPENDERS, POLY_USD
355
+
356
+ # Build approval calls
357
+ max_uint = (1 << 256) - 1
358
+ approve_sel = bytes.fromhex("095ea7b3")
359
+ set_approval_sel = bytes.fromhex("a22cb465")
360
+ calls = []
361
+ for spender in V2_SPENDERS[:3]:
362
+ # pUSD approve(spender, maxUint256)
363
+ data = approve_sel + encode(["address", "uint256"], [spender, max_uint])
364
+ calls.append({"target": POLY_USD, "value": "0", "data": "0x" + data.hex()})
365
+ # CTF setApprovalForAll(spender, true)
366
+ data2 = set_approval_sel + encode(["address", "bool"], [spender, True])
367
+ calls.append({"target": CTF, "value": "0", "data": "0x" + data2.hex()})
368
+
369
+ # Get nonce
370
+ async with httpx.AsyncClient(timeout=20.0) as client:
371
+ r = await client.get(f"{self.relayer_url}/nonce", params={"address": eoa_address, "type": "WALLET"})
372
+ r.raise_for_status()
373
+ nonce = int(r.json().get("nonce", "0"))
374
+
375
+ deadline = int(time.time()) + 3600
376
+
377
+ # EIP-712 sign the Batch message
378
+ domain = {
379
+ "name": "DepositWallet",
380
+ "version": "1",
381
+ "chainId": self.chain_id,
382
+ "verifyingContract": wallet_address,
383
+ }
384
+ batch_types = {
385
+ "Batch": [
386
+ {"name": "wallet", "type": "address"},
387
+ {"name": "nonce", "type": "uint256"},
388
+ {"name": "deadline", "type": "uint256"},
389
+ {"name": "calls", "type": "Call[]"},
390
+ ],
391
+ "Call": [
392
+ {"name": "target", "type": "address"},
393
+ {"name": "value", "type": "uint256"},
394
+ {"name": "data", "type": "bytes"},
395
+ ],
396
+ }
397
+ message = {
398
+ "wallet": wallet_address,
399
+ "nonce": nonce,
400
+ "deadline": deadline,
401
+ "calls": [{"target": c["target"], "value": 0, "data": bytes.fromhex(c["data"][2:])} for c in calls],
402
+ }
403
+
404
+ pk_hex = signer_pk if signer_pk.startswith("0x") else f"0x{signer_pk}"
405
+ full_types = {"EIP712Domain": [{"name": "name", "type": "string"}, {"name": "version", "type": "string"}, {"name": "chainId", "type": "uint256"}, {"name": "verifyingContract", "type": "address"}], **batch_types}
406
+ full_message = {"types": full_types, "primaryType": "Batch", "domain": domain, "message": message}
407
+ signed = Account.sign_typed_data(pk_hex, full_message=full_message)
408
+ sig_hex = "0x" + signed.signature.hex()
409
+
410
+ body = {
411
+ "type": "WALLET",
412
+ "from": eoa_address,
413
+ "to": DEPOSIT_WALLET_FACTORY,
414
+ "nonce": str(nonce),
415
+ "signature": sig_hex,
416
+ "depositWalletParams": {
417
+ "depositWallet": wallet_address,
418
+ "deadline": str(deadline),
419
+ "calls": calls,
420
+ },
421
+ }
422
+ return await self._submit_with_auth(body)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "polynode"
7
- version = "0.10.3"
7
+ version = "0.10.4"
8
8
  description = "Python SDK for the PolyNode real-time prediction market data platform"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
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