poly-web3 1.0.0__py3-none-any.whl → 1.0.2__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.
- examples/example_redeem.py +7 -7
- examples/example_split_merge.py +56 -0
- poly_web3/const.py +70 -6
- poly_web3/web3_service/base.py +113 -4
- poly_web3/web3_service/eoa_service.py +21 -0
- poly_web3/web3_service/proxy_service.py +15 -11
- poly_web3/web3_service/safe_service.py +7 -2
- {poly_web3-1.0.0.dist-info → poly_web3-1.0.2.dist-info}/METADATA +164 -69
- poly_web3-1.0.2.dist-info/RECORD +19 -0
- {poly_web3-1.0.0.dist-info → poly_web3-1.0.2.dist-info}/WHEEL +1 -1
- poly_web3-1.0.0.dist-info/RECORD +0 -18
- {poly_web3-1.0.0.dist-info → poly_web3-1.0.2.dist-info}/top_level.txt +0 -0
examples/example_redeem.py
CHANGED
|
@@ -24,7 +24,7 @@ if __name__ == "__main__":
|
|
|
24
24
|
host,
|
|
25
25
|
key=os.getenv("POLY_API_KEY"),
|
|
26
26
|
chain_id=chain_id,
|
|
27
|
-
signature_type=1,
|
|
27
|
+
signature_type=1, # signature_type=2 for Safe
|
|
28
28
|
funder=os.getenv("POLYMARKET_PROXY_ADDRESS"),
|
|
29
29
|
)
|
|
30
30
|
creds = client.create_or_derive_api_creds()
|
|
@@ -41,27 +41,27 @@ if __name__ == "__main__":
|
|
|
41
41
|
)
|
|
42
42
|
),
|
|
43
43
|
)
|
|
44
|
-
condition_id = "0x31fb435a9506d14f00b9de5e5e4491cf2223b6d40a2525d9afa8b620b61b50e2"
|
|
45
44
|
service = PolyWeb3Service(
|
|
46
45
|
clob_client=client,
|
|
47
46
|
relayer_client=relayer_client,
|
|
48
47
|
rpc_url="https://polygon-bor.publicnode.com",
|
|
49
48
|
)
|
|
49
|
+
|
|
50
|
+
# Redeem all positions that are currently redeemable (returns list or None)
|
|
51
|
+
redeem_all = service.redeem_all(batch_size=10)
|
|
52
|
+
print(redeem_all)
|
|
53
|
+
|
|
50
54
|
# Redeem in batch
|
|
51
55
|
condition_ids = [
|
|
52
|
-
condition_id,
|
|
53
56
|
"0x31fb435a9506d14f00b9de5e5e4491cf2223b6d40a2525d9afa8b620b61b50e2",
|
|
54
57
|
]
|
|
55
58
|
redeem_batch = service.redeem(condition_ids, batch_size=10)
|
|
56
59
|
print(redeem_batch)
|
|
57
60
|
|
|
58
|
-
# Redeem all positions that are currently redeemable (returns list or None)
|
|
59
|
-
redeem_all = service.redeem_all(batch_size=10)
|
|
60
|
-
print(redeem_all)
|
|
61
61
|
|
|
62
62
|
# Optional - Query operations (可选操作,用于查询)
|
|
63
63
|
# can_redeem = service.is_condition_resolved(condition_id)
|
|
64
64
|
# redeem_balance = service.get_redeemable_index_and_balance(
|
|
65
|
-
# condition_id
|
|
65
|
+
# condition_id
|
|
66
66
|
# )
|
|
67
67
|
# print(can_redeem, redeem_balance)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# -*- coding = utf-8 -*-
|
|
2
|
+
# @Time: 2025-12-30 12:00:00
|
|
3
|
+
# @Author: PinBar
|
|
4
|
+
# @Site:
|
|
5
|
+
# @File: example_split_merge.py
|
|
6
|
+
# @Software: PyCharm
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
import dotenv
|
|
10
|
+
from py_builder_relayer_client.client import RelayClient
|
|
11
|
+
from py_builder_signing_sdk.config import BuilderConfig
|
|
12
|
+
from py_builder_signing_sdk.sdk_types import BuilderApiKeyCreds
|
|
13
|
+
from py_clob_client.client import ClobClient
|
|
14
|
+
|
|
15
|
+
from poly_web3 import RELAYER_URL, PolyWeb3Service
|
|
16
|
+
|
|
17
|
+
dotenv.load_dotenv()
|
|
18
|
+
|
|
19
|
+
if __name__ == "__main__":
|
|
20
|
+
host: str = "https://clob.polymarket.com"
|
|
21
|
+
chain_id: int = 137 # No need to adjust this
|
|
22
|
+
client = ClobClient(
|
|
23
|
+
host,
|
|
24
|
+
key=os.getenv("POLY_API_KEY"),
|
|
25
|
+
chain_id=chain_id,
|
|
26
|
+
signature_type=1, # signature_type=2 for Safe
|
|
27
|
+
funder=os.getenv("POLYMARKET_PROXY_ADDRESS"),
|
|
28
|
+
)
|
|
29
|
+
creds = client.create_or_derive_api_creds()
|
|
30
|
+
client.set_api_creds(creds)
|
|
31
|
+
relayer_client = RelayClient(
|
|
32
|
+
RELAYER_URL,
|
|
33
|
+
chain_id,
|
|
34
|
+
os.getenv("POLY_API_KEY"),
|
|
35
|
+
BuilderConfig(
|
|
36
|
+
local_builder_creds=BuilderApiKeyCreds(
|
|
37
|
+
key=os.getenv("BUILDER_KEY"),
|
|
38
|
+
secret=os.getenv("BUILDER_SECRET"),
|
|
39
|
+
passphrase=os.getenv("BUILDER_PASSPHRASE"),
|
|
40
|
+
)
|
|
41
|
+
),
|
|
42
|
+
)
|
|
43
|
+
service = PolyWeb3Service(
|
|
44
|
+
clob_client=client,
|
|
45
|
+
relayer_client=relayer_client,
|
|
46
|
+
rpc_url="https://polygon-bor.publicnode.com",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
condition_id = "0x58ec217262554683a6c1fa2de9d87addef26dd3348367824d6890c68a98809b0"
|
|
50
|
+
amount = 10 # amount in human USDC units
|
|
51
|
+
|
|
52
|
+
split_result = service.split(condition_id, amount)
|
|
53
|
+
print(split_result)
|
|
54
|
+
|
|
55
|
+
merge_result = service.merge(condition_id, amount)
|
|
56
|
+
print(merge_result)
|
poly_web3/const.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# @Site:
|
|
5
5
|
# @File: const.py
|
|
6
6
|
# @Software: PyCharm
|
|
7
|
-
from
|
|
7
|
+
from eth_utils import to_checksum_address
|
|
8
8
|
|
|
9
9
|
GET_NONCE = "/nonce"
|
|
10
10
|
GET_RELAY_PAYLOAD = "/relay-payload"
|
|
@@ -15,7 +15,7 @@ GET_DEPLOYED = "/deployed"
|
|
|
15
15
|
RPC_URL = "https://polygon-bor.publicnode.com" # "https://polygon-rpc.com"
|
|
16
16
|
RELAYER_URL = "https://relayer-v2.polymarket.com"
|
|
17
17
|
|
|
18
|
-
STATE_NEW =
|
|
18
|
+
STATE_NEW = "STATE_NEW"
|
|
19
19
|
STATE_EXECUTED = "STATE_EXECUTED"
|
|
20
20
|
STATE_MINED = "STATE_MINED"
|
|
21
21
|
STATE_INVALID = "STATE_INVALID"
|
|
@@ -23,13 +23,13 @@ STATE_CONFIRMED = "STATE_CONFIRMED"
|
|
|
23
23
|
STATE_FAILED = "STATE_FAILED"
|
|
24
24
|
|
|
25
25
|
# address
|
|
26
|
-
CTF_ADDRESS =
|
|
27
|
-
USDC_POLYGON =
|
|
28
|
-
NEG_RISK_ADAPTER_ADDRESS =
|
|
26
|
+
CTF_ADDRESS = to_checksum_address("0x4d97dcd97ec945f40cf65f87097ace5ea0476045")
|
|
27
|
+
USDC_POLYGON = to_checksum_address("0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174")
|
|
28
|
+
NEG_RISK_ADAPTER_ADDRESS = to_checksum_address(
|
|
29
29
|
"0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296"
|
|
30
30
|
)
|
|
31
31
|
ZERO_BYTES32 = "0x" + "00" * 32
|
|
32
|
-
proxy_factory_address =
|
|
32
|
+
proxy_factory_address = to_checksum_address(
|
|
33
33
|
"0xaB45c5A4B0c941a2F231C04C3f49182e1A254052"
|
|
34
34
|
)
|
|
35
35
|
SAFE_INIT_CODE_HASH = (
|
|
@@ -78,6 +78,70 @@ CTF_ABI_REDEEM = [
|
|
|
78
78
|
}
|
|
79
79
|
]
|
|
80
80
|
|
|
81
|
+
CTF_ABI_SPLIT = [
|
|
82
|
+
{
|
|
83
|
+
"name": "splitPosition",
|
|
84
|
+
"type": "function",
|
|
85
|
+
"stateMutability": "nonpayable",
|
|
86
|
+
"inputs": [
|
|
87
|
+
{"name": "collateralToken", "type": "address"},
|
|
88
|
+
{"name": "parentCollectionId", "type": "bytes32"},
|
|
89
|
+
{"name": "conditionId", "type": "bytes32"},
|
|
90
|
+
{"name": "partition", "type": "uint256[]"},
|
|
91
|
+
{"name": "amount", "type": "uint256"},
|
|
92
|
+
],
|
|
93
|
+
"outputs": [],
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
CTF_ABI_MERGE = [
|
|
98
|
+
{
|
|
99
|
+
"name": "mergePositions",
|
|
100
|
+
"type": "function",
|
|
101
|
+
"stateMutability": "nonpayable",
|
|
102
|
+
"inputs": [
|
|
103
|
+
{"name": "collateralToken", "type": "address"},
|
|
104
|
+
{"name": "parentCollectionId", "type": "bytes32"},
|
|
105
|
+
{"name": "conditionId", "type": "bytes32"},
|
|
106
|
+
{"name": "partition", "type": "uint256[]"},
|
|
107
|
+
{"name": "amount", "type": "uint256"},
|
|
108
|
+
],
|
|
109
|
+
"outputs": [],
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
CTF_ABI_SPLIT = [
|
|
114
|
+
{
|
|
115
|
+
"name": "splitPosition",
|
|
116
|
+
"type": "function",
|
|
117
|
+
"stateMutability": "nonpayable",
|
|
118
|
+
"inputs": [
|
|
119
|
+
{"name": "collateralToken", "type": "address"},
|
|
120
|
+
{"name": "parentCollectionId", "type": "bytes32"},
|
|
121
|
+
{"name": "conditionId", "type": "bytes32"},
|
|
122
|
+
{"name": "partition", "type": "uint256[]"},
|
|
123
|
+
{"name": "amount", "type": "uint256"},
|
|
124
|
+
],
|
|
125
|
+
"outputs": [],
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
CTF_ABI_MERGE = [
|
|
130
|
+
{
|
|
131
|
+
"name": "mergePositions",
|
|
132
|
+
"type": "function",
|
|
133
|
+
"stateMutability": "nonpayable",
|
|
134
|
+
"inputs": [
|
|
135
|
+
{"name": "collateralToken", "type": "address"},
|
|
136
|
+
{"name": "parentCollectionId", "type": "bytes32"},
|
|
137
|
+
{"name": "conditionId", "type": "bytes32"},
|
|
138
|
+
{"name": "partition", "type": "uint256[]"},
|
|
139
|
+
{"name": "amount", "type": "uint256"},
|
|
140
|
+
],
|
|
141
|
+
"outputs": [],
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
|
|
81
145
|
NEG_RISK_ADAPTER_ABI_REDEEM = [
|
|
82
146
|
{
|
|
83
147
|
"name": "redeemPositions",
|
poly_web3/web3_service/base.py
CHANGED
|
@@ -5,9 +5,11 @@
|
|
|
5
5
|
# @File: base.py
|
|
6
6
|
# @Software: PyCharm
|
|
7
7
|
from typing import Any
|
|
8
|
+
from decimal import Decimal, InvalidOperation, ROUND_DOWN
|
|
8
9
|
|
|
9
10
|
from py_builder_relayer_client.client import RelayClient
|
|
10
11
|
from py_clob_client.client import ClobClient
|
|
12
|
+
from eth_utils import to_checksum_address
|
|
11
13
|
from web3 import Web3
|
|
12
14
|
import requests
|
|
13
15
|
|
|
@@ -18,6 +20,8 @@ from poly_web3.const import (
|
|
|
18
20
|
ZERO_BYTES32,
|
|
19
21
|
USDC_POLYGON,
|
|
20
22
|
CTF_ABI_REDEEM,
|
|
23
|
+
CTF_ABI_SPLIT,
|
|
24
|
+
CTF_ABI_MERGE,
|
|
21
25
|
NEG_RISK_ADAPTER_ADDRESS,
|
|
22
26
|
RELAYER_URL,
|
|
23
27
|
POL,
|
|
@@ -132,7 +136,7 @@ class BaseWeb3Service:
|
|
|
132
136
|
if not winners:
|
|
133
137
|
return []
|
|
134
138
|
ctf = self.w3.eth.contract(address=CTF_ADDRESS, abi=CTF_ABI_PAYOUT)
|
|
135
|
-
owner_checksum =
|
|
139
|
+
owner_checksum = to_checksum_address(owner)
|
|
136
140
|
redeemable: list[tuple] = []
|
|
137
141
|
for index in winners:
|
|
138
142
|
index_set = 1 << index
|
|
@@ -149,7 +153,6 @@ class BaseWeb3Service:
|
|
|
149
153
|
|
|
150
154
|
def build_ctf_redeem_tx_data(self, condition_id: str) -> str:
|
|
151
155
|
ctf = self.w3.eth.contract(address=CTF_ADDRESS, abi=CTF_ABI_REDEEM)
|
|
152
|
-
# 只需要 calldata:encodeABI 即可
|
|
153
156
|
return ctf.functions.redeemPositions(
|
|
154
157
|
USDC_POLYGON,
|
|
155
158
|
ZERO_BYTES32,
|
|
@@ -157,6 +160,40 @@ class BaseWeb3Service:
|
|
|
157
160
|
[1, 2],
|
|
158
161
|
)._encode_transaction_data()
|
|
159
162
|
|
|
163
|
+
def build_ctf_split_tx_data(
|
|
164
|
+
self,
|
|
165
|
+
condition_id: str,
|
|
166
|
+
partition: list[int],
|
|
167
|
+
amount: int,
|
|
168
|
+
collateral_token: str = USDC_POLYGON,
|
|
169
|
+
parent_collection_id: str = ZERO_BYTES32,
|
|
170
|
+
) -> str:
|
|
171
|
+
ctf = self.w3.eth.contract(address=CTF_ADDRESS, abi=CTF_ABI_SPLIT)
|
|
172
|
+
return ctf.functions.splitPosition(
|
|
173
|
+
collateral_token,
|
|
174
|
+
parent_collection_id,
|
|
175
|
+
condition_id,
|
|
176
|
+
partition,
|
|
177
|
+
amount,
|
|
178
|
+
)._encode_transaction_data()
|
|
179
|
+
|
|
180
|
+
def build_ctf_merge_tx_data(
|
|
181
|
+
self,
|
|
182
|
+
condition_id: str,
|
|
183
|
+
partition: list[int],
|
|
184
|
+
amount: int,
|
|
185
|
+
collateral_token: str = USDC_POLYGON,
|
|
186
|
+
parent_collection_id: str = ZERO_BYTES32,
|
|
187
|
+
) -> str:
|
|
188
|
+
ctf = self.w3.eth.contract(address=CTF_ADDRESS, abi=CTF_ABI_MERGE)
|
|
189
|
+
return ctf.functions.mergePositions(
|
|
190
|
+
collateral_token,
|
|
191
|
+
parent_collection_id,
|
|
192
|
+
condition_id,
|
|
193
|
+
partition,
|
|
194
|
+
amount,
|
|
195
|
+
)._encode_transaction_data()
|
|
196
|
+
|
|
160
197
|
def build_neg_risk_redeem_tx_data(
|
|
161
198
|
self, condition_id: str, redeem_amounts: list[int]
|
|
162
199
|
) -> str:
|
|
@@ -171,6 +208,9 @@ class BaseWeb3Service:
|
|
|
171
208
|
def _build_redeem_tx(self, to: str, data: str) -> Any:
|
|
172
209
|
raise NotImplementedError("redeem tx builder not implemented")
|
|
173
210
|
|
|
211
|
+
def _build_ctf_tx(self, to: str, data: str) -> Any:
|
|
212
|
+
return self._build_redeem_tx(to, data)
|
|
213
|
+
|
|
174
214
|
def _build_redeem_txs_from_positions(self, positions: list[dict]) -> list[Any]:
|
|
175
215
|
neg_amounts_by_condition: dict[str, list[float]] = {}
|
|
176
216
|
normal_conditions: set[str] = set()
|
|
@@ -207,8 +247,11 @@ class BaseWeb3Service:
|
|
|
207
247
|
)
|
|
208
248
|
return txs
|
|
209
249
|
|
|
250
|
+
def _submit_transactions(self, txs: list[Any], metadata: str) -> dict | None:
|
|
251
|
+
raise NotImplementedError("transaction submit not implemented")
|
|
252
|
+
|
|
210
253
|
def _submit_redeem(self, txs: list[Any]) -> dict | None:
|
|
211
|
-
|
|
254
|
+
return self._submit_transactions(txs, "redeem")
|
|
212
255
|
|
|
213
256
|
def _redeem_batch(self, condition_ids: list[str], batch_size: int) -> list[dict]:
|
|
214
257
|
"""
|
|
@@ -264,7 +307,7 @@ class BaseWeb3Service:
|
|
|
264
307
|
)
|
|
265
308
|
except Exception as e:
|
|
266
309
|
error_list.extend(batch)
|
|
267
|
-
logger.
|
|
310
|
+
logger.error(f"redeem batch error, {batch=}, error={e}")
|
|
268
311
|
if error_list:
|
|
269
312
|
logger.warning(f"error redeem condition list, {error_list}")
|
|
270
313
|
return redeem_list
|
|
@@ -312,6 +355,26 @@ class BaseWeb3Service:
|
|
|
312
355
|
for i in range(0, len(condition_ids), batch_size)
|
|
313
356
|
]
|
|
314
357
|
|
|
358
|
+
@staticmethod
|
|
359
|
+
def _to_usdc_base_units(amount: int | float | str | Decimal) -> int:
|
|
360
|
+
try:
|
|
361
|
+
if isinstance(amount, Decimal):
|
|
362
|
+
human = amount
|
|
363
|
+
elif isinstance(amount, int):
|
|
364
|
+
human = Decimal(amount)
|
|
365
|
+
else:
|
|
366
|
+
human = Decimal(str(amount))
|
|
367
|
+
except (InvalidOperation, ValueError) as exc:
|
|
368
|
+
raise Exception(f"invalid amount: {amount}") from exc
|
|
369
|
+
if human <= 0:
|
|
370
|
+
raise Exception("amount must be greater than 0")
|
|
371
|
+
base_units = (human * Decimal("1000000")).quantize(
|
|
372
|
+
Decimal("1"), rounding=ROUND_DOWN
|
|
373
|
+
)
|
|
374
|
+
if base_units <= 0:
|
|
375
|
+
raise Exception("amount too small after conversion")
|
|
376
|
+
return int(base_units)
|
|
377
|
+
|
|
315
378
|
def redeem(
|
|
316
379
|
self,
|
|
317
380
|
condition_ids: str | list[str],
|
|
@@ -330,3 +393,49 @@ class BaseWeb3Service:
|
|
|
330
393
|
"""
|
|
331
394
|
positions = self.fetch_positions(user_address=self._resolve_user_address())
|
|
332
395
|
return self._redeem_from_positions(positions, batch_size)
|
|
396
|
+
|
|
397
|
+
def split(
|
|
398
|
+
self,
|
|
399
|
+
condition_id: str,
|
|
400
|
+
amount: int | float | str | Decimal,
|
|
401
|
+
collateral_token: str = USDC_POLYGON,
|
|
402
|
+
parent_collection_id: str = ZERO_BYTES32,
|
|
403
|
+
) -> dict | None:
|
|
404
|
+
"""
|
|
405
|
+
Split a position for binary markets (Yes/No), amount in human units.
|
|
406
|
+
"""
|
|
407
|
+
amount_base_units = self._to_usdc_base_units(amount)
|
|
408
|
+
tx = self._build_ctf_tx(
|
|
409
|
+
CTF_ADDRESS,
|
|
410
|
+
self.build_ctf_split_tx_data(
|
|
411
|
+
condition_id=condition_id,
|
|
412
|
+
partition=[1, 2],
|
|
413
|
+
amount=amount_base_units,
|
|
414
|
+
collateral_token=collateral_token,
|
|
415
|
+
parent_collection_id=parent_collection_id,
|
|
416
|
+
),
|
|
417
|
+
)
|
|
418
|
+
return self._submit_transactions([tx], "split")
|
|
419
|
+
|
|
420
|
+
def merge(
|
|
421
|
+
self,
|
|
422
|
+
condition_id: str,
|
|
423
|
+
amount: int | float | str | Decimal,
|
|
424
|
+
collateral_token: str = USDC_POLYGON,
|
|
425
|
+
parent_collection_id: str = ZERO_BYTES32,
|
|
426
|
+
) -> dict | None:
|
|
427
|
+
"""
|
|
428
|
+
Merge binary positions (Yes/No) back into a single position, amount in human units.
|
|
429
|
+
"""
|
|
430
|
+
amount_base_units = self._to_usdc_base_units(amount)
|
|
431
|
+
tx = self._build_ctf_tx(
|
|
432
|
+
CTF_ADDRESS,
|
|
433
|
+
self.build_ctf_merge_tx_data(
|
|
434
|
+
condition_id=condition_id,
|
|
435
|
+
partition=[1, 2],
|
|
436
|
+
amount=amount_base_units,
|
|
437
|
+
collateral_token=collateral_token,
|
|
438
|
+
parent_collection_id=parent_collection_id,
|
|
439
|
+
),
|
|
440
|
+
)
|
|
441
|
+
return self._submit_transactions([tx], "merge")
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
# @Site:
|
|
5
5
|
# @File: eoa_service.py
|
|
6
6
|
# @Software: PyCharm
|
|
7
|
+
from decimal import Decimal
|
|
8
|
+
|
|
9
|
+
from poly_web3.const import USDC_POLYGON, ZERO_BYTES32
|
|
7
10
|
from poly_web3.web3_service.base import BaseWeb3Service
|
|
8
11
|
|
|
9
12
|
|
|
@@ -17,3 +20,21 @@ class EOAWeb3Service(BaseWeb3Service):
|
|
|
17
20
|
|
|
18
21
|
def redeem_all(self, batch_size: int = 10) -> list[dict]:
|
|
19
22
|
raise ImportError("EOA wallet redeem not supported")
|
|
23
|
+
|
|
24
|
+
def split(
|
|
25
|
+
self,
|
|
26
|
+
condition_id: str,
|
|
27
|
+
amount: int | float | str | Decimal,
|
|
28
|
+
collateral_token: str = USDC_POLYGON,
|
|
29
|
+
parent_collection_id: str = ZERO_BYTES32,
|
|
30
|
+
) -> dict | None:
|
|
31
|
+
raise ImportError("EOA wallet split not supported")
|
|
32
|
+
|
|
33
|
+
def merge(
|
|
34
|
+
self,
|
|
35
|
+
condition_id: str,
|
|
36
|
+
amount: int | float | str | Decimal,
|
|
37
|
+
collateral_token: str = USDC_POLYGON,
|
|
38
|
+
parent_collection_id: str = ZERO_BYTES32,
|
|
39
|
+
) -> dict | None:
|
|
40
|
+
raise ImportError("EOA wallet merge not supported")
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
# @Software: PyCharm
|
|
7
7
|
import requests
|
|
8
8
|
|
|
9
|
-
from
|
|
10
|
-
from eth_utils import to_bytes
|
|
9
|
+
from eth_utils import to_bytes, to_checksum_address
|
|
11
10
|
|
|
12
11
|
from poly_web3.const import (
|
|
13
12
|
proxy_wallet_factory_abi,
|
|
@@ -22,6 +21,8 @@ from poly_web3.web3_service.base import BaseWeb3Service
|
|
|
22
21
|
from poly_web3.signature.build import derive_proxy_wallet, create_struct_hash
|
|
23
22
|
from poly_web3.signature.hash_message import hash_message
|
|
24
23
|
from poly_web3.signature import secp256k1
|
|
24
|
+
|
|
25
|
+
|
|
25
26
|
class ProxyWeb3Service(BaseWeb3Service):
|
|
26
27
|
def _build_redeem_tx(self, to: str, data: str) -> dict:
|
|
27
28
|
return {
|
|
@@ -31,7 +32,9 @@ class ProxyWeb3Service(BaseWeb3Service):
|
|
|
31
32
|
"typeCode": 1,
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
def build_proxy_transaction_request(
|
|
35
|
+
def build_proxy_transaction_request(
|
|
36
|
+
self, args: dict, metadata: str = "redeem"
|
|
37
|
+
) -> dict:
|
|
35
38
|
proxy_contract_config = self.get_contract_config()["ProxyContracts"]
|
|
36
39
|
to = proxy_contract_config["ProxyFactory"]
|
|
37
40
|
proxy = derive_proxy_wallet(args["from"], to, PROXY_INIT_CODE_HASH)
|
|
@@ -79,7 +82,7 @@ class ProxyWeb3Service(BaseWeb3Service):
|
|
|
79
82
|
"signature": final_sig,
|
|
80
83
|
"signatureParams": sig_params,
|
|
81
84
|
"type": self.wallet_type.value,
|
|
82
|
-
"metadata":
|
|
85
|
+
"metadata": metadata,
|
|
83
86
|
}
|
|
84
87
|
return req
|
|
85
88
|
|
|
@@ -92,15 +95,13 @@ class ProxyWeb3Service(BaseWeb3Service):
|
|
|
92
95
|
# Create the contract object
|
|
93
96
|
contract = self.w3.eth.contract(abi=proxy_wallet_factory_abi)
|
|
94
97
|
|
|
95
|
-
# Encode function data
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return function_data
|
|
98
|
+
# Encode function data (compatible with web3 6/7)
|
|
99
|
+
return contract.functions.proxy(calls_data)._encode_transaction_data()
|
|
99
100
|
|
|
100
|
-
def
|
|
101
|
+
def _submit_transactions(self, txs: list[dict], metadata: str) -> dict:
|
|
101
102
|
if self.clob_client is None:
|
|
102
103
|
raise Exception("signer not found")
|
|
103
|
-
_from =
|
|
104
|
+
_from = to_checksum_address(self.clob_client.get_address())
|
|
104
105
|
rp = self._get_relay_payload(_from, self.wallet_type)
|
|
105
106
|
args = {
|
|
106
107
|
"from": _from,
|
|
@@ -109,7 +110,7 @@ class ProxyWeb3Service(BaseWeb3Service):
|
|
|
109
110
|
"relay": rp["address"],
|
|
110
111
|
"nonce": rp["nonce"],
|
|
111
112
|
}
|
|
112
|
-
req = self.build_proxy_transaction_request(args)
|
|
113
|
+
req = self.build_proxy_transaction_request(args, metadata=metadata)
|
|
113
114
|
headers = self.relayer_client._generate_builder_headers(
|
|
114
115
|
"POST", SUBMIT_TRANSACTION, req
|
|
115
116
|
)
|
|
@@ -123,3 +124,6 @@ class ProxyWeb3Service(BaseWeb3Service):
|
|
|
123
124
|
max_polls=100,
|
|
124
125
|
)
|
|
125
126
|
return redeem_res
|
|
127
|
+
|
|
128
|
+
def _submit_redeem(self, txs: list[dict]) -> dict:
|
|
129
|
+
return self._submit_transactions(txs, "redeem")
|
|
@@ -17,8 +17,13 @@ class SafeWeb3Service(BaseWeb3Service):
|
|
|
17
17
|
operation=OperationType.Call,
|
|
18
18
|
)
|
|
19
19
|
|
|
20
|
-
def
|
|
20
|
+
def _submit_transactions(
|
|
21
|
+
self, txs: list[SafeTransaction], metadata: str
|
|
22
|
+
) -> dict | None:
|
|
21
23
|
if self.relayer_client is None:
|
|
22
24
|
raise Exception("relayer_client not found")
|
|
23
|
-
resp = self.relayer_client.execute(txs,
|
|
25
|
+
resp = self.relayer_client.execute(txs, metadata)
|
|
24
26
|
return resp.wait()
|
|
27
|
+
|
|
28
|
+
def _submit_redeem(self, txs: list[SafeTransaction]) -> dict | None:
|
|
29
|
+
return self._submit_transactions(txs, "redeem")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: poly-web3
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: Polymarket Proxy wallet redeem SDK - Execute redeem operations on Polymarket using proxy wallets
|
|
5
5
|
Home-page: https://github.com/tosmart01/poly-web3
|
|
6
6
|
Author: PinBar
|
|
@@ -19,7 +19,7 @@ Requires-Python: >=3.11
|
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
Requires-Dist: py-clob-client>=0.25.0
|
|
21
21
|
Requires-Dist: py-builder-relayer-client>=0.0.1
|
|
22
|
-
Requires-Dist: web3
|
|
22
|
+
Requires-Dist: web3<8,>=7.0.0
|
|
23
23
|
Requires-Dist: eth-utils==5.3.1
|
|
24
24
|
Requires-Dist: setuptools>=80.9.0
|
|
25
25
|
Dynamic: home-page
|
|
@@ -27,16 +27,61 @@ Dynamic: requires-python
|
|
|
27
27
|
|
|
28
28
|
# poly-web3
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+

|
|
31
|
+

|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
Python SDK for redeeming and splitting/merging Polymarket positions via Proxy/Safe wallets (gas-free).
|
|
31
35
|
|
|
32
36
|
[English](README.md) | [中文](README.zh.md)
|
|
33
37
|
|
|
38
|
+
```bash
|
|
39
|
+
Python >= 3.11
|
|
40
|
+
pip install poly-web3
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from poly_web3 import PolyWeb3Service
|
|
45
|
+
|
|
46
|
+
service = PolyWeb3Service(
|
|
47
|
+
clob_client=client,
|
|
48
|
+
relayer_client=relayer_client,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Redeem all redeemable positions for the current account.
|
|
52
|
+
service.redeem_all(batch_size=10)
|
|
53
|
+
|
|
54
|
+
# Split/Merge for binary markets (amount in human USDC units).
|
|
55
|
+
service.split("0x...", 10)
|
|
56
|
+
service.merge("0x...", 10)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
[See the full example](#quick-start)
|
|
60
|
+
|
|
61
|
+
## Redeem Behavior Notes
|
|
62
|
+
|
|
63
|
+
- Redeemable positions are fetched via the official Positions API, which typically has ~1 minute latency.
|
|
64
|
+
- `redeem_all` returns an empty list if there are no redeemable positions. If the returned list contains `None`, the redeem failed and should be retried.
|
|
65
|
+
|
|
66
|
+
## Split/Merge Notes
|
|
67
|
+
|
|
68
|
+
- `split`/`merge` are designed for binary markets (Yes/No) and use the default partition internally.
|
|
69
|
+
- `amount` is in human units (USDC), and is converted to base units internally.
|
|
70
|
+
|
|
71
|
+
## FAQ
|
|
72
|
+
|
|
73
|
+
1. **UI shows redeemable, but `redeem_all` returns `[]`**: The official Positions API can be delayed by 1–3 minutes. Wait a bit and retry.
|
|
74
|
+
2. **RPC error during redeem**: Switch RPC endpoints by setting `rpc_url` when instantiating `PolyWeb3Service`.
|
|
75
|
+
3. **Redeem stuck in `execute`**: The official relayer may be congested. Stop redeeming for 1 hour to avoid nonce looping from repeated submissions.
|
|
76
|
+
4. **Relayer client returns 403**: You need to apply for Builder API access and use a valid key. Reference: Polymarket Builders — Introduction: https://docs.polymarket.com/developers/builders/builder-intro
|
|
77
|
+
5. **Relayer daily limit**: The official relayer typically limits to 100 requests per day. Prefer batch redeem (`batch_size`) to reduce the number of requests and avoid hitting the limit.
|
|
78
|
+
|
|
34
79
|
## About the Project
|
|
35
80
|
|
|
36
|
-
This project is a Python rewrite of Polymarket's official TypeScript implementation of `builder-relayer-client`, designed to provide Python developers with a convenient tool for executing
|
|
81
|
+
This project is a Python rewrite of Polymarket's official TypeScript implementation of `builder-relayer-client`, designed to provide Python developers with a convenient tool for executing Proxy and Safe wallet redeem operations on Polymarket.
|
|
37
82
|
|
|
38
83
|
**Important Notes:**
|
|
39
|
-
- This project
|
|
84
|
+
- This project implements official CTF redeem plus binary split/merge operations
|
|
40
85
|
- Other features (such as trading, order placement, etc.) are not within the scope of this project
|
|
41
86
|
|
|
42
87
|
**Some Polymarket-related redeem or write operations implemented in this project depend on access granted through Polymarket's Builder program. To perform real redeem operations against Polymarket, you must apply for and obtain a Builder key/credentials via Polymarket's official Builder application process. After approval you will receive the credentials required to use the Builder API—only then will the redeem flows in this repository work against the live service. For local development or automated tests, use mocks or testnet setups instead of real keys to avoid exposing production credentials.**
|
|
@@ -45,19 +90,11 @@ Reference:
|
|
|
45
90
|
- Polymarket Builders — Introduction: https://docs.polymarket.com/developers/builders/builder-intro
|
|
46
91
|
|
|
47
92
|
**Current Status:**
|
|
48
|
-
- ✅ **Proxy Wallet** - Fully supported for redeem
|
|
49
|
-
-
|
|
93
|
+
- ✅ **Proxy Wallet** - Fully supported for redeem/split/merge
|
|
94
|
+
- ✅ **Safe Wallet** - Fully supported for redeem/split/merge
|
|
50
95
|
- 🚧 **EOA Wallet** - Under development
|
|
51
96
|
|
|
52
|
-
We welcome community contributions! If you'd like to help implement
|
|
53
|
-
|
|
54
|
-
## Features
|
|
55
|
-
|
|
56
|
-
- ✅ Support for Polymarket Proxy wallet redeem operations (currently only Proxy wallet is supported)
|
|
57
|
-
- ✅ Check if conditions are resolved
|
|
58
|
-
- ✅ Get redeemable indexes and balances
|
|
59
|
-
- ✅ Support for standard CTF redeem and negative risk (neg_risk) redeem
|
|
60
|
-
- ✅ Automatic transaction execution through Relayer service
|
|
97
|
+
We welcome community contributions! If you'd like to help implement EOA wallet redeem functionality, or have other improvement suggestions, please feel free to submit a Pull Request.
|
|
61
98
|
|
|
62
99
|
## Installation
|
|
63
100
|
|
|
@@ -79,7 +116,7 @@ uv add poly-web3
|
|
|
79
116
|
|
|
80
117
|
- `py-clob-client >= 0.25.0` - Polymarket CLOB client
|
|
81
118
|
- `py-builder-relayer-client >= 0.0.1` - Builder Relayer client
|
|
82
|
-
- `web3
|
|
119
|
+
- `web3 >= 7.0.0` - Web3.py library
|
|
83
120
|
- `eth-utils == 5.3.1` - Ethereum utilities library
|
|
84
121
|
|
|
85
122
|
## Quick Start
|
|
@@ -104,7 +141,7 @@ client = ClobClient(
|
|
|
104
141
|
host,
|
|
105
142
|
key=os.getenv("POLY_API_KEY"),
|
|
106
143
|
chain_id=chain_id,
|
|
107
|
-
signature_type=1, # Proxy wallet type
|
|
144
|
+
signature_type=1, # Proxy wallet type (signature_type=2 for Safe)
|
|
108
145
|
funder=os.getenv("POLYMARKET_PROXY_ADDRESS"),
|
|
109
146
|
)
|
|
110
147
|
|
|
@@ -132,35 +169,39 @@ service = PolyWeb3Service(
|
|
|
132
169
|
)
|
|
133
170
|
|
|
134
171
|
|
|
172
|
+
# Redeem all positions that are currently redeemable
|
|
173
|
+
redeem_all_result = service.redeem_all(batch_size=10)
|
|
174
|
+
print(f"Redeem all result: {redeem_all_result}")
|
|
175
|
+
# If redeem_all_result contains None, refer to README FAQ and retry.
|
|
176
|
+
if redeem_all_result and any(item is None for item in redeem_all_result):
|
|
177
|
+
print("Redeem failed for some items; please retry.")
|
|
178
|
+
|
|
135
179
|
# Execute redeem operation (batch)
|
|
136
180
|
condition_ids = [
|
|
137
181
|
"0xc3df016175463c44f9c9f98bddaa3bf3daaabb14b069fb7869621cffe73ddd1c",
|
|
138
182
|
"0x31fb435a9506d14f00b9de5e5e4491cf2223b6d40a2525d9afa8b620b61b50e2",
|
|
139
183
|
]
|
|
140
|
-
redeem_batch_result = service.redeem(condition_ids, batch_size=
|
|
184
|
+
redeem_batch_result = service.redeem(condition_ids, batch_size=10)
|
|
141
185
|
print(f"Redeem batch result: {redeem_batch_result}")
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
redeem_all_result = service.redeem_all(batch_size=20)
|
|
145
|
-
print(f"Redeem all result: {redeem_all_result}")
|
|
186
|
+
if redeem_all_result and any(item is None for item in redeem_all_result):
|
|
187
|
+
print("Redeem failed for some items; please retry.")
|
|
146
188
|
```
|
|
147
189
|
|
|
148
|
-
###
|
|
149
|
-
|
|
150
|
-
Before executing redeem, you can optionally check the condition status and query redeemable balances:
|
|
190
|
+
### Basic Usage - Split/Merge (Binary Markets)
|
|
151
191
|
|
|
152
192
|
```python
|
|
153
|
-
#
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
# Get redeemable indexes and balances
|
|
158
|
-
redeem_balance = service.get_redeemable_index_and_balance(
|
|
159
|
-
condition_id, owner=client.builder.funder
|
|
193
|
+
# amount is in human units (USDC)
|
|
194
|
+
split_result = service.split(
|
|
195
|
+
"0x31fb435a9506d14f00b9de5e5e4491cf2223b6d40a2525d9afa8b620b61b50e2",
|
|
196
|
+
1.5,
|
|
160
197
|
)
|
|
198
|
+
print(f"Split result: {split_result}")
|
|
161
199
|
|
|
162
|
-
|
|
163
|
-
|
|
200
|
+
merge_result = service.merge(
|
|
201
|
+
"0x31fb435a9506d14f00b9de5e5e4491cf2223b6d40a2525d9afa8b620b61b50e2",
|
|
202
|
+
1.5,
|
|
203
|
+
)
|
|
204
|
+
print(f"Merge result: {merge_result}")
|
|
164
205
|
```
|
|
165
206
|
|
|
166
207
|
## API Documentation
|
|
@@ -171,6 +212,74 @@ The main service class that automatically selects the appropriate service implem
|
|
|
171
212
|
|
|
172
213
|
#### Methods
|
|
173
214
|
|
|
215
|
+
##### `redeem(condition_ids: list[str], batch_size: int = 20)`
|
|
216
|
+
|
|
217
|
+
Execute redeem operation.
|
|
218
|
+
|
|
219
|
+
**Parameters:**
|
|
220
|
+
- `condition_ids` (list[str]): List of condition IDs
|
|
221
|
+
- `batch_size` (int): Batch size for redeem requests
|
|
222
|
+
|
|
223
|
+
**Returns:**
|
|
224
|
+
- `dict | list[dict]`: Transaction result(s) containing transaction status and related information
|
|
225
|
+
|
|
226
|
+
**Examples:**
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
# Batch redeem
|
|
230
|
+
result = service.redeem(["0x...", "0x..."], batch_size=10)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
##### `redeem_all(batch_size: int = 20) -> list[dict]`
|
|
234
|
+
|
|
235
|
+
Redeem all positions that are currently redeemable for the authenticated account.
|
|
236
|
+
|
|
237
|
+
**Returns:**
|
|
238
|
+
- `list[dict]`: List of redeem results; empty list if no redeemable positions. If the list contains `None`, the redeem failed and should be retried.
|
|
239
|
+
|
|
240
|
+
**Examples:**
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
# Redeem all positions that can be redeemed
|
|
244
|
+
service.redeem_all(batch_size=10)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
##### `split(condition_id: str, amount: int | float | str)`
|
|
248
|
+
|
|
249
|
+
Split a binary (Yes/No) position. `amount` is in human USDC units.
|
|
250
|
+
|
|
251
|
+
**Parameters:**
|
|
252
|
+
- `condition_id` (str): Condition ID
|
|
253
|
+
- `amount` (int | float | str): Amount in USDC
|
|
254
|
+
|
|
255
|
+
**Returns:**
|
|
256
|
+
- `dict | None`: Transaction result
|
|
257
|
+
|
|
258
|
+
**Examples:**
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
result = service.split("0x...", 1.25)
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
##### `merge(condition_id: str, amount: int | float | str)`
|
|
265
|
+
|
|
266
|
+
Merge a binary (Yes/No) position. `amount` is in human USDC units.
|
|
267
|
+
|
|
268
|
+
**Parameters:**
|
|
269
|
+
- `condition_id` (str): Condition ID
|
|
270
|
+
- `amount` (int | float | str): Amount in USDC
|
|
271
|
+
|
|
272
|
+
**Returns:**
|
|
273
|
+
- `dict | None`: Transaction result
|
|
274
|
+
|
|
275
|
+
**Examples:**
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
result = service.merge("0x...", 1.25)
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
#### Optional APIs
|
|
282
|
+
|
|
174
283
|
##### `is_condition_resolved(condition_id: str) -> bool`
|
|
175
284
|
|
|
176
285
|
Check if the specified condition is resolved.
|
|
@@ -202,36 +311,22 @@ Get redeemable indexes and balances for the specified address.
|
|
|
202
311
|
**Returns:**
|
|
203
312
|
- `list[tuple]`: List of tuples containing (index, balance), balance is in USDC units
|
|
204
313
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
Execute redeem operation.
|
|
208
|
-
|
|
209
|
-
**Parameters:**
|
|
210
|
-
- `condition_ids` (list[str]): List of condition IDs
|
|
211
|
-
- `batch_size` (int): Batch size for redeem requests
|
|
212
|
-
|
|
213
|
-
**Returns:**
|
|
214
|
-
- `dict | list[dict]`: Transaction result(s) containing transaction status and related information
|
|
314
|
+
## Optional: Query Operations
|
|
215
315
|
|
|
216
|
-
|
|
316
|
+
Before executing redeem, you can optionally check the condition status and query redeemable balances:
|
|
217
317
|
|
|
218
318
|
```python
|
|
219
|
-
#
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
##### `redeem_all(batch_size: int = 20) -> list[dict] | None`
|
|
224
|
-
|
|
225
|
-
Redeem all positions that are currently redeemable for the authenticated account.
|
|
226
|
-
|
|
227
|
-
**Returns:**
|
|
228
|
-
- `list[dict] | None`: List of redeem results, or `None` if no redeemable positions
|
|
319
|
+
# Check if condition is resolved
|
|
320
|
+
condition_id = "0xc3df016175463c44f9c9f98bddaa3bf3daaabb14b069fb7869621cffe73ddd1c"
|
|
321
|
+
can_redeem = service.is_condition_resolved(condition_id)
|
|
229
322
|
|
|
230
|
-
|
|
323
|
+
# Get redeemable indexes and balances
|
|
324
|
+
redeem_balance = service.get_redeemable_index_and_balance(
|
|
325
|
+
condition_id, owner=client.builder.funder
|
|
326
|
+
)
|
|
231
327
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
service.redeem_all(batch_size=20)
|
|
328
|
+
print(f"Can redeem: {can_redeem}")
|
|
329
|
+
print(f"Redeemable balance: {redeem_balance}")
|
|
235
330
|
```
|
|
236
331
|
|
|
237
332
|
## Project Structure
|
|
@@ -249,14 +344,14 @@ poly_web3/
|
|
|
249
344
|
├── base.py # Base service class
|
|
250
345
|
├── proxy_service.py # Proxy wallet service (✅ Implemented)
|
|
251
346
|
├── eoa_service.py # EOA wallet service (🚧 Under development)
|
|
252
|
-
└── safe_service.py # Safe wallet service (
|
|
347
|
+
└── safe_service.py # Safe wallet service (✅ Implemented)
|
|
253
348
|
```
|
|
254
349
|
|
|
255
350
|
## Notes
|
|
256
351
|
|
|
257
352
|
1. **Environment Variable Security**: Make sure `.env` file is added to `.gitignore`, do not commit sensitive information to the code repository
|
|
258
353
|
2. **Network Support**: Currently mainly supports Polygon mainnet (chain_id: 137), Amoy testnet may have limited functionality
|
|
259
|
-
3. **Wallet Type**:
|
|
354
|
+
3. **Wallet Type**: Proxy (signature_type: 1) and Safe (signature_type: 2) are supported; EOA wallet operations are under development
|
|
260
355
|
4. **Gas Fees**: Transactions are executed through Relayer, gas fees are handled by the Relayer
|
|
261
356
|
|
|
262
357
|
## Development
|
|
@@ -271,18 +366,18 @@ uv pip install -e ".[dev]"
|
|
|
271
366
|
|
|
272
367
|
```bash
|
|
273
368
|
python examples/example_redeem.py
|
|
369
|
+
python examples/example_split_merge.py
|
|
274
370
|
```
|
|
275
371
|
|
|
276
372
|
### Contributing
|
|
277
373
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
- Implement Safe or EOA wallet support
|
|
281
|
-
- Fix bugs or improve existing functionality
|
|
282
|
-
- Add new features or improve documentation
|
|
283
|
-
- Make suggestions or report issues
|
|
374
|
+
Simple contribution flow:
|
|
284
375
|
|
|
285
|
-
|
|
376
|
+
1. Open an Issue to describe the change (bug/feature/doc).
|
|
377
|
+
2. Fork and create a branch: `feat/xxx` or `fix/xxx`.
|
|
378
|
+
3. Make changes and update/add docs if needed.
|
|
379
|
+
4. Run: `uv run python -m examples.example_redeem` or `uv run python -m examples.example_split_merge` (if applicable).
|
|
380
|
+
5. Open a Pull Request and link the Issue.
|
|
286
381
|
|
|
287
382
|
## License
|
|
288
383
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
examples/example_redeem.py,sha256=r4tNcrhOIMBebZ1eVudswQKoMjhNZ-BkujNqx0w0sAI,2041
|
|
2
|
+
examples/example_split_merge.py,sha256=hM76YUBNakfwpWgRQ5rAGlMnVVzrEJvA5rtOJvLzwHs,1704
|
|
3
|
+
poly_web3/__init__.py,sha256=O4xBBGCQoO453RdGZ9eWpjpOEOz_kFoU_TTnigbBaPs,1078
|
|
4
|
+
poly_web3/const.py,sha256=uEH42ac-AHqSQSZGmB57IygJl_1C5hGs4JiDM9y2QZo,6858
|
|
5
|
+
poly_web3/log.py,sha256=NPY6X7Ysw-5ds3JkA26vhfge2Dc39ptezmCWYbwT-FM,986
|
|
6
|
+
poly_web3/schema.py,sha256=GTzpEy8-mqw2fCqoQKQFn6ieyhXdSnW6I9YQMKGnnhM,435
|
|
7
|
+
poly_web3/signature/__init__.py,sha256=p4EwohjUtwEsFqrc7eeqY5sQa14GWc8BdR6km8c7SH8,123
|
|
8
|
+
poly_web3/signature/build.py,sha256=PEyMFbE2PM2Xvz3wvmA6T6FVnU3mB7uanoEutbneFQ8,3614
|
|
9
|
+
poly_web3/signature/hash_message.py,sha256=hREtjuOdLcm_IlBz1YuzyrObVdxs7Yn-ULfh09PeNmk,1319
|
|
10
|
+
poly_web3/signature/secp256k1.py,sha256=IBgp0vNJyskU7ZUcWCdDttrzmJgEWH6lakB74whur_w,1500
|
|
11
|
+
poly_web3/web3_service/__init__.py,sha256=HNRh06yZNYXDmGS69ISXG7_PPG9foGXLyHOdnbgYXk0,315
|
|
12
|
+
poly_web3/web3_service/base.py,sha256=fEWn1CTfYDjQlPYopMGg2UTnZuxfIEVGfedtfDh4Y0Q,16036
|
|
13
|
+
poly_web3/web3_service/eoa_service.py,sha256=H9brj_em-o66O4JlJfQTcQlUvdw08-_6gKReIbxi79c,1159
|
|
14
|
+
poly_web3/web3_service/proxy_service.py,sha256=ztT2WGoj34Q6EN8UISlWatid-oSzY83W0W23V3u6Oos,4370
|
|
15
|
+
poly_web3/web3_service/safe_service.py,sha256=Fjb0x_e9K2gAOhh0sF6JM9zbizx5zLbYbSrZvH1sXpQ,945
|
|
16
|
+
poly_web3-1.0.2.dist-info/METADATA,sha256=5MCq15yl5ifEpr2oXZb-ckHFPJwlJ3So_FJ8aHgdf0M,12834
|
|
17
|
+
poly_web3-1.0.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
18
|
+
poly_web3-1.0.2.dist-info/top_level.txt,sha256=wW40wsocHfhFgqSWWvYWrhwKGQU5IWkhyaz5J90vmHo,19
|
|
19
|
+
poly_web3-1.0.2.dist-info/RECORD,,
|
poly_web3-1.0.0.dist-info/RECORD
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
examples/example_redeem.py,sha256=grSaAsmjgQDKd1zpd17-cYkAv7fkqFUqDEvCr3gXJtA,2149
|
|
2
|
-
poly_web3/__init__.py,sha256=O4xBBGCQoO453RdGZ9eWpjpOEOz_kFoU_TTnigbBaPs,1078
|
|
3
|
-
poly_web3/const.py,sha256=UYBs1b9P2YJw1isbUzlGOxMWIqWyRiyGt9D2WmZCYfU,4959
|
|
4
|
-
poly_web3/log.py,sha256=NPY6X7Ysw-5ds3JkA26vhfge2Dc39ptezmCWYbwT-FM,986
|
|
5
|
-
poly_web3/schema.py,sha256=GTzpEy8-mqw2fCqoQKQFn6ieyhXdSnW6I9YQMKGnnhM,435
|
|
6
|
-
poly_web3/signature/__init__.py,sha256=p4EwohjUtwEsFqrc7eeqY5sQa14GWc8BdR6km8c7SH8,123
|
|
7
|
-
poly_web3/signature/build.py,sha256=PEyMFbE2PM2Xvz3wvmA6T6FVnU3mB7uanoEutbneFQ8,3614
|
|
8
|
-
poly_web3/signature/hash_message.py,sha256=hREtjuOdLcm_IlBz1YuzyrObVdxs7Yn-ULfh09PeNmk,1319
|
|
9
|
-
poly_web3/signature/secp256k1.py,sha256=IBgp0vNJyskU7ZUcWCdDttrzmJgEWH6lakB74whur_w,1500
|
|
10
|
-
poly_web3/web3_service/__init__.py,sha256=HNRh06yZNYXDmGS69ISXG7_PPG9foGXLyHOdnbgYXk0,315
|
|
11
|
-
poly_web3/web3_service/base.py,sha256=SwiJ3nTPHUTYH5gDwjDPRoxjZNICfYKsy6w4pWiG73U,12195
|
|
12
|
-
poly_web3/web3_service/eoa_service.py,sha256=mTJ0OHJvpzkrYvom1wDlA7EyV_tJFwxekpgPSXMXz0Y,515
|
|
13
|
-
poly_web3/web3_service/proxy_service.py,sha256=-Odgpq24dKnBmtuwQ3RRINS88zzTFEQCbtaTZ4WNLs8,4181
|
|
14
|
-
poly_web3/web3_service/safe_service.py,sha256=D9rHcxbU9rjvDd5k__qu8MCZ8srdQITS8g4JNkoE7Uo,776
|
|
15
|
-
poly_web3-1.0.0.dist-info/METADATA,sha256=7r6FXHqXFPdPz8IpQHSEoI-Qm0-ZdrgVL1k_UiZf0fc,9765
|
|
16
|
-
poly_web3-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
17
|
-
poly_web3-1.0.0.dist-info/top_level.txt,sha256=wW40wsocHfhFgqSWWvYWrhwKGQU5IWkhyaz5J90vmHo,19
|
|
18
|
-
poly_web3-1.0.0.dist-info/RECORD,,
|
|
File without changes
|