Rust
hivekit-rs compiles a cdylib crate for wasm32-unknown-unknown and packages it as a .hbc. Rust gives
the smallest gas for real work and access to no_std-friendly crates.
Project setup
Section titled “Project setup”[lib]crate-type = ["cdylib", "rlib"] # rlib lets `cargo test` use the module natively
[dependencies]hivekit = { path = "../necter-sdk/hivekit-rs" }serde = { version = "1", features = ["derive"] }
[profile.release]opt-level = "s"lto = truecodegen-units = 1panic = "abort"strip = trueExporting functions
Section titled “Exporting functions”use hivekit::prelude::*;use serde::{Deserialize, Serialize};
#[derive(Deserialize)]struct Submit { pair: String, price: u64 }
#[derive(Serialize, Deserialize)]struct Quote { price: u64, updates: u64 }
/// Exported as "submit". Input is parsed from JSON into `Submit`; invalid input fails the call.#[hive_export]fn submit(input: Submit) -> Result<Json<Quote>, String> { let key = format!("price:{}", input.pair); let prev: Option<Quote> = storage::get_json(&key); let q = Quote { price: input.price, updates: prev.map_or(0, |p| p.updates) + 1 }; storage::set_json(&key, &q); emit("price_updated", &json!({ "pair": input.pair, "price": q.price })); Ok(Json(q))}
/// Exported under an explicit name.#[hive_export("latestPrice")]fn price(input: Value) -> Result<Value, String> { let pair = input["pair"].as_str().ok_or("`pair` is required")?; let q: Quote = storage::get_json(&format!("price:{pair}")).ok_or("no price")?; Ok(json!({ "pair": pair, "price": q.price }))}
hive_module!(submit, price); // every exported function, once per crate#[hive_export]acceptsfn(T) -> Rorfn() -> R.Tis anyDeserializeOwnedtype (empty input isnull). The export name is the camelCase of the identifier (add_numbers→addNumbers) unless you give one.Rmay beserde_json::Value,hivekit::Json<impl Serialize>,String/&'static str(returned as raw text),()(empty output), orResult<any of those, impl Display>.Erraborts the call with the message.hive_module!sorts the exports by name at compile time (duplicates are a compile error), writes them into ahivekit.functionscustom section thathivec buildreads for the manifest, and generatespub static HIVE_MODULE.- Panics are reported as an abort with the panic message. A failed call commits nothing.
Host API
Section titled “Host API”| Function | Host import | Notes |
|---|---|---|
storage::get / get_string / get_json |
storage.get |
None if absent |
storage::set / set_json |
storage.set |
key 1–256 bytes, value ≤ 64 KiB; empty value deletes |
storage::del |
storage.del |
|
emit(name, &data) |
hive.emit |
no floats; integers within ±(2^53−1) |
call(addr, fn, &[u8]), call_json(addr, fn, &Value) |
hive.call |
Err(CallError); e.code() gives −1, −2, −3, −5 or −6 |
hash(&[u8]) |
crypto.hash |
Keccak-256 as 0x… |
log(&str) |
console.log |
debug only |
abort(&str) -> ! |
hive.abort |
fails the call |
The compiled module imports only the functions you use, so a module without storage::* and call* is
stateless and can be a committee worker.
Using crates
Section titled “Using crates”Any crate that compiles for wasm32-unknown-unknown without WASI, clocks or randomness works. Two that are
used in the use cases and verified under NDSR:
k256(default-features = false, features = ["ecdsa"]): secp256k1 / EIP-191 signature recovery, about 9.6 M gas per recovery. Attestationed25519-dalek(default-features = false): ed25519 verification, about 2.5 M gas per signature. Telemetry
hivec build # current crate → dist/<name>.hbchivec build --example counter # build a cargo example instead of the libraryhivec build path/to/module.wasm --functions a,b # package a wasm you built yourselfhivec inspect dist/my_module.hbc # verify like NDSR's loader; --json for machine outputhivec functions dist/my_module.hbc # func_id → namehivec run dist/my_module.hbc increment '{"by":2}' --data-dir .nodehivec run dist/counter.hbc callAdd '{"module":"0x…","a":1,"b":2}' --module dist/math_module.hbchivec run has no interpreter of its own: it calls ndsr run, so results are exactly what a node
produces. --module places another artifact in <data-dir>/modules/<address>.hbc so hive.call can reach
it. Full flags: hivec CLI.
Examples in the SDK
Section titled “Examples in the SDK”hivekit-rs/examples/: math_module (pure functions, crypto.hash, a storage-writing record),
counter (storage, events, logging, a failing function, hive.call into math_module), price_oracle
(typed input and Json<T> output). Built from source they reproduce the addresses deployed on the testnet:
math_module = 0x87597a6f0bff260f27026945649ad6889c71848b2a2e47e8ba6daf5cde4cdad3,
counter = 0xd67ffc0300427c9c5d391f31ad4379717d749a33b2e3459d9c44b89d7fbd80f3.
Testing: Testing modules.