Skip to main content
The Rust SDK is the canonical client for the Grid. The gen CLI uses it under the hood, and so does every Rust integration. This page covers what to install, how to configure a client, and a worked example for the most common job: sending a transfer. For the full API reference, see the rustdoc on docs.rs (when published) or build it locally with cargo doc -p client-sdk --open.

Crates

CrateWhat it is
gen-rpc-clientLow-level JSON-RPC client. Implements every method on the JSON-RPC API.
client-sdkRuntime helpers for GenClient, GenSigner, shared payload types, account helpers, errors, and test utilities.
client-sdk-macros#[generate_component_client] and #[generate_contract_client] macros that generate typed payload clients from ABI or manifest inputs.
dynamic-codecsDynamic ABI-driven encoding and decoding used by CLI tooling and runtime contract interaction without compile-time types.

Install

The crates are not yet published to crates.io. Pull them from the gen-bc repo by Git tag:
cargo add tokio --features full
cargo add client-sdk client-sdk-macros --git https://github.com/gen-bc/gen --tag v0.1.0 --features http
Or pin them in Cargo.toml directly:
[dependencies]
client-sdk = { git = "https://github.com/gen-bc/gen", tag = "v0.1.0", features = ["http"] }
client-sdk-macros = { git = "https://github.com/gen-bc/gen", tag = "v0.1.0" }
tokio = { version = "1", features = ["full"] }
Replace v0.1.0 with the tag matching your target network.

Configure a client

GenClient owns RPC access, view execution, activation submission, and waiting. Most apps construct one and reuse it.
DevNet access. Ask your Gen Labs contact for the RPC URL and a bearer token, then substitute them for <DEVNET_RPC_URL> and <your-jwt> in the examples below.
use client_sdk::GenClient;

#[tokio::main]
async fn main() -> Result<(), client_sdk::SdkError> {
    let client = GenClient::new_http("<DEVNET_RPC_URL>")?;
    Ok(())
}
new_http_with_rpc_config(...) accepts a ClientConfig if you need custom headers, timeouts, or a different RPC URL per request.

First call

Probe the validator to confirm connectivity:
let version = client.get_version().await?;
println!("validator {}, rpc protocol {}", version.release_version, version.rpc_protocol_version);
That single call rules out the most common setup failures: wrong endpoint, network unreachable, protocol version mismatch.

Send a transfer

Sending a transfer is a four-step flow: load a signer, build the activation payload, sign and submit it, await the result. The SDK collapses the last two into one call.
use client_sdk::{GenClient, GenSigner};
use client_sdk::faucet::{build_transfer_payload, FaucetTransferOptions};
use client_sdk::types::{AmountInSubunits, GvmAccount};

#[tokio::main]
async fn main() -> Result<(), client_sdk::SdkError> {
    let client = GenClient::new_http("<DEVNET_RPC_URL>")?;

    // 1. Load the sender's signing key.
    let signer = GenSigner::from_private_key_bytes(&[0u8; 32])?; // replace with your key

    // 2. Build the transfer payload.
    let recipient: GvmAccount = "grd@1qyqqqqqj6jdqp...".parse()?;
    let amount = AmountInSubunits::new(1_000);
    let payload = build_transfer_payload(recipient, amount, FaucetTransferOptions::builder().build())?;

    // 3. Sign, submit, and wait for finality.
    let outcome = client
        .sign_and_submit_and_wait_activation(&signer, payload)
        .await?;

    // 4. Inspect the outcome.
    println!("activation_id: {:?}", outcome.terminal_activation().id());
    println!("status: {:?}", outcome.terminal_activation().status());
    Ok(())
}
A few notes:
  • The example uses build_transfer_payload from client_sdk::faucet. That helper is the canonical path for moving the genesis token between accounts. To call a custom token contract, generate a typed client with #[generate_contract_client] and call its transfer method instead.
  • sign_and_submit_and_wait_activation polls until the activation reaches a terminal state. If you need fire-and-forget semantics use sign_and_submit_activation and follow up later with client.wait(activation_id).
  • AmountInSubunits is the smallest unit of the token. The genesis token uses 18 decimals; convert as needed before passing.

