polynode 0.7.0__py3-none-any.whl → 0.7.1__py3-none-any.whl

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.
@@ -39,5 +39,8 @@ POLY_USD = "0xc011a7e12a19f7b1f670d46f03b03f3342e82dfb"
39
39
  COLLATERAL_ONRAMP = "0x93070a847efef7f70739046a929d47a521f5b8ee"
40
40
  COLLATERAL_OFFRAMP = "0x2957922eb93258b93368531d39facca3b4dc5854"
41
41
 
42
+ # Fee Escrow
43
+ FEE_ESCROW_ADDRESS = "0xa11D28433B79D0A88F3119b16A090075752258EA"
44
+
42
45
  # Metadata cache TTL (5 minutes)
43
46
  META_TTL_SECONDS = 300
@@ -0,0 +1,166 @@
1
+ """Fee Escrow — EIP-712 signing, fee calculation, and nonce fetching
2
+ for the on-chain FeeEscrow contract.
3
+
4
+ The escrow is completely optional. When fee_bps=0, none of this code runs.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import math
10
+ import os
11
+ import secrets
12
+ from dataclasses import dataclass
13
+ from typing import Any
14
+
15
+ import httpx
16
+
17
+ from .constants import CHAIN_ID, FEE_ESCROW_ADDRESS
18
+ from .types import Eip712Payload
19
+
20
+ # ── EIP-712 Types ──
21
+
22
+ FEE_AUTH_DOMAIN = {
23
+ "name": "PolyNodeFeeEscrow",
24
+ "version": "1",
25
+ "chainId": CHAIN_ID,
26
+ "verifyingContract": FEE_ESCROW_ADDRESS,
27
+ }
28
+
29
+ FEE_AUTH_TYPES = {
30
+ "FeeAuth": [
31
+ {"name": "orderId", "type": "bytes32"},
32
+ {"name": "payer", "type": "address"},
33
+ {"name": "signer", "type": "address"},
34
+ {"name": "feeAmount", "type": "uint256"},
35
+ {"name": "deadline", "type": "uint256"},
36
+ {"name": "nonce", "type": "uint256"},
37
+ ],
38
+ }
39
+
40
+ ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
41
+
42
+
43
+ # ── Fee Calculation ──
44
+
45
+ def calculate_fee(price: float, size: float, fee_bps: int) -> int:
46
+ """Calculate fee amount in raw USDC (6 decimals).
47
+
48
+ Args:
49
+ price: Order price (e.g. 0.55)
50
+ size: Order size in tokens (e.g. 100)
51
+ fee_bps: Fee in basis points (e.g. 50 = 0.5%)
52
+
53
+ Returns:
54
+ Fee amount as int in raw USDC units
55
+ """
56
+ notional_raw = math.floor(price * size * 1e6)
57
+ fee = math.floor(notional_raw * fee_bps / 10000)
58
+ return max(fee, 0)
59
+
60
+
61
+ # ── Order ID Generation ──
62
+
63
+ def generate_escrow_order_id() -> str:
64
+ """Generate a random bytes32 escrow order ID (0x-prefixed hex)."""
65
+ return "0x" + secrets.token_hex(32)
66
+
67
+
68
+ # ── Nonce Fetching ──
69
+
70
+ async def fetch_escrow_nonce(rpc_url: str, signer_address: str) -> int:
71
+ """Fetch the current nonce for a signer from the FeeEscrow contract via eth_call."""
72
+ # getNonce(address) selector = 0x2d0335ab
73
+ addr = signer_address.lower().replace("0x", "").zfill(64)
74
+ data = "0x2d0335ab" + addr
75
+
76
+ async with httpx.AsyncClient() as client:
77
+ resp = await client.post(
78
+ rpc_url,
79
+ json={
80
+ "jsonrpc": "2.0",
81
+ "id": 1,
82
+ "method": "eth_call",
83
+ "params": [{"to": FEE_ESCROW_ADDRESS, "data": data}, "latest"],
84
+ },
85
+ )
86
+ result = resp.json()
87
+
88
+ if "error" in result:
89
+ raise RuntimeError(f"Failed to fetch escrow nonce: {result['error']}")
90
+ return int(result.get("result", "0x0"), 16)
91
+
92
+
93
+ # ── EIP-712 Signing ──
94
+
95
+ @dataclass
96
+ class FeeAuthRequest:
97
+ escrow_order_id: str
98
+ payer: str
99
+ signer: str
100
+ fee_amount: str
101
+ deadline: int
102
+ nonce: int
103
+ signature: str
104
+ affiliate: str
105
+ affiliate_share_bps: int
106
+
107
+
108
+ async def sign_fee_auth(
109
+ sign_typed_data: Any,
110
+ *,
111
+ escrow_order_id: str,
112
+ payer: str,
113
+ signer_address: str,
114
+ fee_amount: int,
115
+ deadline: int,
116
+ nonce: int,
117
+ affiliate: str | None = None,
118
+ affiliate_share_bps: int | None = None,
119
+ ) -> FeeAuthRequest:
120
+ """Sign a FeeAuth EIP-712 message.
121
+
122
+ Args:
123
+ sign_typed_data: Callable that signs an Eip712Payload and returns a hex signature.
124
+ escrow_order_id: Random bytes32 hex string.
125
+ payer: Safe wallet address (where USDC is pulled from).
126
+ signer_address: EOA address (signs the message).
127
+ fee_amount: Fee in raw USDC (6 decimals).
128
+ deadline: Unix timestamp — authorization expires after this.
129
+ nonce: Signer's current nonce from the escrow contract.
130
+ affiliate: Partner wallet address.
131
+ affiliate_share_bps: Partner's share of fee in bps.
132
+
133
+ Returns:
134
+ FeeAuthRequest ready for the cosigner.
135
+ """
136
+ message = {
137
+ "orderId": escrow_order_id,
138
+ "payer": payer,
139
+ "signer": signer_address,
140
+ "feeAmount": str(fee_amount),
141
+ "deadline": str(deadline),
142
+ "nonce": str(nonce),
143
+ }
144
+
145
+ payload = Eip712Payload(
146
+ domain=FEE_AUTH_DOMAIN,
147
+ types=FEE_AUTH_TYPES,
148
+ primary_type="FeeAuth",
149
+ message=message,
150
+ )
151
+
152
+ signature = await sign_typed_data(payload)
153
+ if not signature.startswith("0x"):
154
+ signature = f"0x{signature}"
155
+
156
+ return FeeAuthRequest(
157
+ escrow_order_id=escrow_order_id,
158
+ payer=payer,
159
+ signer=signer_address,
160
+ fee_amount=str(fee_amount),
161
+ deadline=deadline,
162
+ nonce=nonce,
163
+ signature=signature,
164
+ affiliate=affiliate or ZERO_ADDRESS,
165
+ affiliate_share_bps=affiliate_share_bps or 0,
166
+ )
@@ -28,6 +28,7 @@ from .constants import (
28
28
  SPENDERS,
29
29
  USDC,
30
30
  V2_SPENDERS,
31
+ FEE_ESCROW_ADDRESS,
31
32
  )
32
33
  from .types import ApprovalStatus, BalanceInfo, ExchangeVersion, SignatureType
33
34
 
@@ -185,6 +186,11 @@ async def check_approvals(
185
186
  approved = ctf_contract.functions.isApprovedForAll(funder, spender_addr).call()
186
187
  ctf_status[name] = approved
187
188
 
189
+ # Fee Escrow USDC approval (always USDC.e regardless of exchange version)
190
+ usdc_contract = w3.eth.contract(address=Web3.to_checksum_address(USDC), abi=erc20_abi)
191
+ escrow_allowance = usdc_contract.functions.allowance(funder, Web3.to_checksum_address(FEE_ESCROW_ADDRESS)).call()
192
+ usdc_status["fee_escrow"] = escrow_allowance >= threshold
193
+
188
194
  all_approved = all(usdc_status.values()) and all(ctf_status.values())
189
195
 
190
196
  return ApprovalStatus(
@@ -264,6 +270,17 @@ async def set_approvals(
264
270
  tx_hashes.append(tx_hash.hex())
265
271
  nonce += 1
266
272
 
273
+ # Fee Escrow USDC approval (always USDC.e regardless of exchange version)
274
+ escrow_contract = w3.eth.contract(address=Web3.to_checksum_address(USDC), abi=erc20_abi)
275
+ tx = escrow_contract.functions.approve(Web3.to_checksum_address(FEE_ESCROW_ADDRESS), max_uint).build_transaction({
276
+ "from": account.address,
277
+ "nonce": nonce,
278
+ "chainId": CHAIN_ID,
279
+ })
280
+ signed = account.sign_transaction(tx)
281
+ tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
282
+ tx_hashes.append(tx_hash.hex())
283
+
267
284
  return tx_hashes
268
285
 
269
286
 
@@ -13,11 +13,14 @@ from .types import HistoryParams, MarketMeta, OrderHistoryRow, SignatureType, St
13
13
  class TradingSqliteBackend:
14
14
  """Local SQLite storage for trading module."""
15
15
 
16
+ SCHEMA_VERSION = 2
17
+
16
18
  def __init__(self, db_path: str) -> None:
17
19
  self._db = sqlite3.connect(db_path)
18
20
  self._db.execute("PRAGMA journal_mode=WAL")
19
21
  self._db.execute("PRAGMA synchronous=NORMAL")
20
22
  self._init_schema()
23
+ self._migrate()
21
24
 
22
25
  def _init_schema(self) -> None:
23
26
  self._db.executescript("""
