dipcoin-client 1.3.0__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 (36) hide show
  1. dipcoin_client-1.3.0/LICENSE +21 -0
  2. dipcoin_client-1.3.0/PKG-INFO +397 -0
  3. dipcoin_client-1.3.0/README.md +379 -0
  4. dipcoin_client-1.3.0/pyproject.toml +32 -0
  5. dipcoin_client-1.3.0/setup.cfg +4 -0
  6. dipcoin_client-1.3.0/src/dipcoin_client/__init__.py +9 -0
  7. dipcoin_client-1.3.0/src/dipcoin_client/api_service.py +147 -0
  8. dipcoin_client-1.3.0/src/dipcoin_client/client.py +1001 -0
  9. dipcoin_client-1.3.0/src/dipcoin_client/constants.py +60 -0
  10. dipcoin_client-1.3.0/src/dipcoin_client/contracts.py +145 -0
  11. dipcoin_client-1.3.0/src/dipcoin_client/enumerations.py +98 -0
  12. dipcoin_client-1.3.0/src/dipcoin_client/interfaces.py +130 -0
  13. dipcoin_client-1.3.0/src/dipcoin_client/onboarding_signer.py +34 -0
  14. dipcoin_client-1.3.0/src/dipcoin_client/order_signer.py +123 -0
  15. dipcoin_client-1.3.0/src/dipcoin_client/socket_manager.py +110 -0
  16. dipcoin_client-1.3.0/src/dipcoin_client/sui_graphql_client.py +326 -0
  17. dipcoin_client-1.3.0/src/dipcoin_client/util.py +344 -0
  18. dipcoin_client-1.3.0/src/dipcoin_client/wallets.py +309 -0
  19. dipcoin_client-1.3.0/src/dipcoin_client/websocket_client.py +181 -0
  20. dipcoin_client-1.3.0/src/dipcoin_client.egg-info/PKG-INFO +397 -0
  21. dipcoin_client-1.3.0/src/dipcoin_client.egg-info/SOURCES.txt +34 -0
  22. dipcoin_client-1.3.0/src/dipcoin_client.egg-info/dependency_links.txt +1 -0
  23. dipcoin_client-1.3.0/src/dipcoin_client.egg-info/requires.txt +7 -0
  24. dipcoin_client-1.3.0/src/dipcoin_client.egg-info/top_level.txt +2 -0
  25. dipcoin_client-1.3.0/src/sui_utils/__init__.py +8 -0
  26. dipcoin_client-1.3.0/src/sui_utils/account.py +67 -0
  27. dipcoin_client-1.3.0/src/sui_utils/bcs.py +135 -0
  28. dipcoin_client-1.3.0/src/sui_utils/coin_utils.py +164 -0
  29. dipcoin_client-1.3.0/src/sui_utils/enumerations.py +6 -0
  30. dipcoin_client-1.3.0/src/sui_utils/rpc.py +344 -0
  31. dipcoin_client-1.3.0/src/sui_utils/signer.py +250 -0
  32. dipcoin_client-1.3.0/src/sui_utils/sui_interfaces.py +92 -0
  33. dipcoin_client-1.3.0/src/sui_utils/utilities.py +356 -0
  34. dipcoin_client-1.3.0/tests/test_evm_chains.py +119 -0
  35. dipcoin_client-1.3.0/tests/test_margin_relayer.py +197 -0
  36. dipcoin_client-1.3.0/tests/test_max_removable_margin.py +120 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [2022] [Seed Labs]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,397 @@