Loading keys

GenSigner accepts raw bytes today. Most production agents will load from a wallet file written by the CLI or from a KMS. The CLI’s wallet store lives at ~/.gen/wallets/. To bridge from there programmatically, use gen wallet export (see gen wallet) and feed the result to GenSigner::from_private_key_bytes. Never hard-code a private key in source. The example above uses [0u8; 32] only as a placeholder.

GenClient API surface

Every public method on GenClient, in source order. For full signatures and documentation, see the rustdoc.
MethodKindDescription
new(...)sync
new_http(...)syncCreates a new GenClient connected to the given HTTP RPC endpoint.
new_http_with_rpc_config(...)syncCreates a new GenClient using a caller-provided transport configuration.
rpc(...)syncExposes the underlying GenRpcApiClient for direct RPC access.
poll_config(...)sync
wait_strategy(...)sync
config(...)sync
get_version(...)asyncReturns the server’s reported artifact release version and RPC protocol version.
build_signable_activation(...)syncBuilds the canonical unsigned activation that will later be signed,
build_signable_activation_with_options(...)syncBuilds the canonical unsigned activation that will later be signed.
view(...)asyncExecutes a read-only view call and returns the raw result bytes.
simulate_activation(...)asyncSimulates a transaction without submitting it to the network.
simulate_activation_with_options(...)asyncSimulates a transaction without submitting it to the network, using
simulate_signable_activation(...)asyncSimulates a pre-built canonical unsigned activation without submitting it.
submit_activation(...)asyncSubmits a transaction and returns the activation ID.
sign_and_submit_activation(...)asyncBuilds, signs, and submits a transaction in one step.
sign_and_submit_activation_with_options(...)asyncBuilds, signs, and submits a transaction in one step, using
wait(...)asyncPolls an already-submitted activation until it reaches a terminal state
submit_activation_and_wait(...)asyncSubmits a transaction and polls until the activation reaches a terminal
sign_and_submit_and_wait_activation(...)asyncBuilds, signs, submits, and waits for a transaction in one step.
sign_and_submit_and_wait_activation_with_options(...)asyncBuilds, signs, submits, and waits for a transaction in one step, using
get_activation(...)asyncQueries the current status of an activation.
get_account(...)asyncReturns entity information (owner, installed components).
get_balance(...)asyncReturns the default GEN token balance for an account.
get_balances(...)asyncReturns all fungible balances for an account.
get_current_block_index(...)asyncReturns the latest finalized block index.
get_block(...)asyncReturns an aggregated closed block for a given block index.
get_component(...)asyncReturns component metadata and ABI.
get_storage_at(...)asyncReturns the raw storage value for a component at a given key.
get_contract(...)asyncReturns contract metadata and all component ABIs.
get_abi_by_contract_id(...)asyncReturns contract ABIs by contract ID.
get_abi_by_contract_code_id(...)asyncReturns contract ABIs by contract code ID.
get_trace(...)asyncReturns every activation ID in a trace by its trace ID.
create_account(...)asyncSubmits a faucet-signed Account::create_entity_with_id(account)
faucet(...)asyncSubmits a faucet-signed transfer (or transfer_with_confirmation
wait_for_tree_completion(...)asyncWaits for the entire activation tree rooted at activation_id to reach

Errors

The SDK returns structured SdkError variants. The ones you are likely to handle in production:
VariantWhen it fires
TransportNetwork error reaching the validator. Retry with backoff.
ServerValidator returned a JSON-RPC error. Do not retry without inspecting code.
ActivationPollingPolling for activation status timed out. Re-check via get_activation.
ActivationResultThe activation reached a non-success terminal state. The variant carries the failure reason.
Encode / DecodeBorsh serialization failure on inputs or outputs. Almost always a type mismatch in your code.
See the rustdoc for the full enum.

Next steps