tonlib-rs

repository·main·Indexed 42 days ago

https://github.com/ston-fi/tonlib-rs

A Rust SDK for The Open Network (TON) consisting of tonlib-client, a thin wrapper for tonlibjson providing low-level blockchain access, and tonlib-core, a high-level API for common interactions. It supports Jetton data retrieval, wallet address derivation, TON mnemonics, and the construction and parsing of Cells and Bags of Cells.

Tokens
22.1K
Snippets
63
Records
81
Agent score
54%

What's inside tonlib-rs

  1. Overview of tonlib-core package contents

    main

    The tonlib-core package contains several specialized modules for TON development:

    • Cell: Data structures and helpers for building and parsing Cell and Bag of Cells.
    • Message: Data structures, builders, and parsers for Messages, including standard messages for Jetton, NFT, and Soulbound NFT (per TEP-0001).
    • Mnemonic: Data structures for storing mnemonics.
    • Types: Data structures for storage and conversion of Ton Smart-contract Address and Ton Transaction Id.
    • Wallet: Data structures for deriving wallet addresses.
  2. Overview of tonlib-client features

    main

    The tonlib-client is a Rust client for The Open Network (TON) that uses tonlibjson as its data provider. Key capabilities include:

    • Jetton Support: Functions for retrieving jetton data and wallet addresses, as well as loading internal and external jetton metadata (including IPFS support).
    • Reliability: Built-in connection pooling and retry support for improved server-level interaction.
    • Core Integration: Built upon tonlib-sys and tonlib-core.
  3. Overview of tonlib-rs modules

    main

    The tonlib-rs project provides two primary modules for interacting with The Open Network (TON):

    1. tonlib-client: A low-level Rust client for direct interaction with the TON blockchain, providing core functionality and network access.
    2. tonlib-core: A high-level API built on top of tonlib-client. It provides simplified methods and structures for common blockchain interactions.

    Both modules utilize tonlib-sys to handle lower-level bindings to the TON library, supporting both static and shared library integration.

  4. Core features of tonlib-core

    main

    The SDK provides the following capabilities:

    • Parsing and generation of Cell and BagOfCell.
    • Support for existing Wallet versions.
    • Derivation of wallet addresses.
    • Support for TON Mnemonics.
    • NaCl-compatible Ed25519 signing of transactions.
  5. Work with Jettons and Contracts

    main

    The library provides a TonContractFactory to interact with smart contracts.

    Interacting with Jettons

    • Use get_contract on the factory to get a JettonMasterContract.
    • Use get_jetton_data() to retrieve jetton information.
    • Use get_wallet_address(&owner_address) to find the specific jetton wallet address for a user.
    • Use JettonMetaLoader to load token metadata from the content field.
    use tonlib_client::client::TonClient;
    use tonlib_client::contract::TonContractFactory;
    use tonlib_client::contract::JettonMasterContract;
    use tonlib_client::meta::JettonMetaLoader;
    
    async fn load_meta() -> anyhow::Result<()> {
        let client = TonClient::builder().build().await?;
        let contract_factory = TonContractFactory::builder(&client).build().await?;
        let contract = contract_factory.get_contract(&"EQB-MPwrd1G6WKNkLz_VnV6WqBDd142KMQv-g1O-8QUA3728".parse()?); 
        let jetton_data = contract.get_jetton_data().await?;
        let loader = JettonMetaLoader::default()?;
        let content_res = loader.load(&jetton_data.content).await?;
        Ok(())
    }
  6. Add tonlib-rs to your Rust project

    main

    To use the SDK in your application, add both tonlib-core and tonlib-client to your Cargo.toml file. Ensure you replace "version" with the latest available version from Crates.io.

    [dependencies]
    tonlib-core = "version"
    tonlib-client = "version"
  7. Build and parse Cells with CellBuilder and Cell

    main

    The library provides Cell and BagOfCell support for interacting with TON data structures. Use CellBuilder to construct a cell by writing various data types (integers, bits, slices, addresses, strings) and then call .build() to finalize it. To read data, use the .parser() method on an existing Cell to obtain a reader that supports loading specific types.

    ### Creating a `Cell` and writing data to it:
    
    ```rust
    use anyhow::anyhow;
    use tonlib_core::TonAddress;
    use tonlib_core::cell::CellBuilder;
    
    fn write_cell() -> anyhow::Result<()> {
    let mut writer = CellBuilder::new();
    let addr = TonAddress::from_base64_url("EQDk2VTvn04SUKJrW7rXahzdF8_Qi6utb0wj43InCu9vdjrR")?;
    let cell = writer
        .store_u32(32, 0xFAD45AADu32)?
        .store_bit(true)?
        .store_u8(8, 234u8)?
        .store_slice(&[0xFA, 0xD4, 0x5A, 0xAD, 0xAA, 0x12, 0xFF, 0x45])?
        .store_address(&addr)?
        .store_string("Hello, TON")?
        .build()?;
        # Ok(())
    }

    Reading data from a Cell:

    use tonlib_core::cell::Cell;
    fn read_cell(cell: Cell) -> anyhow::Result<()> {
        let mut reader = cell.parser();
        let u32_value = reader.load_u32(32)?;
        let bit_value = reader.load_bit()?;
        let u8_value = reader.load_u8(8)?;
        let bytes_value = reader.load_bytes(8)?;
        let address_value = reader.load_address()?;
        let str_value = reader.ensure_empty()?;
        Ok(())
    }
  8. Set up the IPFS server for development using docker-compose

    main

    For development and testing of tonlib-rs features that require IPFS metadata, you can use the provided docker-compose configuration. Currently, this setup only includes an IPFS server service.

    To start the services in the background, run the following command from the client/compose directory:

    docker-compose up -d
  9. Install prerequisites for tonlib-client

    main

    Before building or using tonlib-client, ensure your system has the necessary development libraries installed. Use the commands corresponding to your operating system:

    Linux (Ubuntu/Debian): Install build-essential, cmake, libsodium-dev, libsecp256k1-dev, and lz4 libraries.

    macOS: Install readline, secp256k1, ccache, pkgconfig, cmake, and libsodium using Homebrew.

    # Linux
    sudo apt install build-essential cmake libsodium-dev libsecp256k1-dev lz4 liblz4-dev
    
    # macOS
    brew install readline secp256k1 ccache pkgconfig cmake libsodium
  10. Send transactions to the TON blockchain

    main

    To send messages (transfers), you must first manage your credentials and then construct a signed message.

    1. Manage Credentials

    Create a KeyPair from a mnemonic phrase using Mnemonic and to_key_pair().

    2. Construct and Sign Messages

    • Simple TON Transfer: Use TransferMessage with CommonMsgInfo::ExternalIncomingMessage and a TonWallet to create, sign, and wrap the body.
    • Jetton Transfer: Use JettonTransferMessage to define the token transfer details, then wrap it into a TransferMessage for the wallet to sign.

    3. Broadcast

    Serialize the resulting BagOfCells into a transaction and use client.send_raw_message_return_hash(tx.as_slice()) to broadcast it.

    use tonlib_core::wallet::ton_wallet::TonWallet;
    use tonlib_core::wallet::wallet_version::WalletVersion;
    use tonlib_core::message::TransferMessage;
    use tonlib_core::message::CommonMsgInfo;
    use tonlib_core::message::ExternalIncomingMessage;
    use tonlib_core::cell::BagOfCells;
    
    async fn create_simple_transfer() -> anyhow::Result<()> {
        // ... setup mnemonic and key_pair ...
        let client = TonClient::default().await?;
        let wallet = TonWallet::new(WalletVersion::V4R2, key_pair)?;
        let src: TonAddress = "<source_address>".parse()?;
        let dest: TonAddress = "<dest_address>".parse()?;
        let value = BigUint::from(10000000u64); // 0.01 TON
    
        let external_msg_info = ExternalIncomingMessage{
            src,
            dest,
            import_fee: value,
        };
        let common_msg_info = CommonMsgInfo::ExternalIncomingMessage(external_msg_info);
        let transfer = TransferMessage::new(common_msg_info).build()?;
        
        let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs() as u32;
        let body = wallet.create_external_body(now + 60, seqno, vec![Arc::new(transfer)])?;
        let signed = wallet.sign_external_body(&body)?;
        let wrapped = wallet.wrap_signed_body(signed, true)?;
        let boc = BagOfCells::from_root(wrapped);
        let tx = boc.serialize(true)?;
    
        let hash = client.send_raw_message_return_hash(tx.as_slice()).await?;
        Ok(())
    }