helius-python 0.1.1__tar.gz → 0.2.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.1.1 → helius_python-0.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +1 -1
- {helius_python-0.1.1 → helius_python-0.2.0}/AGENTS.md +9 -9
- {helius_python-0.1.1 → helius_python-0.2.0}/CONTRIBUTING.md +1 -1
- {helius_python-0.1.1 → helius_python-0.2.0}/PKG-INFO +12 -60
- {helius_python-0.1.1 → helius_python-0.2.0}/README.md +11 -59
- {helius_python-0.1.1 → helius_python-0.2.0}/examples/block_explorer.py +9 -6
- {helius_python-0.1.1 → helius_python-0.2.0}/examples/devnet_airdrop.py +2 -2
- {helius_python-0.1.1 → helius_python-0.2.0}/examples/network_status.py +2 -2
- {helius_python-0.1.1 → helius_python-0.2.0}/examples/priority_fees.py +2 -2
- {helius_python-0.1.1 → helius_python-0.2.0}/examples/stake_overview.py +22 -14
- {helius_python-0.1.1 → helius_python-0.2.0}/examples/token_inspector.py +2 -2
- {helius_python-0.1.1 → helius_python-0.2.0}/examples/transaction_inspector.py +5 -4
- {helius_python-0.1.1 → helius_python-0.2.0}/examples/wallet_tracker.py +9 -6
- {helius_python-0.1.1 → helius_python-0.2.0}/pyproject.toml +1 -1
- helius_python-0.1.1/src/helius/client.py → helius_python-0.2.0/src/helius/solana_rpc.py +28 -3
- {helius_python-0.1.1 → helius_python-0.2.0}/tests/unit/test_helius_client.py +191 -92
- {helius_python-0.1.1 → helius_python-0.2.0}/tests/unit/test_rpc_request.py +4 -2
- {helius_python-0.1.1 → helius_python-0.2.0}/.editorconfig +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/.github/workflows/python-package.yml +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/.github/workflows/python-publish.yml +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/.gitignore +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/CLAUDE.md +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/LICENSE +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/requirements.txt +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/src/helius/__init__.py +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/src/helius/models.py +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/tests/fixtures/account.json +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/tests/fixtures/supply.json +0 -0
- {helius_python-0.1.1 → helius_python-0.2.0}/tests/unit/test_models.py +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
When implementing a function for a RPC method in the
|
|
1
|
+
When implementing a function for a RPC method in the SolanaRpcClient class, read the docs for the specific RPC method. For example, for the get_supply function (getSupply RPC method) you should read https://www.helius.dev/docs/rpc/guides/getsupply and https://www.helius.dev/docs/api-reference/rpc/http/getsupply.
|
|
2
2
|
|
|
3
3
|
# API Reference
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@ The API reference is generated from **Google-style docstrings** on every public
|
|
|
6
6
|
|
|
7
7
|
## Where docstrings live
|
|
8
8
|
|
|
9
|
-
- **Client methods** (`
|
|
9
|
+
- **Client methods** (`SolanaRpcClient.get_*`, `is_*`, `request_*`, etc.) — every public method gets a docstring. Private methods (`_send`, dunders) do not need one.
|
|
10
10
|
- **Models** (`src/helius/models.py`) — every public model class gets a docstring describing what it represents. Individual fields don't need per-field docstrings if their names and types are self-explanatory; only document fields where the meaning, units, or nullability isn't obvious from the type alone.
|
|
11
11
|
- **Builders / helpers** (`RpcRequest`) — class docstring describing purpose, plus one-line docstrings on each public method.
|
|
12
12
|
|
|
@@ -123,7 +123,7 @@ tests/
|
|
|
123
123
|
unit/
|
|
124
124
|
test_rpc_request.py # RpcRequest builder
|
|
125
125
|
test_models.py # pydantic model validation against fixtures
|
|
126
|
-
|
|
126
|
+
test_solana_rpc.py # one test (or small group) per client method
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
## Three Layers
|
|
@@ -154,7 +154,7 @@ One fixture per model is enough. The goal is to catch schema mismatches (missing
|
|
|
154
154
|
|
|
155
155
|
### 3. Client methods — `respx`-mocked tests
|
|
156
156
|
|
|
157
|
-
For each method on `
|
|
157
|
+
For each method on `SolanaRpcClient`, write at least one test that asserts **both** sides of the wire:
|
|
158
158
|
|
|
159
159
|
- **Outgoing request:** the JSON body sent to Helius matches the JSON-RPC payload you expect — correct `method`, correct positional `params`, correct config object with snake → camel mapping, and optional arguments omitted when `None`.
|
|
160
160
|
- **Return value:** the method correctly parses a canned response into the documented return shape (model, tuple, primitive, etc.).
|
|
@@ -169,7 +169,7 @@ Skeleton:
|
|
|
169
169
|
import json
|
|
170
170
|
import httpx
|
|
171
171
|
import respx
|
|
172
|
-
from helius.
|
|
172
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
173
173
|
|
|
174
174
|
@respx.mock
|
|
175
175
|
def test_get_balance():
|
|
@@ -183,7 +183,7 @@ def test_get_balance():
|
|
|
183
183
|
},
|
|
184
184
|
)
|
|
185
185
|
)
|
|
186
|
-
with
|
|
186
|
+
with SolanaRpcClient(api_key="test") as c:
|
|
187
187
|
assert c.get_balance("So11...112", commitment="finalized") == 42
|
|
188
188
|
|
|
189
189
|
sent = route.calls.last.request
|
|
@@ -197,9 +197,9 @@ For methods with branching logic (e.g. `get_block_production`, `get_token_accoun
|
|
|
197
197
|
|
|
198
198
|
## Conventions
|
|
199
199
|
|
|
200
|
-
- Construct `
|
|
201
|
-
- Use the context-manager form (`with
|
|
202
|
-
- Group tests in `tests/unit/
|
|
200
|
+
- Construct `SolanaRpcClient` in tests with an explicit `api_key="test"` (or similar). Never rely on a real `.env` file.
|
|
201
|
+
- Use the context-manager form (`with SolanaRpcClient(...) as c:`) in tests so the `httpx.Client` is closed cleanly.
|
|
202
|
+
- Group tests in `tests/unit/test_solana_rpc.py` by method, but a single file is fine until it grows unwieldy.
|
|
203
203
|
- Test names should describe the behavior, not the implementation: `test_get_balance_includes_commitment_in_config`, not `test_get_balance_calls_set`.
|
|
204
204
|
- When adding a new client method, the PR must include: (a) a `respx` test asserting the request payload, and (b) a fixture-based model test if the method introduces or uses a model. This is enforced in `CONTRIBUTING.md`.
|
|
205
205
|
|
|
@@ -66,7 +66,7 @@ prior discussion; just send them.
|
|
|
66
66
|
## Codebase Conventions
|
|
67
67
|
|
|
68
68
|
Please match the existing style of the codebase. Skim
|
|
69
|
-
[`src/helius/
|
|
69
|
+
[`src/helius/solana_rpc.py`](src/helius/solana_rpc.py) and
|
|
70
70
|
[`src/helius/models.py`](src/helius/models.py) before writing new code. In
|
|
71
71
|
particular:
|
|
72
72
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: helius-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.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
|
|
@@ -118,55 +118,6 @@ Description-Content-Type: text/markdown
|
|
|
118
118
|
</p>
|
|
119
119
|
|
|
120
120
|
**A complete, typed Python client for [Helius](https://helius.dev) — the Solana developer platform.**
|
|
121
|
-
<br />
|
|
122
|
-
|
|
123
|
-
## TL;DR
|
|
124
|
-
|
|
125
|
-
```bash
|
|
126
|
-
pip install helius-python
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
```python
|
|
130
|
-
# export HELIUS_API_KEY=your_key (or put it in .env)
|
|
131
|
-
|
|
132
|
-
from helius.client import HeliusClient
|
|
133
|
-
|
|
134
|
-
with HeliusClient() as helius:
|
|
135
|
-
_ctx, lamports = helius.get_balance("7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU")
|
|
136
|
-
print(f"{lamports / 1_000_000_000:.4f} SOL")
|
|
137
|
-
|
|
138
|
-
for sig in helius.get_signatures_for_address(
|
|
139
|
-
"7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", limit=5
|
|
140
|
-
):
|
|
141
|
-
print(sig.slot, "ERR" if sig.err else "OK ", sig.signature)
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
`HELIUS_API_KEY` is read from the environment (or `.env`), the
|
|
145
|
-
client is a context manager, and every return value is fully typed.
|
|
146
|
-
|
|
147
|
-
## Why this over `solana-py` / `solders`?
|
|
148
|
-
|
|
149
|
-
`solders` is for building and signing transactions. `solana-py` is a generic Solana RPC client. Use them for that.
|
|
150
|
-
|
|
151
|
-
This library is for talking to **Helius** specifically — typed `pydantic` responses, snake_case, and (eventually) the Helius-only endpoints (DAS, Enhanced Transactions, Webhooks, priority fees) the others don't cover. Plays nicely alongside `solders`: sign with `solders`, read with `helius-python`.
|
|
152
|
-
|
|
153
|
-
## Example: wallet tracker
|
|
154
|
-
|
|
155
|
-
See [`examples/wallet_tracker.py`](examples/wallet_tracker.py) for a
|
|
156
|
-
runnable script that takes a wallet address and prints:
|
|
157
|
-
|
|
158
|
-
- SOL balance
|
|
159
|
-
- All non-empty SPL token accounts (mint, balance, account)
|
|
160
|
-
- The last N transactions (timestamp, slot, success/error, signature)
|
|
161
|
-
|
|
162
|
-
```bash
|
|
163
|
-
export HELIUS_API_KEY=your_helius_api_key
|
|
164
|
-
python examples/wallet_tracker.py 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU --limit 20
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
It uses `get_balance`, `get_token_accounts_by_owner` (with
|
|
168
|
-
`encoding="jsonParsed"`), and `get_signatures_for_address` — pure
|
|
169
|
-
stdlib plus this library, no `solana-py` or `solders` needed.
|
|
170
121
|
|
|
171
122
|
## Coverage
|
|
172
123
|
|
|
@@ -206,9 +157,9 @@ wraps it.
|
|
|
206
157
|
Pass your Helius API key explicitly:
|
|
207
158
|
|
|
208
159
|
```python
|
|
209
|
-
from helius.
|
|
160
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
210
161
|
|
|
211
|
-
client =
|
|
162
|
+
client = SolanaRpcClient(api_key="YOUR_HELIUS_API_KEY")
|
|
212
163
|
```
|
|
213
164
|
|
|
214
165
|
or set `HELIUS_API_KEY` as an environment variable:
|
|
@@ -225,9 +176,9 @@ HELIUS_API_KEY=your_helius_api_key
|
|
|
225
176
|
```
|
|
226
177
|
|
|
227
178
|
```python
|
|
228
|
-
from helius.
|
|
179
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
229
180
|
|
|
230
|
-
client =
|
|
181
|
+
client = SolanaRpcClient() # reads HELIUS_API_KEY from the environment or .env
|
|
231
182
|
```
|
|
232
183
|
|
|
233
184
|
## Usage
|
|
@@ -235,9 +186,9 @@ client = HeliusClient() # reads HELIUS_API_KEY from the environment or .env
|
|
|
235
186
|
### As a context manager (recommended)
|
|
236
187
|
|
|
237
188
|
```python
|
|
238
|
-
from helius.
|
|
189
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
239
190
|
|
|
240
|
-
with
|
|
191
|
+
with SolanaRpcClient(api_key="YOUR_HELIUS_API_KEY") as client:
|
|
241
192
|
_ctx, balance = client.get_balance("So11111111111111111111111111111111111111112")
|
|
242
193
|
_ctx, supply = client.get_supply()
|
|
243
194
|
nodes = client.get_cluster_nodes()
|
|
@@ -245,7 +196,7 @@ with HeliusClient(api_key="YOUR_HELIUS_API_KEY") as client:
|
|
|
245
196
|
tx = client.get_transaction("5j7s...signature...")
|
|
246
197
|
```
|
|
247
198
|
|
|
248
|
-
`
|
|
199
|
+
`SolanaRpcClient` implements the context-manager protocol via `__enter__` /
|
|
249
200
|
`__exit__`, so the underlying `httpx.Client` is closed cleanly when the
|
|
250
201
|
`with` block exits.
|
|
251
202
|
|
|
@@ -255,9 +206,9 @@ If a `with` block doesn't fit your code structure (e.g. the client lives
|
|
|
255
206
|
on a long-lived object), call `close()` yourself when you're done:
|
|
256
207
|
|
|
257
208
|
```python
|
|
258
|
-
from helius.
|
|
209
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
259
210
|
|
|
260
|
-
client =
|
|
211
|
+
client = SolanaRpcClient(api_key="YOUR_HELIUS_API_KEY")
|
|
261
212
|
try:
|
|
262
213
|
_ctx, balance = client.get_balance("So11111111111111111111111111111111111111112")
|
|
263
214
|
_ctx, supply = client.get_supply()
|
|
@@ -303,7 +254,7 @@ The method names map 1:1 to the Solana JSON-RPC spec, just converted to
|
|
|
303
254
|
## Status
|
|
304
255
|
|
|
305
256
|
Actively expanding toward full coverage of the Helius API. See
|
|
306
|
-
[`src/helius/
|
|
257
|
+
[`src/helius/solana_rpc.py`](src/helius/solana_rpc.py) for the current list of
|
|
307
258
|
implemented methods; missing endpoints are tracked as issues and added
|
|
308
259
|
continuously.
|
|
309
260
|
|
|
@@ -359,6 +310,7 @@ continuously.
|
|
|
359
310
|
| `isBlockhashValid` | `is_blockhash_valid(...)` | [guide](https://www.helius.dev/docs/rpc/guides/isblockhashvalid), [reference](https://www.helius.dev/docs/api-reference/rpc/http/isblockhashvalid) |
|
|
360
311
|
| `minimumLedgerSlot` | `minimum_ledger_slot()` | [guide](https://www.helius.dev/docs/rpc/guides/minimumledgerslot), [reference](https://www.helius.dev/docs/api-reference/rpc/http/minimumledgerslot) |
|
|
361
312
|
| `requestAirdrop` | `request_airdrop(...)` | [guide](https://www.helius.dev/docs/rpc/guides/requestairdrop), [reference](https://www.helius.dev/docs/api-reference/rpc/http/requestairdrop) |
|
|
313
|
+
| `sendTransaction` | `send_transaction(...)` | [guide](https://www.helius.dev/docs/rpc/guides/sendtransaction), [reference](https://www.helius.dev/docs/api-reference/rpc/http/sendtransaction) |
|
|
362
314
|
|
|
363
315
|
## License
|
|
364
316
|
|
|
@@ -98,55 +98,6 @@
|
|
|
98
98
|
</p>
|
|
99
99
|
|
|
100
100
|
**A complete, typed Python client for [Helius](https://helius.dev) — the Solana developer platform.**
|
|
101
|
-
<br />
|
|
102
|
-
|
|
103
|
-
## TL;DR
|
|
104
|
-
|
|
105
|
-
```bash
|
|
106
|
-
pip install helius-python
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
```python
|
|
110
|
-
# export HELIUS_API_KEY=your_key (or put it in .env)
|
|
111
|
-
|
|
112
|
-
from helius.client import HeliusClient
|
|
113
|
-
|
|
114
|
-
with HeliusClient() as helius:
|
|
115
|
-
_ctx, lamports = helius.get_balance("7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU")
|
|
116
|
-
print(f"{lamports / 1_000_000_000:.4f} SOL")
|
|
117
|
-
|
|
118
|
-
for sig in helius.get_signatures_for_address(
|
|
119
|
-
"7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU", limit=5
|
|
120
|
-
):
|
|
121
|
-
print(sig.slot, "ERR" if sig.err else "OK ", sig.signature)
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
`HELIUS_API_KEY` is read from the environment (or `.env`), the
|
|
125
|
-
client is a context manager, and every return value is fully typed.
|
|
126
|
-
|
|
127
|
-
## Why this over `solana-py` / `solders`?
|
|
128
|
-
|
|
129
|
-
`solders` is for building and signing transactions. `solana-py` is a generic Solana RPC client. Use them for that.
|
|
130
|
-
|
|
131
|
-
This library is for talking to **Helius** specifically — typed `pydantic` responses, snake_case, and (eventually) the Helius-only endpoints (DAS, Enhanced Transactions, Webhooks, priority fees) the others don't cover. Plays nicely alongside `solders`: sign with `solders`, read with `helius-python`.
|
|
132
|
-
|
|
133
|
-
## Example: wallet tracker
|
|
134
|
-
|
|
135
|
-
See [`examples/wallet_tracker.py`](examples/wallet_tracker.py) for a
|
|
136
|
-
runnable script that takes a wallet address and prints:
|
|
137
|
-
|
|
138
|
-
- SOL balance
|
|
139
|
-
- All non-empty SPL token accounts (mint, balance, account)
|
|
140
|
-
- The last N transactions (timestamp, slot, success/error, signature)
|
|
141
|
-
|
|
142
|
-
```bash
|
|
143
|
-
export HELIUS_API_KEY=your_helius_api_key
|
|
144
|
-
python examples/wallet_tracker.py 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU --limit 20
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
It uses `get_balance`, `get_token_accounts_by_owner` (with
|
|
148
|
-
`encoding="jsonParsed"`), and `get_signatures_for_address` — pure
|
|
149
|
-
stdlib plus this library, no `solana-py` or `solders` needed.
|
|
150
101
|
|
|
151
102
|
## Coverage
|
|
152
103
|
|
|
@@ -186,9 +137,9 @@ wraps it.
|
|
|
186
137
|
Pass your Helius API key explicitly:
|
|
187
138
|
|
|
188
139
|
```python
|
|
189
|
-
from helius.
|
|
140
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
190
141
|
|
|
191
|
-
client =
|
|
142
|
+
client = SolanaRpcClient(api_key="YOUR_HELIUS_API_KEY")
|
|
192
143
|
```
|
|
193
144
|
|
|
194
145
|
or set `HELIUS_API_KEY` as an environment variable:
|
|
@@ -205,9 +156,9 @@ HELIUS_API_KEY=your_helius_api_key
|
|
|
205
156
|
```
|
|
206
157
|
|
|
207
158
|
```python
|
|
208
|
-
from helius.
|
|
159
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
209
160
|
|
|
210
|
-
client =
|
|
161
|
+
client = SolanaRpcClient() # reads HELIUS_API_KEY from the environment or .env
|
|
211
162
|
```
|
|
212
163
|
|
|
213
164
|
## Usage
|
|
@@ -215,9 +166,9 @@ client = HeliusClient() # reads HELIUS_API_KEY from the environment or .env
|
|
|
215
166
|
### As a context manager (recommended)
|
|
216
167
|
|
|
217
168
|
```python
|
|
218
|
-
from helius.
|
|
169
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
219
170
|
|
|
220
|
-
with
|
|
171
|
+
with SolanaRpcClient(api_key="YOUR_HELIUS_API_KEY") as client:
|
|
221
172
|
_ctx, balance = client.get_balance("So11111111111111111111111111111111111111112")
|
|
222
173
|
_ctx, supply = client.get_supply()
|
|
223
174
|
nodes = client.get_cluster_nodes()
|
|
@@ -225,7 +176,7 @@ with HeliusClient(api_key="YOUR_HELIUS_API_KEY") as client:
|
|
|
225
176
|
tx = client.get_transaction("5j7s...signature...")
|
|
226
177
|
```
|
|
227
178
|
|
|
228
|
-
`
|
|
179
|
+
`SolanaRpcClient` implements the context-manager protocol via `__enter__` /
|
|
229
180
|
`__exit__`, so the underlying `httpx.Client` is closed cleanly when the
|
|
230
181
|
`with` block exits.
|
|
231
182
|
|
|
@@ -235,9 +186,9 @@ If a `with` block doesn't fit your code structure (e.g. the client lives
|
|
|
235
186
|
on a long-lived object), call `close()` yourself when you're done:
|
|
236
187
|
|
|
237
188
|
```python
|
|
238
|
-
from helius.
|
|
189
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
239
190
|
|
|
240
|
-
client =
|
|
191
|
+
client = SolanaRpcClient(api_key="YOUR_HELIUS_API_KEY")
|
|
241
192
|
try:
|
|
242
193
|
_ctx, balance = client.get_balance("So11111111111111111111111111111111111111112")
|
|
243
194
|
_ctx, supply = client.get_supply()
|
|
@@ -283,7 +234,7 @@ The method names map 1:1 to the Solana JSON-RPC spec, just converted to
|
|
|
283
234
|
## Status
|
|
284
235
|
|
|
285
236
|
Actively expanding toward full coverage of the Helius API. See
|
|
286
|
-
[`src/helius/
|
|
237
|
+
[`src/helius/solana_rpc.py`](src/helius/solana_rpc.py) for the current list of
|
|
287
238
|
implemented methods; missing endpoints are tracked as issues and added
|
|
288
239
|
continuously.
|
|
289
240
|
|
|
@@ -339,6 +290,7 @@ continuously.
|
|
|
339
290
|
| `isBlockhashValid` | `is_blockhash_valid(...)` | [guide](https://www.helius.dev/docs/rpc/guides/isblockhashvalid), [reference](https://www.helius.dev/docs/api-reference/rpc/http/isblockhashvalid) |
|
|
340
291
|
| `minimumLedgerSlot` | `minimum_ledger_slot()` | [guide](https://www.helius.dev/docs/rpc/guides/minimumledgerslot), [reference](https://www.helius.dev/docs/api-reference/rpc/http/minimumledgerslot) |
|
|
341
292
|
| `requestAirdrop` | `request_airdrop(...)` | [guide](https://www.helius.dev/docs/rpc/guides/requestairdrop), [reference](https://www.helius.dev/docs/api-reference/rpc/http/requestairdrop) |
|
|
293
|
+
| `sendTransaction` | `send_transaction(...)` | [guide](https://www.helius.dev/docs/rpc/guides/sendtransaction), [reference](https://www.helius.dev/docs/api-reference/rpc/http/sendtransaction) |
|
|
342
294
|
|
|
343
295
|
## License
|
|
344
296
|
|
|
@@ -21,7 +21,7 @@ import argparse
|
|
|
21
21
|
import datetime as dt
|
|
22
22
|
import sys
|
|
23
23
|
|
|
24
|
-
from helius.
|
|
24
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
25
25
|
|
|
26
26
|
LAMPORTS_PER_SOL = 1_000_000_000
|
|
27
27
|
|
|
@@ -36,9 +36,11 @@ def main() -> int:
|
|
|
36
36
|
)
|
|
37
37
|
args = parser.parse_args()
|
|
38
38
|
|
|
39
|
-
with
|
|
40
|
-
slot =
|
|
41
|
-
|
|
39
|
+
with SolanaRpcClient() as helius:
|
|
40
|
+
slot = (
|
|
41
|
+
args.slot
|
|
42
|
+
if args.slot is not None
|
|
43
|
+
else helius.get_slot(commitment="finalized")
|
|
42
44
|
)
|
|
43
45
|
block = helius.get_block(
|
|
44
46
|
slot,
|
|
@@ -70,8 +72,9 @@ def main() -> int:
|
|
|
70
72
|
print(f"\nTransactions : {total:,} total")
|
|
71
73
|
print(f" succeeded : {succeeded:,}")
|
|
72
74
|
print(f" failed : {failed:,}")
|
|
73
|
-
print(
|
|
74
|
-
|
|
75
|
+
print(
|
|
76
|
+
f"Total fees : {fees / LAMPORTS_PER_SOL:.9f} SOL " f"({fees:,} lamports)"
|
|
77
|
+
)
|
|
75
78
|
|
|
76
79
|
if block.rewards:
|
|
77
80
|
print(f"\nRewards ({len(block.rewards)}):")
|
|
@@ -24,7 +24,7 @@ import argparse
|
|
|
24
24
|
import sys
|
|
25
25
|
import time
|
|
26
26
|
|
|
27
|
-
from helius.
|
|
27
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
28
28
|
|
|
29
29
|
LAMPORTS_PER_SOL = 1_000_000_000
|
|
30
30
|
DEVNET_URL = "https://devnet.helius-rpc.com"
|
|
@@ -48,7 +48,7 @@ def main() -> int:
|
|
|
48
48
|
args = parser.parse_args()
|
|
49
49
|
lamports = int(args.sol * LAMPORTS_PER_SOL)
|
|
50
50
|
|
|
51
|
-
client =
|
|
51
|
+
client = SolanaRpcClient(base_url=DEVNET_URL)
|
|
52
52
|
try:
|
|
53
53
|
print(f"Requesting {args.sol} SOL airdrop to {args.address} on devnet...")
|
|
54
54
|
signature = client.request_airdrop(args.address, lamports)
|
|
@@ -18,11 +18,11 @@ from __future__ import annotations
|
|
|
18
18
|
|
|
19
19
|
import sys
|
|
20
20
|
|
|
21
|
-
from helius.
|
|
21
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def main() -> int:
|
|
25
|
-
with
|
|
25
|
+
with SolanaRpcClient() as helius:
|
|
26
26
|
healthy = helius.get_health()
|
|
27
27
|
solana_core, feature_set = helius.get_version()
|
|
28
28
|
identity = helius.get_identity()
|
|
@@ -25,7 +25,7 @@ import argparse
|
|
|
25
25
|
import statistics
|
|
26
26
|
import sys
|
|
27
27
|
|
|
28
|
-
from helius.
|
|
28
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def percentile(sorted_values: list[int], pct: float) -> int:
|
|
@@ -46,7 +46,7 @@ def main() -> int:
|
|
|
46
46
|
args = parser.parse_args()
|
|
47
47
|
accounts = args.account or None
|
|
48
48
|
|
|
49
|
-
with
|
|
49
|
+
with SolanaRpcClient() as helius:
|
|
50
50
|
samples = helius.get_recent_prioritization_fees(
|
|
51
51
|
locked_writable_accounts=accounts
|
|
52
52
|
)
|
|
@@ -18,13 +18,13 @@ from __future__ import annotations
|
|
|
18
18
|
|
|
19
19
|
import sys
|
|
20
20
|
|
|
21
|
-
from helius.
|
|
21
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
22
22
|
|
|
23
23
|
LAMPORTS_PER_SOL = 1_000_000_000
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
def main() -> int:
|
|
27
|
-
client =
|
|
27
|
+
client = SolanaRpcClient()
|
|
28
28
|
try:
|
|
29
29
|
rate = client.get_inflation_rate()
|
|
30
30
|
gov = client.get_inflation_governor()
|
|
@@ -44,35 +44,43 @@ def main() -> int:
|
|
|
44
44
|
print(f" initial : {gov.initial * 100:.2f}%")
|
|
45
45
|
print(f" terminal : {gov.terminal * 100:.2f}%")
|
|
46
46
|
print(f" taper : {gov.taper * 100:.2f}% per year")
|
|
47
|
-
print(
|
|
48
|
-
|
|
47
|
+
print(
|
|
48
|
+
f" foundation : {gov.foundation * 100:.2f}% for "
|
|
49
|
+
f"{gov.foundation_term:.1f} years"
|
|
50
|
+
)
|
|
49
51
|
|
|
50
52
|
print("\n=== Supply ===\n")
|
|
51
53
|
print(f"Total : {supply.total / LAMPORTS_PER_SOL:>16,.4f} SOL")
|
|
52
54
|
print(f"Circulating : {supply.circulating / LAMPORTS_PER_SOL:>16,.4f} SOL")
|
|
53
|
-
print(
|
|
54
|
-
|
|
55
|
+
print(
|
|
56
|
+
f"Non-circulating : {supply.non_circulating / LAMPORTS_PER_SOL:>16,.4f} SOL"
|
|
57
|
+
)
|
|
55
58
|
|
|
56
59
|
print("\n=== Stake ===\n")
|
|
57
60
|
print(f"Minimum delegation : {min_stake / LAMPORTS_PER_SOL:.9f} SOL")
|
|
58
61
|
active_stake = sum(v.activated_stake for v in current)
|
|
59
62
|
delinquent_stake = sum(v.activated_stake for v in delinquent)
|
|
60
63
|
total_stake = active_stake + delinquent_stake
|
|
61
|
-
print(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
print(
|
|
65
|
+
f"Active validators : {len(current):>5} "
|
|
66
|
+
f"{active_stake / LAMPORTS_PER_SOL:>16,.0f} SOL"
|
|
67
|
+
)
|
|
68
|
+
print(
|
|
69
|
+
f"Delinquent : {len(delinquent):>5} "
|
|
70
|
+
f"{delinquent_stake / LAMPORTS_PER_SOL:>16,.0f} SOL"
|
|
71
|
+
)
|
|
65
72
|
if total_stake:
|
|
66
|
-
print(f"Delinquent share : "
|
|
67
|
-
f"{100 * delinquent_stake / total_stake:.3f}%")
|
|
73
|
+
print(f"Delinquent share : {100 * delinquent_stake / total_stake:.3f}%")
|
|
68
74
|
|
|
69
75
|
top = sorted(current, key=lambda v: v.activated_stake, reverse=True)[:10]
|
|
70
76
|
print(f"\nTop {len(top)} validators by active stake:")
|
|
71
77
|
for rank, v in enumerate(top, start=1):
|
|
72
78
|
sol = v.activated_stake / LAMPORTS_PER_SOL
|
|
73
79
|
share = 100 * v.activated_stake / active_stake if active_stake else 0.0
|
|
74
|
-
print(
|
|
75
|
-
|
|
80
|
+
print(
|
|
81
|
+
f" {rank:>2}. {v.vote_pubkey} "
|
|
82
|
+
f"{sol:>14,.0f} SOL ({share:5.2f}%) comm={v.commission}%"
|
|
83
|
+
)
|
|
76
84
|
|
|
77
85
|
return 0
|
|
78
86
|
|
|
@@ -22,7 +22,7 @@ from __future__ import annotations
|
|
|
22
22
|
import argparse
|
|
23
23
|
import sys
|
|
24
24
|
|
|
25
|
-
from helius.
|
|
25
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def main() -> int:
|
|
@@ -30,7 +30,7 @@ def main() -> int:
|
|
|
30
30
|
parser.add_argument("mint", help="SPL token mint address (base58)")
|
|
31
31
|
args = parser.parse_args()
|
|
32
32
|
|
|
33
|
-
client =
|
|
33
|
+
client = SolanaRpcClient()
|
|
34
34
|
try:
|
|
35
35
|
_ctx, supply = client.get_token_supply(args.mint)
|
|
36
36
|
_ctx, holders = client.get_token_largest_accounts(args.mint)
|
|
@@ -19,7 +19,7 @@ import argparse
|
|
|
19
19
|
import datetime as dt
|
|
20
20
|
import sys
|
|
21
21
|
|
|
22
|
-
from helius.
|
|
22
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
23
23
|
|
|
24
24
|
LAMPORTS_PER_SOL = 1_000_000_000
|
|
25
25
|
|
|
@@ -29,7 +29,7 @@ def main() -> int:
|
|
|
29
29
|
parser.add_argument("signature", help="Transaction signature (base58)")
|
|
30
30
|
args = parser.parse_args()
|
|
31
31
|
|
|
32
|
-
with
|
|
32
|
+
with SolanaRpcClient() as helius:
|
|
33
33
|
tx = helius.get_transaction(
|
|
34
34
|
args.signature,
|
|
35
35
|
encoding="jsonParsed",
|
|
@@ -49,8 +49,9 @@ def main() -> int:
|
|
|
49
49
|
print("\n(no metadata returned)")
|
|
50
50
|
return 0
|
|
51
51
|
|
|
52
|
-
print(
|
|
53
|
-
|
|
52
|
+
print(
|
|
53
|
+
f"Fee : {meta.fee} lamports ({meta.fee / LAMPORTS_PER_SOL:.9f} SOL)"
|
|
54
|
+
)
|
|
54
55
|
print(f"Result : {'ERROR ' + str(meta.err) if meta.err else 'success'}")
|
|
55
56
|
|
|
56
57
|
# Account balance changes ------------------------------------------------
|
|
@@ -23,7 +23,7 @@ import argparse
|
|
|
23
23
|
import datetime as dt
|
|
24
24
|
import sys
|
|
25
25
|
|
|
26
|
-
from helius.
|
|
26
|
+
from helius.solana_rpc import SolanaRpcClient
|
|
27
27
|
|
|
28
28
|
# SPL Token program ID — used to list every token account owned by a wallet.
|
|
29
29
|
TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
|
|
@@ -41,12 +41,14 @@ def main() -> int:
|
|
|
41
41
|
)
|
|
42
42
|
args = parser.parse_args()
|
|
43
43
|
|
|
44
|
-
with
|
|
44
|
+
with SolanaRpcClient() as client: # reads HELIUS_API_KEY from env / .env
|
|
45
45
|
# --- SOL balance ---------------------------------------------------
|
|
46
46
|
_ctx, lamports = client.get_balance(args.address)
|
|
47
47
|
print(f"\n=== {args.address} ===\n")
|
|
48
|
-
print(
|
|
49
|
-
|
|
48
|
+
print(
|
|
49
|
+
f"SOL balance: {lamports / LAMPORTS_PER_SOL:.9f} SOL "
|
|
50
|
+
f"({lamports} lamports)\n"
|
|
51
|
+
)
|
|
50
52
|
|
|
51
53
|
# --- SPL token holdings -------------------------------------------
|
|
52
54
|
_ctx, token_accounts = client.get_token_accounts_by_owner(
|
|
@@ -77,8 +79,9 @@ def main() -> int:
|
|
|
77
79
|
print(f"Last {len(sigs)} signatures:")
|
|
78
80
|
for sig in sigs:
|
|
79
81
|
ts = (
|
|
80
|
-
dt.datetime.fromtimestamp(sig.block_time, tz=dt.timezone.utc)
|
|
81
|
-
|
|
82
|
+
dt.datetime.fromtimestamp(sig.block_time, tz=dt.timezone.utc).strftime(
|
|
83
|
+
"%Y-%m-%d %H:%M:%SZ"
|
|
84
|
+
)
|
|
82
85
|
if sig.block_time is not None
|
|
83
86
|
else " (no time) "
|
|
84
87
|
)
|
|
@@ -28,7 +28,7 @@ from helius.models import (
|
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
class
|
|
31
|
+
class SolanaRpcClient:
|
|
32
32
|
def __init__(
|
|
33
33
|
self,
|
|
34
34
|
*,
|
|
@@ -924,6 +924,11 @@ class HeliusClient:
|
|
|
924
924
|
value = response["result"]["value"]
|
|
925
925
|
return context, value
|
|
926
926
|
|
|
927
|
+
def minimum_ledger_slot(self) -> int:
|
|
928
|
+
request = RpcRequest(method="minimumLedgerSlot").build()
|
|
929
|
+
response = self._send(request)
|
|
930
|
+
return response["result"]
|
|
931
|
+
|
|
927
932
|
def request_airdrop(
|
|
928
933
|
self,
|
|
929
934
|
*,
|
|
@@ -944,8 +949,28 @@ class HeliusClient:
|
|
|
944
949
|
response = self._send(request)
|
|
945
950
|
return response["result"]
|
|
946
951
|
|
|
947
|
-
def
|
|
948
|
-
|
|
952
|
+
def send_transaction(
|
|
953
|
+
self,
|
|
954
|
+
*,
|
|
955
|
+
transaction: str,
|
|
956
|
+
encoding: Literal["base58", "base64"] | None = None,
|
|
957
|
+
skip_preflight: bool | None = None,
|
|
958
|
+
preflight_commitment: (
|
|
959
|
+
Literal["finalized", "confirmed", "processed"] | None
|
|
960
|
+
) = None,
|
|
961
|
+
max_retries: int | None = None,
|
|
962
|
+
min_context_slot: int | None = None,
|
|
963
|
+
) -> str:
|
|
964
|
+
request = (
|
|
965
|
+
RpcRequest(method="sendTransaction")
|
|
966
|
+
.add(transaction)
|
|
967
|
+
.set("encoding", encoding)
|
|
968
|
+
.set("skipPreflight", skip_preflight)
|
|
969
|
+
.set("preflightCommitment", preflight_commitment)
|
|
970
|
+
.set("maxRetries", max_retries)
|
|
971
|
+
.set("minContextSlot", min_context_slot)
|
|
972
|
+
.build()
|
|
973
|
+
)
|
|
949
974
|
response = self._send(request)
|
|
950
975
|
return response["result"]
|
|
951
976
|
|