cryptochief-crypto-processing-python 0.4.0__tar.gz → 0.6.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.
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/PKG-INFO +44 -4
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/README.md +43 -3
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/pyproject.toml +1 -1
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/__init__.py +4 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/_version.py +1 -1
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/errors.py +18 -4
- cryptochief_crypto_processing_python-0.6.0/src/cryptochief/py.typed +0 -0
- cryptochief_crypto_processing_python-0.6.0/src/cryptochief/services/wallets.py +222 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/transport.py +27 -7
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/webhook.py +65 -0
- cryptochief_crypto_processing_python-0.4.0/src/cryptochief/services/wallets.py +0 -86
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/.gitignore +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/LICENSE +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/_models.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/amount.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/assets.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/chains.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/client.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/contract/__init__.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/contract/base58.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/contract/borsh.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/contract/evm_abi.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/contract/keccak.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/contract/tron_address.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/pagination.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/poll.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/rsa.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/sentinels.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/services/__init__.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/services/base.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/services/blockchain.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/services/credits.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/services/currencies.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/services/payins.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/services/payouts.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/services/static_deposits.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/services/sweeps.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/services/transactions.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/services/withdrawals.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/sign.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/ton/__init__.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/ton/address.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/ton/messages.py +0 -0
- {cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/src/cryptochief/ton/rpc.py +0 -0
{cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cryptochief-crypto-processing-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Official async Python SDK for the Crypto Chief crypto payment gateway and crypto processing API. Accept crypto payments, send single and mass crypto payouts, sign on-chain transactions and smart-contract calls, manage wallets, convert fiat to crypto, and verify webhooks across Ethereum, BNB Smart Chain, Polygon, Tron, TON, Solana, Bitcoin, XRP and 20+ blockchains. USDT and USDC stablecoin support with int-precise amounts and asyncio/httpx.
|
|
5
5
|
Project-URL: Homepage, https://crypto-chief.com/processing/
|
|
6
6
|
Project-URL: Documentation, https://docs-sdk.crypto-chief.com/processing/python
|
|
@@ -120,7 +120,7 @@ Both credentials come from the Dashboard -> Project.
|
|
|
120
120
|
| Solana programs | `client.transactions` | `sign_anchor_call`, `sign_solana_call` |
|
|
121
121
|
| TON contract calls (Jetton / NFT / text) | `client.transactions` | `jetton_transfer`, `nft_transfer`, `send_ton_comment`, `sign_ton_call` |
|
|
122
122
|
| Accept incoming payments | `client.pay_ins` | `create`, `select_asset`, `reset_asset`, `cancel`, `info`, `history`, `wait_for` |
|
|
123
|
-
| Wallet management + RSA decrypt | `client.wallets` | `generate`, `list`, `info`, `freeze`, `decrypt_private_key` |
|
|
123
|
+
| Wallet management + RSA decrypt | `client.wallets` | `generate`, `list`, `info`, `freeze`, `rebind_master`, `set_callback_url`, `set_label`, `decrypt_private_key` |
|
|
124
124
|
| Treasury sweeps | `client.sweeps` | `force`, `history`, `wallet_history`, `settings`, `update_settings` |
|
|
125
125
|
| Withdrawals (read-only) | `client.withdrawals` | `info`, `history` |
|
|
126
126
|
| Static-deposit history | `client.static_deposits` | `info`, `history` |
|
|
@@ -200,6 +200,14 @@ decimal strings round-trip exactly. Discover an asset's decimals with
|
|
|
200
200
|
|
|
201
201
|
## Contract calls without hand-encoding
|
|
202
202
|
|
|
203
|
+
> **This snippet shows the encoder, not a complete swap.** Uniswap's router
|
|
204
|
+
> moves your input token with `transferFrom`, so it needs an ERC-20
|
|
205
|
+
> `approve(address,uint256)` on that token first, confirmed before the swap is
|
|
206
|
+
> signed — without it the swap reverts and burns the gas. And an `amountOutMin`
|
|
207
|
+
> of `0` accepts whatever the pool returns, which on a public mempool hands the
|
|
208
|
+
> trade to the first sandwich bot that sees it. The runnable version, with both,
|
|
209
|
+
> is in `examples/`.
|
|
210
|
+
|
|
203
211
|
```python
|
|
204
212
|
from cryptochief import EvmCallRequest, Erc20TransferRequest, Chain, human_to_base
|
|
205
213
|
|
|
@@ -294,8 +302,11 @@ the sender IPs in `WEBHOOK_SENDER_IPS` at your edge for defense in depth.
|
|
|
294
302
|
## Errors
|
|
295
303
|
|
|
296
304
|
Everything the SDK raises derives from `CryptoChiefError`. API failures are
|
|
297
|
-
`APIError` with a stable `.code` (
|
|
298
|
-
|
|
305
|
+
`APIError` with a stable `.code` (plus `.message`, `.http_status` and the
|
|
306
|
+
untouched `.raw` body); branch on `ErrorCode` rather than parsing messages. Both
|
|
307
|
+
envelope shapes the gateway sends - its own refusals, which carry the code in
|
|
308
|
+
`error`, and refusals relayed from upstream as `SERVICE_ERROR` with the code in
|
|
309
|
+
`msg` - resolve to `.code`. 5xx and network errors are retried automatically;
|
|
299
310
|
4xx is raised immediately.
|
|
300
311
|
|
|
301
312
|
```python
|
|
@@ -363,6 +374,35 @@ priv = client.wallets.decrypt_private_key(wallet.private_key_encrypted)
|
|
|
363
374
|
`completed_at` filled in. Earlier platform versions reported `completed` at
|
|
364
375
|
broadcast, so a sweep could read as settled while its transaction was still
|
|
365
376
|
unconfirmed.
|
|
377
|
+
- **My deposits are settling on the wrong master wallet.**
|
|
378
|
+
`client.wallets.rebind_master(address, master_wallet_address)` re-points a
|
|
379
|
+
transit or static wallet at another master of the project - the link is
|
|
380
|
+
otherwise decided at creation, falling back to the project's *oldest* master
|
|
381
|
+
of that chain family when none was named. It moves no money: it changes where
|
|
382
|
+
the **next** sweep settles, including sweeps already queued, and anything
|
|
383
|
+
already swept sits on the previous master and has to be sent from there as an
|
|
384
|
+
ordinary payout. It is idempotent, so re-running the same list is safe.
|
|
385
|
+
- **A static address is announcing deposits to the wrong URL.** Deposits go to
|
|
386
|
+
the callback the *address* carries, fixed when it was minted - so an address
|
|
387
|
+
you did not create through your own integration, or one minted before your
|
|
388
|
+
endpoint moved, keeps notifying somewhere else.
|
|
389
|
+
`client.wallets.set_callback_url(address, url)` corrects it, from the next
|
|
390
|
+
deposit on (one already announced is not re-announced). Pass `""` to clear it
|
|
391
|
+
and stop the announcements - the SDK sends the empty string rather than
|
|
392
|
+
dropping it the way it drops unset optional fields, and the wallet then reads
|
|
393
|
+
back `callback_url=None`. Static wallets only.
|
|
394
|
+
- **How do I name a wallet?** Pass `label` on
|
|
395
|
+
`client.wallets.generate(GenerateWalletRequest(..., label="EU shop"))`. It
|
|
396
|
+
applies to every wallet type, is up to 255 characters, and is yours alone -
|
|
397
|
+
nothing on chain and nothing in routing depends on it.
|
|
398
|
+
- **How do I rename a wallet I already have?**
|
|
399
|
+
`client.wallets.set_label(address, "EU shop")` - every wallet type, master
|
|
400
|
+
and transit included, unlike the deposit callback. Pass `""` to clear the
|
|
401
|
+
name: as with `set_callback_url`, the empty string is sent rather than
|
|
402
|
+
dropped, and the wallet then reads back `label=None`. The name comes back on
|
|
403
|
+
every response that describes a wallet - generation, `info`, `list`, and the
|
|
404
|
+
answers of `rebind_master` / `set_callback_url` / `set_label` itself - as
|
|
405
|
+
`wallet.label`, `None` when the wallet is unnamed.
|
|
366
406
|
- **How do I keep test payments off real chains?** Set `environment` on
|
|
367
407
|
`CreatePayInRequest` to `Environment.TESTNET` or `Environment.MAINNET`. It
|
|
368
408
|
constrains the asset the platform picks when you have not named a concrete
|
{cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/README.md
RENAMED
|
@@ -81,7 +81,7 @@ Both credentials come from the Dashboard -> Project.
|
|
|
81
81
|
| Solana programs | `client.transactions` | `sign_anchor_call`, `sign_solana_call` |
|
|
82
82
|
| TON contract calls (Jetton / NFT / text) | `client.transactions` | `jetton_transfer`, `nft_transfer`, `send_ton_comment`, `sign_ton_call` |
|
|
83
83
|
| Accept incoming payments | `client.pay_ins` | `create`, `select_asset`, `reset_asset`, `cancel`, `info`, `history`, `wait_for` |
|
|
84
|
-
| Wallet management + RSA decrypt | `client.wallets` | `generate`, `list`, `info`, `freeze`, `decrypt_private_key` |
|
|
84
|
+
| Wallet management + RSA decrypt | `client.wallets` | `generate`, `list`, `info`, `freeze`, `rebind_master`, `set_callback_url`, `set_label`, `decrypt_private_key` |
|
|
85
85
|
| Treasury sweeps | `client.sweeps` | `force`, `history`, `wallet_history`, `settings`, `update_settings` |
|
|
86
86
|
| Withdrawals (read-only) | `client.withdrawals` | `info`, `history` |
|
|
87
87
|
| Static-deposit history | `client.static_deposits` | `info`, `history` |
|
|
@@ -161,6 +161,14 @@ decimal strings round-trip exactly. Discover an asset's decimals with
|
|
|
161
161
|
|
|
162
162
|
## Contract calls without hand-encoding
|
|
163
163
|
|
|
164
|
+
> **This snippet shows the encoder, not a complete swap.** Uniswap's router
|
|
165
|
+
> moves your input token with `transferFrom`, so it needs an ERC-20
|
|
166
|
+
> `approve(address,uint256)` on that token first, confirmed before the swap is
|
|
167
|
+
> signed — without it the swap reverts and burns the gas. And an `amountOutMin`
|
|
168
|
+
> of `0` accepts whatever the pool returns, which on a public mempool hands the
|
|
169
|
+
> trade to the first sandwich bot that sees it. The runnable version, with both,
|
|
170
|
+
> is in `examples/`.
|
|
171
|
+
|
|
164
172
|
```python
|
|
165
173
|
from cryptochief import EvmCallRequest, Erc20TransferRequest, Chain, human_to_base
|
|
166
174
|
|
|
@@ -255,8 +263,11 @@ the sender IPs in `WEBHOOK_SENDER_IPS` at your edge for defense in depth.
|
|
|
255
263
|
## Errors
|
|
256
264
|
|
|
257
265
|
Everything the SDK raises derives from `CryptoChiefError`. API failures are
|
|
258
|
-
`APIError` with a stable `.code` (
|
|
259
|
-
|
|
266
|
+
`APIError` with a stable `.code` (plus `.message`, `.http_status` and the
|
|
267
|
+
untouched `.raw` body); branch on `ErrorCode` rather than parsing messages. Both
|
|
268
|
+
envelope shapes the gateway sends - its own refusals, which carry the code in
|
|
269
|
+
`error`, and refusals relayed from upstream as `SERVICE_ERROR` with the code in
|
|
270
|
+
`msg` - resolve to `.code`. 5xx and network errors are retried automatically;
|
|
260
271
|
4xx is raised immediately.
|
|
261
272
|
|
|
262
273
|
```python
|
|
@@ -324,6 +335,35 @@ priv = client.wallets.decrypt_private_key(wallet.private_key_encrypted)
|
|
|
324
335
|
`completed_at` filled in. Earlier platform versions reported `completed` at
|
|
325
336
|
broadcast, so a sweep could read as settled while its transaction was still
|
|
326
337
|
unconfirmed.
|
|
338
|
+
- **My deposits are settling on the wrong master wallet.**
|
|
339
|
+
`client.wallets.rebind_master(address, master_wallet_address)` re-points a
|
|
340
|
+
transit or static wallet at another master of the project - the link is
|
|
341
|
+
otherwise decided at creation, falling back to the project's *oldest* master
|
|
342
|
+
of that chain family when none was named. It moves no money: it changes where
|
|
343
|
+
the **next** sweep settles, including sweeps already queued, and anything
|
|
344
|
+
already swept sits on the previous master and has to be sent from there as an
|
|
345
|
+
ordinary payout. It is idempotent, so re-running the same list is safe.
|
|
346
|
+
- **A static address is announcing deposits to the wrong URL.** Deposits go to
|
|
347
|
+
the callback the *address* carries, fixed when it was minted - so an address
|
|
348
|
+
you did not create through your own integration, or one minted before your
|
|
349
|
+
endpoint moved, keeps notifying somewhere else.
|
|
350
|
+
`client.wallets.set_callback_url(address, url)` corrects it, from the next
|
|
351
|
+
deposit on (one already announced is not re-announced). Pass `""` to clear it
|
|
352
|
+
and stop the announcements - the SDK sends the empty string rather than
|
|
353
|
+
dropping it the way it drops unset optional fields, and the wallet then reads
|
|
354
|
+
back `callback_url=None`. Static wallets only.
|
|
355
|
+
- **How do I name a wallet?** Pass `label` on
|
|
356
|
+
`client.wallets.generate(GenerateWalletRequest(..., label="EU shop"))`. It
|
|
357
|
+
applies to every wallet type, is up to 255 characters, and is yours alone -
|
|
358
|
+
nothing on chain and nothing in routing depends on it.
|
|
359
|
+
- **How do I rename a wallet I already have?**
|
|
360
|
+
`client.wallets.set_label(address, "EU shop")` - every wallet type, master
|
|
361
|
+
and transit included, unlike the deposit callback. Pass `""` to clear the
|
|
362
|
+
name: as with `set_callback_url`, the empty string is sent rather than
|
|
363
|
+
dropped, and the wallet then reads back `label=None`. The name comes back on
|
|
364
|
+
every response that describes a wallet - generation, `info`, `list`, and the
|
|
365
|
+
answers of `rebind_master` / `set_callback_url` / `set_label` itself - as
|
|
366
|
+
`wallet.label`, `None` when the wallet is unnamed.
|
|
327
367
|
- **How do I keep test payments off real chains?** Set `environment` on
|
|
328
368
|
`CreatePayInRequest` to `Environment.TESTNET` or `Environment.MAINNET`. It
|
|
329
369
|
constrains the asset the platform picks when you have not named a concrete
|
|
@@ -170,6 +170,8 @@ from .webhook import (
|
|
|
170
170
|
PayInWebhookEvent,
|
|
171
171
|
PayoutWebhookEvent,
|
|
172
172
|
StaticDepositWebhookEvent,
|
|
173
|
+
SweepWebhookEvent,
|
|
174
|
+
SWEEP_EVENT_CONFIRMED,
|
|
173
175
|
TransactionWebhookEvent,
|
|
174
176
|
WebhookSignatureError,
|
|
175
177
|
coerce_webhook_event,
|
|
@@ -230,6 +232,8 @@ __all__ = [
|
|
|
230
232
|
"TransactionWebhookEvent",
|
|
231
233
|
"PayInWebhookEvent",
|
|
232
234
|
"StaticDepositWebhookEvent",
|
|
235
|
+
"SweepWebhookEvent",
|
|
236
|
+
"SWEEP_EVENT_CONFIRMED",
|
|
233
237
|
# Services
|
|
234
238
|
"PayoutsService",
|
|
235
239
|
"TransactionsService",
|
|
@@ -19,19 +19,27 @@ class CryptoChiefError(Exception):
|
|
|
19
19
|
class APIError(CryptoChiefError):
|
|
20
20
|
"""A typed Crypto Chief error response.
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
:attr:`code` is the machine-readable identifier to branch on, whichever
|
|
23
|
+
envelope shape the refusal arrived in: the gateway's own refusals carry the
|
|
24
|
+
code in ``error`` and an English sentence in ``msg``
|
|
25
|
+
(``{"error": "LABEL_TOO_LONG", "msg": "label is longer than 255 characters"}``),
|
|
26
|
+
while a relayed upstream refusal carries the generic ``SERVICE_ERROR``
|
|
27
|
+
marker in ``error`` and the code in ``msg``
|
|
28
|
+
(``{"error": "SERVICE_ERROR", "msg": "wallet_not_found"}``). Both resolve to
|
|
29
|
+
:attr:`code`::
|
|
26
30
|
|
|
27
31
|
try:
|
|
28
32
|
await client.payouts.execute(req)
|
|
29
33
|
except APIError as e:
|
|
30
34
|
if e.code == ErrorCode.INSUFFICIENT_FUNDS:
|
|
31
35
|
... # top up and retry
|
|
36
|
+
|
|
37
|
+
:attr:`message` is the human-readable half - the sentence when the gateway
|
|
38
|
+
sent one - and :attr:`raw` is the untouched response body.
|
|
32
39
|
"""
|
|
33
40
|
|
|
34
41
|
code: str
|
|
42
|
+
message: str
|
|
35
43
|
http_status: int
|
|
36
44
|
raw: Optional[str]
|
|
37
45
|
|
|
@@ -46,6 +54,7 @@ class APIError(CryptoChiefError):
|
|
|
46
54
|
# Normalize an ErrorCode member to its wire string ("NETWORK_ERROR"),
|
|
47
55
|
# not its enum repr ("ErrorCode.NETWORK_ERROR").
|
|
48
56
|
self.code = code.value if isinstance(code, Enum) else str(code)
|
|
57
|
+
self.message = message or ""
|
|
49
58
|
self.http_status = http_status
|
|
50
59
|
self.raw = raw
|
|
51
60
|
super().__init__(self._format(http_status, self.code, message))
|
|
@@ -75,6 +84,11 @@ class ErrorCode(str, Enum):
|
|
|
75
84
|
ORDER_NOT_LIVE = "ORDER_NOT_LIVE"
|
|
76
85
|
ASSET_ALREADY_SELECTED = "ASSET_ALREADY_SELECTED"
|
|
77
86
|
INVALID_PARAMS = "INVALID_PARAMS"
|
|
87
|
+
#: A wallet label over 255 characters.
|
|
88
|
+
LABEL_TOO_LONG = "LABEL_TOO_LONG"
|
|
89
|
+
#: The gateway's marker for a refusal relayed from an upstream service; the
|
|
90
|
+
#: machine code then travels in ``msg`` and is what :attr:`APIError.code`
|
|
91
|
+
#: reports, so this member is rarely what you compare against.
|
|
78
92
|
SERVICE_ERROR = "SERVICE_ERROR"
|
|
79
93
|
UNAUTHORIZED = "UNAUTHORIZED"
|
|
80
94
|
URL_CALLBACK_REQUIRED = "URL_CALLBACK_REQUIRED"
|
|
File without changes
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""Wallet management + local RSA private-key decryption."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import List, Optional
|
|
8
|
+
|
|
9
|
+
from .._models import from_dict
|
|
10
|
+
from ..errors import CryptoChiefError
|
|
11
|
+
from .base import BaseService
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class WalletType(str, Enum):
|
|
15
|
+
MASTER = "master"
|
|
16
|
+
TRANSIT = "transit"
|
|
17
|
+
STATIC = "static"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(kw_only=True)
|
|
21
|
+
class GenerateWalletRequest:
|
|
22
|
+
wallet_type: str
|
|
23
|
+
chain_family: str
|
|
24
|
+
master_wallet_address: Optional[str] = None # transit/static wallets only
|
|
25
|
+
callback_url: Optional[str] = None # static wallets only - per-deposit webhook URL
|
|
26
|
+
#: A name for the wallet, for people reading a list of them. Applies to
|
|
27
|
+
#: every wallet type - it names the wallet, it is not a property of its
|
|
28
|
+
#: role - and is yours alone: nothing on chain and nothing in routing
|
|
29
|
+
#: depends on it. Up to 255 characters, longer answers ``LABEL_TOO_LONG``.
|
|
30
|
+
#: Leave it ``None`` to omit it; the endpoint rejects unknown fields, and an
|
|
31
|
+
#: empty string is a name rather than the absence of one.
|
|
32
|
+
#: :meth:`WalletsService.set_label` renames the wallet afterwards.
|
|
33
|
+
label: Optional[str] = None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass(kw_only=True)
|
|
37
|
+
class WalletCoinBalance:
|
|
38
|
+
address: Optional[str] = None
|
|
39
|
+
chain: Optional[str] = None
|
|
40
|
+
coin: Optional[str] = None
|
|
41
|
+
contract: Optional[str] = None
|
|
42
|
+
decimals: int = 0
|
|
43
|
+
value: Optional[str] = None
|
|
44
|
+
human_value: Optional[str] = None
|
|
45
|
+
amount_usd: Optional[str] = None
|
|
46
|
+
timestamp: Optional[int] = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass(kw_only=True)
|
|
50
|
+
class Wallet:
|
|
51
|
+
address: str = ""
|
|
52
|
+
chain_family: Optional[str] = None
|
|
53
|
+
type: Optional[str] = None
|
|
54
|
+
wallet_type: Optional[str] = None
|
|
55
|
+
frozen: Optional[bool] = None
|
|
56
|
+
#: The master this wallet sweeps into, ``None`` when it has none - a master
|
|
57
|
+
#: wallet has no master of its own. The API always sends the key and sends
|
|
58
|
+
#: ``null`` rather than an empty string, so ``None`` here means "no master",
|
|
59
|
+
#: not "not reported". :meth:`WalletsService.rebind_master` changes it.
|
|
60
|
+
master_wallet_address: Optional[str] = None
|
|
61
|
+
#: Where deposits to this address are announced, ``None`` when nowhere. Only
|
|
62
|
+
#: a static wallet has one: a master or transit always reads ``None``.
|
|
63
|
+
#: :meth:`WalletsService.set_callback_url` changes it.
|
|
64
|
+
callback_url: Optional[str] = None
|
|
65
|
+
#: The wallet's name, ``None`` when it has none. Every wallet type can carry
|
|
66
|
+
#: one, and every response that describes a wallet reports it. The API
|
|
67
|
+
#: always sends the key and sends ``null`` rather than an empty string, so
|
|
68
|
+
#: ``None`` here means "unnamed" - a cleared label reads back as ``None``,
|
|
69
|
+
#: never as ``""``. :meth:`WalletsService.set_label` changes it.
|
|
70
|
+
label: Optional[str] = None
|
|
71
|
+
#: Base64 RSA-OAEP/SHA-256 ciphertext - decrypt with ``decrypt_private_key``.
|
|
72
|
+
private_key_encrypted: Optional[str] = None
|
|
73
|
+
created_at: Optional[str] = None
|
|
74
|
+
coins: Optional[List[WalletCoinBalance]] = None
|
|
75
|
+
total_balance_usd: Optional[str] = None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass(kw_only=True)
|
|
79
|
+
class ListWalletsResponse:
|
|
80
|
+
items: Optional[List[Wallet]] = None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class WalletsService(BaseService):
|
|
84
|
+
async def generate(self, req: GenerateWalletRequest) -> Wallet:
|
|
85
|
+
"""Provision a new wallet on the requested chain family."""
|
|
86
|
+
return from_dict(Wallet, await self._post("/v1/wallets/generate", req))
|
|
87
|
+
|
|
88
|
+
async def list(self) -> ListWalletsResponse:
|
|
89
|
+
"""Every wallet on the project."""
|
|
90
|
+
return from_dict(ListWalletsResponse, await self._post("/v1/wallets/list", {}))
|
|
91
|
+
|
|
92
|
+
async def info(self, address: str) -> Wallet:
|
|
93
|
+
"""Details and current balances of one wallet."""
|
|
94
|
+
return from_dict(Wallet, await self._post("/v1/wallets/info", {"address": address}))
|
|
95
|
+
|
|
96
|
+
async def freeze(self, address: str) -> Wallet:
|
|
97
|
+
"""Toggle the frozen flag - the response's ``frozen`` field is the new state."""
|
|
98
|
+
return from_dict(Wallet, await self._post("/v1/wallets/freeze", {"address": address}))
|
|
99
|
+
|
|
100
|
+
async def rebind_master(self, address: str, master_wallet_address: str) -> Wallet:
|
|
101
|
+
"""Re-point a transit or static wallet at another master of the project.
|
|
102
|
+
|
|
103
|
+
The master link is decided when the wallet is created - at the master
|
|
104
|
+
named on that request, or, when none was named, at the project's *oldest*
|
|
105
|
+
master of that chain family, which on a project with more than one master
|
|
106
|
+
is rarely the one you meant. This is the way back.
|
|
107
|
+
|
|
108
|
+
It moves no money. It changes where the *next* sweep settles, including
|
|
109
|
+
sweeps already queued, because the destination is resolved when the sweep
|
|
110
|
+
runs; anything already swept sits on the previous master and has to be
|
|
111
|
+
sent from there as an ordinary payout.
|
|
112
|
+
|
|
113
|
+
Idempotent - a wallet already bound to that master answers 200 unchanged,
|
|
114
|
+
so re-running the same list is safe. A master wallet cannot be
|
|
115
|
+
re-pointed at all (``only transit and static wallets have a master``);
|
|
116
|
+
naming something that is not a master as the TARGET is a different
|
|
117
|
+
refusal (``not_a_master_wallet``). The target master must be the same
|
|
118
|
+
chain family (``chain_family_mismatch``) and not frozen
|
|
119
|
+
(``master_wallet_frozen``), since sweeping into a frozen master would
|
|
120
|
+
strand the funds there.
|
|
121
|
+
|
|
122
|
+
The gateway relays every upstream refusal as
|
|
123
|
+
``{"error": "SERVICE_ERROR", "msg": "<token>"}``, and the SDK reports
|
|
124
|
+
that token as ``APIError.code`` - so branch on the code, not on the
|
|
125
|
+
message text. These tokens are per-endpoint and are not
|
|
126
|
+
:class:`~cryptochief.ErrorCode` members. Memo/tag-based families share one deposit
|
|
127
|
+
account across orders and are excluded
|
|
128
|
+
(``shared_transit_cannot_be_rebound``). Both addresses resolve against
|
|
129
|
+
the authenticated project, so one that is not yours answers
|
|
130
|
+
``wallet_not_found`` / ``master_wallet_not_found`` rather than revealing
|
|
131
|
+
that it exists elsewhere.
|
|
132
|
+
|
|
133
|
+
Returns the wallet as it now stands.
|
|
134
|
+
"""
|
|
135
|
+
return from_dict(
|
|
136
|
+
Wallet,
|
|
137
|
+
await self._post(
|
|
138
|
+
"/v1/wallets/rebind-master",
|
|
139
|
+
{"address": address, "master_wallet_address": master_wallet_address},
|
|
140
|
+
),
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
async def set_callback_url(self, address: str, callback_url: str) -> Wallet:
|
|
144
|
+
"""Set or clear a static wallet's deposit webhook after creation.
|
|
145
|
+
|
|
146
|
+
Deposits are announced to the callback URL the *address* carries, which
|
|
147
|
+
is fixed when the address is minted - so an address you did not create
|
|
148
|
+
through your own integration, or one minted before your endpoint moved,
|
|
149
|
+
keeps announcing its deposits somewhere else, or nowhere. This corrects
|
|
150
|
+
it, from the next deposit on: one already announced is not re-announced
|
|
151
|
+
to the new URL.
|
|
152
|
+
|
|
153
|
+
Pass ``""`` to clear it and stop announcing deposits for the address.
|
|
154
|
+
That is a real instruction rather than a missing field, so the SDK sends
|
|
155
|
+
the empty string instead of dropping it the way it drops unset optional
|
|
156
|
+
fields; the wallet then reads back ``callback_url=None``. ``None`` is
|
|
157
|
+
not that instruction and is refused here rather than silently leaving
|
|
158
|
+
the field off the body.
|
|
159
|
+
|
|
160
|
+
Static wallets only - a master or transit has no per-deposit callback
|
|
161
|
+
and answers 400. The address resolves against the authenticated project,
|
|
162
|
+
so one that is not yours answers ``wallet_not_found``.
|
|
163
|
+
|
|
164
|
+
Returns the wallet as it now stands.
|
|
165
|
+
"""
|
|
166
|
+
if callback_url is None:
|
|
167
|
+
raise CryptoChiefError(
|
|
168
|
+
'cryptochief: set_callback_url: callback_url is required; pass "" to clear it'
|
|
169
|
+
)
|
|
170
|
+
return from_dict(
|
|
171
|
+
Wallet,
|
|
172
|
+
await self._post(
|
|
173
|
+
"/v1/wallets/callback-url",
|
|
174
|
+
{"address": address, "callback_url": callback_url},
|
|
175
|
+
),
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
async def set_label(self, address: str, label: str) -> Wallet:
|
|
179
|
+
"""Set or clear a wallet's label - the name it is read by.
|
|
180
|
+
|
|
181
|
+
A label is yours alone: nothing on chain and nothing in routing depends
|
|
182
|
+
on it. It is also the only thing telling one freshly minted address
|
|
183
|
+
apart from the next in a list, so a wallet created before the label was
|
|
184
|
+
supported, or minted somewhere other than your own integration, is worth
|
|
185
|
+
naming after the fact. This is how.
|
|
186
|
+
|
|
187
|
+
Every wallet type can be renamed - master, transit and static alike,
|
|
188
|
+
because a label names the wallet rather than describing its role. That
|
|
189
|
+
is unlike :meth:`set_callback_url`, which only a static wallet has.
|
|
190
|
+
|
|
191
|
+
Pass ``""`` to clear the name and leave the wallet unnamed. That is a
|
|
192
|
+
real instruction rather than a missing field, so the SDK sends the empty
|
|
193
|
+
string instead of dropping it the way it drops unset optional fields;
|
|
194
|
+
the wallet then reads back ``label=None``. ``None`` is not that
|
|
195
|
+
instruction and is refused here rather than silently leaving the field
|
|
196
|
+
off the body.
|
|
197
|
+
|
|
198
|
+
Up to 255 characters, longer answers ``LABEL_TOO_LONG``. The address
|
|
199
|
+
resolves against the authenticated project, so one that is not yours
|
|
200
|
+
answers ``wallet_not_found`` rather than revealing that it exists
|
|
201
|
+
elsewhere.
|
|
202
|
+
|
|
203
|
+
Returns the wallet as it now stands.
|
|
204
|
+
"""
|
|
205
|
+
if label is None:
|
|
206
|
+
raise CryptoChiefError(
|
|
207
|
+
'cryptochief: set_label: label is required; pass "" to clear it'
|
|
208
|
+
)
|
|
209
|
+
return from_dict(
|
|
210
|
+
Wallet,
|
|
211
|
+
await self._post("/v1/wallets/label", {"address": address, "label": label}),
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
def decrypt_private_key(self, encrypted: str) -> str:
|
|
215
|
+
"""Decrypt a generated wallet's ``private_key_encrypted`` field locally.
|
|
216
|
+
|
|
217
|
+
Uses the RSA private key configured on the client (``rsa_private_key``
|
|
218
|
+
option) and returns the chain-native hex private key. Raises
|
|
219
|
+
:class:`RsaKeyNotConfiguredError` if no key was configured. Synchronous -
|
|
220
|
+
never touches the network.
|
|
221
|
+
"""
|
|
222
|
+
return self._client.rsa_decrypt(encrypted)
|
|
@@ -8,11 +8,26 @@ import random
|
|
|
8
8
|
from .errors import APIError, ErrorCode
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
def _field(env: dict, key: str) -> str:
|
|
12
|
+
"""Read ``key`` from an error envelope as a trimmed string (``""`` if absent)."""
|
|
13
|
+
value = env.get(key)
|
|
14
|
+
return value.strip() if isinstance(value, str) else ""
|
|
15
|
+
|
|
16
|
+
|
|
11
17
|
def parse_api_error(status: int, body: str) -> APIError:
|
|
12
18
|
"""Parse a non-2xx response body into an :class:`APIError` with a stable code.
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
``msg``
|
|
20
|
+
Refusals arrive in two envelope shapes. When the gateway itself refuses, the
|
|
21
|
+
machine code is in ``error`` and ``msg`` holds an English sentence
|
|
22
|
+
(``{"error": "LABEL_TOO_LONG", "msg": "label is longer than 255 characters"}``).
|
|
23
|
+
When it relays an upstream refusal, ``error`` is the generic
|
|
24
|
+
``SERVICE_ERROR`` marker and the machine code is in ``msg``
|
|
25
|
+
(``{"error": "SERVICE_ERROR", "msg": "wallet_not_found"}``).
|
|
26
|
+
|
|
27
|
+
So the code is ``error`` unless that is ``SERVICE_ERROR``, in which case it
|
|
28
|
+
is ``msg``; an empty result falls back to ``error`` and then
|
|
29
|
+
``HTTP_<status>``. The human-readable message prefers ``msg`` and falls back
|
|
30
|
+
to ``error``.
|
|
16
31
|
"""
|
|
17
32
|
env: dict = {}
|
|
18
33
|
try:
|
|
@@ -21,11 +36,16 @@ def parse_api_error(status: int, body: str) -> APIError:
|
|
|
21
36
|
env = parsed
|
|
22
37
|
except ValueError:
|
|
23
38
|
pass # non-JSON error body -> fall back to HTTP_<status>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return APIError(
|
|
39
|
+
|
|
40
|
+
error = _field(env, "error")
|
|
41
|
+
msg = _field(env, "msg")
|
|
42
|
+
code = error if error and error != ErrorCode.SERVICE_ERROR else (msg or error)
|
|
43
|
+
return APIError(
|
|
44
|
+
code or f"HTTP_{status}",
|
|
45
|
+
http_status=status,
|
|
46
|
+
message=msg or error,
|
|
47
|
+
raw=body,
|
|
48
|
+
)
|
|
29
49
|
|
|
30
50
|
|
|
31
51
|
def backoff_delay(attempt: int, base_ms: float, max_ms: float) -> float:
|
|
@@ -175,11 +175,75 @@ class StaticDepositWebhookEvent:
|
|
|
175
175
|
paid_at: Optional[str] = None
|
|
176
176
|
|
|
177
177
|
|
|
178
|
+
#: The only sweep event the platform emits. There is deliberately no
|
|
179
|
+
#: ``sweep.broadcasted``: "we sent it" is not something you can act on, and an
|
|
180
|
+
#: event that means "maybe" is one more thing to reconcile.
|
|
181
|
+
SWEEP_EVENT_CONFIRMED = "sweep.confirmed"
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@dataclass(kw_only=True)
|
|
185
|
+
class SweepWebhookEvent:
|
|
186
|
+
"""Funds swept off a deposit wallet, confirmed on chain.
|
|
187
|
+
|
|
188
|
+
A ``static_deposit.paid`` tells you a customer paid you. This tells you the
|
|
189
|
+
money has finished moving into your own custody - until it fires, the
|
|
190
|
+
balance still sits on the deposit address. Reconciliation, treasury
|
|
191
|
+
reporting and "funds available to pay out" all key off this event, not off
|
|
192
|
+
the deposit.
|
|
193
|
+
|
|
194
|
+
Sweeps run on static deposit wallets *and* on the transit wallets issued per
|
|
195
|
+
pay-in order; both deliver here, to the callback URL configured for the
|
|
196
|
+
wallet the funds left.
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
event: str = ""
|
|
200
|
+
#: The sweeper task. One sweep settles once - use it as your idempotency key.
|
|
201
|
+
task_id: str = ""
|
|
202
|
+
#: Always ``"completed"``. A sweep reaches you in no other state.
|
|
203
|
+
status: str = ""
|
|
204
|
+
|
|
205
|
+
#: The wallet the funds left - the address your customer paid into.
|
|
206
|
+
wallet_address: str = ""
|
|
207
|
+
#: The master wallet they landed on.
|
|
208
|
+
to_address: Optional[str] = None
|
|
209
|
+
|
|
210
|
+
network: str = ""
|
|
211
|
+
chain_family: Optional[str] = None
|
|
212
|
+
asset_symbol: str = ""
|
|
213
|
+
asset_contract: Optional[str] = None
|
|
214
|
+
#: ``"native"`` or ``"token"``.
|
|
215
|
+
asset_type: Optional[str] = None
|
|
216
|
+
amount_raw: Optional[str] = None
|
|
217
|
+
amount_human: Optional[str] = None
|
|
218
|
+
|
|
219
|
+
sweep_tx_hash: str = ""
|
|
220
|
+
#: Set when the platform had to fund gas on the wallet before it could sweep.
|
|
221
|
+
gas_pump_tx_hash: Optional[str] = None
|
|
222
|
+
|
|
223
|
+
#: What makes this event true rather than hopeful, and never zero. It
|
|
224
|
+
#: travels with the event rather than being implied by it: "confirmed" is
|
|
225
|
+
#: not the same number on every chain, so if you run your own finality
|
|
226
|
+
#: policy you need the count to apply it.
|
|
227
|
+
sweep_confirmations: int = 0
|
|
228
|
+
|
|
229
|
+
#: When the chain was observed to hold the sweep. NOT the task's completion
|
|
230
|
+
#: timestamp, which is stamped on every terminal outcome - failures
|
|
231
|
+
#: included - and so says nothing about settlement.
|
|
232
|
+
confirmed_at: Optional[str] = None
|
|
233
|
+
|
|
234
|
+
#: What triggered it: ``"momentum"``, ``"threshold"`` or ``"force"``.
|
|
235
|
+
type_work: Optional[str] = None
|
|
236
|
+
#: What the sweep cost: network fee plus any gas or energy the platform
|
|
237
|
+
#: fronted to make it possible.
|
|
238
|
+
total_fee_usd: Optional[str] = None
|
|
239
|
+
|
|
240
|
+
|
|
178
241
|
WebhookEvent = Union[
|
|
179
242
|
PayoutWebhookEvent,
|
|
180
243
|
TransactionWebhookEvent,
|
|
181
244
|
PayInWebhookEvent,
|
|
182
245
|
StaticDepositWebhookEvent,
|
|
246
|
+
SweepWebhookEvent,
|
|
183
247
|
Dict[str, Any],
|
|
184
248
|
]
|
|
185
249
|
|
|
@@ -188,4 +252,5 @@ _EVENT_BY_PREFIX = {
|
|
|
188
252
|
"transaction": TransactionWebhookEvent,
|
|
189
253
|
"invoice": PayInWebhookEvent,
|
|
190
254
|
"static_deposit": StaticDepositWebhookEvent,
|
|
255
|
+
"sweep": SweepWebhookEvent,
|
|
191
256
|
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
"""Wallet management + local RSA private-key decryption."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from dataclasses import dataclass
|
|
6
|
-
from enum import Enum
|
|
7
|
-
from typing import List, Optional
|
|
8
|
-
|
|
9
|
-
from .._models import from_dict
|
|
10
|
-
from .base import BaseService
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class WalletType(str, Enum):
|
|
14
|
-
MASTER = "master"
|
|
15
|
-
TRANSIT = "transit"
|
|
16
|
-
STATIC = "static"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@dataclass(kw_only=True)
|
|
20
|
-
class GenerateWalletRequest:
|
|
21
|
-
wallet_type: str
|
|
22
|
-
chain_family: str
|
|
23
|
-
master_wallet_address: Optional[str] = None # transit/static wallets only
|
|
24
|
-
callback_url: Optional[str] = None # static wallets only - per-deposit webhook URL
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@dataclass(kw_only=True)
|
|
28
|
-
class WalletCoinBalance:
|
|
29
|
-
address: Optional[str] = None
|
|
30
|
-
chain: Optional[str] = None
|
|
31
|
-
coin: Optional[str] = None
|
|
32
|
-
contract: Optional[str] = None
|
|
33
|
-
decimals: int = 0
|
|
34
|
-
value: Optional[str] = None
|
|
35
|
-
human_value: Optional[str] = None
|
|
36
|
-
amount_usd: Optional[str] = None
|
|
37
|
-
timestamp: Optional[int] = None
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@dataclass(kw_only=True)
|
|
41
|
-
class Wallet:
|
|
42
|
-
address: str = ""
|
|
43
|
-
chain_family: Optional[str] = None
|
|
44
|
-
type: Optional[str] = None
|
|
45
|
-
wallet_type: Optional[str] = None
|
|
46
|
-
frozen: Optional[bool] = None
|
|
47
|
-
master_wallet_address: Optional[str] = None
|
|
48
|
-
callback_url: Optional[str] = None
|
|
49
|
-
#: Base64 RSA-OAEP/SHA-256 ciphertext - decrypt with ``decrypt_private_key``.
|
|
50
|
-
private_key_encrypted: Optional[str] = None
|
|
51
|
-
created_at: Optional[str] = None
|
|
52
|
-
coins: Optional[List[WalletCoinBalance]] = None
|
|
53
|
-
total_balance_usd: Optional[str] = None
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
@dataclass(kw_only=True)
|
|
57
|
-
class ListWalletsResponse:
|
|
58
|
-
items: Optional[List[Wallet]] = None
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class WalletsService(BaseService):
|
|
62
|
-
async def generate(self, req: GenerateWalletRequest) -> Wallet:
|
|
63
|
-
"""Provision a new wallet on the requested chain family."""
|
|
64
|
-
return from_dict(Wallet, await self._post("/v1/wallets/generate", req))
|
|
65
|
-
|
|
66
|
-
async def list(self) -> ListWalletsResponse:
|
|
67
|
-
"""Every wallet on the project."""
|
|
68
|
-
return from_dict(ListWalletsResponse, await self._post("/v1/wallets/list", {}))
|
|
69
|
-
|
|
70
|
-
async def info(self, address: str) -> Wallet:
|
|
71
|
-
"""Details and current balances of one wallet."""
|
|
72
|
-
return from_dict(Wallet, await self._post("/v1/wallets/info", {"address": address}))
|
|
73
|
-
|
|
74
|
-
async def freeze(self, address: str) -> Wallet:
|
|
75
|
-
"""Toggle the frozen flag - the response's ``frozen`` field is the new state."""
|
|
76
|
-
return from_dict(Wallet, await self._post("/v1/wallets/freeze", {"address": address}))
|
|
77
|
-
|
|
78
|
-
def decrypt_private_key(self, encrypted: str) -> str:
|
|
79
|
-
"""Decrypt a generated wallet's ``private_key_encrypted`` field locally.
|
|
80
|
-
|
|
81
|
-
Uses the RSA private key configured on the client (``rsa_private_key``
|
|
82
|
-
option) and returns the chain-native hex private key. Raises
|
|
83
|
-
:class:`RsaKeyNotConfiguredError` if no key was configured. Synchronous -
|
|
84
|
-
never touches the network.
|
|
85
|
-
"""
|
|
86
|
-
return self._client.rsa_decrypt(encrypted)
|
{cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/.gitignore
RENAMED
|
File without changes
|
{cryptochief_crypto_processing_python-0.4.0 → cryptochief_crypto_processing_python-0.6.0}/LICENSE
RENAMED
|
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
|