@@ -54,13 +57,27 @@ class TradingSqliteBackend:
54
57
  status TEXT NOT NULL DEFAULT 'submitting',
55
58
  error_msg TEXT,
56
59
  response_json TEXT,
57
- created_at REAL NOT NULL
60
+ created_at REAL NOT NULL,
61
+ fee_amount_raw TEXT,
62
+ escrow_order_id TEXT,
63
+ fee_escrow_tx_hash TEXT
58
64
  );
59
65
 
60
66
  CREATE INDEX IF NOT EXISTS idx_order_history_wallet ON order_history(wallet_address);
61
67
  CREATE INDEX IF NOT EXISTS idx_order_history_token ON order_history(token_id);
62
68
  """)
63
69
 
70
+ def _migrate(self) -> None:
71
+ """Run schema migrations for existing databases."""
72
+ # Check if fee escrow columns exist (v2 migration)
73
+ cols = {row[1] for row in self._db.execute("PRAGMA table_info(order_history)").fetchall()}
74
+ if "fee_amount_raw" not in cols:
75
+ self._db.executescript("""
76
+ ALTER TABLE order_history ADD COLUMN fee_amount_raw TEXT;
77
+ ALTER TABLE order_history ADD COLUMN escrow_order_id TEXT;
78
+ ALTER TABLE order_history ADD COLUMN fee_escrow_tx_hash TEXT;
79
+ """)
80
+
64
81
  def get_credentials(self, wallet_address: str) -> StoredCredentials | None:
65
82
  row = self._db.execute(
66
83
  "SELECT * FROM clob_credentials WHERE wallet_address = ? COLLATE NOCASE",
@@ -148,13 +165,16 @@ class TradingSqliteBackend:
148
165
  cur = self._db.execute(
149
166
  """INSERT INTO order_history
