polynode 0.6.1__tar.gz → 0.6.2__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.
- {polynode-0.6.1 → polynode-0.6.2}/PKG-INFO +1 -1
- {polynode-0.6.1 → polynode-0.6.2}/polynode/short_form.py +1 -1
- {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/__init__.py +4 -0
- polynode-0.6.2/polynode/trading/position_management.py +104 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/trader.py +24 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/types.py +42 -0
- {polynode-0.6.1 → polynode-0.6.2}/pyproject.toml +1 -1
- {polynode-0.6.1 → polynode-0.6.2}/.gitignore +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/README.md +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/__init__.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/_version.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/cache/__init__.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/client.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/engine.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/errors.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/orderbook.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/orderbook_state.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/redemption_watcher.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/subscription.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/testing.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/clob_api.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/constants.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/cosigner.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/eip712.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/onboarding.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/privy.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/signer.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/trading/sqlite_backend.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/types/__init__.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/types/enums.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/types/events.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/types/orderbook.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/types/rest.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/types/short_form.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/types/ws.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/polynode/ws.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/tests/__init__.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/tests/conftest.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/tests/test_client.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/tests/test_orderbook.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/tests/test_trading.py +0 -0
- {polynode-0.6.1 → polynode-0.6.2}/tests/test_types.py +0 -0
|
@@ -37,7 +37,7 @@ COIN_SYMBOLS: dict[ShortFormCoin, str] = {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
INTERVAL_VARIANT: dict[ShortFormInterval, str] = {
|
|
40
|
-
"5m": "
|
|
40
|
+
"5m": "fiveminute", "15m": "fifteen", "1h": "hourly",
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
WINDOW_SECONDS: dict[ShortFormInterval, int] = {
|
|
@@ -5,6 +5,7 @@ from .constants import * # noqa: F401, F403
|
|
|
5
5
|
from .signer import NormalizedSigner, normalize_signer
|
|
6
6
|
from .cosigner import build_l2_headers, send_via_cosigner
|
|
7
7
|
from .onboarding import derive_safe_address, derive_proxy_address, detect_wallet_type
|
|
8
|
+
from .position_management import build_split_txn, build_merge_txn, build_convert_txn
|
|
8
9
|
from .trader import PolyNodeTrader
|
|
9
10
|
from .privy import PrivySigner, PrivyConfig
|
|
10
11
|
|
|
@@ -20,4 +21,7 @@ __all__ = [
|
|
|
20
21
|
"derive_safe_address",
|
|
21
22
|
"derive_proxy_address",
|
|
22
23
|
"detect_wallet_type",
|
|
24
|
+
"build_split_txn",
|
|
25
|
+
"build_merge_txn",
|
|
26
|
+
"build_convert_txn",
|
|
23
27
|
]
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Position management — build transactions for split, merge, and convert on Polymarket.
|
|
3
|
+
|
|
4
|
+
These functions return TransactionRequest objects containing the contract address
|
|
5
|
+
and ABI-encoded calldata. Submit them via the Polymarket relayer (gasless for
|
|
6
|
+
Safe wallets) or directly on-chain.
|
|
7
|
+
|
|
8
|
+
from polynode.trading.position_management import build_split_txn, build_convert_txn
|
|
9
|
+
|
|
10
|
+
# Split $100 into YES + NO tokens
|
|
11
|
+
tx = build_split_txn("0xabc...conditionId", 100.0, neg_risk=True)
|
|
12
|
+
|
|
13
|
+
# Convert NO positions on outcomes 0 and 1
|
|
14
|
+
tx = build_convert_txn("0xdef...marketId", [0, 1], 50.0)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from .constants import CTF, NEG_RISK_ADAPTER, USDC
|
|
18
|
+
from .types import TransactionRequest
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def build_split_txn(condition_id: str, amount: float, neg_risk: bool = True) -> TransactionRequest:
|
|
22
|
+
"""Build a split transaction: USDC -> YES + NO outcome tokens.
|
|
23
|
+
|
|
24
|
+
Routes to NegRiskAdapter for neg-risk markets, CTF for standard markets.
|
|
25
|
+
Amount is in USDC (e.g. 100.0 = $100).
|
|
26
|
+
"""
|
|
27
|
+
amount_raw = int(amount * 1_000_000)
|
|
28
|
+
|
|
29
|
+
if neg_risk:
|
|
30
|
+
# NegRiskAdapter.splitPosition(bytes32 conditionId, uint256 amount)
|
|
31
|
+
data = "0xa3d7da1d" + _encode_bytes32(condition_id) + _encode_uint256(amount_raw)
|
|
32
|
+
return TransactionRequest(to=NEG_RISK_ADAPTER, data=data)
|
|
33
|
+
else:
|
|
34
|
+
# CTF.splitPosition(address, bytes32, bytes32, uint256[], uint256)
|
|
35
|
+
data = (
|
|
36
|
+
"0x72108503"
|
|
37
|
+
+ _encode_address(USDC)
|
|
38
|
+
+ "00" * 32 # parentCollectionId = bytes32(0)
|
|
39
|
+
+ _encode_bytes32(condition_id)
|
|
40
|
+
+ _encode_uint256(160) # offset to partition array
|
|
41
|
+
+ _encode_uint256(amount_raw)
|
|
42
|
+
+ _encode_uint256(2) # partition length
|
|
43
|
+
+ _encode_uint256(1)
|
|
44
|
+
+ _encode_uint256(2)
|
|
45
|
+
)
|
|
46
|
+
return TransactionRequest(to=CTF, data=data)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def build_merge_txn(condition_id: str, amount: float, neg_risk: bool = True) -> TransactionRequest:
|
|
50
|
+
"""Build a merge transaction: YES + NO outcome tokens -> USDC."""
|
|
51
|
+
amount_raw = int(amount * 1_000_000)
|
|
52
|
+
|
|
53
|
+
if neg_risk:
|
|
54
|
+
# NegRiskAdapter.mergePositions(bytes32 conditionId, uint256 amount)
|
|
55
|
+
data = "0x5d03f453" + _encode_bytes32(condition_id) + _encode_uint256(amount_raw)
|
|
56
|
+
return TransactionRequest(to=NEG_RISK_ADAPTER, data=data)
|
|
57
|
+
else:
|
|
58
|
+
# CTF.mergePositions(address, bytes32, bytes32, uint256[], uint256)
|
|
59
|
+
data = (
|
|
60
|
+
"0xcad9440e"
|
|
61
|
+
+ _encode_address(USDC)
|
|
62
|
+
+ "00" * 32
|
|
63
|
+
+ _encode_bytes32(condition_id)
|
|
64
|
+
+ _encode_uint256(160)
|
|
65
|
+
+ _encode_uint256(amount_raw)
|
|
66
|
+
+ _encode_uint256(2)
|
|
67
|
+
+ _encode_uint256(1)
|
|
68
|
+
+ _encode_uint256(2)
|
|
69
|
+
)
|
|
70
|
+
return TransactionRequest(to=CTF, data=data)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def build_convert_txn(market_id: str, outcome_indices: list[int], amount: float) -> TransactionRequest:
|
|
74
|
+
"""Build a convert transaction: NO positions -> USDC + YES on complementary outcomes.
|
|
75
|
+
|
|
76
|
+
Only works on neg-risk multi-outcome markets.
|
|
77
|
+
outcome_indices: which outcomes' NOs to convert (e.g. [0, 1]).
|
|
78
|
+
"""
|
|
79
|
+
amount_raw = int(amount * 1_000_000)
|
|
80
|
+
|
|
81
|
+
# Compute indexSet bitmask
|
|
82
|
+
index_set = 0
|
|
83
|
+
for idx in outcome_indices:
|
|
84
|
+
index_set |= 1 << idx
|
|
85
|
+
|
|
86
|
+
# NegRiskAdapter.convertPositions(bytes32 marketId, uint256 indexSet, uint256 amount)
|
|
87
|
+
data = "0xc64748c4" + _encode_bytes32(market_id) + _encode_uint256(index_set) + _encode_uint256(amount_raw)
|
|
88
|
+
return TransactionRequest(to=NEG_RISK_ADAPTER, data=data)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# ── Encoding helpers ──
|
|
92
|
+
|
|
93
|
+
def _encode_bytes32(hex_str: str) -> str:
|
|
94
|
+
s = hex_str.removeprefix("0x")
|
|
95
|
+
return s.zfill(64)[:64]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _encode_address(addr: str) -> str:
|
|
99
|
+
s = addr.removeprefix("0x")
|
|
100
|
+
return s.lower().zfill(64)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _encode_uint256(val: int) -> str:
|
|
104
|
+
return hex(val)[2:].zfill(64)
|
|
@@ -478,6 +478,30 @@ class PolyNodeTrader:
|
|
|
478
478
|
db.upsert_market_meta(meta)
|
|
479
479
|
return meta
|
|
480
480
|
|
|
481
|
+
# ── Position Management (split/merge/convert) ──
|
|
482
|
+
|
|
483
|
+
def split(self, params: "SplitParams") -> "TransactionRequest":
|
|
484
|
+
"""Build a split transaction: USDC -> YES + NO outcome tokens.
|
|
485
|
+
|
|
486
|
+
Returns a TransactionRequest to submit via the Polymarket relayer or on-chain.
|
|
487
|
+
For gasless execution, use the TypeScript SDK's trader.split().
|
|
488
|
+
"""
|
|
489
|
+
from .position_management import build_split_txn
|
|
490
|
+
return build_split_txn(params.condition_id, params.amount, neg_risk=True)
|
|
491
|
+
|
|
492
|
+
def merge(self, params: "MergeParams") -> "TransactionRequest":
|
|
493
|
+
"""Build a merge transaction: YES + NO outcome tokens -> USDC."""
|
|
494
|
+
from .position_management import build_merge_txn
|
|
495
|
+
return build_merge_txn(params.condition_id, params.amount, neg_risk=True)
|
|
496
|
+
|
|
497
|
+
def convert(self, params: "ConvertParams") -> "TransactionRequest":
|
|
498
|
+
"""Build a convert transaction: NO positions -> USDC + YES on complementary outcomes.
|
|
499
|
+
|
|
500
|
+
Only works on neg-risk multi-outcome markets.
|
|
501
|
+
"""
|
|
502
|
+
from .position_management import build_convert_txn
|
|
503
|
+
return build_convert_txn(params.market_id, params.outcome_indices, params.amount)
|
|
504
|
+
|
|
481
505
|
# ── History ──
|
|
482
506
|
|
|
483
507
|
def get_order_history(self, params: HistoryParams | None = None) -> list[OrderHistoryRow]:
|
|
@@ -153,6 +153,48 @@ class OpenOrder:
|
|
|
153
153
|
order_type: str
|
|
154
154
|
|
|
155
155
|
|
|
156
|
+
# ── Position Management (split/merge/convert) ──
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@dataclass
|
|
160
|
+
class SplitParams:
|
|
161
|
+
"""Parameters for splitting USDC into YES + NO outcome tokens."""
|
|
162
|
+
condition_id: str
|
|
163
|
+
amount: float # USDC amount (e.g. 100.0 = $100)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@dataclass
|
|
167
|
+
class MergeParams:
|
|
168
|
+
"""Parameters for merging YES + NO outcome tokens back into USDC."""
|
|
169
|
+
condition_id: str
|
|
170
|
+
amount: float
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@dataclass
|
|
174
|
+
class ConvertParams:
|
|
175
|
+
"""Parameters for converting NO positions on selected outcomes.
|
|
176
|
+
Only works on neg-risk multi-outcome markets."""
|
|
177
|
+
market_id: str
|
|
178
|
+
outcome_indices: list[int] # e.g. [0, 1]
|
|
179
|
+
amount: float
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@dataclass
|
|
183
|
+
class TransactionRequest:
|
|
184
|
+
"""A pre-built transaction ready for submission."""
|
|
185
|
+
to: str
|
|
186
|
+
data: str # hex-encoded calldata
|
|
187
|
+
value: str = "0"
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@dataclass
|
|
191
|
+
class PositionResult:
|
|
192
|
+
"""Result of a position management operation."""
|
|
193
|
+
success: bool
|
|
194
|
+
tx_hash: str | None = None
|
|
195
|
+
error: str | None = None
|
|
196
|
+
|
|
197
|
+
|
|
156
198
|
@dataclass
|
|
157
199
|
class MarketMeta:
|
|
158
200
|
token_id: str
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|