tonlib-client 0.23.1

Thin wrapper for tonlibjson
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
# Rust client for The Open Network

Rust client for [The Open Network](https://ton.org/)

## Features

* Rust client for The Open Network
* Using `tonlibjson` as data provider
* Support jetton functions: getting of jetton data and wallet address for jetton
* Support internal and external jetton metadata loading
* Connection pooling & retries support for better server-level interaction
* Support of IPFS jetton metadata

### Feature flags
- `state_cache` - Enables caching of ton contract states. This feature is recommended to use if the contract state received from blockchain is reused multiple times. 
- `emulate_get_method` - Enables the usage of emulator to run get_methods locally. 
- `no_avx512` - Forces dependent tonlib-sys to be built without avx512 instruction set.
- `with_debug_info` - Enables debug information and stack-trace received from underlying  tonlibjson C++ code.


## Dependencies

`tonlib-sys` - https://github.com/ston-fi/tonlib-sys
`tonlib-core` - https://github.com/ston-fi/tonlib-rs

## Prerequisites

For Linux:
```shell
sudo apt install build-essential cmake libsodium-dev libsecp256k1-dev lz4 liblz4-dev
```

For macOS:
```shell
brew install readline secp256k1 ccache pkgconfig cmake libsodium
```


## Usage

To use this library in your Rust application, add the following to your Cargo.toml file:

```toml
[dependencies]
tonlib-client = "version"
```

Then, in your Rust code, you can import the library with:

```rust
use tonlib_client;
```


### TON blockchain client

To call methods, create a client:

```rust
use tonlib_client::client::TonClient;
use tonlib_client::client::TonClientBuilder;
async fn create_client()-> anyhow::Result<()>{
    TonClient::set_log_verbosity_level(2); //setup of logging level
    let client = TonClientBuilder::new()
    .with_pool_size(10)
    .with_keystore_dir(String::from("/tmp"))
    .build()
    .await?;
Ok(())
}
```



`TonClient::set_log_verbosity_level(2);` sets the logging level.

By default, the connection is made to mainnet. But you can also specify a test network when creating the client:

```rust
use tonlib_client::config::TESTNET_CONFIG;
use tonlib_client::client::TonConnectionParams;
use tonlib_client::client::TonClientBuilder;
async fn create_client_with_conn_params()-> anyhow::Result<()>{
    let client = TonClientBuilder::new()
        .with_connection_params(&TonConnectionParams {
            config: TESTNET_CONFIG.to_string(),
            blockchain_name: None,
            use_callbacks_for_network: false,
            ignore_cache: false,
            keystore_dir: None,
            ..Default::default()
        })
        .with_pool_size(10)
        .build()
        .await?;
    Ok(())
}
```


After creating the client, you can call methods on the TON blockchain:

```rust
use tonlib_core::TonAddress;
use tonlib_client::tl::InternalTransactionId;
use tonlib_core::types::ZERO_HASH;
use tonlib_client::tl::NULL_BLOCKS_ACCOUNT_TRANSACTION_ID;
use tonlib_client::tl::BlocksTransactions;
use tonlib_client::tl::BlocksShards;
use tonlib_client::tl::BlockId;
use tonlib_client::tl::BlocksMasterchainInfo;
use tonlib_client::client::TonClient;
use tonlib_client::client::TonClientInterface;
use tonlib_core::TonHash;

async fn call_blockchain_methods()-> anyhow::Result<()>{
    let client = TonClient::builder().build().await?;
    let (_, info) = client.get_masterchain_info().await?;
    println!("MasterchainInfo: {:?}", &info);
    let block_id = BlockId {
        workchain: info.last.workchain,
        shard: info.last.shard,
        seqno: info.last.seqno,
    };
    let block_id_ext = client.lookup_block(1, &block_id, 0, 0).await?;
    println!("BlockIdExt: {:?}", &block_id_ext);
    let block_shards: BlocksShards = client.get_block_shards(&info.last).await?;
    let mut shards = block_shards.shards.clone();
    println!("Shards: {:?}", &block_shards);
    shards.insert(0, info.last.clone());
    for shard in &shards {
        println!("Processing shard: {:?}", shard);
        let workchain = shard.workchain;
        let txs: BlocksTransactions = client
            .get_block_transactions(&shard, 7, 1024, &NULL_BLOCKS_ACCOUNT_TRANSACTION_ID)
            .await?;
        println!(
            "Number of transactions: {}, incomplete: {}",
            txs.transactions.len(),
            txs.incomplete
        );
        for tx_id in txs.transactions {
            let t = TonHash::try_from(tx_id.account.as_slice())?;
            let addr = TonAddress::new(workchain, &t);
            let id = InternalTransactionId {
                hash: tx_id.hash.clone(),
                lt: tx_id.lt,
            };
            let tx = client
                .get_raw_transactions_v2(&addr, &id, 1, false)
                .await?;
            println!("Tx: {:?}", tx.transactions[0])
        }
    }
    Ok(())
}
```

You can get the account state for any contract:

```rust
use tonlib_core::TonAddress;
use tonlib_client::client::TonClient;
use crate::tonlib_client::client::TonClientInterface;

async fn get_state()-> anyhow::Result<()>{  
    let client = TonClient::builder().build().await?;
    let address = TonAddress::from_base64_url(
        "EQB3ncyBUTjZUA5EnFKR5_EnOMI9V1tTEAAPaiU71gc4TiUt-",
    )?;
    let r = client
            .get_account_state(&address)
            .await;
    Ok(())
}
```



### Working with contracts and jettons

Methods for working with tokens and wallets:

``` rust
use tonlib_client::client::TonClient;
use tonlib_client::contract::TonContractFactory;
use tonlib_client::contract::JettonMasterContract;
use tonlib_client::contract::JettonWalletContract;

async fn method_call() -> anyhow::Result<()> { 
    let client = TonClient::builder().build().await?;
    let contract_factory = TonContractFactory::builder(&client).build().await?;
    let master_contract = contract_factory.get_contract(
        &"EQDk2VTvn04SUKJrW7rXahzdF8_Qi6utb0wj43InCu9vdjrR".parse()?,
    );
    let jetton_data = master_contract.get_jetton_data().await?;

    let wallet_contract = contract_factory.get_contract(
        &"EQCGY3OVLtD9KRcOsP2ldQDtuY0FMzV7wPoxjrFbayBXc23c".parse()?,
    );
    let wallet_data = wallet_contract.get_wallet_data().await?;
    Ok(())
}
```

To load the metadata of the token, one may use generic `MetaLoader` and it type aliases: `JettonMetaLoader, NftItemMetaLoader NftColletionMetaLoader`:

```rust
use tonlib_client::client::TonClient;
use tonlib_client::contract::TonContractFactory;
use tonlib_client::contract::JettonMasterContract;
use tonlib_client::meta::JettonMetaLoader;
use tonlib_client::meta::LoadMeta;

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(())
}
```


Get the wallet address for the token:

```rust
use tonlib_core::TonAddress;
use tonlib_client::client::TonClient;
use tonlib_client::contract::TonContractFactory;
use tonlib_client::contract::JettonMasterContract; 

async fn get_wallet_address() -> anyhow::Result<()> {

    let client = TonClient::default().await?;
    let contract_factory = TonContractFactory::builder(&client).build().await?;
    let contract =
        contract_factory.get_contract(&"EQDk2VTvn04SUKJrW7rXahzdF8_Qi6utb0wj43InCu9vdjrR".parse()?,
    );
    let owner_address = TonAddress::from_base64_url(
        "EQB2BtXDXaQuIcMYW7JEWhHmwHfPPwa-eoCdefiAxOhU3pQg",
    )?;
    let wallet_address = contract.get_wallet_address(&owner_address).await?;
    Ok(())
}
```

### Send message to TON

Create key pair from secret phrase ( )

```rust
use tonlib_core::mnemonic::Mnemonic;
use tonlib_core::mnemonic::KeyPair;
async fn create_key_pair() -> anyhow::Result<()> {
    let mnemonic = Mnemonic::new(
        vec![
            "dose", "ice", "enrich", "trigger", "test", "dove", "century", "still", "betray",
            "gas", "diet", "dune",
        ],
        &None,
        )?;
    let key_pair = mnemonic.to_key_pair();
    Ok(())
}

```
And now you are ready to send transfer messages to TON blockchain.

Create a jetton transfer:

```rust


use num_bigint::BigUint;
use std::time::SystemTime;
use std::sync::Arc;
use tonlib_core::TonAddress;
use tonlib_core::cell::BagOfCells;
use tonlib_client::client::TonClient;
use tonlib_client::client::TonClientInterface;
use tonlib_client::contract::TonContractFactory;
use tonlib_client::contract::JettonMasterContract;
use tonlib_core::message::JettonTransferMessage;
use tonlib_core::message::TransferMessage;
use tonlib_core::message::TonMessage;
use tonlib_core::message::HasOpcode;
use tonlib_core::mnemonic::KeyPair;
use tonlib_core::mnemonic::Mnemonic;
use tonlib_core::wallet::TonWallet;
use tonlib_core::wallet::WalletVersion;
use tonlib_core::message::CommonMsgInfo;
use tonlib_core::message::ExternalIncomingMessage;

async fn create_jetton_transfer() -> anyhow::Result<()> {

    let seqno:i32 = 30000000;

    let self_address: TonAddress = "EQB2BtXDXaQuIcMYW7JEWhHmwHfPPwa-eoCdefiAxOhU3pQg "
        .parse()
        .unwrap();
    let mnemonic_str = "mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic mnemonic";
    let mnemonic: Mnemonic = Mnemonic::from_str(mnemonic_str, &None).unwrap();
    let key_pair: KeyPair = mnemonic.to_key_pair().unwrap();
    let jetton_master_address: TonAddress = "EQDCJL0iQHofcBBvFBHdVG233Ri2V4kCNFgfRT-gqAd3Oc86"
        .parse()
        .unwrap();

    let client = TonClient::default().await?;
        let contract_factory = TonContractFactory::builder(&client).build().await?;
    let jetton_master =
        contract_factory.get_contract(&jetton_master_address);
    let self_jetton_wallet_addr = jetton_master.get_wallet_address(&self_address).await?;
    let wallet = TonWallet::derive_default(WalletVersion::V4R2, &key_pair)?;
    let dest: TonAddress = "<destination wallet address>".parse()?;
    let src: TonAddress = "<source wallet address>".parse()?;
    let jetton_amount = BigUint::from(1000000u64);
    let jetton_transfer = JettonTransferMessage::new(&dest, &jetton_amount)
        .with_query_id(100500)
        .with_response_destination(&self_address)
        .build()?;
    let ton_amount = BigUint::from(200000000u64); // 0.2 TON
    let external_msg_info = ExternalIncomingMessage{
        src,
        dest,
        import_fee: ton_amount,
    };
    let common_msg_info = CommonMsgInfo::ExternalIncomingMessage(external_msg_info);
    let transfer = TransferMessage::new(common_msg_info)
        .with_data(jetton_transfer.into())
        .build()?;
    let now = SystemTime::now()
        .duration_since(SystemTime::UNIX_EPOCH)?
        .as_secs() as u32;
    let body = wallet.create_external_body(now + 60, seqno.try_into().unwrap(), 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(())
}
```

Create a simple transfer:

```rust

use anyhow::anyhow;
use num_bigint::BigUint;
use std::time::SystemTime;
use std::sync::Arc;

use tonlib_core::TonAddress;
use tonlib_core::cell::BagOfCells;
use tonlib_core::message::TransferMessage;
use tonlib_core::wallet::TonWallet;
use tonlib_client::client::TonClient;
use tonlib_client::client::TonClientInterface;
use tonlib_core::mnemonic::KeyPair;
use tonlib_core::mnemonic::Mnemonic;
use tonlib_core::wallet::WalletVersion;
use tonlib_core::message::TonMessage;
use tonlib_core::message::CommonMsgInfo;
use tonlib_core::message::ExternalIncomingMessage;

async fn create_simple_transfer() -> anyhow::Result<()> {
    let mnemonic = Mnemonic::new(
        vec![
            "dose", "ice", "enrich", "trigger", "test", "dove", "century", "still", "betray",
            "gas", "diet", "dune",
        ],
        &None,
        )?;
    let key_pair = mnemonic.to_key_pair()?;
    let seqno =  30000000;
    

    let client = TonClient::default().await?;
    let wallet = TonWallet::derive_default(WalletVersion::V4R2, &key_pair)?;
    let src: TonAddress = "<source wallet address>".parse()?;
    let dest: TonAddress = "<destination wallet 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(())
}
```

## Contributing

If you want to contribute to this library, please feel free to open a pull request on GitHub.

## License
This library is licensed under the MIT license. See the LICENSE file for details. -->