150
167
  (wallet_address, order_id, token_id, side, price, size, order_type,
151
- status, error_msg, response_json, created_at)
152
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
168
+ status, error_msg, response_json, created_at,
169
+ fee_amount_raw, escrow_order_id, fee_escrow_tx_hash)
170
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
153
171
  (
154
172
  order["wallet_address"], order.get("order_id"), order["token_id"],
155
173
  order["side"], order["price"], order["size"], order.get("order_type", "GTC"),
156
174
  order.get("status", "submitting"), order.get("error_msg"),
157
175
  order.get("response_json"), order.get("created_at", time.time()),
176
+ order.get("fee_amount_raw"), order.get("escrow_order_id"),
177
+ order.get("fee_escrow_tx_hash"),
158
178
  ),
159
179
  )
160
180
  self._db.commit()
@@ -163,13 +183,17 @@ class TradingSqliteBackend:
163
183
  def update_order_status(
164
184
  self, row_id: int, status: str, order_id: str | None = None,
165
185
  error_msg: str | None = None, response_json: str | None = None,
186
+ fee_amount_raw: str | None = None, escrow_order_id: str | None = None,
187
+ fee_escrow_tx_hash: str | None = None,
166
188
  ) -> None:
167
189
  self._db.execute(
168
190
  """UPDATE order_history
169
191
  SET status = ?, order_id = COALESCE(?, order_id),
170
- error_msg = COALESCE(?, error_msg), response_json = COALESCE(?, response_json)
192
+ error_msg = COALESCE(?, error_msg), response_json = COALESCE(?, response_json),
193
+ fee_amount_raw = COALESCE(?, fee_amount_raw), escrow_order_id = COALESCE(?, escrow_order_id),
194
+ fee_escrow_tx_hash = COALESCE(?, fee_escrow_tx_hash)
171
195
  WHERE id = ?""",
172
- (status, order_id, error_msg, response_json, row_id),
196
+ (status, order_id, error_msg, response_json, fee_amount_raw, escrow_order_id, fee_escrow_tx_hash, row_id),
173
197
  )
