helius-python 0.3.3__tar.gz → 0.4.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.
- {helius_python-0.3.3 → helius_python-0.4.0}/PKG-INFO +50 -11
- {helius_python-0.3.3 → helius_python-0.4.0}/README.md +49 -10
- {helius_python-0.3.3 → helius_python-0.4.0}/TODO.md +2 -0
- helius_python-0.4.0/examples/laserstream/websocket_logs.py +76 -0
- helius_python-0.4.0/examples/solana_rpc/address_transactions.py +125 -0
- helius_python-0.4.0/examples/solana_rpc/address_transfers.py +118 -0
- {helius_python-0.3.3/examples → helius_python-0.4.0/examples/solana_rpc}/block_explorer.py +4 -3
- {helius_python-0.3.3/examples → helius_python-0.4.0/examples/solana_rpc}/devnet_airdrop.py +26 -4
- {helius_python-0.3.3/examples → helius_python-0.4.0/examples/solana_rpc}/network_status.py +1 -1
- {helius_python-0.3.3/examples → helius_python-0.4.0/examples/solana_rpc}/priority_fees.py +2 -2
- {helius_python-0.3.3/examples → helius_python-0.4.0/examples/solana_rpc}/stake_overview.py +5 -2
- {helius_python-0.3.3/examples → helius_python-0.4.0/examples/solana_rpc}/token_inspector.py +12 -5
- {helius_python-0.3.3/examples → helius_python-0.4.0/examples/solana_rpc}/transaction_inspector.py +2 -2
- {helius_python-0.3.3/examples → helius_python-0.4.0/examples/solana_rpc}/wallet_tracker.py +4 -4
- helius_python-0.4.0/examples/webhooks/webhook_crud.py +190 -0
- helius_python-0.4.0/examples/webhooks/webhook_receiver.py +109 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/pyproject.toml +1 -1
- {helius_python-0.3.3 → helius_python-0.4.0}/src/helius/laserstream/websockets.py +1 -1
- {helius_python-0.3.3 → helius_python-0.4.0}/src/helius/solana_rpc/client.py +1 -1
- {helius_python-0.3.3 → helius_python-0.4.0}/src/helius/solana_rpc/models.py +0 -2
- helius_python-0.4.0/src/helius/utils/__init__.py +3 -0
- helius_python-0.4.0/src/helius/webhooks/__init__.py +0 -0
- helius_python-0.4.0/src/helius/webhooks/webhooks.py +722 -0
- helius_python-0.4.0/test_examples.py +226 -0
- {helius_python-0.3.3/tests/unit/rpc → helius_python-0.4.0/tests/unit/utils}/test_json_rpc_request.py +1 -1
- helius_python-0.4.0/tests/unit/webhooks/test_webhook.py +26 -0
- helius_python-0.4.0/tests/unit/webhooks/test_webhooks_api_client.py +168 -0
- helius_python-0.3.3/src/helius/rpc/__init__.py +0 -3
- {helius_python-0.3.3 → helius_python-0.4.0}/.editorconfig +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/.github/workflows/python-package.yml +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/.github/workflows/python-publish.yml +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/.gitignore +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/AGENTS.md +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/CLAUDE.md +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/CONTRIBUTING.md +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/LICENSE +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/requirements.txt +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/src/helius/__init__.py +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/src/helius/admin/__init__.py +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/src/helius/admin/admin.py +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/src/helius/solana_rpc/__init__.py +0 -0
- {helius_python-0.3.3/src/helius/rpc → helius_python-0.4.0/src/helius/utils}/json_rpc_request.py +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/tests/fixtures/account.json +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/tests/fixtures/supply.json +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/tests/unit/admin/test_admin.py +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/tests/unit/lasterstream/test_websockets.py +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/tests/unit/solana_rpc/test_client.py +0 -0
- {helius_python-0.3.3 → helius_python-0.4.0}/tests/unit/solana_rpc/test_models.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: helius-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Typed Python client for the Helius API
|
|
5
5
|
Project-URL: Homepage, https://github.com/markosnarinian/helius-python
|
|
6
6
|
Project-URL: Issues, https://github.com/markosnarinian/helius-python/issues
|
|
@@ -135,9 +135,10 @@ wraps it.
|
|
|
135
135
|
- 🚧 **All Helius-specific RPC extensions** — enhanced transactions, DAS
|
|
136
136
|
(Digital Asset Standard) methods, priority fee estimation, and the
|
|
137
137
|
rest of the Helius-only RPC namespace. **(in progress)**
|
|
138
|
-
-
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
- ✅ **Webhooks API** — create, fetch, update, enable/disable, and delete
|
|
139
|
+
Helius webhooks. **(supported today)**
|
|
140
|
+
- 🚧 **Remaining Helius REST endpoints** — Enhanced Transactions API,
|
|
141
|
+
Mint API, token metadata, address lookups, and beyond. **(in progress)**
|
|
141
142
|
- 🚧 **Platform features** — streaming, websockets, and any new
|
|
142
143
|
capability Helius adds to its API. The full WebSocket subscription
|
|
143
144
|
surface (`accountSubscribe`, `transactionSubscribe`, `logsSubscribe`,
|
|
@@ -145,10 +146,10 @@ wraps it.
|
|
|
145
146
|
platform features are **in progress**.
|
|
146
147
|
|
|
147
148
|
**Current status:** the standard Solana JSON-RPC surface, the
|
|
148
|
-
WebSocket subscription surface, and the Admin
|
|
149
|
-
usage endpoint are implemented today. Support for
|
|
150
|
-
extensions and the remaining REST endpoints is actively
|
|
151
|
-
on.
|
|
149
|
+
WebSocket subscription surface, the Webhooks API, and the Admin
|
|
150
|
+
(account management) usage endpoint are implemented today. Support for
|
|
151
|
+
Helius RPC extensions and the remaining REST endpoints is actively
|
|
152
|
+
being worked on.
|
|
152
153
|
|
|
153
154
|
## Goals
|
|
154
155
|
|
|
@@ -266,9 +267,9 @@ The method names map 1:1 to the Solana JSON-RPC spec, just converted to
|
|
|
266
267
|
## Status
|
|
267
268
|
|
|
268
269
|
Actively expanding toward full coverage of the Helius API. See
|
|
269
|
-
[`src/helius/solana_rpc.py`](src/helius/solana_rpc.py) for the
|
|
270
|
-
|
|
271
|
-
continuously.
|
|
270
|
+
[`src/helius/solana_rpc/client.py`](src/helius/solana_rpc/client.py) for the
|
|
271
|
+
current Solana JSON-RPC implementation; supported surfaces are listed below,
|
|
272
|
+
and missing endpoints are tracked as issues and added continuously.
|
|
272
273
|
|
|
273
274
|
| Solana JSON-RPC method | Python method | Helius docs |
|
|
274
275
|
| ----------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
@@ -372,6 +373,44 @@ them; both yield a `(context, notification, subscription)` tuple where
|
|
|
372
373
|
| `vote_subscribe()` | `vote_unsubscribe(...)` | `VoteNotification` | [reference](https://www.helius.dev/docs/api-reference/rpc/websocket/votesubscribe) |
|
|
373
374
|
| `transaction_subscribe(...)` | `transaction_unsubscribe(...)` | `TransactionNotification` | [reference](https://www.helius.dev/docs/api-reference/rpc/websocket/slotunsubscribe) |
|
|
374
375
|
|
|
376
|
+
## Webhooks API
|
|
377
|
+
|
|
378
|
+
`WebhooksApiClient` wraps the Helius Webhooks REST API. It can create,
|
|
379
|
+
fetch, list, update, enable/disable, and delete webhook subscriptions,
|
|
380
|
+
returning typed `Webhook` models where the endpoint returns a webhook.
|
|
381
|
+
|
|
382
|
+
```python
|
|
383
|
+
from helius.webhooks.webhooks import WebhooksApiClient
|
|
384
|
+
|
|
385
|
+
with WebhooksApiClient(api_key="YOUR_HELIUS_API_KEY") as webhooks:
|
|
386
|
+
webhook = webhooks.create_webhook(
|
|
387
|
+
webhook_url="https://example.com/helius-webhook",
|
|
388
|
+
transaction_types=["TRANSFER"],
|
|
389
|
+
account_addresses=["So11111111111111111111111111111111111111112"],
|
|
390
|
+
webhook_type="enhanced",
|
|
391
|
+
auth_header="Bearer your-shared-secret",
|
|
392
|
+
encoding="jsonParsed",
|
|
393
|
+
txn_status="all",
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
webhooks.toggle_webhook(webhook.webhook_id, active=False)
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Like the other clients, it supports the context-manager protocol and a
|
|
400
|
+
manual `close()`. The constructor defaults to
|
|
401
|
+
`https://mainnet.helius-rpc.com/v0/webhooks` and reads `HELIUS_API_KEY`
|
|
402
|
+
from the environment or `.env` when `api_key` is omitted; optional
|
|
403
|
+
`headers` and `proxy` arguments are also accepted.
|
|
404
|
+
|
|
405
|
+
| REST operation | Python method | Helius docs |
|
|
406
|
+
| -------------- | -------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
407
|
+
| Create webhook | `create_webhook(...)` | [reference](https://www.helius.dev/docs/api-reference/webhooks/create-webhook) |
|
|
408
|
+
| Get webhook | `get_webhook(...)` | [reference](https://www.helius.dev/docs/api-reference/webhooks/get-webhook) |
|
|
409
|
+
| List webhooks | `get_all_webhooks()` | [reference](https://www.helius.dev/docs/api-reference/webhooks/get-all-webhooks) |
|
|
410
|
+
| Update webhook | `update_webhook(...)` | [reference](https://www.helius.dev/docs/api-reference/webhooks/update-webhook) |
|
|
411
|
+
| Toggle webhook | `toggle_webhook(...)` | [reference](https://www.helius.dev/docs/api-reference/webhooks/toggle-webhook) |
|
|
412
|
+
| Delete webhook | `delete_webhook(...)` | [reference](https://www.helius.dev/docs/api-reference/webhooks/delete-webhook) |
|
|
413
|
+
|
|
375
414
|
## Admin API
|
|
376
415
|
|
|
377
416
|
`AccountManagementClient` wraps the Helius admin API. Today it exposes
|
|
@@ -113,9 +113,10 @@ wraps it.
|
|
|
113
113
|
- 🚧 **All Helius-specific RPC extensions** — enhanced transactions, DAS
|
|
114
114
|
(Digital Asset Standard) methods, priority fee estimation, and the
|
|
115
115
|
rest of the Helius-only RPC namespace. **(in progress)**
|
|
116
|
-
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
- ✅ **Webhooks API** — create, fetch, update, enable/disable, and delete
|
|
117
|
+
Helius webhooks. **(supported today)**
|
|
118
|
+
- 🚧 **Remaining Helius REST endpoints** — Enhanced Transactions API,
|
|
119
|
+
Mint API, token metadata, address lookups, and beyond. **(in progress)**
|
|
119
120
|
- 🚧 **Platform features** — streaming, websockets, and any new
|
|
120
121
|
capability Helius adds to its API. The full WebSocket subscription
|
|
121
122
|
surface (`accountSubscribe`, `transactionSubscribe`, `logsSubscribe`,
|
|
@@ -123,10 +124,10 @@ wraps it.
|
|
|
123
124
|
platform features are **in progress**.
|
|
124
125
|
|
|
125
126
|
**Current status:** the standard Solana JSON-RPC surface, the
|
|
126
|
-
WebSocket subscription surface, and the Admin
|
|
127
|
-
usage endpoint are implemented today. Support for
|
|
128
|
-
extensions and the remaining REST endpoints is actively
|
|
129
|
-
on.
|
|
127
|
+
WebSocket subscription surface, the Webhooks API, and the Admin
|
|
128
|
+
(account management) usage endpoint are implemented today. Support for
|
|
129
|
+
Helius RPC extensions and the remaining REST endpoints is actively
|
|
130
|
+
being worked on.
|
|
130
131
|
|
|
131
132
|
## Goals
|
|
132
133
|
|
|
@@ -244,9 +245,9 @@ The method names map 1:1 to the Solana JSON-RPC spec, just converted to
|
|
|
244
245
|
## Status
|
|
245
246
|
|
|
246
247
|
Actively expanding toward full coverage of the Helius API. See
|
|
247
|
-
[`src/helius/solana_rpc.py`](src/helius/solana_rpc.py) for the
|
|
248
|
-
|
|
249
|
-
continuously.
|
|
248
|
+
[`src/helius/solana_rpc/client.py`](src/helius/solana_rpc/client.py) for the
|
|
249
|
+
current Solana JSON-RPC implementation; supported surfaces are listed below,
|
|
250
|
+
and missing endpoints are tracked as issues and added continuously.
|
|
250
251
|
|
|
251
252
|
| Solana JSON-RPC method | Python method | Helius docs |
|
|
252
253
|
| ----------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
@@ -350,6 +351,44 @@ them; both yield a `(context, notification, subscription)` tuple where
|
|
|
350
351
|
| `vote_subscribe()` | `vote_unsubscribe(...)` | `VoteNotification` | [reference](https://www.helius.dev/docs/api-reference/rpc/websocket/votesubscribe) |
|
|
351
352
|
| `transaction_subscribe(...)` | `transaction_unsubscribe(...)` | `TransactionNotification` | [reference](https://www.helius.dev/docs/api-reference/rpc/websocket/slotunsubscribe) |
|
|
352
353
|
|
|
354
|
+
## Webhooks API
|
|
355
|
+
|
|
356
|
+
`WebhooksApiClient` wraps the Helius Webhooks REST API. It can create,
|
|
357
|
+
fetch, list, update, enable/disable, and delete webhook subscriptions,
|
|
358
|
+
returning typed `Webhook` models where the endpoint returns a webhook.
|
|
359
|
+
|
|
360
|
+
```python
|
|
361
|
+
from helius.webhooks.webhooks import WebhooksApiClient
|
|
362
|
+
|
|
363
|
+
with WebhooksApiClient(api_key="YOUR_HELIUS_API_KEY") as webhooks:
|
|
364
|
+
webhook = webhooks.create_webhook(
|
|
365
|
+
webhook_url="https://example.com/helius-webhook",
|
|
366
|
+
transaction_types=["TRANSFER"],
|
|
367
|
+
account_addresses=["So11111111111111111111111111111111111111112"],
|
|
368
|
+
webhook_type="enhanced",
|
|
369
|
+
auth_header="Bearer your-shared-secret",
|
|
370
|
+
encoding="jsonParsed",
|
|
371
|
+
txn_status="all",
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
webhooks.toggle_webhook(webhook.webhook_id, active=False)
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Like the other clients, it supports the context-manager protocol and a
|
|
378
|
+
manual `close()`. The constructor defaults to
|
|
379
|
+
`https://mainnet.helius-rpc.com/v0/webhooks` and reads `HELIUS_API_KEY`
|
|
380
|
+
from the environment or `.env` when `api_key` is omitted; optional
|
|
381
|
+
`headers` and `proxy` arguments are also accepted.
|
|
382
|
+
|
|
383
|
+
| REST operation | Python method | Helius docs |
|
|
384
|
+
| -------------- | -------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
385
|
+
| Create webhook | `create_webhook(...)` | [reference](https://www.helius.dev/docs/api-reference/webhooks/create-webhook) |
|
|
386
|
+
| Get webhook | `get_webhook(...)` | [reference](https://www.helius.dev/docs/api-reference/webhooks/get-webhook) |
|
|
387
|
+
| List webhooks | `get_all_webhooks()` | [reference](https://www.helius.dev/docs/api-reference/webhooks/get-all-webhooks) |
|
|
388
|
+
| Update webhook | `update_webhook(...)` | [reference](https://www.helius.dev/docs/api-reference/webhooks/update-webhook) |
|
|
389
|
+
| Toggle webhook | `toggle_webhook(...)` | [reference](https://www.helius.dev/docs/api-reference/webhooks/toggle-webhook) |
|
|
390
|
+
| Delete webhook | `delete_webhook(...)` | [reference](https://www.helius.dev/docs/api-reference/webhooks/delete-webhook) |
|
|
391
|
+
|
|
353
392
|
## Admin API
|
|
354
393
|
|
|
355
394
|
`AccountManagementClient` wraps the Helius admin API. Today it exposes
|
|
@@ -2,3 +2,5 @@
|
|
|
2
2
|
- WebSocket subscription manager
|
|
3
3
|
- Use typeddicts where useful
|
|
4
4
|
- When Python 3.10 and 3.11 go out of support we should use TypedDict from typing instead of typing_extensions
|
|
5
|
+
- Improve camelCase <-> snake_case in typing
|
|
6
|
+
- Handle HTTP response codes and idiomatic error messages in responses
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Listen for Solana log notifications over Helius WebSockets.
|
|
2
|
+
|
|
3
|
+
Subscribes with `logsSubscribe`, prints a small number of notifications,
|
|
4
|
+
then unsubscribes cleanly. Use `--mentions <ADDRESS>` to filter logs to a
|
|
5
|
+
single account or program; otherwise the example listens to all logs.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
|
|
9
|
+
export HELIUS_API_KEY=your_helius_api_key
|
|
10
|
+
python examples/laserstream/websocket_logs.py --mentions <ADDRESS>
|
|
11
|
+
python examples/laserstream/websocket_logs.py --count 3
|
|
12
|
+
|
|
13
|
+
Docs:
|
|
14
|
+
https://www.helius.dev/docs/api-reference/rpc/websocket/logssubscribe
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import argparse
|
|
20
|
+
from contextlib import suppress
|
|
21
|
+
import sys
|
|
22
|
+
|
|
23
|
+
from helius.laserstream.websockets import WebSocketClient
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main() -> int:
|
|
27
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
28
|
+
parser.add_argument(
|
|
29
|
+
"--mentions",
|
|
30
|
+
help="Only receive logs mentioning this account or program address",
|
|
31
|
+
)
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--count",
|
|
34
|
+
type=int,
|
|
35
|
+
default=5,
|
|
36
|
+
help="Number of notifications to print before exiting (default 5)",
|
|
37
|
+
)
|
|
38
|
+
args = parser.parse_args()
|
|
39
|
+
|
|
40
|
+
log_filter = {"mentions": [args.mentions]} if args.mentions else "all"
|
|
41
|
+
|
|
42
|
+
with WebSocketClient() as client:
|
|
43
|
+
subscription = client.logs_subscribe(
|
|
44
|
+
filter=log_filter,
|
|
45
|
+
commitment="confirmed",
|
|
46
|
+
)
|
|
47
|
+
print(f"Subscribed to logs with id {subscription}. Waiting...\n")
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
for index, (context, notification, _subscription) in enumerate(
|
|
51
|
+
client.listen(), start=1
|
|
52
|
+
):
|
|
53
|
+
slot = context.get("slot") if context else "unknown"
|
|
54
|
+
status = "ERR" if notification.err else "OK "
|
|
55
|
+
print(f"[{index}/{args.count}] slot={slot} {status} {notification.signature}")
|
|
56
|
+
for line in notification.logs[:5]:
|
|
57
|
+
print(f" {line}")
|
|
58
|
+
if len(notification.logs) > 5:
|
|
59
|
+
print(f" ... {len(notification.logs) - 5} more log lines")
|
|
60
|
+
print()
|
|
61
|
+
if index >= args.count:
|
|
62
|
+
break
|
|
63
|
+
finally:
|
|
64
|
+
# A busy `logsSubscribe` stream can deliver another notification
|
|
65
|
+
# between our unsubscribe request and the unsubscribe response. The
|
|
66
|
+
# client helper currently expects the very next frame to be the RPC
|
|
67
|
+
# response, so ignore that race here and let the context manager
|
|
68
|
+
# close the socket cleanly.
|
|
69
|
+
with suppress(KeyError):
|
|
70
|
+
client.logs_unsubscribe(subscription)
|
|
71
|
+
|
|
72
|
+
return 0
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
if __name__ == "__main__":
|
|
76
|
+
sys.exit(main())
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""List Helius enhanced transactions for an address.
|
|
2
|
+
|
|
3
|
+
Uses Helius's `getTransactionsForAddress` RPC method, which can return
|
|
4
|
+
either compact signature rows or full transaction payloads with pagination.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
|
|
8
|
+
export HELIUS_API_KEY=your_helius_api_key
|
|
9
|
+
python examples/solana_rpc/address_transactions.py <ADDRESS> [--limit 10]
|
|
10
|
+
python examples/solana_rpc/address_transactions.py <ADDRESS> --full --limit 5
|
|
11
|
+
|
|
12
|
+
Docs:
|
|
13
|
+
https://www.helius.dev/docs/getting-data/get-transactions-for-address
|
|
14
|
+
|
|
15
|
+
Note:
|
|
16
|
+
Helius documents this exclusive RPC method as requiring a Developer plan
|
|
17
|
+
or higher.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import argparse
|
|
23
|
+
import datetime as dt
|
|
24
|
+
import sys
|
|
25
|
+
|
|
26
|
+
import httpx
|
|
27
|
+
|
|
28
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def format_time(block_time: int | None) -> str:
|
|
32
|
+
if block_time is None:
|
|
33
|
+
return "(no time)"
|
|
34
|
+
return dt.datetime.fromtimestamp(block_time, tz=dt.timezone.utc).strftime(
|
|
35
|
+
"%Y-%m-%d %H:%M:%SZ"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def main() -> int:
|
|
40
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
41
|
+
parser.add_argument("address", help="Wallet, account, or program address")
|
|
42
|
+
parser.add_argument(
|
|
43
|
+
"--limit",
|
|
44
|
+
type=int,
|
|
45
|
+
default=10,
|
|
46
|
+
help="Number of rows to fetch (1-1000, default 10)",
|
|
47
|
+
)
|
|
48
|
+
parser.add_argument(
|
|
49
|
+
"--pagination-token",
|
|
50
|
+
help="Token returned by a previous page of results",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"--full",
|
|
54
|
+
action="store_true",
|
|
55
|
+
help="Fetch full transaction details instead of signature rows",
|
|
56
|
+
)
|
|
57
|
+
parser.add_argument(
|
|
58
|
+
"--dry-run",
|
|
59
|
+
action="store_true",
|
|
60
|
+
help="Validate arguments and print the planned request without sending it",
|
|
61
|
+
)
|
|
62
|
+
args = parser.parse_args()
|
|
63
|
+
|
|
64
|
+
details = "full" if args.full else "signatures"
|
|
65
|
+
if args.dry_run:
|
|
66
|
+
print("Would call get_transactions_for_address with:")
|
|
67
|
+
print(f" address={args.address}")
|
|
68
|
+
print(f" transaction_details={details}")
|
|
69
|
+
print(f" limit={args.limit}")
|
|
70
|
+
print(f" pagination_token={args.pagination_token}")
|
|
71
|
+
print(f" encoding={'jsonParsed' if args.full else None}")
|
|
72
|
+
return 0
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
with SolanaRpcClient() as client:
|
|
76
|
+
transactions, next_token = client.get_transactions_for_address(
|
|
77
|
+
address=args.address,
|
|
78
|
+
transaction_details=details,
|
|
79
|
+
sort_order="desc",
|
|
80
|
+
commitment="finalized",
|
|
81
|
+
limit=args.limit,
|
|
82
|
+
pagination_token=args.pagination_token,
|
|
83
|
+
encoding="jsonParsed" if args.full else None,
|
|
84
|
+
max_supported_transaction_version=0 if args.full else None,
|
|
85
|
+
)
|
|
86
|
+
except httpx.HTTPStatusError as exc:
|
|
87
|
+
print(
|
|
88
|
+
f"HTTP {exc.response.status_code}: getTransactionsForAddress was rejected. "
|
|
89
|
+
"This Helius-exclusive method may require a Developer plan or higher.",
|
|
90
|
+
file=sys.stderr,
|
|
91
|
+
)
|
|
92
|
+
return 2
|
|
93
|
+
|
|
94
|
+
print(f"\n=== Transactions for {args.address} ===\n")
|
|
95
|
+
if not transactions:
|
|
96
|
+
print("No transactions returned.")
|
|
97
|
+
return 0
|
|
98
|
+
|
|
99
|
+
for tx in transactions:
|
|
100
|
+
if details == "signatures":
|
|
101
|
+
status = "ERR" if tx.err else "OK "
|
|
102
|
+
print(
|
|
103
|
+
f"{format_time(tx.block_time)} slot={tx.slot:<12} "
|
|
104
|
+
f"idx={tx.transaction_index:<4} {status} {tx.signature}"
|
|
105
|
+
)
|
|
106
|
+
else:
|
|
107
|
+
signature = "(signature unavailable)"
|
|
108
|
+
signatures = tx.transaction.get("signatures")
|
|
109
|
+
if isinstance(signatures, list) and signatures:
|
|
110
|
+
signature = signatures[0]
|
|
111
|
+
err = tx.meta.get("err") if isinstance(tx.meta, dict) else None
|
|
112
|
+
status = "ERR" if err else "OK "
|
|
113
|
+
print(
|
|
114
|
+
f"{format_time(tx.block_time)} slot={tx.slot:<12} "
|
|
115
|
+
f"idx={tx.transaction_index:<4} {status} {signature}"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
if next_token:
|
|
119
|
+
print(f"\nNext page token: {next_token}")
|
|
120
|
+
|
|
121
|
+
return 0
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
if __name__ == "__main__":
|
|
125
|
+
sys.exit(main())
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""List token and SOL transfers for an address.
|
|
2
|
+
|
|
3
|
+
Uses Helius's `getTransfersByAddress` RPC method exposed by this client as
|
|
4
|
+
`get_transfers_by_address`.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
|
|
8
|
+
export HELIUS_API_KEY=your_helius_api_key
|
|
9
|
+
python examples/solana_rpc/address_transfers.py <ADDRESS> [--limit 20]
|
|
10
|
+
python examples/solana_rpc/address_transfers.py <ADDRESS> --direction in --mint <MINT>
|
|
11
|
+
|
|
12
|
+
Docs:
|
|
13
|
+
https://www.helius.dev/docs/getting-data/get-transfers-by-address
|
|
14
|
+
|
|
15
|
+
Note:
|
|
16
|
+
Helius documents this exclusive RPC method as requiring a Developer plan
|
|
17
|
+
or higher.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import argparse
|
|
23
|
+
import datetime as dt
|
|
24
|
+
import sys
|
|
25
|
+
|
|
26
|
+
import httpx
|
|
27
|
+
|
|
28
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def format_time(block_time: int) -> str:
|
|
32
|
+
return dt.datetime.fromtimestamp(block_time, tz=dt.timezone.utc).strftime(
|
|
33
|
+
"%Y-%m-%d %H:%M:%SZ"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def main() -> int:
|
|
38
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
39
|
+
parser.add_argument("address", help="Wallet, token account, or owner address")
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"--limit",
|
|
42
|
+
type=int,
|
|
43
|
+
default=20,
|
|
44
|
+
help="Number of transfers to fetch (1-100, default 20)",
|
|
45
|
+
)
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
"--direction",
|
|
48
|
+
choices=("in", "out", "any"),
|
|
49
|
+
default="any",
|
|
50
|
+
help="Transfer direction relative to address (default any)",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument("--with-address", help="Counterparty address filter")
|
|
53
|
+
parser.add_argument("--mint", help="Mint address filter")
|
|
54
|
+
parser.add_argument(
|
|
55
|
+
"--pagination-token",
|
|
56
|
+
help="Token returned by a previous page of results",
|
|
57
|
+
)
|
|
58
|
+
parser.add_argument(
|
|
59
|
+
"--dry-run",
|
|
60
|
+
action="store_true",
|
|
61
|
+
help="Validate arguments and print the planned request without sending it",
|
|
62
|
+
)
|
|
63
|
+
args = parser.parse_args()
|
|
64
|
+
|
|
65
|
+
if args.dry_run:
|
|
66
|
+
print("Would call get_transfers_by_address with:")
|
|
67
|
+
print(f" address={args.address}")
|
|
68
|
+
print(f" with_address={args.with_address}")
|
|
69
|
+
print(f" direction={args.direction}")
|
|
70
|
+
print(f" mint={args.mint}")
|
|
71
|
+
print(f" limit={args.limit}")
|
|
72
|
+
print(f" pagination_token={args.pagination_token}")
|
|
73
|
+
return 0
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
with SolanaRpcClient() as client:
|
|
77
|
+
transfers, next_token = client.get_transfers_by_address(
|
|
78
|
+
address=args.address,
|
|
79
|
+
with_address=args.with_address,
|
|
80
|
+
direction=args.direction,
|
|
81
|
+
mint=args.mint,
|
|
82
|
+
limit=args.limit,
|
|
83
|
+
pagination_token=args.pagination_token,
|
|
84
|
+
commitment="finalized",
|
|
85
|
+
sort_order="desc",
|
|
86
|
+
)
|
|
87
|
+
except httpx.HTTPStatusError as exc:
|
|
88
|
+
print(
|
|
89
|
+
f"HTTP {exc.response.status_code}: getTransfersByAddress was rejected. "
|
|
90
|
+
"This Helius-exclusive method may require a Developer plan or higher.",
|
|
91
|
+
file=sys.stderr,
|
|
92
|
+
)
|
|
93
|
+
return 2
|
|
94
|
+
|
|
95
|
+
print(f"\n=== Transfers for {args.address} ===\n")
|
|
96
|
+
if not transfers:
|
|
97
|
+
print("No transfers returned.")
|
|
98
|
+
return 0
|
|
99
|
+
|
|
100
|
+
for transfer in transfers:
|
|
101
|
+
from_acct = transfer.from_user_account or transfer.from_token_account or "-"
|
|
102
|
+
to_acct = transfer.to_user_account or transfer.to_token_account or "-"
|
|
103
|
+
print(
|
|
104
|
+
f"{format_time(transfer.block_time)} slot={transfer.slot:<12} "
|
|
105
|
+
f"{transfer.type:<11} {transfer.ui_amount:>18} mint={transfer.mint}"
|
|
106
|
+
)
|
|
107
|
+
print(f" from={from_acct}")
|
|
108
|
+
print(f" to ={to_acct}")
|
|
109
|
+
print(f" sig ={transfer.signature}")
|
|
110
|
+
|
|
111
|
+
if next_token:
|
|
112
|
+
print(f"\nNext page token: {next_token}")
|
|
113
|
+
|
|
114
|
+
return 0
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if __name__ == "__main__":
|
|
118
|
+
sys.exit(main())
|
|
@@ -8,8 +8,8 @@ breakdown of successful vs. failed transactions plus total fees paid.
|
|
|
8
8
|
Usage:
|
|
9
9
|
|
|
10
10
|
export HELIUS_API_KEY=your_helius_api_key
|
|
11
|
-
python examples/block_explorer.py
|
|
12
|
-
python examples/block_explorer.py --slot 250000000
|
|
11
|
+
python examples/solana_rpc/block_explorer.py
|
|
12
|
+
python examples/solana_rpc/block_explorer.py --slot 250000000
|
|
13
13
|
|
|
14
14
|
Uses (with `with`):
|
|
15
15
|
get_slot, get_block.
|
|
@@ -43,9 +43,10 @@ def main() -> int:
|
|
|
43
43
|
else helius.get_slot(commitment="finalized")
|
|
44
44
|
)
|
|
45
45
|
block = helius.get_block(
|
|
46
|
-
slot,
|
|
46
|
+
slot=slot,
|
|
47
47
|
commitment="finalized",
|
|
48
48
|
encoding="jsonParsed",
|
|
49
|
+
rewards=False,
|
|
49
50
|
max_supported_transcation_version=0,
|
|
50
51
|
)
|
|
51
52
|
|
|
@@ -7,7 +7,7 @@ polls `getSignatureStatuses` until the airdrop transaction reaches a
|
|
|
7
7
|
Usage:
|
|
8
8
|
|
|
9
9
|
export HELIUS_API_KEY=your_helius_api_key
|
|
10
|
-
python examples/devnet_airdrop.py <WALLET_ADDRESS> [--sol 1.0]
|
|
10
|
+
python examples/solana_rpc/devnet_airdrop.py <WALLET_ADDRESS> [--sol 1.0]
|
|
11
11
|
|
|
12
12
|
Note:
|
|
13
13
|
`requestAirdrop` is only available on Devnet and Testnet — never on
|
|
@@ -24,6 +24,8 @@ import argparse
|
|
|
24
24
|
import sys
|
|
25
25
|
import time
|
|
26
26
|
|
|
27
|
+
import httpx
|
|
28
|
+
|
|
27
29
|
from helius.solana_rpc import SolanaRpcClient
|
|
28
30
|
|
|
29
31
|
LAMPORTS_PER_SOL = 1_000_000_000
|
|
@@ -45,20 +47,40 @@ def main() -> int:
|
|
|
45
47
|
default=30.0,
|
|
46
48
|
help="Seconds to wait for confirmation (default: 30)",
|
|
47
49
|
)
|
|
50
|
+
parser.add_argument(
|
|
51
|
+
"--dry-run",
|
|
52
|
+
action="store_true",
|
|
53
|
+
help="Validate arguments and print the planned airdrop without sending it",
|
|
54
|
+
)
|
|
48
55
|
args = parser.parse_args()
|
|
49
56
|
lamports = int(args.sol * LAMPORTS_PER_SOL)
|
|
50
57
|
|
|
58
|
+
if args.dry_run:
|
|
59
|
+
print("Would request devnet airdrop with:")
|
|
60
|
+
print(f" address={args.address}")
|
|
61
|
+
print(f" sol={args.sol}")
|
|
62
|
+
print(f" lamports={lamports}")
|
|
63
|
+
print(f" timeout={args.timeout}")
|
|
64
|
+
return 0
|
|
65
|
+
|
|
51
66
|
client = SolanaRpcClient(base_url=DEVNET_URL)
|
|
52
67
|
try:
|
|
53
68
|
print(f"Requesting {args.sol} SOL airdrop to {args.address} on devnet...")
|
|
54
|
-
|
|
69
|
+
try:
|
|
70
|
+
signature = client.request_airdrop(public_key=args.address, lamports=lamports)
|
|
71
|
+
except httpx.HTTPStatusError as exc:
|
|
72
|
+
print(
|
|
73
|
+
f"HTTP {exc.response.status_code}: devnet airdrop request was rejected.",
|
|
74
|
+
file=sys.stderr,
|
|
75
|
+
)
|
|
76
|
+
return 2
|
|
55
77
|
print(f" signature: {signature}")
|
|
56
78
|
|
|
57
79
|
deadline = time.monotonic() + args.timeout
|
|
58
80
|
status = None
|
|
59
81
|
while time.monotonic() < deadline:
|
|
60
82
|
_ctx, statuses = client.get_signature_statuses(
|
|
61
|
-
[signature], search_transaction_history=True
|
|
83
|
+
signatures=[signature], search_transaction_history=True
|
|
62
84
|
)
|
|
63
85
|
status = statuses[0]
|
|
64
86
|
if status is not None and status.confirmation_status in (
|
|
@@ -79,7 +101,7 @@ def main() -> int:
|
|
|
79
101
|
return 1
|
|
80
102
|
print(f" status: {status.confirmation_status} at slot {status.slot}")
|
|
81
103
|
|
|
82
|
-
_ctx, balance = client.get_balance(args.address)
|
|
104
|
+
_ctx, balance = client.get_balance(public_key=args.address)
|
|
83
105
|
print(f"Post-airdrop balance: {balance / LAMPORTS_PER_SOL:.9f} SOL")
|
|
84
106
|
finally:
|
|
85
107
|
client.close()
|
|
@@ -7,7 +7,7 @@ recent-performance summary (avg TPS over the last samples).
|
|
|
7
7
|
Usage:
|
|
8
8
|
|
|
9
9
|
export HELIUS_API_KEY=your_helius_api_key
|
|
10
|
-
python examples/network_status.py
|
|
10
|
+
python examples/solana_rpc/network_status.py
|
|
11
11
|
|
|
12
12
|
Uses (with `with`):
|
|
13
13
|
get_health, get_version, get_slot, get_block_height, get_epoch_info,
|
|
@@ -12,8 +12,8 @@ sample only counts transactions that locked those accounts as writable
|
|
|
12
12
|
Usage:
|
|
13
13
|
|
|
14
14
|
export HELIUS_API_KEY=your_helius_api_key
|
|
15
|
-
python examples/priority_fees.py
|
|
16
|
-
python examples/priority_fees.py --account <PUBKEY> --account <PUBKEY>
|
|
15
|
+
python examples/solana_rpc/priority_fees.py
|
|
16
|
+
python examples/solana_rpc/priority_fees.py --account <PUBKEY> --account <PUBKEY>
|
|
17
17
|
|
|
18
18
|
Uses (with `with`):
|
|
19
19
|
get_recent_prioritization_fees.
|
|
@@ -7,7 +7,7 @@ validator set (top 10 by stake).
|
|
|
7
7
|
Usage:
|
|
8
8
|
|
|
9
9
|
export HELIUS_API_KEY=your_helius_api_key
|
|
10
|
-
python examples/stake_overview.py
|
|
10
|
+
python examples/solana_rpc/stake_overview.py
|
|
11
11
|
|
|
12
12
|
Uses (with `try/finally`):
|
|
13
13
|
get_inflation_rate, get_inflation_governor, get_supply,
|
|
@@ -18,6 +18,8 @@ from __future__ import annotations
|
|
|
18
18
|
|
|
19
19
|
import sys
|
|
20
20
|
|
|
21
|
+
import httpx
|
|
22
|
+
|
|
21
23
|
from helius.solana_rpc import SolanaRpcClient
|
|
22
24
|
|
|
23
25
|
LAMPORTS_PER_SOL = 1_000_000_000
|
|
@@ -25,10 +27,11 @@ LAMPORTS_PER_SOL = 1_000_000_000
|
|
|
25
27
|
|
|
26
28
|
def main() -> int:
|
|
27
29
|
client = SolanaRpcClient()
|
|
30
|
+
client._client.timeout = httpx.Timeout(30.0)
|
|
28
31
|
try:
|
|
29
32
|
rate = client.get_inflation_rate()
|
|
30
33
|
gov = client.get_inflation_governor()
|
|
31
|
-
_ctx, supply = client.get_supply(exclude_non_circulating_accounts_list=
|
|
34
|
+
_ctx, supply = client.get_supply(exclude_non_circulating_accounts_list=False)
|
|
32
35
|
_ctx, min_stake = client.get_stake_minimum_delegation()
|
|
33
36
|
current, delinquent = client.get_vote_accounts()
|
|
34
37
|
finally:
|