tonlib-sys 2026.5.1

Rust bindings for tonlibjson library
extern "C" {
    /**
     * @brief Set global verbosity level of the library
     * @param verbosity_level New verbosity level (0 - never, 1 - error, 2 - warning, 3 - info, 4 - debug)
     */
    pub fn emulator_set_verbosity_level(verbosity_level: u32) -> bool;

    /**
     * @brief Create TVM emulator
     * @param code_boc Base64 encoded BoC serialized smart contract code cell
     * @param data_boc Base64 encoded BoC serialized smart contract data cell
     * @param vm_log_verbosity Verbosity level of VM log
     * @return Pointer to TVM emulator object
     */
    pub fn tvm_emulator_create(
        code: *const std::os::raw::c_char,
        data: *const std::os::raw::c_char,
        vm_log_verbosity: u32,
    ) -> *mut ::std::os::raw::c_void;

    /**
     * @brief Set libraries for TVM emulator
     * @param libs_boc Base64 encoded BoC serialized libraries dictionary (HashmapE 256 ^Cell).
     * @return true in case of success, false in case of error
     */
    pub fn tvm_emulator_set_libraries(
        tvm_emulator: *mut std::os::raw::c_void,
        libs_boc: *const std::os::raw::c_char,
    ) -> bool;

    /**
     * @brief Set c7 parameters
     * @param tvm_emulator Pointer to TVM emulator
     * @param address Adress of smart contract
     * @param unixtime Unix timestamp
     * @param balance Smart contract balance
     * @param rand_seed_hex Random seed as hex string of length 64
     * @param config Base64 encoded BoC serialized Config dictionary (Hashmap 32 ^Cell)
     * @return true in case of success, false in case of error
     */
    pub fn tvm_emulator_set_c7(
        tvm_emulator: *mut std::os::raw::c_void,
        address: *const std::os::raw::c_char,
        unixtime: u32,
        balance: u64,
        rand_seed_hex: *const std::os::raw::c_char,
        config: *const std::os::raw::c_char,
    ) -> bool;

    /// Sets extra-currency balances on a TVM emulator.
    ///
    /// `extra_currencies` uses the upstream `currency_id=balance` space-separated format.
    ///
    /// # Safety
    ///
    /// `tvm_emulator` must be a valid, live TVM emulator pointer and `extra_currencies` must point
    /// to a valid, NUL-terminated C string for the duration of the call.
    pub fn tvm_emulator_set_extra_currencies(
        tvm_emulator: *mut std::os::raw::c_void,
        extra_currencies: *const std::os::raw::c_char,
    ) -> bool;

    /// Sets a previously created configuration object on a TVM emulator.
    ///
    /// The configuration remains caller-owned and must outlive the emulator's use of it.
    ///
    /// # Safety
    ///
    /// `tvm_emulator` must be a valid, live TVM emulator pointer and `config` must be a valid,
    /// live pointer returned by [`emulator_config_create`](crate::emulator_config_create).
    pub fn tvm_emulator_set_config_object(
        tvm_emulator: *mut std::os::raw::c_void,
        config: *mut std::os::raw::c_void,
    ) -> bool;

    /// Sets the previous-blocks tuple used as the thirteenth element of `c7`.
    ///
    /// # Safety
    ///
    /// `tvm_emulator` must be a valid, live TVM emulator pointer. If `info_boc` is non-null, it
    /// must point to a valid, NUL-terminated C string for the duration of the call.
    pub fn tvm_emulator_set_prev_blocks_info(
        tvm_emulator: *mut std::os::raw::c_void,
        info_boc: *const std::os::raw::c_char,
    ) -> bool;

    /**
     * @brief Set TVM gas limit
     * @param tvm_emulator Pointer to TVM emulator
     * @param gas_limit Gas limit
     * @return true in case of success, false in case of error
     */
    pub fn tvm_emulator_set_gas_limit(
        tvm_emulator: *mut std::os::raw::c_void,
        gas_limit: u64,
    ) -> bool;

    /**
     * @brief Enable or disable TVM debug primitives
     * @param tvm_emulator Pointer to TVM emulator
     * @param debug_enabled Whether debug primitives should be enabled or not
     * @return true in case of success, false in case of error
     */
    pub fn tvm_emulator_set_debug_enabled(
        tvm_emulator: *mut std::os::raw::c_void,
        debug_enabled: std::os::raw::c_int,
    ) -> bool;

    /**
     * @brief Run get method
     * @param tvm_emulator Pointer to TVM emulator
     * @param method_id Integer method id
     * @param stack_boc Base64 encoded BoC serialized stack (VmStack)
     * @return Json object with error:
     * {
     *   "success": false,
     *   "error": "Error description"
     * }
     * Or success:
     * {
     *   "success": true
     *   "vm_log": "...",
     *   "vm_exit_code": 0,
     *   "stack": "Base64 encoded BoC serialized stack (VmStack)",
     *   "missing_library": null,
     *   "gas_used": 1212
     * }
     */
    pub fn tvm_emulator_run_get_method(
        tvm_emulator: *mut std::os::raw::c_void,
        method_id: i32,
        stack_boc: *const std::os::raw::c_char,
    ) -> *const std::os::raw::c_char;

    /**
     * @brief Run get method with raw params
     * @param len Length of params
     * @param params_boc serialized params
     * @param gas_limit Gas limit
     * @return buffer with result length and result
     * result is serialized cell chat contains:
     * result.code: i32
     * result.gas_used: i64
     * vm stack: ref
     */
    pub fn tvm_emulator_emulate_run_method(
        len: u32,
        params_boc: *const std::os::raw::c_char,
        gas_limit: i64,
    ) -> *const std::os::raw::c_char;

    /// Runs the optimized get-method emulator and returns both the response and VM log.
    ///
    /// The returned opaque result owns both of its string fields and must be released with
    /// [`run_method_detailed_result_destroy`].
    ///
    /// # Safety
    ///
    /// `params_boc` must point to a readable buffer of at least `len` bytes. The returned pointer
    /// must not be used after it is destroyed.
    pub fn tvm_emulator_emulate_run_method_detailed(
        len: u32,
        params_boc: *const std::os::raw::c_char,
        gas_limit: i64,
    ) -> *mut std::os::raw::c_void;

    /// Destroys a detailed get-method result and its response and log fields.
    ///
    /// # Safety
    ///
    /// `detailed_result` must be a valid pointer returned by
    /// [`tvm_emulator_emulate_run_method_detailed`] that has not already been destroyed.
    pub fn run_method_detailed_result_destroy(detailed_result: *mut std::os::raw::c_void);

    /**
     * @brief Send external message
     * @param tvm_emulator Pointer to TVM emulator
     * @param message_body_boc Base64 encoded BoC serialized message body cell.
     * @return Json object with error:
     * {
     *   "success": false,
     *   "error": "Error description"
     * }
     * Or success:
     * {
     *   "success": true,
     *   "new_code": "Base64 boc decoded new code cell",
     *   "new_data": "Base64 boc decoded new data cell",
     *   "accepted": true,
     *   "vm_exit_code": 0,
     *   "vm_log": "...",
     *   "missing_library": null,
     *   "gas_used": 1212,
     *   "actions": "Base64 boc decoded actions cell of type (OutList n)"
     * }
     */
    pub fn tvm_emulator_send_external_message(
        tvm_emulator: *mut std::os::raw::c_void,
        message_body_boc: *const std::os::raw::c_char,
    ) -> *const ::std::os::raw::c_char;

    /**
     * @brief Send internal message
     * @param tvm_emulator Pointer to TVM emulator
     * @param message_body_boc Base64 encoded BoC serialized message body cell.
     * @param amount Amount of nanograms attached with internal message.
     * @return Json object with error:
     * {
     *   "success": false,
     *   "error": "Error description"
     * }
     * Or success:
     * {
     *   "success": true,
     *   "new_code": "Base64 boc decoded new code cell",
     *   "new_data": "Base64 boc decoded new data cell",
     *   "accepted": true,
     *   "vm_exit_code": 0,
     *   "vm_log": "...",
     *   "missing_library": null,
     *   "gas_used": 1212,
     *   "actions": "Base64 boc decoded actions cell of type (OutList n)"
     * }
     */
    pub fn tvm_emulator_send_internal_message(
        tvm_emulator: *mut std::os::raw::c_void,
        message_body_boc: *const std::os::raw::c_char,
        amount: u64,
    ) -> *const ::std::os::raw::c_char;

    /**
     * @brief Destroy TVM emulator object
     * @param tvm_emulator Pointer to TVM emulator object
     */
    pub fn tvm_emulator_destroy(tvm_emulator: *mut std::os::raw::c_void);

    /// Destroys a string allocated by the emulator library.
    ///
    /// Use this for strings returned by emulator functions unless their documentation specifies a
    /// different owner. A null pointer is accepted.
    ///
    /// # Safety
    ///
    /// `string` must be null or a live pointer allocated and returned by the emulator library that
    /// has not already been destroyed. It must not be used after this call.
    pub fn string_destroy(string: *const std::os::raw::c_char);

    /// Returns JSON containing the emulator library's commit hash and commit date.
    ///
    /// The returned string must be released with [`string_destroy`].
    ///
    /// # Safety
    ///
    /// The returned pointer must be checked for null before dereferencing and must not be used after
    /// it is passed to [`string_destroy`].
    pub fn emulator_version() -> *const std::os::raw::c_char;
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::error::Error;
    use std::ffi::{CStr, CString};

    unsafe fn take_emulator_string(
        value: *const std::os::raw::c_char,
    ) -> Result<String, Box<dyn Error>> {
        assert!(!value.is_null());
        let value_owned = CStr::from_ptr(value).to_str()?.to_owned();
        string_destroy(value);
        Ok(value_owned)
    }

    #[test]
    fn test_all_tvm_emulator_exports() -> Result<(), Box<dyn Error>> {
        let code = "te6cckECCwEAAe0AART/APSkE/S88sgLAQIBYgIDAgLMBAUCA3pgCQoD79mRDjgEit8GhpgYC42Eit8H0gGADpj+mf9qJofQB9IGpqGEAKqThdRxgamqiq44L5cCSA/SB9AGoYEGhAMGuQ/QAYEogaKCF4BFAqkGQoAn0BLGeLZmZk9qpwQQg97svvKThdcYEakuAB8YEYAmACcYEvgsIH+XhAYHCACT38FCIBuCoQCaoKAeQoAn0BLGeLAOeLZmSRZGWAiXoAegBlgGSQfIA4OmRlgWUD5f/k6DvADGRlgqxniygCfQEJ5bWJZmZkuP2AQA/jYD+gD6QPgoVBIIcFQgE1QUA8hQBPoCWM8WAc8WzMkiyMsBEvQA9ADLAMn5AHB0yMsCygfL/8nQUAjHBfLgShKhA1AkyFAE+gJYzxbMzMntVAH6QDAg1wsBwwCOH4IQ1TJ223CAEMjLBVADzxYi+gISy2rLH8s/yYBC+wCRW+IAMDUVxwXy4En6QDBZyFAE+gJYzxbMzMntVAAuUUPHBfLgSdQwAchQBPoCWM8WzMzJ7VQAfa289qJofQB9IGpqGDYY/BQAuCoQCaoKAeQoAn0BLGeLAOeLZmSRZGWAiXoAegBlgGT8gDg6ZGWBZQPl/+ToQAAfrxb2omh9AH0gamoYP6qQQFEAfwk=\0";

        let data = "te6cckECFAEAA3wAAlFwOPUE4QoACAG/b+7lv/B/MjjfQ11sWK3b4LOpS7Bc7BSmJBVmyz5hdQECAEoBaHR0cHM6Ly90YXJhbnRpbmkuZGV2L3N0b24vbW9vbi5qc29uART/APSkE/S88sgLAwIBYgQFAgLMBgcAG6D2BdqJofQB9IH0gahhAgHUCAkCAUgKCwC7CDHAJJfBOAB0NMDAXGwlRNfA/AL4PpA+kAx+gAxcdch+gAx+gAwAtMfghAPin6lUiC6lTE0WfAI4IIQF41FGVIgupYxREQD8AngNYIQWV8HvLqTWfAK4F8EhA/y8IAARPpEMHC68uFNgAgEgDA0CASASEwH1APTP/oA+kAh8AHtRND6APpA+kDUMFE2oVIqxwXy4sEowv/y4sJUNEJwVCATVBQDyFAE+gJYzxYBzxbMySLIywES9AD0AMsAySD5AHB0yMsCygfL/8nQBPpA9AQx+gB3gBjIywVQCM8WcPoCF8trE8yCEBeNRRnIyx8ZgDgP3O1E0PoA+kD6QNQwCNM/+gBRUaAF+kD6QFNbxwVUc21wVCATVBQDyFAE+gJYzxYBzxbMySLIywES9AD0AMsAyfkAcHTIywLKB8v/ydBQDccFHLHy4sMK+gBRqKGCCJiWgIIImJaAErYIoYIImJaAoBihJ+MPJdcLAcMAI4A8QEQCayz9QB/oCIs8WUAbPFiX6AlADzxbJUAXMI5FykXHiUAioE6CCCJiWgKoAggiYloCgoBS88uLFBMmAQPsAECPIUAT6AljPFgHPFszJ7VQAcFJ5oBihghBzYtCcyMsfUjDLP1j6AlAHzxZQB88WyXGAGMjLBSTPFlAG+gIVy2oUzMlx+wAQJBAjAA4QSRA4N18EAHbCALCOIYIQ1TJ223CAEMjLBVAIzxZQBPoCFstqEssfEss/yXL7AJM1bCHiA8hQBPoCWM8WAc8WzMntVADbO1E0PoA+kD6QNQwB9M/+gD6QDBRUaFSSccF8uLBJ8L/8uLCggiYloCqABagFrzy4sOCEHvdl97Iyx8Vyz9QA/oCIs8WAc8WyXGAGMjLBSTPFnD6AstqzMmAQPsAQBPIUAT6AljPFgHPFszJ7VSAAgyAINch7UTQ+gD6QPpA1DAE0x+CEBeNRRlSILqCEHvdl94TuhKx8uLF0z8x+gAwE6BQI8hQBPoCWM8WAc8WzMntVIH++ZZY=\0";

        let code_slice = code.as_bytes();
        let data_slice = data.as_bytes();
        let code_packed = code_slice.as_ptr();
        let data_packed = data_slice.as_ptr();
        let empty_cell = CString::new("te6cckEBAQEAAgAAAEysuc0=")?;
        let address = CString::new(format!("0:{}", "F".repeat(64)))?;
        let rand_seed = CString::new("F".repeat(64))?;
        let extra_currencies = CString::new("100=20000 200=1")?;
        let invalid = CString::new("invalid")?;

        unsafe {
            assert!(emulator_set_verbosity_level(0));

            let emulator =
                tvm_emulator_create(code_packed as *const i8, data_packed as *const i8, 2);
            assert!(!emulator.is_null());

            assert!(tvm_emulator_set_libraries(emulator, empty_cell.as_ptr()));
            assert!(tvm_emulator_set_c7(
                emulator,
                address.as_ptr(),
                1_337,
                1_000,
                rand_seed.as_ptr(),
                std::ptr::null(),
            ));
            assert!(tvm_emulator_set_extra_currencies(
                emulator,
                extra_currencies.as_ptr(),
            ));
            assert!(tvm_emulator_set_prev_blocks_info(
                emulator,
                std::ptr::null(),
            ));
            assert!(tvm_emulator_set_gas_limit(emulator, 1_000_000));
            assert!(tvm_emulator_set_debug_enabled(emulator, 1));

            let result = take_emulator_string(tvm_emulator_run_get_method(
                emulator,
                11111123,
                invalid.as_ptr(),
            ))?;
            assert!(result.contains(r#""success":false"#));

            let raw_result = tvm_emulator_emulate_run_method(
                invalid.as_bytes().len() as u32,
                invalid.as_ptr(),
                1_000_000,
            );
            assert!(raw_result.is_null());

            let detailed_result = tvm_emulator_emulate_run_method_detailed(
                invalid.as_bytes().len() as u32,
                invalid.as_ptr(),
                1_000_000,
            );
            assert!(!detailed_result.is_null());
            run_method_detailed_result_destroy(detailed_result);

            let result = take_emulator_string(tvm_emulator_send_external_message(
                emulator,
                invalid.as_ptr(),
            ))?;
            assert!(result.contains(r#""success":false"#));

            let result = take_emulator_string(tvm_emulator_send_internal_message(
                emulator,
                invalid.as_ptr(),
                1_000,
            ))?;
            assert!(result.contains(r#""success":false"#));

            tvm_emulator_destroy(emulator);

            let version = take_emulator_string(emulator_version())?;
            assert!(version.contains("emulatorLibCommitHash"));
            assert!(version.contains("emulatorLibCommitDate"));

            string_destroy(std::ptr::null());
        }

        Ok(())
    }
}