Expand description
§near-kit
A clean, ergonomic Rust client for NEAR Protocol.
near-kit provides a fluent API for interacting with NEAR Protocol,
with a focus on developer experience and type safety. It’s a ground-up
implementation with hand-rolled types based on actual NEAR RPC responses.
§Quick Start
Add near-kit to your Cargo.toml:
cargo add near-kit§Read-Only Operations
No credentials needed for querying blockchain state:
use near_kit::*;
#[tokio::main]
async fn main() -> Result<(), Error> {
let near = Near::testnet().build();
// Check account balance
let balance = near.balance("alice.testnet").await?;
println!("Balance: {}", balance.available);
// Call a view function
let count: u64 = near.view("counter.testnet", "get_count").await?;
println!("Count: {}", count);
Ok(())
}§Transactions (Writes)
For state-changing operations, configure a signer:
use near_kit::*;
#[tokio::main]
async fn main() -> Result<(), Error> {
let near = Near::testnet()
.credentials("ed25519:YOUR_PRIVATE_KEY", "your-account.testnet")?
.build();
// Transfer NEAR
near.transfer("bob.testnet", NearToken::near(1)).await?;
// Call a contract function
near.call("counter.testnet", "increment")
.gas("30 Tgas")
.await?;
Ok(())
}§Design Principles
- Single entry point — Everything flows through the
Nearclient - Configure once — Network and signer are set at client creation
- Type-safe but ergonomic — Accept both typed values and string parsing
- Explicit units — No ambiguous amounts; must specify
NEAR,yocto,Tgas, etc. - Progressive disclosure — Simple things are simple; advanced options available when needed
§Core Types
| Type | Description |
|---|---|
Near | Main client — the single entry point for all operations |
AccountId | Validated NEAR account identifier |
NearToken | Token amount with yoctoNEAR precision |
Gas | Gas units for transactions |
PublicKey / SecretKey | Ed25519 cryptographic keys |
CryptoHash | 32-byte SHA-256 hash (blocks, transactions) |
§Working with Amounts
§Typed Constructors (Recommended)
For compile-time safety, use the typed constructors:
use near_kit::{NearToken, Gas};
// NEAR amounts
let five_near = NearToken::near(5);
let half_near = NearToken::millinear(500);
let one_yocto = NearToken::yocto(1);
// Gas amounts
let gas = Gas::tgas(30); // 30 teragas
let more_gas = Gas::ggas(5); // 5 gigagas§String Parsing (Runtime Input)
For CLI arguments, config files, or user input:
use near_kit::{NearToken, Gas};
// Parse NEAR amounts
let amount: NearToken = "5 NEAR".parse().unwrap();
let small: NearToken = "100 milliNEAR".parse().unwrap();
let tiny: NearToken = "1000 yocto".parse().unwrap();
// Parse gas
let gas: Gas = "30 Tgas".parse().unwrap();Many builder methods also accept strings directly:
near.call("contract.testnet", "method")
.gas("100 Tgas")
.deposit("0.1 NEAR")
.await?;§Query Builders
Read operations return query builders that can be customized before awaiting:
use near_kit::*;
let near = Near::testnet().build();
// Simple query
let balance = near.balance("alice.testnet").await?;
// Query at a specific block height
let old_balance = near.balance("alice.testnet")
.at_block(100_000_000)
.await?;
// Query with different finality
let optimistic = near.balance("alice.testnet")
.finality(Finality::Optimistic)
.await?;§Transaction Builders
Write operations return transaction builders for customization:
use near_kit::*;
// Function call with arguments, gas, and deposit
near.call("nft.testnet", "nft_mint")
.args(serde_json::json!({ "token_id": "1", "receiver_id": "alice.testnet" }))
.gas("100 Tgas")
.deposit("0.1 NEAR")
.await?;
// Wait for different execution levels
near.transfer("bob.testnet", NearToken::near(1))
.wait_until(TxExecutionStatus::Final)
.await?;§Multi-Action Transactions
Chain multiple actions into a single atomic transaction:
use near_kit::*;
// Create a sub-account with funding and deploy a contract
let new_key: PublicKey = "ed25519:6E8sCci...".parse()?;
let wasm = std::fs::read("contract.wasm")?;
near.transaction("sub.alice.testnet")
.create_account()
.transfer(NearToken::near(10))
.add_full_access_key(new_key)
.deploy(wasm)
.call("new")
.args(serde_json::json!({ "owner_id": "alice.testnet" }))
.send()
.await?;§Token Helpers
Built-in support for fungible (NEP-141) and non-fungible (NEP-171) tokens.
For common tokens like USDC, USDT, and wNEAR, use the provided tokens constants
to avoid copy-pasting addresses. They automatically resolve to the correct address
based on the network:
use near_kit::*;
let near = Near::mainnet().build();
// Known tokens auto-resolve based on network
let usdc = near.ft(tokens::USDC)?;
let balance = usdc.balance_of("alice.near").await?;
println!("Balance: {}", balance); // "1.50 USDC"
// Or use raw addresses for any token
let custom = near.ft("my-token.near")?;
// NFTs (NEP-171)
let nft = near.nft("nft.testnet")?;
let tokens = nft.tokens_for_owner("alice.testnet", None, Some(10)).await?;Available known tokens: tokens::USDC, tokens::USDT, tokens::W_NEAR
§Typed Contract Interfaces
Use the #[near_kit::contract] macro for compile-time type safety:
use near_kit::*;
use serde::Serialize;
#[near_kit::contract]
pub trait Counter {
// View method (read-only, no signer needed)
fn get_count(&self) -> u64;
// Change method (requires signer)
#[call]
fn increment(&mut self);
// Change method with arguments
#[call]
fn add(&mut self, args: AddArgs);
}
#[derive(Serialize)]
pub struct AddArgs {
pub value: u64,
}
async fn example(near: &Near) -> Result<(), Error> {
let counter = near.contract::<Counter>("counter.testnet");
// Type-safe view call
let count = counter.get_count().await?;
// Type-safe change calls
counter.increment().await?;
counter.add(AddArgs { value: 5 }).await?;
Ok(())
}§Signers
Several signer implementations are available:
| Signer | Use Case |
|---|---|
InMemorySigner | Simple scripts with a private key |
FileSigner | Load from ~/.near-credentials (near-cli compatible) |
EnvSigner | CI/CD environments via NEAR_ACCOUNT_ID / NEAR_PRIVATE_KEY |
RotatingSigner | High-throughput with multiple keys (avoids nonce collisions) |
KeyringSigner | System keyring (macOS Keychain, etc.) — requires keyring feature |
use near_kit::*;
// Using credentials directly
let near = Near::testnet()
.credentials("ed25519:...", "alice.testnet")?
.build();
// Using a custom signer
let signer = FileSigner::new("testnet", "alice.testnet")?;
let near = Near::testnet().signer(signer).build();
// Environment variables (CI/CD)
let signer = EnvSigner::new()?;
let near = Near::testnet().signer(signer).build();§Multiple Accounts
For production apps that manage multiple accounts, use Near::with_signer to
derive clients that share the same RPC connection but sign as different accounts:
use near_kit::*;
let near = Near::testnet().build();
let alice = near.with_signer(InMemorySigner::new("alice.testnet", "ed25519:...")?);
let bob = near.with_signer(InMemorySigner::new("bob.testnet", "ed25519:...")?);
// Both share the same connection, no overhead
// alice.transfer("carol.testnet", NearToken::near(1)).await?;
// bob.transfer("carol.testnet", NearToken::near(2)).await?;Use with_signer for multi-account management and
RotatingSigner for high-throughput single-account usage (multiple keys to
avoid nonce collisions). For one-off overrides on a single transaction, use
.sign_with() on the transaction builder.
§Sandbox Testing
Enable the sandbox feature for local testing with near-sandbox:
[dev-dependencies]
near-kit = { version = "0.1", features = ["sandbox"] }
near-sandbox = "0.3"use near_kit::*;
use near_sandbox::Sandbox;
#[tokio::test]
async fn test_contract() {
let sandbox = Sandbox::start().await.unwrap();
let near = Near::sandbox(&sandbox);
// Root account is pre-configured with credentials
near.transfer("alice.sandbox", NearToken::near(10)).await.unwrap();
}§Feature Flags
| Feature | Description |
|---|---|
sandbox | Integration with near-sandbox for local testing |
keyring | System keyring signer (macOS Keychain, Windows Credential Manager, etc.) |
§Error Handling
All operations return Result<T, near_kit::Error>. The Error type provides
detailed information about failures:
use near_kit::*;
let near = Near::testnet().build();
match near.balance("nonexistent.testnet").await {
Ok(balance) => println!("Balance: {}", balance.available),
Err(Error::Rpc(RpcError::AccountNotFound(account))) => {
println!("Account {} doesn't exist", account);
}
Err(e) => return Err(e),
}Re-exports§
pub use error::Error;pub use error::RpcError;pub use types::nep413;pub use contract::Contract;pub use contract::ContractClient;pub use client::AccessKeysQuery;pub use client::AccountExistsQuery;pub use client::AccountQuery;pub use client::BalanceQuery;pub use client::CallBuilder;pub use client::DelegateOptions;pub use client::DelegateResult;pub use client::EnvSigner;pub use client::FileSigner;pub use client::InMemorySigner;pub use client::Near;pub use client::NearBuilder;pub use client::RetryConfig;pub use client::RotatingSigner;pub use client::RpcClient;pub use client::SandboxNetwork;pub use client::Signer;pub use client::SigningKey;pub use client::TransactionBuilder;pub use client::TransactionSend;pub use client::ViewCall;pub use client::ViewCallBorsh;pub use client::KeyringSigner;pub use tokens::FtAmount;pub use tokens::FtMetadata;pub use tokens::FungibleToken;pub use tokens::IntoContractId;pub use tokens::KnownToken;pub use tokens::NftContractMetadata;pub use tokens::NftToken;pub use tokens::NftTokenMetadata;pub use tokens::NonFungibleToken;pub use tokens::StorageBalance;pub use tokens::StorageBalanceBounds;pub use tokens::StorageDepositCall;pub use tokens::USDC;pub use tokens::USDT;pub use tokens::W_NEAR;pub use types::*;
Modules§
- client
- Client module for interacting with NEAR Protocol.
- contract
- Typed contract interfaces.
- error
- Error types for near-kit.
- tokens
- Token helpers for NEP-141 (Fungible Tokens) and NEP-171 (Non-Fungible Tokens).
- types
- Core types for NEAR Protocol.