174
198
  self._db.commit()
175
199
 
@@ -200,6 +224,9 @@ class TradingSqliteBackend:
200
224
  id=r[0], wallet_address=r[1], order_id=r[2], token_id=r[3],
201
225
  side=r[4], price=r[5], size=r[6], order_type=r[7],
202
226
  status=r[8], error_msg=r[9], response_json=r[10], created_at=r[11],
227
+ fee_amount_raw=r[12] if len(r) > 12 else None,
228
+ escrow_order_id=r[13] if len(r) > 13 else None,
229
+ fee_escrow_tx_hash=r[14] if len(r) > 14 else None,
203
230
  )
204
231
  for r in rows
205
232
  ]
@@ -24,6 +24,7 @@ from .constants import (
24
24
  )
25
25
  from .cosigner import build_l2_headers, send_via_cosigner
26
26
  from .eip712 import create_signed_order, create_signed_order_v2
27
+ from .escrow import calculate_fee, generate_escrow_order_id, fetch_escrow_nonce, sign_fee_auth
27
28
  from .onboarding import (
28
29
  check_approvals as check_approvals_onchain,
29
30
  check_balance as check_balance_onchain,
@@ -55,6 +56,7 @@ from .types import (
55
56
  TraderConfig,
56
57
  WalletExport,
57
58
  WalletInfo,
59
+ FeeConfig,
58
60
  )
59
61
 
60
62
 
@@ -71,6 +73,7 @@ class PolyNodeTrader:
71
73
  self._rpc_url = c.rpc_url
72
74
  self._builder_credentials = c.builder_credentials
73
75
  self._exchange_version = c.exchange_version
76
+ self._fee_config = c.fee_config
74
77
 
75
78
  self._db: TradingSqliteBackend | None = None
76
79
  self._active_signer: NormalizedSigner | None = None
@@ -579,9 +582,47 @@ class PolyNodeTrader:
579
582
  "status": "submitting",
580
583
  })
581
584
 
585
+ # Build fee auth if escrow is enabled
586
+ fee_config = params.fee_config or self._fee_config
587
+ fee_auth_dict = None
588
+ fee_amount_raw = 0
589
+ if fee_config and fee_config.fee_bps > 0:
590
+ fee_amount_raw = calculate_fee(params.price, params.size, fee_config.fee_bps)
591
+ if fee_amount_raw > 0:
592
+ funder = creds.funder_address or creds.wallet_address
593
+ nonce = await fetch_escrow_nonce(self._rpc_url, signer.address)
594
+ deadline = int(time.time()) + 300
595
+ escrow_oid = generate_escrow_order_id()
596
+ fee_auth = await sign_fee_auth(
597
+ signer.sign_typed_data,
598
+ escrow_order_id=escrow_oid,
599
+ payer=funder,
600
+ signer_address=signer.address,
601
+ fee_amount=fee_amount_raw,
602
+ deadline=deadline,
603
+ nonce=nonce,
604
+ affiliate=fee_config.affiliate,
605
+ affiliate_share_bps=fee_config.affiliate_share_bps,
606
+ )
607
+ fee_auth_dict = {
608
+ "escrow_order_id": fee_auth.escrow_order_id,
609
+ "payer": fee_auth.payer,
610
+ "signer": fee_auth.signer,
611
+ "fee_amount": fee_auth.fee_amount,
612
+ "deadline": fee_auth.deadline,
613
+ "nonce": fee_auth.nonce,
614
+ "signature": fee_auth.signature,
615
+ "affiliate": fee_auth.affiliate,
616
+ "affiliate_share_bps": fee_auth.affiliate_share_bps,
617
+ }
618
+
619
+ request_data: dict[str, Any] = {"method": "POST", "path": "/order", "body": body_str, "headers": headers}
620
+ if fee_auth_dict:
621
+ request_data["fee_auth"] = fee_auth_dict
622
+
582
623
  result = await send_via_cosigner(
583
624
  self._cosigner_url, self._polynode_key, self._fallback_direct,
584
- {"method": "POST", "path": "/order", "body": body_str, "headers": headers},
625
+ request_data,
585
626
  builder_credentials=self._builder_credentials,
586
627
  clob_host=clob_host,
587
628
  )
