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](https://ton.org/) blockchain.

[![CI](https://github.com/ston-fi/ton-rs/actions/workflows/build.yml/badge.svg)](https://github.com/ston-fi/ton-rs/actions/workflows/build.yml)
[![Crates.io](https://img.shields.io/crates/v/ton.svg)](https://crates.io/crates/ton)

This crate is heavily based on the [tonlib-rs](https://github.com/ston-fi/tonlib-rs) repository and also uses [tonlib-sys](https://github.com/ston-fi/tonlib-sys) underneath for the [tonlibjson_client](crates/ton/src/clients/tonlibjson) 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](examples/enum.rs) example). Provides powerful enums, but use them carefully; read the [Enum with TLB macros](#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](crates/ton_core/src/serde.rs). Disabled by default.
- [EmulationProvider](crates/ton_core/src/traits/emulation_provider.rs) - Provider-neutral interface used to execute TVM get methods
- [TonCell](crates/ton_core/src/cell/ton_cell.rs)
- [TonAddress](crates/ton_core/src/types/ton_address.rs)
- [TLB](crates/ton_core/src/traits/tlb.rs) - Trait allows you read/write arbitrary objects in BOC format
- [Types](crates/ton_core/src/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](crates/ton/src/tlb_adapters.rs) - Allows you to work with rust types like HashMap, and still serialize it properly for TON
- [BlockTLB](crates/ton/src/block_tlb.rs) - Bunch of types to interact with raw blockchain data (However it's not fully covered)
- [TonWallet](crates/ton/src/ton_wallet.rs) - Wrapper of wallet to sign and create external messages
- [TLClient](crates/ton/src/tl_client.rs) - Using `tonlibjson` to interact with TON network
- [TonContract](crates/ton/src/contracts/ton_contract.rs) - 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](examples) folder (feel free to add your own)

Interesting one:
* [emulate_get_method](examples/emulate_get_method.rs) - use your own TonContract
* [ton_transfer](examples/ton_transfer.rs) - transfer TONs between wallets using TLClient

### Basic usage
```rust
// 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]);
}
```
```rust
// 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.
```rust 

#[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:
```rust
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](crates/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`](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)