opinion-clob-sdk 0.1.0__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.

Potentially problematic release.


This version of opinion-clob-sdk might be problematic. Click here for more details.

Files changed (42) hide show
  1. chain/__init__.py +0 -0
  2. chain/contract_caller.py +390 -0
  3. chain/contracts/__init__.py +0 -0
  4. chain/contracts/conditional_tokens.py +707 -0
  5. chain/contracts/erc20.py +111 -0
  6. chain/exception.py +11 -0
  7. chain/py_order_utils/__init__.py +0 -0
  8. chain/py_order_utils/builders/__init__.py +0 -0
  9. chain/py_order_utils/builders/base_builder.py +41 -0
  10. chain/py_order_utils/builders/exception.py +2 -0
  11. chain/py_order_utils/builders/order_builder.py +90 -0
  12. chain/py_order_utils/builders/order_builder_test.py +40 -0
  13. chain/py_order_utils/constants.py +2 -0
  14. chain/py_order_utils/model/__init__.py +0 -0
  15. chain/py_order_utils/model/order.py +254 -0
  16. chain/py_order_utils/model/order_type.py +9 -0
  17. chain/py_order_utils/model/sides.py +8 -0
  18. chain/py_order_utils/model/signatures.py +8 -0
  19. chain/py_order_utils/signer.py +20 -0
  20. chain/py_order_utils/utils.py +109 -0
  21. chain/safe/__init__.py +0 -0
  22. chain/safe/constants.py +19 -0
  23. chain/safe/eip712/__init__.py +176 -0
  24. chain/safe/enums.py +6 -0
  25. chain/safe/exceptions.py +94 -0
  26. chain/safe/multisend.py +347 -0
  27. chain/safe/safe.py +141 -0
  28. chain/safe/safe_contracts/__init__.py +0 -0
  29. chain/safe/safe_contracts/compatibility_fallback_handler_v1_3_0.py +327 -0
  30. chain/safe/safe_contracts/multisend_v1_3_0.py +22 -0
  31. chain/safe/safe_contracts/safe_v1_3_0.py +1035 -0
  32. chain/safe/safe_contracts/utils.py +26 -0
  33. chain/safe/safe_signature.py +364 -0
  34. chain/safe/safe_test.py +37 -0
  35. chain/safe/safe_tx.py +437 -0
  36. chain/safe/signatures.py +63 -0
  37. chain/safe/typing.py +17 -0
  38. chain/safe/utils.py +218 -0
  39. opinion_clob_sdk-0.1.0.dist-info/METADATA +97 -0
  40. opinion_clob_sdk-0.1.0.dist-info/RECORD +42 -0
  41. opinion_clob_sdk-0.1.0.dist-info/WHEEL +5 -0
  42. opinion_clob_sdk-0.1.0.dist-info/top_level.txt +1 -0
