ton_core 0.3.2

A collection of types and utilities for interacting with the TON network
Documentation

ton-rs

Set of general-purpose rust libraries to interact with TON blockchain.

CI Crates.io

This crate is heavily based on the tonlib-rs repository and also uses tonlib-sys underneath for the tonlibjson_client implementation.

ton_macros

  • TLB Derive macros: Automatically derive TLB trait for your types based on it's members
  • Native Enum support using TLBPrefix: Automatically match underlying variant by it's prefix (check enum.rs example). Provides powerful enums, but use them carefully; read the Enum with TLB macros chapter.
  • ton_contract!: Generate a TonContract wrapper type and optionally implement method traits for it.
  • #[ton_methods]: Generate async get-method implementations for contract traits or impl blocks, with optional block-level name_format conversion and per-method exact names.

ton_core

  • serde feature: provides few mods to ser/de core types, check ton_core/src/serde.rs. Disabled by default.
  • EmulationProvider - Provider-neutral interface used to execute TVM get methods
  • TonCell
  • TonAddress
  • TLB - Trait allows you read/write arbitrary objects in BOC format
  • Types - Few basic types, common and stable enough to be in core

ton

  • lite-client feature: Disabled by default. Enable it for the ADNL-based LiteClient; it also enables the networking dependencies required by that client.
  • tonlibjson feature: Disabled by default. Enable it for the native TLClient, emulator implementations, TLStateProvider, and ton::emulators::tl_emulation_provider::TLEmulationProvider. ContractClient and TonContract can be used without it by supplying custom providers. This feature includes lite-client because TLClient uses it to refresh the network configuration's init block.
  • WalletVersion and LiteNodeFilter serialize using their Rust variant names; TVMGetMethodID serializes as an integer or string according to its variant.
  • Use TON_NET_CONF_MAINNET_PATH or TON_NET_CONF_TESTNET_PATH env variables to override netconfig.json and use your own TON nodes.
  • TLBAdapters - Allows you to work with rust types like HashMap, and still serialize it properly for TON
  • BlockTLB - Bunch of types to interact with raw blockchain data (However it's not fully covered)
  • TonWallet - Wrapper of wallet to sign and create external messages
  • TLClient - Using tonlibjson to interact with TON network
  • TonContract - Use it with ContractClient::builder(state_provider, emulation_provider) to get data or execute methods on TON contracts
  • Standard Jetton, NFT, SBT, and TON wallet contract wrappers live under contracts::tep, grouped into public modules by standard and implementation. For example, use contracts::tep::jetton::jetton_master_contract::JettonMasterContract or contracts::tep::ton_wallet::TonWalletContract.
  • contracts::tep::metadata::meta_loader::MetaLoader resolves ipfs:// metadata through the IPFS Foundation's best-effort public gateway by default. Production applications should configure their own gateway with MetaLoader::builder().with_ipfs_base_url(...).

ContractClient::builder(...).with_default_caches() configures state caches. When using the native adapter, configure emulator library caches independently with ton::emulators::tl_emulation_provider::TLEmulationProvider::with_default_caches(). State caches require an active Tokio runtime when the client is built and start a background refresh task. Dropping the client does not cancel an in-flight provider call; initial sequence discovery also keeps retrying provider errors until it succeeds. TonContract::new() synchronously stores the contract address and optional transaction ID. load_state() and load_parsed_data() load and retain state; emulation uses retained state when available. Otherwise, it lets the emulation provider resolve the address and transaction ID unless EmulationProvider::requires_resolved_state() returns true, in which case the configured state provider loads it first.

Mnemonic clears its owned words and password on drop, and KeyPair clears its secret key bytes. Caller-owned mnemonic strings and copies read from the public KeyPair::secret_key field remain the caller's responsibility.

Rust version

The minimum supported Rust version (MSRV) is 1.94. CI verifies every published crate, target, and feature against the declared MSRV and checks weekly whether the latest dependency releases still support it. MSRV increases are released as minor compatibility changes.

Getting started

Examples can be found in examples folder (feel free to add your own)

Interesting one:

Basic usage

// Build and read custom cells
fn main() -> anyhow::Result<()> {
    use ton_lib::cell::ton_cell::TonCell;
    let mut builder = TonCell::builder();
    builder.write_bits([1,2,3], 24).unwrap();
    let cell = builder.build().unwrap();
    assert_eq!(cell.data, vec![1, 2, 3]);
    let mut parser = cell.parser();
    let data = parser.read_bits(24).unwrap();
    assert_eq!(data, [1, 2, 3]);
}
// describe TLB type:
#[derive(Debug, Clone, PartialEq, TLB)]
#[tlb(ensure_empty = true)]
pub struct StateInit {
    #[tlb_derive(bits_len = 5)]
    pub split_depth: Option<u8>,
    pub tick_tock: Option<TickTock>,
    pub code: Option<TLBRef<TonCell>>,
    pub data: Option<TLBRef<TonCell>>,
    #[tlb(adapter = "TLBHashMapE::<DictKeyAdapterTonHash, DictValAdapterTLB<_>>::new(256)")]
    pub library: LibsDict,
}

fn main() {
    let boc_hex = "b5ee9c720102160100030400020134020100510000082f29a9a31738dd3a33f904d35e2f4f6f9af2d2f9c563c05faa6bb0b12648d5632083ea3f89400114ff00f4a413f4bcf2c80b03020120090404f8f28308d71820d31fd31fd31f02f823bbf264ed44d0d31fd31fd3fff404d15143baf2a15151baf2a205f901541064f910f2a3f80024a4c8cb1f5240cb1f5230cbff5210f400c9ed54f80f01d30721c0009f6c519320d74a96d307d402fb00e830e021c001e30021c002e30001c0039130e30d03a4c8cb1f12cb1fcbff08070605000af400c9ed54006c810108d718fa00d33f305224810108f459f2a782106473747270748018c8cb05cb025005cf165003fa0213cb6acb1f12cb3fc973fb000070810108d718fa00d33fc8542047810108f451f2a782106e6f746570748018c8cb05cb025006cf165004fa0214cb6a12cb1fcb3fc973fb0002006ed207fa00d4d422f90005c8ca0715cbffc9d077748018c8cb05cb0222cf165005fa0214cb6b12ccccc973fb00c84014810108f451f2a702020148130a0201200c0b0059bd242b6f6a2684080a06b90fa0218470d4080847a4937d29910ce6903e9ff9837812801b7810148987159f31840201200e0d0011b8c97ed44d0d70b1f8020158120f02012011100019af1df6a26840106b90eb858fc00019adce76a26840206b90eb85ffc0003db29dfb513420405035c87d010c00b23281f2fff274006040423d029be84c6002e6d001d0d3032171b0925f04e022d749c120925f04e002d31f218210706c7567bd22821064737472bdb0925f05e003fa403020fa4401c8ca07cbffc9d0ed44d0810140d721f404305c810108f40a6fa131b3925f07e005d33fc8258210706c7567ba923830e30d03821064737472ba925f06e30d1514008a5004810108f45930ed44d0810140d720c801cf16f400c9ed540172b08e23821064737472831eb17080185005cb055003cf1623fa0213cb6acb1fcb3fc98040fb00925f03e2007801fa00f40430f8276f2230500aa121bef2e0508210706c7567831eb17080185004cb0526cf1658fa0219f400cb6917cb1f5260cb3f20c98040fb0006";
    let state_init = StateInit::from_boc_hex(boc_hex).unwrap();
}

Enum with TLB macros

TLB macros can derive TLB for enums. You can define enums with a common prefix or with no common prefix. Enums without a common prefix are tricky: if you embed such an enum into another enum, its variants are effectively inlined into the outer enum.


#[derive(TLB)]
#[tlb(prefix = 0b010, bits_len = 3)]
struct Variant1(u8);

#[derive(TLB)]
#[tlb(prefix = 0b011, bits_len = 3)]
struct Variant2(u8);

#[derive(TLB)]
enum InnerEnum { // No common prefix
    Variant1(Variant1), // Prefix = 0b010
    Variant2(Variant2), // Prefix = 0b011
}

#[derive(TLB)]
#[tlb(prefix = 0b1, bits_len = 1)] // Common prefix 
enum OuterEnum { 
    OuterVariant1(u16), // Prefix overall = 0b101
    OuterVariant2(InnerEnum),
}

This is effectively parsed as:

enum OuterEnum {
    OuterVariant1(u16), // Prefix overall = 0b101
    Variant1(u8),       // Prefix overall = 0b1010
    Variant2(u16),      // Prefix overall = 0b1011
}

Be careful with null (zero-length) prefixes. A null prefix acts like a wildcard; during parsing, variants are tried in declaration order, so a null-prefix variant placed earlier can consume the input before later variants are considered. See tests in ton_core/src/traits/tlb/test_tlb_enum.rs for the shadowing and the safe-prefix example.

Contribution

Repository and crate-specific guidance lives in AGENTS.md. Public API changes must preserve wire formats, document compatibility impact, and keep one supported construction path. Open enums and returned records use #[non_exhaustive]; fixed TLB records remain exhaustive when their fields are the serialization contract.

If you face with some unclear parts or bugs, your can add a new example or improve documentation.

If you implemented some general feature, please make sure it's covered by tests (unit tests if possible)