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.
Files changed (31) hide show
  1. {helius_python-0.1.1 → helius_python-0.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +1 -1
  2. {helius_python-0.1.1 → helius_python-0.2.0}/AGENTS.md +9 -9
  3. {helius_python-0.1.1 → helius_python-0.2.0}/CONTRIBUTING.md +1 -1
  4. {helius_python-0.1.1 → helius_python-0.2.0}/PKG-INFO +12 -60
  5. {helius_python-0.1.1 → helius_python-0.2.0}/README.md +11 -59
  6. {helius_python-0.1.1 → helius_python-0.2.0}/examples/block_explorer.py +9 -6
  7. {helius_python-0.1.1 → helius_python-0.2.0}/examples/devnet_airdrop.py +2 -2
  8. {helius_python-0.1.1 → helius_python-0.2.0}/examples/network_status.py +2 -2
  9. {helius_python-0.1.1 → helius_python-0.2.0}/examples/priority_fees.py +2 -2
  10. {helius_python-0.1.1 → helius_python-0.2.0}/examples/stake_overview.py +22 -14
  11. {helius_python-0.1.1 → helius_python-0.2.0}/examples/token_inspector.py +2 -2
  12. {helius_python-0.1.1 → helius_python-0.2.0}/examples/transaction_inspector.py +5 -4
  13. {helius_python-0.1.1 → helius_python-0.2.0}/examples/wallet_tracker.py +9 -6
  14. {helius_python-0.1.1 → helius_python-0.2.0}/pyproject.toml +1 -1
  15. helius_python-0.1.1/src/helius/client.py → helius_python-0.2.0/src/helius/solana_rpc.py +28 -3
  16. {helius_python-0.1.1 → helius_python-0.2.0}/tests/unit/test_helius_client.py +191 -92
  17. {helius_python-0.1.1 → helius_python-0.2.0}/tests/unit/test_rpc_request.py +4 -2
  18. {helius_python-0.1.1 → helius_python-0.2.0}/.editorconfig +0 -0
  19. {helius_python-0.1.1 → helius_python-0.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  20. {helius_python-0.1.1 → helius_python-0.2.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  21. {helius_python-0.1.1 → helius_python-0.2.0}/.github/workflows/python-package.yml +0 -0
  22. {helius_python-0.1.1 → helius_python-0.2.0}/.github/workflows/python-publish.yml +0 -0
  23. {helius_python-0.1.1 → helius_python-0.2.0}/.gitignore +0 -0
  24. {helius_python-0.1.1 → helius_python-0.2.0}/CLAUDE.md +0 -0
  25. {helius_python-0.1.1 → helius_python-0.2.0}/LICENSE +0 -0
  26. {helius_python-0.1.1 → helius_python-0.2.0}/requirements.txt +0 -0
  27. {helius_python-0.1.1 → helius_python-0.2.0}/src/helius/__init__.py +0 -0
  28. {helius_python-0.1.1 → helius_python-0.2.0}/src/helius/models.py +0 -0
  29. {helius_python-0.1.1 → helius_python-0.2.0}/tests/fixtures/account.json +0 -0
  30. {helius_python-0.1.1 → helius_python-0.2.0}/tests/fixtures/supply.json +0 -0
  31. {helius_python-0.1.1 → helius_python-0.2.0}/tests/unit/test_models.py +0 -0
@@ -24,7 +24,7 @@ body:
24
24
  your API key.
25
25
  render: python
26
26
  placeholder: |
27
- from helius.client import HeliusClient
27
+ from helius.solana_rpc import HeliusClient
28
28
 
29
29
  with HeliusClient(api_key="...") as c:
30
30
  c.get_balance(public_key="...")
@@ -1,4 +1,4 @@
1
- When implementing a function for a RPC method in the HeliusClient 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.
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** (`HeliusClient.get_*`, `is_*`, `request_*`, etc.) — every public method gets a docstring. Private methods (`_send`, dunders) do not need one.
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
- test_client.py # one test (or small group) per client method
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 `HeliusClient`, write at least one test that asserts **both** sides of the wire:
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.client import HeliusClient
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 HeliusClient(api_key="test") as c:
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 `HeliusClient` in tests with an explicit `api_key="test"` (or similar). Never rely on a real `.env` file.
201
- - Use the context-manager form (`with HeliusClient(...) as c:`) in tests so the `httpx.Client` is closed cleanly.
202
- - Group tests in `tests/unit/test_client.py` by method, but a single file is fine until it grows unwieldy.
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/client.py`](src/helius/client.py) and
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.1.1
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.client import HeliusClient
160
+ from helius.solana_rpc import SolanaRpcClient
210
161
 
211
- client = HeliusClient(api_key="YOUR_HELIUS_API_KEY")
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.client import HeliusClient
179
+ from helius.solana_rpc import SolanaRpcClient
229
180
 
230
- client = HeliusClient() # reads HELIUS_API_KEY from the environment or .env
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.client import HeliusClient
189
+ from helius.solana_rpc import SolanaRpcClient
239
190
 
240
- with HeliusClient(api_key="YOUR_HELIUS_API_KEY") as client:
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
- `HeliusClient` implements the context-manager protocol via `__enter__` /
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.client import HeliusClient
209
+ from helius.solana_rpc import SolanaRpcClient
259
210
 
260
- client = HeliusClient(api_key="YOUR_HELIUS_API_KEY")
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/client.py`](src/helius/client.py) for the current list of
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.client import HeliusClient
140
+ from helius.solana_rpc import SolanaRpcClient
190
141
 
191
- client = HeliusClient(api_key="YOUR_HELIUS_API_KEY")
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.client import HeliusClient
159
+ from helius.solana_rpc import SolanaRpcClient
209
160
 
210
- client = HeliusClient() # reads HELIUS_API_KEY from the environment or .env
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.client import HeliusClient
169
+ from helius.solana_rpc import SolanaRpcClient
219
170
 
220
- with HeliusClient(api_key="YOUR_HELIUS_API_KEY") as client:
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
- `HeliusClient` implements the context-manager protocol via `__enter__` /
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.client import HeliusClient
189
+ from helius.solana_rpc import SolanaRpcClient
239
190
 
240
- client = HeliusClient(api_key="YOUR_HELIUS_API_KEY")
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/client.py`](src/helius/client.py) for the current list of
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.client import HeliusClient
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 HeliusClient() as helius:
40
- slot = args.slot if args.slot is not None else helius.get_slot(
41
- commitment="finalized"
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(f"Total fees : {fees / LAMPORTS_PER_SOL:.9f} SOL "
74
- f"({fees:,} lamports)")
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.client import HeliusClient
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 = HeliusClient(base_url=DEVNET_URL)
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.client import HeliusClient
21
+ from helius.solana_rpc import SolanaRpcClient
22
22
 
23
23
 
24
24
  def main() -> int:
25
- with HeliusClient() as helius:
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.client import HeliusClient
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 HeliusClient() as helius:
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.client import HeliusClient
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 = HeliusClient()
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(f" foundation : {gov.foundation * 100:.2f}% for "
48
- f"{gov.foundation_term:.1f} years")
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(f"Non-circulating : "
54
- f"{supply.non_circulating / LAMPORTS_PER_SOL:>16,.4f} SOL")
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(f"Active validators : {len(current):>5} "
62
- f"{active_stake / LAMPORTS_PER_SOL:>16,.0f} SOL")
63
- print(f"Delinquent : {len(delinquent):>5} "
64
- f"{delinquent_stake / LAMPORTS_PER_SOL:>16,.0f} SOL")
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(f" {rank:>2}. {v.vote_pubkey} "
75
- f"{sol:>14,.0f} SOL ({share:5.2f}%) comm={v.commission}%")
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.client import HeliusClient
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 = HeliusClient()
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.client import HeliusClient
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 HeliusClient() as helius:
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(f"Fee : {meta.fee} lamports "
53
- f"({meta.fee / LAMPORTS_PER_SOL:.9f} SOL)")
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.client import HeliusClient
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 HeliusClient() as client: # reads HELIUS_API_KEY from env / .env
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(f"SOL balance: {lamports / LAMPORTS_PER_SOL:.9f} SOL "
49
- f"({lamports} lamports)\n")
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
- .strftime("%Y-%m-%d %H:%M:%SZ")
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
  )
@@ -10,7 +10,7 @@ build-backend = "hatchling.build"
10
10
 
11
11
  [project]
12
12
  name = "helius-python"
13
- version = "0.1.1"
13
+ version = "0.2.0"
14
14
  authors = [
15
15
  { name="Markos Narinian", email="manarinian@gmail.com" },
16
16
  ]
@@ -28,7 +28,7 @@ from helius.models import (
28
28
  )
29
29
 
30
30
 
31
- class HeliusClient:
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 minimum_ledger_slot(self) -> int:
948
- request = RpcRequest(method="minimumLedgerSlot").build()
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