Iroha Special Instructions
Pre-built, optimized commands for common blockchain operations. Fast, secure, and easy to use.
Hyperledger Iroha supports two complementary approaches to programmable logic: Iroha Special Instructions (ISI) for common operations and WASM smart contracts for custom business logic. This dual approach provides both simplicity and flexibility for SORA v3 development.
Iroha Special Instructions
Pre-built, optimized commands for common blockchain operations. Fast, secure, and easy to use.
WASM Contracts
Custom WebAssembly code for complex business logic. Flexible, powerful, and Turing-complete.
ISI are domain-oriented commands that handle common blockchain operations without custom code.
| Benefit | Description |
|---|---|
| Performance | Native execution, no VM overhead |
| Security | Audited, battle-tested implementations |
| Simplicity | No coding required for common tasks |
| Determinism | Guaranteed same result on all nodes |
Create new entities in the blockchain:
// Register a new domainRegister::domain(Domain::new("finance".parse()?))
// Register an accountRegister::account(Account::new( "alice@finance".parse()?))
// Register an asset definitionRegister::asset_definition( AssetDefinition::quantity("usd#finance".parse()?))Move assets between accounts:
// Transfer tokensTransfer::asset_quantity( IdBox::AssetId("xor#sora@alice".parse()?), 100_u32, IdBox::AccountId("bob@sora".parse()?),)
// Transfer domain ownershipTransfer::domain( IdBox::AccountId("alice@sora".parse()?), IdBox::DomainId("finance".parse()?), IdBox::AccountId("bob@sora".parse()?),)Create or destroy assets:
// Mint new tokensMint::asset_quantity( 100_u32, IdBox::AssetId("xor#sora@treasury".parse()?),)
// Burn tokensBurn::asset_quantity( 50_u32, IdBox::AssetId("xor#sora@treasury".parse()?),)Store metadata:
// Set account metadataSetKeyValue::account( "alice@sora".parse()?, "profile".parse()?, "Senior Developer".into(),)
// Set asset metadataSetKeyValue::asset( "nft#sora@alice".parse()?, "image_url".parse()?, "ipfs://Qm...".into(),)Instructions can be combined for complex operations:
// Atomic batch of instructionslet batch = vec![ Register::account(new_account).into(), Mint::asset_quantity(initial_balance, account_asset).into(), SetKeyValue::account(account_id, key, value).into(),];
// All succeed or all failclient.submit_all_blocking(batch)?;For custom business logic, Iroha supports WebAssembly (WASM) smart contracts written in Rust.
#![no_std]
extern crate alloc;
use iroha_wasm::prelude::*;
#[iroha_wasm::main]fn main(host: Iroha) { // Access execution context let authority = host.context().authority();
// Query state let account = host.query_single( FindAccountById::new(authority.clone()) ).unwrap();
// Execute instructions let instruction = Transfer::asset_quantity( source_asset, amount, destination, );
host.submit(instruction).unwrap();}WASM contracts can:
| Capability | Example |
|---|---|
| Query state | Read account balances, asset metadata |
| Execute ISI | Transfer, mint, burn assets |
| Emit events | Trigger external notifications |
| Access context | Get caller, block height, timestamp |
| Validate | Implement custom permission logic |
#![no_std]
extern crate alloc;
use iroha_wasm::prelude::*;use alloc::vec::Vec;
/// Vesting contract that releases tokens over time#[iroha_wasm::main]fn claim_vested(host: Iroha) { let authority = host.context().authority(); let current_time = host.context().block_timestamp();
// Read vesting schedule from account metadata let vesting_start: u128 = host.query_single( FindAccountMetadata::new( authority.clone(), "vesting_start".parse().unwrap() ) ).unwrap().try_into().unwrap();
let vesting_duration: u128 = host.query_single( FindAccountMetadata::new( authority.clone(), "vesting_duration".parse().unwrap() ) ).unwrap().try_into().unwrap();
let total_amount: u32 = host.query_single( FindAccountMetadata::new( authority.clone(), "vesting_amount".parse().unwrap() ) ).unwrap().try_into().unwrap();
// Calculate vested amount let elapsed = current_time.saturating_sub(vesting_start); let vested_fraction = elapsed.min(vesting_duration) as f64 / vesting_duration as f64; let vested_amount = (total_amount as f64 * vested_fraction) as u32;
// Transfer vested tokens let transfer = Transfer::asset_quantity( vesting_pool_asset, vested_amount, authority.clone(), );
host.submit(transfer).dbg_unwrap();}Triggers enable event-driven smart contract execution:
| Type | Fires When |
|---|---|
| By Event | Specific event occurs (transfer, mint, etc.) |
| By Time | Scheduled time reached |
| By Block | New block committed |
| Pre-commit | Before block finalization |
// Register a trigger that collects fees on every transferlet trigger = Trigger::new( "fee_collector".parse()?, Action::new( collect_fee_wasm, // WASM contract bytecode Repeats::Indefinitely, authority, FilterBox::Data(DataEventFilter::ByAssetEventFilter( AssetEventFilter::ByTransferred )), ),);
Register::trigger(trigger);// Grant permission to mint specific assetGrant::permission( PermissionToken::new( "CanMintAssetsWithDefinition".parse()?, json!({ "asset_definition_id": "xor#sora" }), ), IdBox::AccountId("minter@sora".parse()?),)Implement custom validation logic:
#[iroha_wasm::validator]fn validate_transfer( host: Iroha, instruction: InstructionBox,) -> Result { // Only allow transfers during business hours let hour = host.context().block_timestamp() % 86400 / 3600;
if hour < 9 || hour > 17 { return Err(ValidationFail::NotPermitted( "Transfers only allowed 9AM-5PM".into() )); }
Ok(())}# Install Rust toolchainrustup target add wasm32-unknown-unknown
# Install Iroha WASM toolscargo install iroha_wasm_builder# Build optimized WASMcargo build --release --target wasm32-unknown-unknown
# Optimize sizewasm-opt -Oz target/wasm32-unknown-unknown/release/contract.wasm \ -o contract.opt.wasm// Load WASM bytecodelet wasm = fs::read("contract.opt.wasm")?;
// Register as executablelet executable = WasmSmartContract::new(wasm);Register::executable(executable);
// Or register as triggerlet trigger = Trigger::new( trigger_id, Action::new(executable, repeats, authority, filter),);Register::trigger(trigger);#[test]fn test_contract() { let network = TestNetwork::new(); let client = network.client();
// Deploy contract client.submit(Register::trigger(trigger))?;
// Trigger event client.submit(Transfer::asset_quantity(...))?;
// Verify result let balance = client.query(FindAssetQuantityById::new(...))?; assert_eq!(balance, expected);}| Practice | Reason |
|---|---|
| Use ISI when possible | Native execution is faster |
| Batch instructions | Reduce transaction overhead |
| Minimize queries | Each query has latency |
| Optimize WASM size | Smaller = faster deployment |
// Version your contractsconst CONTRACT_VERSION: u32 = 1;
// Store version in metadataSetKeyValue::asset_definition( contract_asset, "version".parse()?, CONTRACT_VERSION.into(),)Iroha Overview
Sumeragi Consensus
Getting Started
Official Docs