This is the official Rust implementation of the Knish.IO client SDK. Its purpose is to expose libraries for building and signing Knish.IO Molecules, composing Atoms, generating Wallets, and much more with native performance, memory safety, and quantum-resistant security.
The SDK can be installed via Cargo:
# Add to Cargo.toml
[dependencies]
knishio-client = "0.1.0"
# Or install from the command line
cargo add knishio-clientRequirements:
- Rust 1.70 or higher
- Cargo for dependency management
- Required dependencies:
serde,sha3,hex,base64,chrono,rand
After installation, import the SDK in your project:
use knishio_client::{KnishIOClient, Molecule, Wallet, Atom};
use knishio_client::crypto::shake256;
use knishio_client::types::{MetaItem, Isotope};The purpose of the Knish.IO SDK is to expose various ledger functions to new or existing applications.
There are two ways to take advantage of these functions:
-
The easy way: use the
KnishIOClientwrapper struct -
The granular way: build
AtomandMoleculeinstances and broadcast GraphQL messages yourself
This document will explain both ways.
-
Include the wrapper struct in your application code:
use knishio_client::{KnishIOClient, ClientBuilder};
-
Instantiate the client — either with the builder (recommended) or directly:
Using
ClientBuilder(recommended):let client = ClientBuilder::new( vec!["https://some.knishio.validator.node.url/graphql".to_string()], "myTopSecretCode".to_string(), ) .cell_slug("my-cell-slug".to_string()) .build()?;
Using
KnishIOClient::new()directly:let mut client = KnishIOClient::new( vec!["https://some.knishio.validator.node.url/graphql".to_string()], Some("my-cell-slug".to_string()), None, // socket config None, // GraphQL client None, // server SDK version None, // logging ); client.set_secret("myTopSecretCode");
-
Set your secret for authentication:
client.set_secret("myTopSecretCode"); // Note: The Rust SDK uses stored secret for cryptographic operations // This is equivalent to the JavaScript SDK's await client.requestAuthToken()
(Note: The
secretparameter can be a salted combination of username + password, a biometric hash, an existing user identifier from an external authentication process, for example) -
Begin using
clientto trigger commands described below...
-
Query metadata for a Wallet Bundle. Omit the
bundle_hashparameter to query your own Wallet Bundle:let response = client.query_bundle( Some("c47e20f99df190e418f0cc5ddfa2791e9ccc4eb297cfa21bd317dc0f98313b1d") ).await?; println!("{}", response); // Raw Metadata as JSON Value
-
Query metadata for a Meta Asset:
let result = client.query_meta( "Vehicle", // meta_type Some("CAR123"), // meta_id Some("LicensePlate"), // key Some("1H17P"), // value Some(true) // through_atom (query via atom path) ).await?; println!("{}", result); // Raw Metadata as JSON Value
-
Writing new metadata for a Meta Asset:
use std::collections::HashMap; use serde_json::json; let mut metadata = HashMap::new(); metadata.insert("type".to_string(), json!("fire")); metadata.insert("weaknesses".to_string(), json!("rock,water,electric")); metadata.insert("immunities".to_string(), json!("ground")); metadata.insert("hp".to_string(), json!("78")); metadata.insert("attack".to_string(), json!("84")); let response = client.create_meta( "Pokemon", // meta_type "Charizard", // meta_id metadata, None // policy (optional) ).await?; if response.success() { println!("Metadata created successfully!"); } println!("{}", response.data()); // Raw response
-
Query Wallets associated with a Wallet Bundle:
let wallets = client.query_wallets( Some("c47e20f99df190e418f0cc5ddfa2791e9ccc4eb297cfa21bd317dc0f98313b1d"), // bundle_hash Some("FOO"), // token (optional) ).await?; println!("{:?}", wallets); // Vec<Wallet>
-
Declaring new Wallets:
(Note: If Tokens are sent to undeclared Wallets, Shadow Wallets will be used (placeholder Wallets that can receive, but cannot send) to store tokens until they are claimed.)
let response = client.create_wallet("FOO").await?; // Token Slug for the wallet we are declaring if response.success() { println!("Wallet created successfully!"); } println!("{}", response.data()); // Raw response
-
Issuing new Tokens:
use std::collections::HashMap; use serde_json::json; let mut token_meta = HashMap::new(); token_meta.insert("name".to_string(), json!("CrazyCoin")); token_meta.insert("fungibility".to_string(), json!("fungible")); token_meta.insert("supply".to_string(), json!("limited")); token_meta.insert("decimals".to_string(), json!("2")); let response = client.create_token( "CRZY", // Token slug (ticker symbol) Some(100000000.0), // Initial amount to issue Some(token_meta), // Token metadata None, // batch_id (optional, for stackable tokens) vec![], // units (optional, for stackable tokens) ).await?; if response.success() { println!("Token created successfully!"); } println!("{}", response.data()); // Raw response
-
Transferring Tokens to other users:
let response = client.transfer_token( "7bf38257401eb3b0f20cabf5e6cf3f14c76760386473b220d95fa1c38642b61d", // Recipient's bundle hash "CRZY", // Token slug Some(100.0), // Amount vec![], // units (optional, for stackable tokens) None, // batch_id (optional, for stackable tokens) None, // source_wallet (optional, auto-resolved) ).await?; if response.success() { println!("Token transferred successfully!"); } println!("{}", response.data()); // Raw response
-
Creating a new Rule:
use serde_json::json; let rule = vec![ json!({"key": "amount", "operator": "<=", "value": "1000"}) ]; let response = client.create_rule( "MyMetaType", // meta_type "MyMetaId", // meta_id rule, None // policy (optional) ).await?; if response.success() { println!("Rule created successfully!"); } println!("{}", response.data()); // Raw response
-
Querying Atoms:
let atoms = client.query_atom( None, // molecular_hash Some("bundle-hash-here"), // bundle_hash None, // position None, // wallet_address Some("V"), // isotope (as string: "V", "C", "M", "T", etc.) Some("CRZY"), // token_slug None, // batch_id None, // meta_type None, // meta_id ).await?; println!("{:?}", atoms); // Vec<Value>
-
Working with Buffer Tokens:
use std::collections::HashMap; // Deposit to buffer let mut trade_rates = HashMap::new(); trade_rates.insert("OTHER_TOKEN".to_string(), 0.5); let deposit_response = client.deposit_buffer_token( "CRZY", // token_slug 100.0, // amount trade_rates, // trade_rates None, // source_wallet (optional) ).await?; // Withdraw from buffer let withdraw_response = client.withdraw_buffer_token( "CRZY", // token_slug 50.0, // amount None, // source_wallet (optional) None, // signing_wallet (optional) ).await?; println!("{} {}", deposit_response.data(), withdraw_response.data());
For more granular control, you can work directly with Molecules:
-
Create a new Molecule:
use knishio_client::Molecule; let mut molecule = Molecule::with_params( Some("secret".to_string()), None, // bundle Some(source_wallet), // source_wallet None, // remainder_wallet Some("cell_slug".to_string()), None // version );
-
Create a custom Mutation:
use knishio_client::mutation::MutationProposeMolecule; let mutation = MutationProposeMolecule::from_molecule(molecule);
-
Sign and check a Molecule:
molecule.sign(None, false, true)?; if molecule.check(None)? { println!("Molecule validation passed!"); } else { println!("Molecule validation failed!"); }
-
Execute a custom Query or Mutation:
let response = client.execute_query(&mutation, None).await?; if response.success() { println!("Molecule executed successfully!"); }
This method involves individually building Atoms and Molecules, triggering the signature and validation processes, and communicating the resulting signed Molecule mutation or Query to a Knish.IO node via GraphQL.
-
Include the relevant structures in your application code:
use knishio_client::{Molecule, Wallet, Atom}; use knishio_client::crypto; use knishio_client::types::{Isotope, MetaItem};
-
Generate a 2048-symbol hexadecimal secret, either randomly, or via hashing login + password + salt, OAuth secret ID, biometric ID, or any other static value.
-
(optional) Initialize a signing wallet with:
let wallet = Wallet::create( Some("secret"), None, // bundle (optional) "USER", // token None, // position (optional) None // characters (optional) )?;
WARNING 1: If ContinuID is enabled on the node, you will need to use a specific wallet, and therefore will first need to query the node to retrieve the
positionfor that wallet.WARNING 2: The Knish.IO protocol mandates that all C and M transactions be signed with a
USERtoken wallet. -
Build your molecule with:
let mut molecule = Molecule::with_params( Some("secret".to_string()), None, // bundle (optional) Some(source_wallet), // source_wallet (optional) None, // remainder_wallet (optional) Some("cell_slug".to_string()), // cell_slug (optional) None // version (optional) );
-
Either use one of the shortcut methods provided by the
Moleculestruct (which will buildAtominstances for you), or createAtominstances yourself.DIY example:
// This example records a new Wallet on the ledger // Define metadata for our new wallet let new_wallet_meta = vec![ MetaItem::new("address", &new_wallet.address), MetaItem::new("token", &new_wallet.token), MetaItem::new("bundle", &new_wallet.bundle), MetaItem::new("position", &new_wallet.position.unwrap_or_default()), MetaItem::new("batchId", &new_wallet.batch_id.unwrap_or_default()), ]; // Build the C isotope atom let wallet_creation_atom = Atom::new( &source_wallet.position.unwrap(), &source_wallet.address, Isotope::C, &source_wallet.token ); wallet_creation_atom.meta_type = Some("wallet".to_string()); wallet_creation_atom.meta_id = Some(new_wallet.address.clone()); wallet_creation_atom.meta = Some(new_wallet_meta); wallet_creation_atom.index = Some(molecule.generate_index()); // Add the atom to our molecule molecule.add_atom(wallet_creation_atom); // Adding a ContinuID / remainder atom molecule.add_continuid_atom()?;
Molecule shortcut method example:
// This example commits metadata to some Meta Asset // Defining our metadata let metadata = vec![ MetaItem::new("foo", "Foo"), MetaItem::new("bar", "Bar"), ]; molecule.init_meta( metadata, "MyMetaType", "MetaId123", None // policy (optional) )?;
-
Sign the molecule with the stored user secret:
molecule.sign(None, false, true)?;
-
Make sure everything checks out by verifying the molecule:
match molecule.check(None) { Ok(true) => { println!("Molecule validation passed!"); } Ok(false) => { println!("Molecule validation failed!"); } Err(e) => { eprintln!("Molecule check error: {:?}", e); } }
-
Broadcast the molecule to a Knish.IO node:
use knishio_client::mutation::MutationProposeMolecule; // Build our mutation object let mutation = MutationProposeMolecule::from_molecule(molecule); // Send the mutation to the node and get a response let response = client.execute_query(&mutation, None).await?;
-
Inspect the response...
// For basic queries, we look at the data property: println!("{}", response.data()); // For mutations, check if the molecule was accepted by the ledger: println!("{}", if response.success() { "Success" } else { "Failed" }); // We can also check the reason for rejection println!("{:?}", response.reason()); // Some queries may also produce a payload, with additional data: println!("{:?}", response.payload());
Payloads are provided by responses to the following queries:
QueryBalanceandQueryContinuId-> returns aWalletinstanceQueryWalletList-> returns a list ofWalletinstancesMutationProposeMolecule,MutationRequestAuthorization,MutationCreateIdentifier,MutationLinkIdentifier,MutationClaimShadowWallet,MutationCreateToken,MutationRequestTokens, andMutationTransferTokens-> returns molecule metadata
The GraphQL transport (reqwest) issues a fresh network request per query — there is no response caching (the connection pool is TCP-level only) — so a long-lived client never serves a stale read of ledger state. No fresh-read knob (e.g. a request policy) is required.
Knish.IO is under active development, and our team is ready to assist with integration questions. The best way to seek help is to stop by our Telegram Support Channel. You can also send us a contact request via our website.