1
+ Metadata-Version: 2.4
2
+ Name: dipcoin-client
3
+ Version: 1.3.0
4
+ Summary: Library to interact with dipcoin perp protocol including its off-chain api-gateway and on-chain contracts
5
+ License-Expression: MIT
6
+ Keywords: exchange,decentralized,perpetuals,blockchain
7
+ Requires-Python: <3.13,>=3.8
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: requests<3,>=2.31
11
+ Requires-Dist: aiohttp<4,>=3.8.5
12
+ Requires-Dist: bip-utils<3,>=2.7
13
+ Requires-Dist: coincurve<21,>=17
14
+ Requires-Dist: eth-utils<3,>=2.2
15
+ Requires-Dist: PyNaCl<2,>=1.5
16
+ Requires-Dist: websocket-client<2,>=1.6
17
+ Dynamic: license-file
18
+
19
+ # Dipcoin Python Client
20
+
21
+ A simple Python client library for interacting with the Dipcoin perp protocol, including its off-chain API gateway and on-chain contracts.
22
+
23
+ ## What's New in 1.3.0
24
+
25
+ - Added Solana wallet support for onboarding plus v3 order and plan-order signing.
26
+ - Added Ethereum, Arbitrum, Optimism, Base, and Polygon wallet support with
27
+ protocol-chain-aware authorization and v3 signing.
28
+ - Sui wallets remain supported; order and plan-order signing now defaults to v3.
29
+ - Added relayer-based margin adjustment for Sui, Solana, and EVM wallets.
30
+ - Added a fixed-point helper for estimating maximum removable margin.
31
+ - Humanized known 10^18-scaled numeric fields in both REST responses and websocket market/user payloads.
32
+ - Switched direct Sui chain helpers to a lightweight GraphQL client without Rust-native dependencies.
33
+
34
+ ## Requirements
35
+
36
+ - Python 3.8 - 3.12 (recommended: Python 3.11)
37
+ - No Rust toolchain, Sui CLI, or local Sui PTB builder is required for the default client.
38
+
39
+ ## Installation
40
+
41
+ ### 1. Create Virtual Environment (Recommended)
42
+
43
+ ```bash
44
+ python3.11 -m venv venv
45
+ source venv/bin/activate # macOS/Linux
46
+ # or
47
+ venv\Scripts\activate # Windows
48
+ ```
49
+
50
+ ### 2. Install Package
51
+
52
+ ```bash
53
+ pip install --upgrade pip
54
+ pip install dipcoin-client
55
+ ```
56
+
57
+ For local development from this repository:
58
+
59
+ ```bash
60
+ pip install -e .
61
+ ```
62
+
63
+ This installs the project and direct dependencies in editable mode, so code changes take effect immediately without reinstalling.
64
+
65
+ ## PyCharm Configuration
66
+
67
+ To enable proper code navigation and autocomplete in PyCharm:
68
+
69
+ 1. **Mark Directories as Sources Root**:
70
+ - Right-click on `src` directory → `Mark Directory as` → `Sources Root`
71
+ - Right-click on `examples` directory → `Mark Directory as` → `Sources Root`
72
+
73
+ 2. **Configure Python Interpreter**:
74
+ - Go to `File` → `Settings` (Windows/Linux) or `PyCharm` → `Preferences` (macOS)
75
+ - Navigate to `Project` → `Python Interpreter`
76
+ - Ensure Python 3.8-3.12 is selected
77
+ - Add project path: Click gear icon → `Show All` → Select interpreter → Click folder icon
78
+ - Add to `Interpreter Paths`: `<project_root>/src`
79
+
80
+ 3. **Invalidate Caches** (if needed):
81
+ - `File` → `Invalidate Caches and Restart`
82
+
83
+ ## Usage
84
+
85
+ ### Configuration
86
+
87
+ Edit `examples/config.py` to set your test credentials:
88
+
89
+ ```python
90
+ TEST_ACCT_KEY = "your_mnemonic_phrase" # or hex private key, suiprivkey bech32, etc.
91
+ TEST_NETWORK = "SUI_STAGING" # mainnet: use "SUI_PROD"
92
+ ```
93
+
94
+ **⚠️ Security Warning**: The `TEST_ACCT_KEY` in `examples/config.py` is a secret (mnemonic or private key). Keep it secure and never commit it to version control.
95
+
96
+ Examples `21.solana_user_data.py`, `22.solana_place_query_cancel_order.py` and
97
+ `23.eth_place_query_cancel_order.py` read the parent/API addresses and API
98
+ private key from environment variables. Copy `examples/.env.example` to
99
+ `examples/.env`, fill in your own test-wallet values, then load them and run:
100
+
101
+ ```bash
102
+ set -a
103
+ source examples/.env
104
+ set +a
105
+ python examples/22.solana_place_query_cancel_order.py
106
+ # or
107
+ python examples/23.eth_place_query_cancel_order.py
108
+ ```
109
+
110
+ The local `examples/.env` is ignored by Git. Never put a private key in a
111
+ tracked source file.
112
+
113
+ ### Run Examples
114
+
115
+ ```bash
116
+ cd examples
117
+ python 1.initialization.py
118
+ ```
119
+
120
+ ### Basic Usage
121
+
122
+ ```python
123
+ from dipcoin_client import DipcoinClient, Networks
124
+ import asyncio
125
+
126
+ async def main():
127
+ client = DipcoinClient(
128
+ True, # Agree to terms and conditions
129
+ Networks["SUI_STAGING"],
130
+ "your_mnemonic_phrase"
131
+ )
132
+ await client.init(True)
133
+ print("Account Address:", client.get_public_address())
134
+
135
+ if __name__ == "__main__":
136
+ asyncio.run(main())
137
+ ```
138
+
139
+ By default, the client decodes the JWT `exp` claim before authenticated REST requests and re-onboards automatically when the token will expire within 10 minutes. It does not retry failed requests after a `401`, so long-running programs should still handle expired-token or authorization errors returned by the API.
140
+
141
+ ```python
142
+ client = DipcoinClient(
143
+ True,
144
+ Networks["SUI_STAGING"],
145
+ "your_mnemonic_or_private_key",
146
+ auto_reauth=True, # default
147
+ token_refresh_margin_seconds=600, # default: 10 minutes
148
+ )
149
+ ```
150
+
151
+ ### EVM and Solana wallets
152
+
153
+ EVM wallets use the same EIP-191 `personal_sign` implementation and signature
154
+ scheme (`4`) on every supported EVM chain. The protocol chain identity is
155
+ separate from the signature scheme:
156
+
157
+ | `wallet_type` | Dipcoin protocol chain ID | Signed creator prefix |
158
+ | --- | ---: | --- |
159
+ | `eth` / `ethereum` / `evm` | 1 | `Ethereum:` |
160
+ | `arbitrum` | 3 | `Arbitrum:` |
161
+ | `optimism` | 4 | `Optimism:` |
162
+ | `base` | 5 | `Base:` |
163
+ | `polygon` | 6 | `Polygon:` |
164
+
165
+ These are Dipcoin protocol chain IDs, not EIP-155/RPC chain IDs. For example,
166
+ use `3` for Arbitrum rather than `42161`, and `5` for Base rather than `8453`.
167
+ The client sends the selected protocol chain ID to `/api/authorize`; the gateway
168
+ stores it in the JWT and injects `X-Wallet-Chain-Id` into downstream requests.
169
+
170
+ ```python
171
+ client = DipcoinClient(
172
+ True,
173
+ Networks["SUI_STAGING"],
174
+ "0x...evm_private_key",
175
+ wallet_type="arbitrum",
176
+ )
177
+ await client.init(True)
178
+ ```
179
+
180
+ For configuration-driven integrations, keep `wallet_type="eth"` and pass the
181
+ protocol chain separately:
182
+
183
+ ```python
184
+ from dipcoin_client import ARBITRUM_CHAIN_ID
185
+
186
+ client = DipcoinClient(
187
+ True,
188
+ Networks["SUI_STAGING"],
189
+ "0x...evm_private_key",
190
+ wallet_type="eth",
191
+ protocol_chain_id=ARBITRUM_CHAIN_ID,
192
+ )
193
+ ```
194
+
195
+ Use `wallet_type="solana"` for Solana onboarding and v3 order, cancel, and
196
+ plan-order signatures.
197
+
198
+ Solana accepts a 32-byte seed or 64-byte keypair encoded as hex, base64, base58, or a JSON byte array.
199
+
200
+ Order and plan-order signatures default to `payloadVersion=3`. The client reads `marketEpoch` from exchange info during `init()` and falls back to `0` only when the market does not expose it yet. In a long-running process, refresh the market cache before signing when its 60-second TTL has elapsed:
201
+
202
+ ```python
203
+ await client.refresh_market_info_if_stale()
204
+ signed_order = client.create_signed_order(order_request)
205
+ ```
206
+
207
+ The refresh interval can be changed with `market_info_cache_ttl_seconds` when creating `DipcoinClient`. `get_exchange_info()` also updates the signing cache with the data it fetches. Pass `payloadVersion` or `marketEpoch` only when you need to override those defaults for a specific request.
208
+
209
+ ### Wallet credentials (mnemonic or private key)
210
+
211
+ `DipcoinClient` accepts either:
212
+
213
+ - **BIP39 mnemonic** — space-separated phrase (typically 12 or 24 words). The client detects a mnemonic heuristically (word count and alphabetic words).
214
+ - **Sui private key export** — any of:
215
+ - 64 hex characters (optional `0x` prefix)
216
+ - Standard or URL-safe **base64** (32 bytes, or 33 bytes with a leading `0x00` byte)
217
+ - **`suiprivkey1...`** Bech32 string (SIP-15), as exported by Sui tooling
218
+
219
+ The derived address and signing path match Sui’s Ed25519 wallet behavior (including correct address derivation from `scheme || public key`).
220
+
221
+ ### Sub-accounts and `parentAddress`
222
+
223
+ Some setups use a **sub-account** key that only has trading/API permissions, while the **main wallet** remains the parent on-chain identity.
224
+
225
+ - When you authenticate with the **sub-account** key, pass the **main wallet address** as `parentAddress` in `DipcoinClient(...)`.
226
+ - For Solana, both the sub-account and `parentAddress` are Solana addresses. The JWT is issued for the signing sub-account, while query/body `parentAddress` remains the raw parent Solana address.
227
+ - When you use the **main wallet** mnemonic or private key directly, you normally **do not** need `parentAddress`; the client defaults it from your own address.
228
+
229
+ Example (sub-account key + main wallet as parent), see `examples/test_sui_taker_pingpong.py`:
230
+
231
+ ```python
232
+ client = DipcoinClient(
233
+ True,
234
+ Networks["SUI_STAGING"], # use Networks["SUI_PROD"] on mainnet
235
+ TEST_ACCT_KEY, # sub-account / API trading key
236
+ parentAddress="0x...main_wallet_address...",
237
+ )
238
+ ```
239
+
240
+ For **mainnet**, pass `Networks["SUI_PROD"]` as the second argument instead of `SUI_STAGING` (see `src/dipcoin_client/constants.py`).
241
+
242
+ ### Sui GraphQL helpers
243
+
244
+ Direct Sui chain methods are no longer exposed on `DipcoinClient`. Use `SuiGraphQLClient` for lightweight direct Sui reads and GraphQL transaction submission without native dependencies.
245
+
246
+ ```python
247
+ from dipcoin_client import DipcoinClient, Networks, SuiGraphQLClient
248
+
249
+ client = DipcoinClient(True, Networks["SUI_PROD"], PRIVATE_KEY)
250
+ await client.init(True)
251
+ sui_chain = SuiGraphQLClient(client)
252
+ balance = await sui_chain.get_native_chain_token_balance()
253
+ ```
254
+
255
+ GraphQL execution is available through `SuiGraphQLClient.execute_transaction(transaction_data_bcs, signatures)`. Local PTB construction is not bundled because direct Sui writes are not a core SDK requirement and most product flows should go through Dipcoin relayers.
256
+
257
+ If local Sui PTB construction becomes important, evaluate community tooling such as `pysui` or the Java reference implementation in `sui4j` as a separate package instead of adding native dependencies to this client.
258
+
259
+ Add/remove margin uses the Dipcoin relayer for Sui, Solana, and all supported EVM chains:
260
+
261
+ ```python
262
+ await client.add_margin(MARKET_SYMBOLS.ETH, "1")
263
+ await client.remove_margin(MARKET_SYMBOLS.ETH, "0.5")
264
+ ```
265
+
266
+ Before removing margin, the SDK can estimate the maximum from a humanized
267
+ position snapshot. The helper uses `fundingDue` and mirrors the protocol's
268
+ 10^18 fixed-point arithmetic:
269
+
270
+ ```python
271
+ from dipcoin_client import calculate_max_removable_margin
272
+
273
+ response = await client.get_user_position({"symbol": MARKET_SYMBOLS.ETH})
274
+ position = response["data"][0]
275
+ maximum = calculate_max_removable_margin(position)
276
+ conservative = calculate_max_removable_margin(position, safety_factor="0.98")
277
+ ```
278
+
279
+ The value is only an estimate: oracle price and unsettled funding may change
280
+ before the relayer executes the removal. The optional `0.98` factor matches the
281
+ current backend safety buffer.
282
+
283
+ ### API numeric scaling (10¹⁸)
284
+
285
+ Read endpoints such as order book, ticker, exchange info, orders, positions, trades, funding history, and account data now convert known 10¹⁸ fixed-point fields into human-readable strings without losing precision.
286
+
287
+ Websocket payloads for ticker, order book, recent trades, and known user / market update topics are also normalized before your listener callback receives them, so websocket handling stays consistent with REST reads.
288
+
289
+ Order placement and signatures still accept human-readable inputs and convert request fields to base-18 integers before submitting.
290
+
291
+ ### Update: take profit & stop loss (plan orders)
292
+
293
+ The client supports **position-linked TP/SL plan orders** (single side per request: either TP or SL, not both; additive flow rather than editing existing plans in one call):
294
+
295
+ - `DipcoinClient.set_take_profit_plan(...)` — submit a take-profit plan close order (signed like a normal reduce-only order via `create_signed_order`).
296
+ - `DipcoinClient.set_stop_loss_plan(...)` — same for stop-loss.
297
+ - `DipcoinClient.get_position_tpsl_plans(position_id, tpsl_type, parent_address=...)` — list TP/SL plans for a position (`tpsl_type`: `"normal"` or `"position"`).
298
+
299
+ Human-readable prices and quantities should be aligned to the contract tick/step (or decimal precision) **before** calling these methods. You can use `normalize_price` / `normalize_qty` in `dipcoin_client.util` for simple `round(..., precision)` style formatting, or apply tick/step rounding in your strategy.
300
+
301
+ **`get_orders` and plan order types:** responses can include **ordinary limit/market orders and plan (TP/SL) orders** in the same list. Use the order field **`planOrderType`** to tell them apart:
302
+
303
+ | `planOrderType` | Meaning |
304
+ |-----------------|--------|
305
+ | `open` | Regular order(open/close) |
306
+ | `takeProfit` | Take-profit plan order |
307
+ | `stopLoss` | Stop-loss plan order |
308
+
309
+ Filter or branch on this field when you only want classic working orders or only TP/SL plans.
310
+
311
+ ### Getting productive quickly
312
+
313
+ If you run into integration issues, **LLM / AI coding assistants** work well with this repo: point the tool at **`examples/`** and this README so it can map patterns (initialization, signing, orders, `parentAddress`) to your use case.
314
+
315
+ ## Project Structure
316
+
317
+ ```
318
+ dipcoin-client-python/
319
+ ├── src/
320
+ │ ├── dipcoin_client/ # Main client package
321
+ │ └── sui_utils/ # SUI blockchain utilities
322
+ ├── examples/ # Example code
323
+ ├── tests/ # Test code
324
+ ├── pyproject.toml # Project configuration
325
+ └── requirements.in # Dependencies list
326
+ ```
327
+
328
+ ## Troubleshooting
329
+
330
+ ### Issue: coincurve Installation Error
331
+
332
+ **Solution**:
333
+ ```bash
334
+ source venv/bin/activate
335
+ pip uninstall coincurve -y
336
+ pip install --no-cache-dir --force-reinstall coincurve==17.0.0
337
+ ```
338
+
339
+ ### Issue: Import Errors in PyCharm
340
+
341
+ **Error**: `ModuleNotFoundError: No module named 'sui_utils'`
342
+
343
+ **Solutions**:
344
+ 1. Ensure `pip install -e .` has been run
345
+ 2. Mark `src` directory as Sources Root in PyCharm
346
+ 3. Configure Python interpreter paths correctly
347
+ 4. Invalidate caches and restart PyCharm
348
+
349
+ ### Issue: Build Errors
350
+
351
+ **Error**: `error: subprocess-exited-with-error`
352
+
353
+ **Solutions**:
354
+ 1. Check Python version (should be 3.8-3.12)
355
+ 2. Upgrade pip and setuptools:
356
+ ```bash
357
+ pip install --upgrade pip setuptools wheel
358
+ ```
359
+ 3. Install build tools:
360
+ ```bash
361
+ # macOS
362
+ xcode-select --install
363
+
364
+ # Ubuntu/Debian
365
+ sudo apt-get install build-essential python3-dev
366
+ ```
367
+
368
+ ## Quick Reference
369
+
370
+ ```bash
371
+ # Install project (development mode)
372
+ pip install -e .
373
+
374
+ # Uninstall project
375
+ pip uninstall dipcoin-client
376
+
377
+ # Check installed package
378
+ pip show dipcoin-client
379
+
380
+ # Upgrade pip
381
+ pip install --upgrade pip
382
+
383
+ # Create virtual environment
384
+ python3.11 -m venv venv
385
+ source venv/bin/activate # macOS/Linux
386
+ ```
387
+
388
+ ## Notes
389
+
390
+ - **Python Version**: Use Python 3.8-3.12. Python 3.13 is not supported.
391
+ - **Virtual Environment**: Always use a virtual environment to isolate dependencies.
392
+ - **Security**: Never commit private keys or mnemonic phrases to version control.
393
+ - **Dependencies**: If you modify `pyproject.toml`, reinstall with `pip install -e .`
394
+
395
+ ## License
396
+
397
+ See LICENSE file for details.