coolcode / octotype

Web3 Vagabond
https://web3v.netlify.app
0 stars 0 forks source link

A Fun Guide to Quickly Developing a TON Transfer Application Using Rust #4

Open coolcode opened 1 month ago

coolcode commented 1 month ago

A Fun Guide to Quickly Developing a TON Transfer Application Using Rust

Introduction

The blockchain landscape is ever-evolving, with new networks offering unique features and capabilities. The Open Network (TON) is one such blockchain that stands out for its high performance and throughput. If you're a developer keen on diving into blockchain development, exploring how to build on TON is an exciting prospect. And what better language to use than Rust—known for its safety and efficiency.

In this blog post, we'll embark on a fun journey to create a simple TON transfer application using Rust. Don't worry if you're new to TON or Rust; we'll guide you through the basics step by step, making the process enjoyable and accessible.


Why Choose Rust and TON?

The Advantages of Rust

The Features of TON


Getting Ready

1. Install Rust

First, ensure that Rust is installed on your machine.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

After installation, verify that Rust is correctly set up:

rustc --version

2. Install TON Development Tools

To interact with the TON network, we'll need to install the development tools provided by TON.

Install tonos-cli

tonos-cli is the official command-line tool provided by TON for interacting with the blockchain.

Download and install the latest version from the TON Labs GitHub repository.

# Clone the tonos-cli repository
git clone https://github.com/tonlabs/tonos-cli.git
cd tonos-cli

# Compile and install
cargo install --path .

3. Set Up the Development Environment

Create a new directory for your project.

mkdir ton-transfer-app
cd ton-transfer-app

Let's Start Coding

1. Create a Cargo Project

Initialize a new Rust project in your project directory.

cargo init --bin

2. Add Dependencies

In your Cargo.toml, add the necessary dependencies.

[dependencies]
ton-client = "1.44.2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
anyhow = "1.0"

3. Write the Code

In src/main.rs, we'll write the code to interact with the TON network.

Import Necessary Modules

use ton_client::{ClientConfig, ClientContext};
use ton_client::abi::{Abi, CallSet, ParamsOfEncodeMessage, Signer};
use ton_client::processing::{ParamsOfProcessMessage, ProcessingEvent};
use ton_client::crypto::KeyPair;
use serde_json::json;
use anyhow::Result;

Initialize the TON Client

async fn create_client() -> Result<ClientContext> {
    let config = ClientConfig {
        network: ton_client::net::NetworkConfig {
            server_address: Some("https://main.ton.dev".to_owned()),
            ..Default::default()
        },
        ..Default::default()
    };
    Ok(ClientContext::new(config)?)
}

Define the Transfer Function

async fn transfer_grams(
    client: &ClientContext,
    sender_keys: &KeyPair,
    sender_address: &str,
    recipient: &str,
    amount: u64,
) -> Result<()> {
    // Use the wallet contract's ABI
    let abi = Abi::from_json(r#"
    {
        "ABI version": 2,
        "header": ["time", "expire"],
        "functions": [
            {
                "name": "sendTransaction",
                "inputs": [
                    {"name":"dest","type":"address"},
                    {"name":"value","type":"uint128"},
                    {"name":"bounce","type":"bool"},
                    {"name":"flags","type":"uint8"},
                    {"name":"payload","type":"cell"}
                ],
                "outputs": []
            }
        ],
        "events": [],
        "data": []
    }
    "#)?;

    let call_set = CallSet {
        function_name: "sendTransaction".to_owned(),
        input: Some(json!({
            "dest": recipient,
            "value": amount.to_string(),
            "bounce": false,
            "flags": 3,
            "payload": ""
        })),
        header: None,
    };

    let params = ParamsOfProcessMessage {
        message_encode_params: ParamsOfEncodeMessage {
            abi: abi.clone(),
            address: Some(sender_address.to_owned()), // Replace with your wallet address
            call_set: Some(call_set),
            signer: Signer::Keys { keys: sender_keys.clone() },
            ..Default::default()
        },
        send_events: false,
        ..Default::default()
    };

    let response = ton_client::processing::process_message(client, params, |_| {}).await?;

    println!("Transfer completed. Transaction ID: {}", response.transaction.id);

    Ok(())
}

The Main Function

#[tokio::main]
async fn main() -> Result<()> {
    let client = create_client().await?;

    // Load your key pair (make sure to replace with your actual keys)
    let sender_keys = KeyPair {
        public: "your_public_key".to_owned(),
        secret: "your_private_key".to_owned(),
    };

    // Set your wallet address
    let sender_address = "your_wallet_address"; // Replace with your wallet address

    // Set the recipient's address and the amount to transfer
    let recipient_address = "recipient_address"; // Replace with the recipient's address
    let amount = 1_000_000_000u64; // 1 TON = 1,000,000,000 nanotons

    transfer_grams(&client, &sender_keys, sender_address, recipient_address, amount).await?;

    Ok(())
}

4. Run the Application

After replacing the placeholders with your actual sender and recipient information, run the application:

cargo run

If everything goes smoothly, you'll see a message indicating the transfer is complete.


Exploring Further

Generating Key Pairs and Wallets

If you don't have a TON wallet and key pair, you can generate them using tonos-cli.

# Generate a mnemonic phrase
tonos-cli genphrase

# Generate a key pair from the mnemonic phrase
tonos-cli getkeypair keyfile.json "your mnemonic phrase"

# Deploy a wallet contract (e.g., SafeMultisigWallet)
tonos-cli deploy SafeMultisigWallet.tvc \
'{"owners":["0xYourPublicKey"],"reqConfirms":1}' \
--abi SafeMultisigWallet.abi.json \
--sign keyfile.json \
--wc 0

Checking Account Balance

You can extend your application to include functionality for checking an account's balance.

async fn get_account_balance(client: &ClientContext, address: &str) -> Result<u64> {
    use ton_client::net::{ParamsOfQueryCollection, query_collection};

    let result = query_collection(
        client,
        ParamsOfQueryCollection {
            collection: "accounts".to_string(),
            filter: Some(json!({ "id": { "eq": address } })),
            result: "balance".to_string(),
            limit: Some(1),
            order: None,
        },
    ).await?;

    if let Some(account) = result.result.first() {
        let balance_str = account["balance"].as_str().unwrap_or("0");
        let balance: u64 = balance_str.parse()?;
        Ok(balance)
    } else {
        Ok(0)
    }
}

Conclusion

By using Rust, we can interact with the TON network efficiently and safely. While this example is a simple transfer application, it showcases the potential of using Rust for blockchain development. You can build upon this foundation to develop more complex features, such as querying account balances, interacting with smart contracts, and more.

We hope this blog post has sparked your interest in Rust and TON development, and encourages you to try building your own blockchain applications!


References


Happy coding! If you have any questions or need further assistance, feel free to leave a comment.