chain/safe/utils.py ADDED
@@ -0,0 +1,218 @@
1
+ import os
2
+ from functools import lru_cache
3
+ from typing import Any, Union
4
+
5
+ import eth_abi
6
+ from eth_account import Account
7
+ from eth_typing import Address, AnyAddress, ChecksumAddress, Hash32, HexAddress, HexStr
8
+ from eth_utils import to_normalized_address
9
+ from hexbytes import HexBytes
10
+ # from sha3 import keccak_256
11
+ from web3.types import TxParams, Wei
12
+
13
+
14
+ def get_empty_tx_params() -> TxParams:
15
+ """
16
+ :return: Empty tx params, so calls like `build_transaction` don't call the RPC trying to get information
17
+ """
18
+ return {
19
+ "gas": Wei(1),
20
+ "gasPrice": Wei(1),
21
+ }
22
+
23
+
24
+ @lru_cache(maxsize=int(os.getenv("CACHE_KECCAK", 512)))
25
+ def _keccak_256(value: bytes) -> bytes:
26
+ import web3
27
+ return web3.Web3.keccak(value)
28
+ # return keccak_256(value)
29
+
30
+
31
+ def fast_keccak(value: bytes) -> Hash32:
32
+ """
33
+ Calculates ethereum keccak256 using fast library `pysha3`
34
+
35
+ :param value:
36
+ :return: Keccak256 used by ethereum as `HexBytes`
37
+ """
38
+ return Hash32(HexBytes(_keccak_256(value)))
39
+
40
+
41
+ def fast_keccak_text(value: str) -> Hash32:
42
+ """
43
+ Calculates ethereum keccak256 using fast library `pysha3`
44
+
45
+ :param value:
46
+ :return: Keccak256 used by ethereum as `HexBytes`
47
+ """
48
+ return fast_keccak(value.encode())
49
+
50
+
51
+ def fast_keccak_hex(value: bytes) -> HexStr:
52
+ """
53
+ Same as `fast_keccak`, but it's a little more optimal calling `hexdigest()`
54
+ than calling `digest()` and then `hex()`
55
+
56
+ :param value:
57
+ :return: Keccak256 used by ethereum as a hex string (not 0x prefixed)
58
+ """
59
+ return HexStr(_keccak_256(value).hex())
60
+
61
+
62
+ def _build_checksum_address(
63
+ norm_address: HexStr, address_hash: HexStr
64
+ ) -> ChecksumAddress:
65
+ """
66
+ https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md
67
+
68
+ :param norm_address: address in lowercase (not 0x prefixed)
69
+ :param address_hash: keccak256 of `norm_address` (not 0x prefixed)
70
+ :return:
71
+ """
72
+ return ChecksumAddress(
73
+ HexAddress(
74
+ HexStr(
75
+ "0x"
76
+ + (
77
+ "".join(
78
+ (
79
+ norm_address[i].upper()
80
+ if int(str(address_hash[i]), 16) > 7
81
+ else norm_address[i]
82
+ )
83
+ for i in range(0, 40)
84
+ )
85
+ )
86
+ )
87
+ )
88
+ )
89
+
90
+
91
+ @lru_cache(maxsize=int(os.getenv("CACHE_CHECKSUM_ADDRESS", 1_000_000_000)))
92
+ def _fast_to_checksum_address(address: HexAddress):
93
+ # print("_fast_to_checksum_address: {}".format(address))
94
+ address_hash = fast_keccak_hex(address.encode())
95
+ return _build_checksum_address(address, address_hash)
96
+
97
+
98
+ def fast_to_checksum_address(value: Union[AnyAddress, str, bytes]) -> ChecksumAddress:
99
+ """
100
+ Converts to checksum_address. Uses more optimal `pysha3` instead of `eth_utils` for keccak256 calculation
101
+
102
+ :param value:
103
+ :return:
104
+ """
105
+ # print("fast_to_checksum_address: {}".format(value))
106
+ if isinstance(value, bytes):
107
+ if len(value) != 20:
108
+ raise ValueError(
109
+ "Cannot convert %s to a checksum address, 20 bytes were expected"
110
+ )
111
+
112
+ norm_address = HexAddress(HexStr(to_normalized_address(value)[2:]))
113
+ return _fast_to_checksum_address(norm_address)
114
+
115
+
116
+ def fast_bytes_to_checksum_address(value: bytes) -> ChecksumAddress:
117
+ """
118
+ Converts to checksum_address. Uses more optimal `pysha3` instead of `eth_utils` for keccak256 calculation.
119
+ As input is already in bytes, some checks and conversions can be skipped, providing a speedup of ~50%
120
+
121
+ :param value:
122
+ :return:
123
+ """
124
+ if len(value) != 20:
125
+ raise ValueError(
126
+ "Cannot convert %s to a checksum address, 20 bytes were expected"
127
+ )
128
+ norm_address = HexAddress(HexStr(bytes(value).hex()))
129
+ return _fast_to_checksum_address(norm_address)
130
+
131
+
132
+ def fast_is_checksum_address(value: Union[AnyAddress, str, bytes]) -> bool:
133
+ """
134
+ Fast version to check if an address is a checksum_address
135
+
136
+ :param value:
137
+ :return: `True` if checksummed, `False` otherwise
138
+ """
139
+ if not isinstance(value, str) or len(value) != 42 or not value.startswith("0x"):
140
+ return False
141
+ try:
142
+ return fast_to_checksum_address(value) == value
143
+ except ValueError:
144
+ return False
145
+
146
+
147
+ def get_eth_address_with_invalid_checksum() -> str:
148
+ address = Account.create().address
149
+ return "0x" + "".join(
150
+ [c.lower() if c.isupper() else c.upper() for c in address[2:]]
151
+ )
152
+
153
+
154
+ def decode_string_or_bytes32(data: bytes) -> str:
155
+ try:
156
+ return eth_abi.decode(["string"], data)[0]
157
+ except (OverflowError, eth_abi.exceptions.DecodingError):
158
+ name = eth_abi.decode(["bytes32"], data)[0]
159
+ end_position = name.find(b"\x00")
160
+ if end_position == -1:
161
+ return name.decode()
162
+ else:
163
+ return name[:end_position].decode()
164
+
165
+
166
+ def remove_swarm_metadata(code: bytes) -> bytes:
167
+ """
168
+ Remove swarm metadata from Solidity bytecode
169
+
170
+ :param code:
171
+ :return: Code without metadata
172
+ """
173
+ swarm = b"\xa1\x65bzzr0"
174
+ position = code.rfind(swarm)
175
+ if position == -1:
176
+ raise ValueError("Swarm metadata not found in code %s" % code.hex())
177
+ return code[:position]
178
+
179
+
180
+ def compare_byte_code(code_1: bytes, code_2: bytes) -> bool:
181
+ """
182
+ Compare code, removing swarm metadata if necessary
183
+
184
+ :param code_1:
185
+ :param code_2:
186
+ :return: True if same code, False otherwise
187
+ """
188
+ if code_1 == code_2:
189
+ return True
190
+ else:
191
+ codes = []
192
+ for code in (code_1, code_2):
193
+ try:
194
+ codes.append(remove_swarm_metadata(code))
195
+ except ValueError:
196
+ codes.append(code)
197
+
198
+ return codes[0] == codes[1]
199
+
200
+
201
+ def bytes_to_float(value: Any) -> float:
202
+ """
203
+ Convert a value of type Any to float.
204
+
205
+ :param value: The value to convert.
206
+ :return: The converted float value.
207
+ :raises ValueError: If the value cannot be converted to float.
208
+ """
209
+ assert value is not None, "Cannot convert None to float"
210
+ if isinstance(value, (int, float)):
211
+ return float(value)
212
+ elif isinstance(value, bytes):
213
+ try:
214
+ return float(int.from_bytes(value, "big"))
215
+ except (ValueError, OverflowError) as e:
216
+ raise ValueError(f"Cannot convert bytes to float: {e}")
217
+ else:
218
+ raise ValueError(f"Unsupported type for conversion to float: {type(value)}")
@@ -0,0 +1,97 @@
1
+ Metadata-Version: 2.4
2
+ Name: opinion_clob_sdk
3
+ Version: 0.1.0
4
+ Summary: Opinion CLOB SDK - Python SDK for Opinion Prediction Market Central Limit Order Book API
5
+ Home-page: https://opinion.trade
6
+ Author: Opinion Labs
7
+ Author-email: support@opinion.trade
8
+ Keywords: PredictionMarket,CLOB,Trading,Blockchain,Base,Opinion
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: urllib3>=2.3.0
22
+ Requires-Dist: six>=1.17.0
23
+ Requires-Dist: certifi>=2024.12.14
24
+ Requires-Dist: python-dateutil>=2.9.0.post0
25
+ Requires-Dist: hexbytes>=1.2.1
26
+ Requires-Dist: web3>=7.6.1
27
+ Requires-Dist: eth_account>=0.13.0
28
+ Requires-Dist: poly_eip712_structs>=0.0.1
29
+ Requires-Dist: opinion_api>=0.1.0
30
+ Requires-Dist: pytest>=7.0.0
31
+ Dynamic: author
32
+ Dynamic: author-email
33
+ Dynamic: classifier
34
+ Dynamic: description
35
+ Dynamic: description-content-type
36
+ Dynamic: home-page
37
+ Dynamic: keywords
38
+ Dynamic: requires-dist
39
+ Dynamic: requires-python
40
+ Dynamic: summary
41
+
42
+
43
+ # Opinion CLOB SDK
44
+
45
+ Python SDK for interacting with Opinion prediction markets via the CLOB (Central Limit Order Book) API.
46
+
47
+ ## Features
48
+
49
+ - Market data queries (markets, orderbooks, prices, candles)
50
+ - Order management (place, cancel, query orders)
51
+ - Position and balance tracking
52
+ - Smart contract interactions (split, merge, redeem)
53
+ - Support for Base mainnet (chain ID 8453)
54
+
55
+ ## Installation
56
+
57
+ ```bash
58
+ pip install opinion_clob_sdk
59
+ ```
60
+
61
+ ## Quick Start
62
+
63
+ ```python
64
+ from opinion_clob_sdk import Client
65
+
66
+ client = Client(
67
+ host='https://api.opinion.trade',
68
+ apikey='your_api_key',
69
+ chain_id=8453, # Base mainnet
70
+ rpc_url='your_rpc_url',
71
+ private_key='your_private_key',
72
+ multi_sig_addr='your_multi_sig_address'
73
+ )
74
+
75
+ # Get markets
76
+ markets = client.get_markets(page=1, limit=10)
77
+
78
+ # Get orderbook
79
+ orderbook = client.get_orderbook(token_id='token_id')
80
+
81
+ # Place an order
82
+ from opinion_clob_sdk.chain.py_order_utils.model.order import PlaceOrderDataInput
83
+ from opinion_clob_sdk.chain.py_order_utils.model.sides import OrderSide
84
+ from opinion_clob_sdk.chain.py_order_utils.model.order_type import LIMIT_ORDER
85
+
86
+ order_data = PlaceOrderDataInput(
87
+ marketId=123,
88
+ tokenId='token_id',
89
+ side=OrderSide.BUY,
90
+ orderType=LIMIT_ORDER,
91
+ price='0.5',
92
+ makerAmountInQuoteToken=10
93
+ )
94
+
95
+ result = client.place_order(order_data)
96
+ ```
97
+
@@ -0,0 +1,42 @@
1
+ chain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ chain/contract_caller.py,sha256=AKCD1ZvLTbJX_YWFJecRtZ4Pi7L3_20Q7YOSGfAolEY,17148
3
+ chain/exception.py,sha256=6SSx4T_WZL8BxzRbfGSDp6eGD4zJ5ACeBB58DlrpmoA,234
4
+ chain/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ chain/contracts/conditional_tokens.py,sha256=P_MpetUKMNnT_hchZ0A9q7-g_ZKjkOr-BLldPXB4J7o,13998
6
+ chain/contracts/erc20.py,sha256=C56GdZeMxcgdJTmMQKSfA8xHzDdNT71SaNf6xhJIVMY,2843
7
+ chain/py_order_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ chain/py_order_utils/constants.py,sha256=afsZ0OahGbCzNPE2rXKU1k8gQymkh4ODLKh4KPklvnA,70
9
+ chain/py_order_utils/signer.py,sha256=NAMHcMREbRUgrz1-28sqpPoMD8LkRJSyUn7-FLUkYsM,447
10
+ chain/py_order_utils/utils.py,sha256=-sf0Vq16bJ8eAc-p63r0TLqtbQkKWEQ6ccSAoQy1r7M,3837
11
+ chain/py_order_utils/builders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ chain/py_order_utils/builders/base_builder.py,sha256=lw925Mz6MerqCyXNgonhNP-495gZPm_me4HtlhyhVHM,1272
13
+ chain/py_order_utils/builders/exception.py,sha256=525fSH8Q241VjxdllBkWi3DiW_-6I1AmG-iHwZBTp4E,47
14
+ chain/py_order_utils/builders/order_builder.py,sha256=NybKbNhRd1jceSjtp6lL9x1DjDzJ4ClhsAK2zS58P4c,2968
15
+ chain/py_order_utils/builders/order_builder_test.py,sha256=0xPLO9rEDsw_s3UQiooquEarvFe8KneafiaY6PgkLIo,1773
16
+ chain/py_order_utils/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ chain/py_order_utils/model/order.py,sha256=fI2NhqX_cdUmZivliki4rHXJCxQQY5ykjh8a58FFfPE,5852
18
+ chain/py_order_utils/model/order_type.py,sha256=kYXJ0Ikk3Qnr00yCIfrtJibFve8DUjNSJ_xiLw7IphY,185
19
+ chain/py_order_utils/model/sides.py,sha256=FZVZnutyLmgiNCVoz-1fjxxFzhH3z24xy5BY6pkIfs8,177
20
+ chain/py_order_utils/model/signatures.py,sha256=lKoqi7gVay9NjCv_2QTdelP4EFy61Ez0UeY1ytOmooM,224
21
+ chain/safe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ chain/safe/constants.py,sha256=H4UKUXJxR9pvwRHU4WM1p6wZ6yGjApOpWfEMYj-W_iE,572
23
+ chain/safe/enums.py,sha256=aP9-PfC97ZYtX0dKOYKAyxITVrCDMIAY2_mHMdU8IJM,90
24
+ chain/safe/exceptions.py,sha256=kp0jfnP93JyEkEgwPERL6MZ9D8ozbioURcKjMwSLjgE,1498
25
+ chain/safe/multisend.py,sha256=l-lWlb7jSzmNCyFbpAr-d8SYEKM4QRm_h0tF53T3CzE,12659
26
+ chain/safe/safe.py,sha256=OO-010or-qCCwCSTSh4qKGmoSwEsL2IYECW8IYmSmKQ,5216
27
+ chain/safe/safe_signature.py,sha256=W1Xn73DSzE3PZ6ITyikhdWhosY3wdey-scX0Jci037I,12559
28
+ chain/safe/safe_test.py,sha256=pbCYOLa_6cQbC0KOA7t41ItunauhHfgN7uneENfMXPk,1384
29
+ chain/safe/safe_tx.py,sha256=QxKzv0EA7uwjakFMDVoDLrzYlZANpEhblPBQ7ZcF9zE,17211
30
+ chain/safe/signatures.py,sha256=8l6t6R21E9Mj4_USagIp1GiUlJmAp0Cqq9VpB7Zk960,1978
31
+ chain/safe/typing.py,sha256=wytgXXRbpyccM_HxpQLeDzfo40Ch_K-Z_ivORb-eNZo,419
32
+ chain/safe/utils.py,sha256=1u4yKwMCvfOlg9NsWbsM2WszQoO1wd6D2Z2aGAb1jjo,6469
33
+ chain/safe/eip712/__init__.py,sha256=ge0S6t2RtFc_mLFr4D93l6WLS2EONKgkuPGkcP_nDJ4,5915
34
+ chain/safe/safe_contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
+ chain/safe/safe_contracts/compatibility_fallback_handler_v1_3_0.py,sha256=_aENMzhiQgKSzXxn-TnVFWE84lIgDv1Iiw-VdIC1IMw,5968
36
+ chain/safe/safe_contracts/multisend_v1_3_0.py,sha256=8oGhNkS2k2Cy5pG6YNt_BKytS3AEtPeXv4rkyXv_p0M,380
37
+ chain/safe/safe_contracts/safe_v1_3_0.py,sha256=YCUWTpf_pR44iUUkDl42f3n2YXSVGlTBcvMtReN7rlM,21922
38
+ chain/safe/safe_contracts/utils.py,sha256=xnW8JSq8tVMfvZ4lhT-L96P3Usjs2zrZ5jzrNZvFHjc,631
39
+ opinion_clob_sdk-0.1.0.dist-info/METADATA,sha256=PaYXOI7kFUuxqyrPEZ320lR-A0xCCYcRqQyIDOow-nw,2776
40
+ opinion_clob_sdk-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
41
+ opinion_clob_sdk-0.1.0.dist-info/top_level.txt,sha256=O2U8tt1VAqoTZR-urcArMMWdyf_x0FZEcZ1-vur6gus,6
42
+ opinion_clob_sdk-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ chain