Skip to content

Commit 5ac18f7

Browse files
madninjaclaude
andauthored
chore: overhaul docs and fix associated_token_address typo (#517)
* chore: overhaul docs and fix associated_token_address typo Rewrite root README with complete CLI command reference including the new swap command, all environment variables, and workspace overview. Add helium-lib crate README with module table, feature flags, and usage example. Add rustdoc comments across all public items in helium-lib. Rename associated_token_adress -> associated_token_address throughout the codebase. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address PR review findings - Remove nonexistent --format global option from README - Fix verify -> info for sharded wallet example - Remove false transfer/pay alias claim - Remove dc from transferable token list - Fix Jupiter V6 -> V2 in helium-lib README - Fix inaccurate module docs (queue, schedule, boosting, dc) - Standardize all doc comments to third-person voice (RFC 505) - Add missing blank lines before doc comments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: cargo fmt after associated_token_address rename The one-character longer method name pushed a line over the width limit, triggering cargo fmt --check failure in the hygiene CI step. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 77b9123 commit 5ac18f7

29 files changed

Lines changed: 756 additions & 153 deletions

README.md

Lines changed: 201 additions & 132 deletions
Large diffs are not rendered by default.

helium-lib/README.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# helium-lib
2+
3+
Core Rust library for interacting with the Helium network on Solana. Used by
4+
the `helium-wallet` CLI and available for integration into other Rust projects.
5+
6+
## Modules
7+
8+
| Module | Purpose |
9+
|--------|---------|
10+
| `asset` | Compressed NFT asset operations (fetch, transfer, burn, search) |
11+
| `b64` | Base64 message encoding/decoding |
12+
| `boosting` | Mobile hotspot hex boosting |
13+
| `client` | Solana RPC client wrapper with DAS (Digital Asset Standard) and gRPC config support |
14+
| `dao` | Helium DAO and SubDAO operations (HNT, IOT, MOBILE) |
15+
| `dc` | Data credit minting, delegation, and burning |
16+
| `entity_key` | Entity key management for hotspots |
17+
| `error` | Error types (`Error`, `DecodeError`, `EncodeError`, `ConfirmationError`, `JupiterError`) |
18+
| `hotspot` | Hotspot CRUD, transfer, and onboarding (submodules: `dataonly`, `info`, `cert`) |
19+
| `jupiter` | Token swaps via Jupiter V2 API |
20+
| `keypair` | Solana keypair wrappers with optional BIP39 mnemonic support |
21+
| `kta` | KeyToAsset (KTA) lookups |
22+
| `memo` | Memo encoding/decoding |
23+
| `message` | Versioned transaction message building |
24+
| `onboarding` | Hotspot onboarding API client |
25+
| `priority_fee` | Compute budget and priority fee calculation |
26+
| `programs` | On-chain program IDs (`helium_sub_daos`, `lazy_distributor`, etc.) |
27+
| `queue` | Reward queue operations |
28+
| `reward` | Reward claiming via lazy distributor |
29+
| `schedule` | Schedule-based reward claiming |
30+
| `token` | Token operations (HNT, MOBILE, IOT, DC, SOL, USDC) -- balances, transfers, burns, prices |
31+
| `transaction` | Versioned transaction building and confirmation |
32+
33+
## Feature Flags
34+
35+
| Feature | Description |
36+
|---------|-------------|
37+
| `clap` | Adds CLI argument parsing support (value parsers for `Token` types) |
38+
| `mnemonic` | Enables BIP39 mnemonic/seed phrase support for keypairs via `helium-mnemonic` |
39+
40+
## Re-exports
41+
42+
The crate re-exports several foundational Solana and Anchor crates for
43+
convenience, so downstream consumers do not need to manage version alignment
44+
themselves:
45+
46+
- `anchor_client`
47+
- `anchor_lang`
48+
- `anchor_spl`
49+
- `solana_sdk` (includes `bs58`)
50+
- `solana_program`
51+
- `solana_client`
52+
- `solana_transaction_status`
53+
- `tuktuk_sdk`
54+
55+
## Usage
56+
57+
Add `helium-lib` to your `Cargo.toml`:
58+
59+
```toml
60+
[dependencies]
61+
helium-lib = { git = "https://github.com/helium/helium-wallet-rs" }
62+
```
63+
64+
### Creating a client and querying a token balance
65+
66+
```rust
67+
use helium_lib::{
68+
client::Client,
69+
keypair::Pubkey,
70+
token::{self, Token},
71+
};
72+
use std::str::FromStr;
73+
74+
#[tokio::main]
75+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
76+
// Connect to mainnet (accepts "m", "mainnet-beta", "d", "devnet", or a URL)
77+
let client = Client::try_from("m")?;
78+
79+
// Initialize the KeyToAsset cache
80+
helium_lib::init(client.solana_client.clone())?;
81+
82+
// Look up the HNT associated token address for a wallet
83+
let wallet = Pubkey::from_str("YOUR_SOLANA_PUBKEY")?;
84+
let hnt_address = Token::Hnt.associated_token_address(&wallet);
85+
86+
// Fetch the balance
87+
if let Some(balance) = token::balance_for_address(&client, &hnt_address).await? {
88+
println!("HNT balance: {}", balance.amount);
89+
}
90+
91+
Ok(())
92+
}
93+
```

helium-lib/src/asset.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use serde::{Deserialize, Serialize};
2121
use solana_sdk::{signature::NullSigner, signer::Signer};
2222
use std::{collections::HashMap, result::Result as StdResult, str::FromStr};
2323

24+
/// Fetches a compressed NFT asset for a given Helium entity key (e.g., hotspot public key).
2425
pub async fn for_entity_key<E, C: AsRef<DasClient>>(
2526
client: &C,
2627
entity_key: &E,
@@ -32,6 +33,7 @@ where
3233
for_kta(client, &kta).await
3334
}
3435

36+
/// Fetches compressed NFT assets for multiple entity keys in batch.
3537
pub async fn for_entity_keys<E, C: AsRef<DasClient>>(
3638
client: &C,
3739
entity_keys: &[E],
@@ -43,13 +45,15 @@ where
4345
for_ktas(client, ktas.as_slice()).await
4446
}
4547

48+
/// Fetches the compressed NFT asset referenced by a key-to-asset account.
4649
pub async fn for_kta<C: AsRef<DasClient>>(
4750
client: &C,
4851
kta: &helium_entity_manager::accounts::KeyToAssetV0,
4952
) -> Result<Asset, Error> {
5053
get(client, &kta.asset).await
5154
}
5255

56+
/// Fetches compressed NFT assets for multiple key-to-asset accounts in batch.
5357
pub async fn for_ktas<C: AsRef<DasClient>>(
5458
client: &C,
5559
ktas: &[helium_entity_manager::accounts::KeyToAssetV0],
@@ -58,18 +62,21 @@ pub async fn for_ktas<C: AsRef<DasClient>>(
5862
get_many(client, &pubkeys).await
5963
}
6064

65+
/// Fetches both the asset and its Merkle proof from a key-to-asset account.
6166
pub async fn for_kta_with_proof<C: AsRef<DasClient> + AsRef<SolanaRpcClient>>(
6267
client: &C,
6368
kta: &helium_entity_manager::accounts::KeyToAssetV0,
6469
) -> Result<(Asset, AssetProof), Error> {
6570
get_with_proof(client, &kta.asset).await
6671
}
6772

73+
/// Fetches a single compressed NFT asset by its Solana public key.
6874
pub async fn get<C: AsRef<DasClient>>(client: &C, pubkey: &Pubkey) -> Result<Asset, Error> {
6975
let asset_response: Asset = client.as_ref().get_asset(pubkey).await?;
7076
Ok(asset_response)
7177
}
7278

79+
/// Fetches multiple compressed NFT assets by their Solana public keys (batched in chunks of 1000).
7380
pub async fn get_many<C: AsRef<DasClient>>(
7481
client: &C,
7582
pubkeys: &[Pubkey],
@@ -86,6 +93,7 @@ pub async fn get_many<C: AsRef<DasClient>>(
8693
Ok(assets)
8794
}
8895

96+
/// Fetches an asset and its Merkle proof concurrently. Needed for transfer/burn operations.
8997
pub async fn get_with_proof<C: AsRef<DasClient> + AsRef<SolanaRpcClient>>(
9098
client: &C,
9199
pubkey: &Pubkey,
@@ -94,6 +102,7 @@ pub async fn get_with_proof<C: AsRef<DasClient> + AsRef<SolanaRpcClient>>(
94102
Ok((asset, asset_proof))
95103
}
96104

105+
/// Derives the Metaplex metadata PDA for a collection mint.
97106
pub fn collection_metadata_key(collection_key: &Pubkey) -> Pubkey {
98107
let (collection_metadata, _bump) = Pubkey::find_program_address(
99108
&[
@@ -106,6 +115,7 @@ pub fn collection_metadata_key(collection_key: &Pubkey) -> Pubkey {
106115
collection_metadata
107116
}
108117

118+
/// Derives the Metaplex master edition PDA for a collection mint.
109119
pub fn collection_master_edition_key(collection_key: &Pubkey) -> Pubkey {
110120
let (collection_master_edition, _cme_bump) = Pubkey::find_program_address(
111121
&[
@@ -119,18 +129,21 @@ pub fn collection_master_edition_key(collection_key: &Pubkey) -> Pubkey {
119129
collection_master_edition
120130
}
121131

132+
/// Derives the Bubblegum tree authority PDA for a given Merkle tree.
122133
pub fn merkle_tree_authority(merkle_tree: &Pubkey) -> Pubkey {
123134
let (tree_authority, _ta_bump) =
124135
Pubkey::find_program_address(&[merkle_tree.as_ref()], &bubblegum::ID);
125136
tree_authority
126137
}
127138

139+
/// Derives the Bubblegum collection CPI signer PDA.
128140
pub fn bubblegum_signer() -> Pubkey {
129141
let (bubblegum_signer, _bump) =
130142
Pubkey::find_program_address(&[b"collection_cpi"], &bubblegum::ID);
131143
bubblegum_signer
132144
}
133145

146+
/// Utilities for determining Merkle tree canopy heights, used to trim proof sizes.
134147
pub mod canopy {
135148
use super::*;
136149
use crate::spl_account_compression::types::{
@@ -169,6 +182,7 @@ pub mod canopy {
169182
Ok(canopy_depth as usize)
170183
}
171184

185+
/// Returns the canopy height for a single Merkle tree.
172186
pub async fn height<C: AsRef<SolanaRpcClient>>(
173187
client: &C,
174188
tree: &Pubkey,
@@ -180,6 +194,7 @@ pub mod canopy {
180194
height_from_account(&tree_account)
181195
}
182196

197+
/// Returns canopy heights for multiple Merkle trees, using a remote cache when available.
183198
pub async fn heights<C: AsRef<SolanaRpcClient>>(
184199
client: &C,
185200
trees: &[Pubkey],
@@ -325,9 +340,11 @@ pub mod canopy {
325340
}
326341
}
327342

343+
/// Functions for fetching Merkle proofs from DAS, with canopy height applied.
328344
pub mod proof {
329345
use super::*;
330346

347+
/// Fetches the Merkle proof for a single asset, including canopy height.
331348
pub async fn get<C: AsRef<DasClient> + AsRef<SolanaRpcClient>>(
332349
client: &C,
333350
pubkey: &Pubkey,
@@ -339,6 +356,7 @@ pub mod proof {
339356
Ok(asset_proof)
340357
}
341358

359+
/// Fetches Merkle proofs for multiple assets in batch, including canopy heights.
342360
pub async fn get_many<C: AsRef<DasClient> + AsRef<SolanaRpcClient>>(
343361
client: &C,
344362
pubkeys: &[Pubkey],
@@ -369,13 +387,15 @@ pub mod proof {
369387
}
370388
}
371389

390+
/// Searches for compressed NFT assets using DAS search parameters.
372391
pub async fn search<C: AsRef<DasClient>>(
373392
client: &C,
374393
params: DasSearchAssetsParams,
375394
) -> Result<AssetPage, Error> {
376395
Ok(client.as_ref().search_assets(params).await?)
377396
}
378397

398+
/// Returns all assets owned by a wallet that match a given creator, with automatic pagination.
379399
pub async fn for_owner<C: AsRef<DasClient>>(
380400
client: &C,
381401
creator: &Pubkey,
@@ -402,6 +422,7 @@ pub async fn for_owner<C: AsRef<DasClient>>(
402422
Ok(results)
403423
}
404424

425+
/// Builds a Bubblegum transfer instruction for a compressed NFT asset.
405426
pub fn transfer_instruction(
406427
recipient: &Pubkey,
407428
asset: &Asset,
@@ -441,7 +462,7 @@ pub fn transfer_instruction(
441462
Ok(ix)
442463
}
443464

444-
/// Get an unsigned transaction for an asset transfer
465+
/// Gets an unsigned transaction for an asset transfer.
445466
///
446467
/// The asset is transferred from the owner to the given recipient
447468
/// Note that the owner is currently expected to sign this transaction and pay for
@@ -467,6 +488,7 @@ pub async fn transfer_transaction<C: AsRef<SolanaRpcClient> + AsRef<DasClient>>(
467488
Ok((txn, block_height))
468489
}
469490

491+
/// Signs and returns a transaction to transfer a compressed NFT to a new owner.
470492
pub async fn transfer<C: AsRef<SolanaRpcClient> + AsRef<DasClient>>(
471493
client: &C,
472494
pubkey: &Pubkey,
@@ -481,7 +503,7 @@ pub async fn transfer<C: AsRef<SolanaRpcClient> + AsRef<DasClient>>(
481503
Ok((txn, block_height))
482504
}
483505

484-
/// Get an unsigned burn transaction for an asset
506+
/// Gets an unsigned burn transaction for an asset.
485507
pub async fn burn_message<C: AsRef<SolanaRpcClient> + AsRef<DasClient>>(
486508
client: &C,
487509
pubkey: &Pubkey,
@@ -529,6 +551,7 @@ pub async fn burn_message<C: AsRef<SolanaRpcClient> + AsRef<DasClient>>(
529551
message::mk_message(client, ixs, &opts.lut_addresses, &asset.ownership.owner).await
530552
}
531553

554+
/// Signs and returns a transaction to permanently burn (destroy) a compressed NFT.
532555
pub async fn burn<C: AsRef<SolanaRpcClient> + AsRef<DasClient>>(
533556
client: &C,
534557
pubkey: &Pubkey,
@@ -540,6 +563,7 @@ pub async fn burn<C: AsRef<SolanaRpcClient> + AsRef<DasClient>>(
540563
Ok((txn, block_height))
541564
}
542565

566+
/// A paginated list of compressed NFT assets returned from a DAS search.
543567
#[derive(Deserialize, Serialize, Clone)]
544568
pub struct AssetPage {
545569
pub total: u32,
@@ -548,8 +572,10 @@ pub struct AssetPage {
548572
pub items: Vec<Asset>,
549573
}
550574

575+
/// A Solana compressed NFT (cNFT) representing a Helium entity such as a hotspot.
551576
#[derive(Debug, Serialize, Deserialize, Clone)]
552577
pub struct Asset {
578+
/// The asset's on-chain address.
553579
#[serde(with = "serde_pubkey")]
554580
pub id: Pubkey,
555581
pub compression: AssetCompression,
@@ -561,6 +587,7 @@ pub struct Asset {
561587
pub burnt: bool,
562588
}
563589

590+
/// A creator entry on a compressed NFT, with verification status and royalty share.
564591
#[derive(Debug, Deserialize, Serialize, Clone)]
565592
pub struct AssetCreator {
566593
#[serde(with = "serde_pubkey")]
@@ -571,6 +598,7 @@ pub struct AssetCreator {
571598

572599
pub type Hash = [u8; 32];
573600

601+
/// Compression metadata for a cNFT: hashes, leaf position, and the Merkle tree it belongs to.
574602
#[derive(Debug, Deserialize, Serialize, Clone)]
575603
pub struct AssetCompression {
576604
#[serde(with = "serde_hash")]
@@ -588,13 +616,15 @@ impl AssetCompression {
588616
}
589617
}
590618

619+
/// A collection group that a compressed NFT belongs to (e.g., the Helium hotspot collection).
591620
#[derive(Debug, Deserialize, Serialize, Clone)]
592621
pub struct AssetGroup {
593622
pub group_key: String,
594623
#[serde(with = "serde_pubkey")]
595624
pub group_value: Pubkey,
596625
}
597626

627+
/// Ownership information for a compressed NFT: current owner and optional delegate.
598628
#[derive(Debug, Deserialize, Serialize, Clone)]
599629
pub struct AssetOwnership {
600630
#[serde(with = "serde_pubkey")]
@@ -603,6 +633,7 @@ pub struct AssetOwnership {
603633
pub delegate: Option<Pubkey>,
604634
}
605635

636+
/// Merkle proof for a compressed NFT, required for on-chain operations (transfer, burn, etc.).
606637
#[derive(Debug, Deserialize, Clone)]
607638
pub struct AssetProof {
608639
pub proof: Vec<String>,
@@ -665,12 +696,14 @@ impl AssetProof {
665696
}
666697
}
667698

699+
/// The off-chain content associated with a compressed NFT (metadata URI and parsed metadata).
668700
#[derive(Debug, Deserialize, Serialize, Clone)]
669701
pub struct AssetContent {
670702
pub metadata: AssetMetadata,
671703
pub json_uri: url::Url,
672704
}
673705

706+
/// Parsed JSON metadata for a compressed NFT, including name, symbol, and trait attributes.
674707
#[derive(Debug, Deserialize, Serialize, Clone)]
675708
pub struct AssetMetadata {
676709
#[serde(default)]
@@ -690,6 +723,7 @@ impl AssetMetadata {
690723
}
691724
}
692725

726+
/// A single key-value trait attribute from an asset's metadata (e.g., `"trait_type": "entity_key"`).
693727
#[derive(Debug, Deserialize, Serialize, Clone)]
694728
pub struct AssetMetadataAttribute {
695729
#[serde(default)]

0 commit comments

Comments
 (0)