Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

TVM Primitives

The tvm feature enables TON cells, builders, slices, BoC helpers, addresses, dictionaries, and TVM stack values. It also enables tl because several public types map cells and addresses into LiteAPI structures.

Audience: users working with offline cells, BoC payloads, TL-B models, addresses, or get-method stack values. Prerequisites: tvm feature only; no live network access is required unless the BoC or stack payload came from LiteClient calls.

Cells, Builders, And Slices

A cell stores up to 1023 bits and up to 4 references. Builder and CellBuilder write values into a cell, and Slice reads them back in order.

#![allow(unused)]
fn main() {
use num_bigint::BigUint;
use tonutils::tvm::{Builder, Slice};

fn example() -> anyhow::Result<()> {
    let value = BigUint::from(1u64) << 96;
    let mut builder = Builder::new();
    builder.store_uint::<u32>(0x12345678)?;
    builder.store_uint_custom::<u8>(0b101, 3)?;
    builder.store_big_uint(&value, 128)?;
    let cell = builder.end_cell()?;

    let mut slice = Slice::new(cell);
    assert_eq!(slice.load_uint::<u32>()?, 0x12345678);
    assert_eq!(slice.load_uint_custom::<u8>(3)?, 0b101);
    assert_eq!(slice.load_big_uint(128)?, value);
    Ok(())
}
}

Reads and writes are bounds checked. Loading too many bits or references returns an error instead of silently truncating data.

BoC

BoC helpers serialize and parse a root cell:

#![allow(unused)]
fn main() {
use tonutils::tvm::{Builder, deserialize_boc, serialize_boc};

fn example() -> anyhow::Result<()> {
    let mut builder = Builder::new();
    builder.store_byte(7)?;
    let cell = builder.end_cell()?;
    let boc = serialize_boc(&cell, true)?;
    let decoded = deserialize_boc(&boc)?;
    assert_eq!(decoded.hash(), cell.hash());
    Ok(())
}
}

Convenience helpers convert BoC data to and from hex and base64. Current BoC support covers the crate’s ordinary-cell use cases; index table modes, cache bits, exotic cells, and official golden fixture coverage are still being expanded.

Addresses

Address parses raw workchain:hash strings and user-friendly base64 forms, and can convert to LiteAPI AccountId:

#![allow(unused)]
fn main() {
use std::str::FromStr;
use tonutils::tvm::Address;

fn example(address: &str) -> anyhow::Result<()> {
    let parsed = Address::from_str(address)?;
    let account = parsed.to_account_id();
    println!("{} {}", account.workchain, parsed.to_hex());
    Ok(())
}
}

Address formatting exposes bounceable and test-only flags. Callers should keep test-only addresses out of mainnet workflows.

Dictionaries

HashmapE stores fixed-width BitKey values with callback-based value codecs. The higher-level Dict wrapper supports integer keys and cell values for the current public surface.

#![allow(unused)]
fn main() {
use tonutils::tvm::{Dict, DictValue};

fn example() -> anyhow::Result<()> {
    let mut dict = Dict::new(16);
    dict.set_int_key(7, DictValue::Uint(42, 32))?;
    let root = dict.serialize()?;
    assert!(root.is_some());
    Ok(())
}
}

The dictionary encoder implements canonical labels and fork nodes. TL-B code can use tlb::TlbHashmapE<T, N> when dictionary values implement the TL-B runtime traits. Official TON golden fixtures and proof-friendly traversal remain TODO items.

TL-B Models And Derive

The tvm feature exposes tonutils::tlb for typed cell models. Messages, accounts, transactions, common transaction phases, block roots, config wrappers, and proof wrappers are public APIs. Some deep block and shard-state families are raw-preserving wrappers while the full upstream block.tlb generator is still being expanded.

#![allow(unused)]
fn main() {
use tonutils::tlb::{Account, TlbDeserialize, TlbSerialize};
use tonutils::tvm::boc_to_hex;

fn example() -> anyhow::Result<()> {
    let cell = Account::None.to_cell()?;
    let decoded = Account::from_cell(cell.clone())?;
    assert_eq!(decoded, Account::None);
    println!("{}", boc_to_hex(&cell, false)?);
    Ok(())
}
}

Custom TL-B structs can use the optional tlb-derive feature:

#![allow(unused)]
fn main() {
use tonutils::tlb::{Tlb, TlbDeserialize, TlbSerialize};

#[derive(Tlb)]
#[tlb(tag = "0x0f8a7ea5")]
struct Body {
    query_id: u64,
}
}

The derive writes existing TlbSerialize and TlbDeserialize impls. Use #[tlb(reference)] for ^T fields. Tags accept binary strings, 0b..., 0x..., and TL-B-style #... hex forms. Unsigned primitive fields u8, u16, u32, u64, and u128 infer their natural bit width; use #[tlb(bits = N)] when the TL-B width differs or for signed integer and hash fields. Float primitive fields are rejected because the runtime does not define TL-B float semantics.

Stack Values

TvmStack is used by contract get-method helpers. It supports nulls, integers, cells, slices, tuples, lists, and explicit unsupported payloads for lossless roundtrips.

#![allow(unused)]
fn main() {
use tonutils::tvm::{TvmStack, TvmStackEntry};

fn example() -> anyhow::Result<()> {
    let stack = TvmStack::new(vec![TvmStackEntry::int(10)]);
    let boc = stack.to_boc()?;
    let decoded = TvmStack::from_boc(&boc)?;
    assert_eq!(decoded.entries().len(), 1);
    Ok(())
}
}

Compatibility with every liteserver runSmcMethod return shape is still being verified with live and golden fixtures.