@@ -603,6 +644,8 @@ class PolyNodeTrader:
603
644
  error=error,
604
645
  making_amount=result.get("makingAmount"),
605
646
  taking_amount=result.get("takingAmount"),
647
+ fee_escrow_tx_hash=result.get("feeEscrowTxHash"),
648
+ fee_amount=str(fee_amount_raw / 1e6) if fee_amount_raw > 0 else None,
606
649
  )
607
650
 
608
651
  async def cancel_order(self, order_id: str) -> CancelResult:
polynode/trading/types.py CHANGED
@@ -38,6 +38,14 @@ class GeneratedWallet:
38
38
  address: str
39
39
 
40
40
 
41
+ @dataclass
42
+ class FeeConfig:
43
+ """Optional fee configuration for per-order fee collection via on-chain escrow."""
44
+ fee_bps: int # fee in basis points (e.g. 50 = 0.5%)
45
+ affiliate: str | None = None # partner wallet address
46
+ affiliate_share_bps: int | None = None # partner's share of fee in bps
47
+
48
+
41
49
  @dataclass
42
50
  class BuilderCredentials:
43
51
  """Polymarket builder credentials for order attribution."""
@@ -56,6 +64,7 @@ class TraderConfig:
56
64
  rpc_url: str = "https://polygon-bor-rpc.publicnode.com"
57
65
  builder_credentials: BuilderCredentials | None = None
58
66
  exchange_version: ExchangeVersion = ExchangeVersion.V1
67
+ fee_config: FeeConfig | None = None
59
68
 
60
69
 
61
70
  @dataclass
@@ -127,6 +136,7 @@ class OrderParams:
127
136
  type: OrderType = "GTC"
128
137
  expiration: int | None = None
129
138
  post_only: bool = False
139
+ fee_config: FeeConfig | None = None
130
140
 
131
141
 
132
142
  @dataclass
@@ -137,6 +147,8 @@ class OrderResult:
137
147
  error: str | None = None
138
148
  making_amount: str | None = None
139
149
  taking_amount: str | None = None
150
+ fee_escrow_tx_hash: str | None = None
151
+ fee_amount: str | None = None
140
152
 
141
153
 
142
154
  @dataclass
@@ -224,6 +236,9 @@ class OrderHistoryRow:
224
236
  error_msg: str | None
225
237
  response_json: str | None
226
238
  created_at: float
239
+ fee_amount_raw: str | None = None
240
+ escrow_order_id: str | None = None
241
+ fee_escrow_tx_hash: str | None = None
227
242
 
228
243
 
229
244
  @dataclass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polynode
3
- Version: 0.7.0
3
+ Version: 0.7.1
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
@@ -13,16 +13,17 @@ polynode/ws.py,sha256=VZdn2dkUJH2-CYBu_L45YnvCU0kQejxHcy2Ji2pRu60,9653
13
13
  polynode/cache/__init__.py,sha256=A9lXcIE3ISKKo1r0o3o-CkmQpBhLdKwdQfCR0eW5i9o,519
14
14
  polynode/trading/__init__.py,sha256=0mtvY4w2k1x000YOX7_ua9JZj4CY27Cz7p0u6L3Hfrw,906
15
15
  polynode/trading/clob_api.py,sha256=ygaOoMIg4PGtMzNBT70wk4XrSbVX0EyCCU6PmXK3xrs,5308
