helius-python 0.3.2__tar.gz → 0.3.4__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.2 → helius_python-0.3.4}/AGENTS.md +1 -12
- {helius_python-0.3.2 → helius_python-0.3.4}/PKG-INFO +4 -1
- {helius_python-0.3.2 → helius_python-0.3.4}/README.md +2 -0
- helius_python-0.3.4/TODO.md +4 -0
- helius_python-0.3.4/examples/README.md +4 -0
- helius_python-0.3.4/examples/laserstream/websocket_logs.py +76 -0
- helius_python-0.3.4/examples/solana_rpc/address_transactions.py +125 -0
- helius_python-0.3.4/examples/solana_rpc/address_transfers.py +118 -0
- {helius_python-0.3.2/examples → helius_python-0.3.4/examples/solana_rpc}/block_explorer.py +4 -3
- {helius_python-0.3.2/examples → helius_python-0.3.4/examples/solana_rpc}/devnet_airdrop.py +26 -4
- {helius_python-0.3.2/examples → helius_python-0.3.4/examples/solana_rpc}/network_status.py +1 -1
- {helius_python-0.3.2/examples → helius_python-0.3.4/examples/solana_rpc}/priority_fees.py +2 -2
- {helius_python-0.3.2/examples → helius_python-0.3.4/examples/solana_rpc}/stake_overview.py +5 -2
- {helius_python-0.3.2/examples → helius_python-0.3.4/examples/solana_rpc}/token_inspector.py +12 -5
- {helius_python-0.3.2/examples → helius_python-0.3.4/examples/solana_rpc}/transaction_inspector.py +2 -2
- {helius_python-0.3.2/examples → helius_python-0.3.4/examples/solana_rpc}/wallet_tracker.py +4 -4
- {helius_python-0.3.2 → helius_python-0.3.4}/pyproject.toml +2 -1
- {helius_python-0.3.2 → helius_python-0.3.4}/src/helius/laserstream/websockets.py +2 -1
- {helius_python-0.3.2 → helius_python-0.3.4}/src/helius/solana_rpc/client.py +85 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/src/helius/solana_rpc/models.py +98 -0
- helius_python-0.3.4/test_examples.py +216 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/tests/unit/solana_rpc/test_client.py +333 -0
- helius_python-0.3.2/TODO.md +0 -3
- {helius_python-0.3.2 → helius_python-0.3.4}/.editorconfig +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/.github/workflows/python-package.yml +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/.github/workflows/python-publish.yml +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/.gitignore +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/CLAUDE.md +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/CONTRIBUTING.md +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/LICENSE +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/requirements.txt +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/src/helius/__init__.py +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/src/helius/admin/__init__.py +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/src/helius/admin/admin.py +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/src/helius/rpc/__init__.py +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/src/helius/rpc/json_rpc_request.py +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/src/helius/solana_rpc/__init__.py +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/tests/fixtures/account.json +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/tests/fixtures/supply.json +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/tests/unit/admin/test_admin.py +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/tests/unit/lasterstream/test_websockets.py +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/tests/unit/rpc/test_json_rpc_request.py +0 -0
- {helius_python-0.3.2 → helius_python-0.3.4}/tests/unit/solana_rpc/test_models.py +0 -0
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
## Conventions
|
|
3
|
-
|
|
4
|
-
- Use **double-quoted triple strings** (`"""..."""`).
|
|
5
|
-
- Wrap docstring lines at 88 columns.
|
|
6
|
-
- Refer to parameters in backticks: `` `commitment` ``, `` `min_context_slot` ``.
|
|
7
|
-
- Refer to other client methods with their snake_case name in backticks: `` `get_balance` ``.
|
|
8
|
-
- Do NOT include the upstream JSON-RPC method name in the summary — that's already in the See Also URLs.
|
|
9
|
-
- Do NOT copy-paste large chunks from the Helius docs. Summarize and link.
|
|
10
|
-
- Examples (`Example:` section) are encouraged for methods with non-trivial argument combinations (e.g. `get_block_production`, `get_token_accounts_by_owner`), optional for everything else.
|
|
11
|
-
|
|
12
1
|
## Implementation conventions
|
|
13
2
|
|
|
14
3
|
- **If the RPC returns an `RpcResponse` wrapper (`{context, value}`), the Python method MUST return `(context, value)`** — never silently drop `context`. For methods whose `value` is itself a small composite, flatten the tuple (e.g. `get_latest_blockhash` returns `tuple[dict, str, int]`, not `tuple[dict, tuple[str, int]]`). Check the upstream Helius API reference page to see whether the response is wrapped.
|
|
@@ -124,7 +113,7 @@ For methods with branching logic (e.g. `get_block_production`, `get_token_accoun
|
|
|
124
113
|
## Running
|
|
125
114
|
|
|
126
115
|
```bash
|
|
127
|
-
pytest
|
|
116
|
+
.venv/bin/pytest
|
|
128
117
|
```
|
|
129
118
|
|
|
130
119
|
All tests must pass and there must be no real network traffic. If a test fails because it tried to hit the network, that's a bug in the test — add the missing `@respx.mock` or `respx` route.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: helius-python
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
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
|
|
@@ -13,6 +13,7 @@ Requires-Python: >=3.10
|
|
|
13
13
|
Requires-Dist: httpx
|
|
14
14
|
Requires-Dist: pydantic
|
|
15
15
|
Requires-Dist: python-dotenv
|
|
16
|
+
Requires-Dist: typing-extensions
|
|
16
17
|
Requires-Dist: websockets
|
|
17
18
|
Provides-Extra: dev
|
|
18
19
|
Requires-Dist: pytest; extra == 'dev'
|
|
@@ -322,6 +323,8 @@ continuously.
|
|
|
322
323
|
| `minimumLedgerSlot` | `minimum_ledger_slot()` | [guide](https://www.helius.dev/docs/rpc/guides/minimumledgerslot), [reference](https://www.helius.dev/docs/api-reference/rpc/http/minimumledgerslot) |
|
|
323
324
|
| `requestAirdrop` | `request_airdrop(...)` | [guide](https://www.helius.dev/docs/rpc/guides/requestairdrop), [reference](https://www.helius.dev/docs/api-reference/rpc/http/requestairdrop) |
|
|
324
325
|
| `sendTransaction` | `send_transaction(...)` | [guide](https://www.helius.dev/docs/rpc/guides/sendtransaction), [reference](https://www.helius.dev/docs/api-reference/rpc/http/sendtransaction) |
|
|
326
|
+
| `getTransactionsForAddress` | `get_transactions_for_address(...)` | [reference](https://www.helius.dev/docs/api-reference/rpc/http/gettransactionsforaddress) |
|
|
327
|
+
| `getTransfersByAddress` | `get_transfers_by_address(...)` | [guide](https://www.helius.dev/docs/rpc/gettransfersbyaddress), [reference](https://www.helius.dev/docs/api-reference/rpc/http/gettransfersbyaddress) |
|
|
325
328
|
|
|
326
329
|
## WebSocket subscriptions
|
|
327
330
|
|
|
@@ -301,6 +301,8 @@ continuously.
|
|
|
301
301
|
| `minimumLedgerSlot` | `minimum_ledger_slot()` | [guide](https://www.helius.dev/docs/rpc/guides/minimumledgerslot), [reference](https://www.helius.dev/docs/api-reference/rpc/http/minimumledgerslot) |
|
|
302
302
|
| `requestAirdrop` | `request_airdrop(...)` | [guide](https://www.helius.dev/docs/rpc/guides/requestairdrop), [reference](https://www.helius.dev/docs/api-reference/rpc/http/requestairdrop) |
|
|
303
303
|
| `sendTransaction` | `send_transaction(...)` | [guide](https://www.helius.dev/docs/rpc/guides/sendtransaction), [reference](https://www.helius.dev/docs/api-reference/rpc/http/sendtransaction) |
|
|
304
|
+
| `getTransactionsForAddress` | `get_transactions_for_address(...)` | [reference](https://www.helius.dev/docs/api-reference/rpc/http/gettransactionsforaddress) |
|
|
305
|
+
| `getTransfersByAddress` | `get_transfers_by_address(...)` | [guide](https://www.helius.dev/docs/rpc/gettransfersbyaddress), [reference](https://www.helius.dev/docs/api-reference/rpc/http/gettransfersbyaddress) |
|
|
304
306
|
|
|
305
307
|
## WebSocket subscriptions
|
|
306
308
|
|
|
@@ -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:
|
|
@@ -7,11 +7,15 @@ Given a mint address, prints:
|
|
|
7
7
|
Usage:
|
|
8
8
|
|
|
9
9
|
export HELIUS_API_KEY=your_helius_api_key
|
|
10
|
-
python examples/token_inspector.py <MINT_ADDRESS>
|
|
10
|
+
python examples/solana_rpc/token_inspector.py <MINT_ADDRESS>
|
|
11
11
|
|
|
12
|
-
Example with
|
|
12
|
+
Example with a small-holder-count mint:
|
|
13
13
|
|
|
14
|
-
python examples/token_inspector.py
|
|
14
|
+
python examples/solana_rpc/token_inspector.py J5iyNuTa6zqqA62Xe4h1VBvcBW5CTSNNva3QPh8DU5RV
|
|
15
|
+
|
|
16
|
+
Note:
|
|
17
|
+
Very large mints may be rejected by `getTokenLargestAccounts` if the
|
|
18
|
+
upstream RPC would need to scan too many accounts.
|
|
15
19
|
|
|
16
20
|
Uses (with `try/finally`):
|
|
17
21
|
get_token_supply, get_token_largest_accounts.
|
|
@@ -22,6 +26,8 @@ from __future__ import annotations
|
|
|
22
26
|
import argparse
|
|
23
27
|
import sys
|
|
24
28
|
|
|
29
|
+
import httpx
|
|
30
|
+
|
|
25
31
|
from helius.solana_rpc import SolanaRpcClient
|
|
26
32
|
|
|
27
33
|
|
|
@@ -31,9 +37,10 @@ def main() -> int:
|
|
|
31
37
|
args = parser.parse_args()
|
|
32
38
|
|
|
33
39
|
client = SolanaRpcClient()
|
|
40
|
+
client._client.timeout = httpx.Timeout(30.0)
|
|
34
41
|
try:
|
|
35
|
-
_ctx, supply = client.get_token_supply(args.mint)
|
|
36
|
-
_ctx, holders = client.get_token_largest_accounts(args.mint)
|
|
42
|
+
_ctx, supply = client.get_token_supply(mint_address=args.mint)
|
|
43
|
+
_ctx, holders = client.get_token_largest_accounts(mint=args.mint)
|
|
37
44
|
finally:
|
|
38
45
|
client.close()
|
|
39
46
|
|
{helius_python-0.3.2/examples → helius_python-0.3.4/examples/solana_rpc}/transaction_inspector.py
RENAMED
|
@@ -7,7 +7,7 @@ involved, and any log messages emitted by the on-chain programs.
|
|
|
7
7
|
Usage:
|
|
8
8
|
|
|
9
9
|
export HELIUS_API_KEY=your_helius_api_key
|
|
10
|
-
python examples/transaction_inspector.py <SIGNATURE>
|
|
10
|
+
python examples/solana_rpc/transaction_inspector.py <SIGNATURE>
|
|
11
11
|
|
|
12
12
|
Uses (with `with`):
|
|
13
13
|
get_transaction.
|
|
@@ -31,7 +31,7 @@ def main() -> int:
|
|
|
31
31
|
|
|
32
32
|
with SolanaRpcClient() as helius:
|
|
33
33
|
tx = helius.get_transaction(
|
|
34
|
-
args.signature,
|
|
34
|
+
transaction_signature=args.signature,
|
|
35
35
|
encoding="jsonParsed",
|
|
36
36
|
max_supported_transaction_version=0,
|
|
37
37
|
)
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
Usage:
|
|
4
4
|
|
|
5
5
|
export HELIUS_API_KEY=your_helius_api_key
|
|
6
|
-
python examples/wallet_tracker.py <WALLET_ADDRESS> [--limit 20]
|
|
6
|
+
python examples/solana_rpc/wallet_tracker.py <WALLET_ADDRESS> [--limit 20]
|
|
7
7
|
|
|
8
8
|
Example (Helius's own treasury-ish address, replace with any):
|
|
9
9
|
|
|
10
|
-
python examples/wallet_tracker.py 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU
|
|
10
|
+
python examples/solana_rpc/wallet_tracker.py 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU
|
|
11
11
|
|
|
12
12
|
It prints:
|
|
13
13
|
- SOL balance (in SOL, not lamports)
|
|
@@ -43,7 +43,7 @@ def main() -> int:
|
|
|
43
43
|
|
|
44
44
|
with SolanaRpcClient() as client: # reads HELIUS_API_KEY from env / .env
|
|
45
45
|
# --- SOL balance ---------------------------------------------------
|
|
46
|
-
_ctx, lamports = client.get_balance(args.address)
|
|
46
|
+
_ctx, lamports = client.get_balance(public_key=args.address)
|
|
47
47
|
print(f"\n=== {args.address} ===\n")
|
|
48
48
|
print(
|
|
49
49
|
f"SOL balance: {lamports / LAMPORTS_PER_SOL:.9f} SOL "
|
|
@@ -75,7 +75,7 @@ def main() -> int:
|
|
|
75
75
|
print("SPL token accounts: none with non-zero balance.\n")
|
|
76
76
|
|
|
77
77
|
# --- Recent activity ----------------------------------------------
|
|
78
|
-
sigs = client.get_signatures_for_address(args.address, limit=args.limit)
|
|
78
|
+
sigs = client.get_signatures_for_address(address=args.address, limit=args.limit)
|
|
79
79
|
print(f"Last {len(sigs)} signatures:")
|
|
80
80
|
for sig in sigs:
|
|
81
81
|
ts = (
|
|
@@ -10,7 +10,7 @@ build-backend = "hatchling.build"
|
|
|
10
10
|
|
|
11
11
|
[project]
|
|
12
12
|
name = "helius-python"
|
|
13
|
-
version = "0.3.
|
|
13
|
+
version = "0.3.4"
|
|
14
14
|
authors = [
|
|
15
15
|
{ name="Markos Narinian", email="manarinian@gmail.com" },
|
|
16
16
|
]
|
|
@@ -21,6 +21,7 @@ dependencies = [
|
|
|
21
21
|
"httpx",
|
|
22
22
|
"pydantic",
|
|
23
23
|
"python-dotenv",
|
|
24
|
+
"typing-extensions",
|
|
24
25
|
"websockets",
|
|
25
26
|
]
|
|
26
27
|
classifiers = [
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from os import environ
|
|
3
|
-
from typing import Annotated, Literal
|
|
3
|
+
from typing import Annotated, Literal
|
|
4
4
|
|
|
5
5
|
import httpx
|
|
6
6
|
from dotenv import dotenv_values
|
|
7
7
|
from pydantic import AliasGenerator, BaseModel, ConfigDict, Field, model_validator
|
|
8
8
|
from pydantic.alias_generators import to_camel
|
|
9
|
+
from typing_extensions import TypedDict
|
|
9
10
|
from websockets.sync.client import connect
|
|
10
11
|
|
|
11
12
|
from helius.rpc import JsonRpcRequest
|