16
- polynode/trading/constants.py,sha256=CjHcfaOTzPFvlorY4XeyGtMS8XNKH4jjoxqKtpN6NmY,1782
16
+ polynode/trading/constants.py,sha256=_DDwutJkOfeyPkClrTcyJCOYMoqDymZzDpjYWeHbfG0,1862
17
17
  polynode/trading/cosigner.py,sha256=Fww9OgaKdHQAHd8Kom1AJBtmMGC8FbNZxdFaFALNBY8,3058
18
18
  polynode/trading/eip712.py,sha256=pZf0Pf4DDIPpK4qbz4DWfcdOeU8PlCQhJPpKSQ97pC4,9553
19
- polynode/trading/onboarding.py,sha256=ouP9bzioFHCt4fnluAXLWL8O8U6d_1ePeu5JmBXeDyc,13768
19
+ polynode/trading/escrow.py,sha256=mDNAUQUzFOvzo6HpmqJTzjMEx7o3ySQHoVbvNiqIwmA,4549
20
+ polynode/trading/onboarding.py,sha256=-Ub5tsJA4vqPJmkNLx2OE_szUY08UmXYi_9ATThajkA,14670
20
21
  polynode/trading/position_management.py,sha256=z2pYls4ErhyRE6thQdOs45BF4llKvKNNruQgcMEFT_U,3827
21
22
  polynode/trading/privy.py,sha256=iiUQZsBqjj29C7oUiFFktoT2muZY06bcMzABKstFKqE,4523
22
23
  polynode/trading/signer.py,sha256=piifRquwnwFwrKLL24jsRQYMh_cdkz8wNz99Vx8_KTY,3413
23
- polynode/trading/sqlite_backend.py,sha256=9ho7DnQVE_nJqmPH5yPSAYcVjVmTS1XmD3NebR-UAwA,7986
24
- polynode/trading/trader.py,sha256=VVNQ_DEkum5u3IC2M5IfLml7s06A7fCqjGXvSX3ayCg,29497
25
- polynode/trading/types.py,sha256=WGSH25c1LIZax4KNPavHz0G6HEPLUK9ak9VnEYd8fxM,4944
24
+ polynode/trading/sqlite_backend.py,sha256=zfo4WevuunWV-7i6Z3gQi_e7Tonw-7m1TsEd88O5I4w,9486
25
+ polynode/trading/trader.py,sha256=U2dghRO5Ra1-2UqCBzOkI3GYvGPvAHKJAc2lFF-UJXQ,31541
26
+ polynode/trading/types.py,sha256=JxhjsRRhh8WA127VNNPLf7QJKn5e_PZucaG7WAfdOsM,5528
26
27
  polynode/types/__init__.py,sha256=0v_CByqG-zT1xucbT2So_77YDmsPj9u956at94nyrLM,280
27
28
  polynode/types/enums.py,sha256=2cx9l10A-LUeDNBJZn7l0XBTka2YfxRQcXW0s7s3_4k,1082
28
29
  polynode/types/events.py,sha256=MJGZqxBFKfT1y44dZ96bHbwvoPpGvtutBwYE6OTT6nU,6880
@@ -30,6 +31,6 @@ polynode/types/orderbook.py,sha256=MwD6P3poo3F70bONUZ5i3ajk1sgw39hHTOw6D0fP5_8,1
30
31
  polynode/types/rest.py,sha256=ftJKQZH0wBrR_l199rDMqnVS8cyt8YnCvo9cKIsTcCw,7012
31
32
  polynode/types/short_form.py,sha256=xfGklDi587u6K2aXaRWiwbxqkipW8BiEPeNIDT45v2Y,799
32
33
  polynode/types/ws.py,sha256=EzE9Vzrb6cILemfssmnqM8fbHt4USn3latpUHKatwk4,994
33
- polynode-0.7.0.dist-info/METADATA,sha256=qIF1aMlx-nQAUySzKpoqj3y9Mx66vRNnG4Cuuwvbt0Q,3302
34
- polynode-0.7.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
35
- polynode-0.7.0.dist-info/RECORD,,
34
+ polynode-0.7.1.dist-info/METADATA,sha256=-RaAIV8DkzVWW3HIGy-5bkdSkThsihEk909bBWjMsx8,3302
35
+ polynode-0.7.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
36
+ polynode-0.7.1.dist-info/RECORD,,