Comprehensive Guide to Handling NFTs and TON Tokens in TON Smart Contracts

In TON (The Open Network) smart contracts, the management of Non-Fungible Tokens (NFTs) and TON tokens is a core feature. This tutorial aims to provide you with a comprehensive guide, helping you understand how to use a set of utility functions to manage the sending of NFTs, conduct NFT lotteries, check specific conditions, and send TON tokens.

Tutorial Overview

  1. Sending NFTs: An introduction to sending NFTs to a specified recipient.
  2. Conducting NFT Lottery: Demonstrating how to randomly allocate NFTs.
  3. Checking Specific Conditions: Explaining how to verify that transaction conditions are met.
  4. Sending TON Tokens: A description of how to send TON tokens to a recipient.
  5. Supplementary Code: Additional utility functions to enhance the contract.

1. Sending NFTs

Function Definition

The utils::send_nft function is used to send NFTs.

Parameters

  • mode: The sending mode.
  • amount: The amount to be sent.
  • to: The recipient’s address.
  • nft_addr: The NFT address.

Steps

  1. Verify Ownership: Ensure the sender owns the NFT.
  2. Construct Message: Create a message containing operation codes, query IDs, etc.
  3. Send Message: Send the message via the send_raw_message function.

Supplementary Code: Ownership Verification

() utils::send_nft(int mode, int amount, slice to, int nft_addr) impure inline_ref {
    builder body = begin_cell()
        .store_uint(op::transfer(), 32) ;; op
        .store_uint(cur_lt(), 64)       ;; query id
        .store_slice(to)                ;; new owner
        .store_slice(to)                ;; response destination
        .store_int(0, 1)                ;; custom payload
        .store_coins(0)                 ;; fwd ton amount
        .store_int(0, 1);               ;; fwd custom payload

    builder msg = begin_cell()
        .store_uint(0x18, 6)
        .store_uint(2, 2) ;; addr std
        .store_uint(0, 1) ;; anycast
        .store_uint(0, 8) ;; wc
        .store_uint(nft_addr, 256)
        .store_coins(amount)
        .store_uint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1)
        .store_ref(body.end_cell());

    send_raw_message(msg.end_cell(), mode);
}

2. Conducting NFT Lottery

Function Definition

The utils::raffle_nfts function randomly assigns NFTs.

Parameters

  • raffled_nfts: A dictionary to store the lottery results.
  • nfts: A dictionary containing all NFTs.

Steps

  1. Iterate Over NFT Dictionary: Loop through all NFTs.
  2. Random Allocation: Use a random number to decide the NFT allocation.
  3. Record Results: Store the results in the raffled_nfts dictionary.
cell utils::raffle_nfts(cell raffled_nfts, cell nfts) inline_ref {
    int key = -1;
    do {
        (key, slice data, int found) = nfts.udict_get_next?(256, key);
        if (found) {
            if (rand(2) == 0) {
                raffled_nfts~udict_set(256, key, begin_cell().store_uint(1, 1).end_cell().begin_parse());
            } else {
                raffled_nfts~udict_set(256, key, begin_cell().store_uint(0, 1).end_cell().begin_parse());
            }
        }
    } until (~ found)
    return raffled_nfts;
}

3. Checking Specific Conditions

Function Definition

The utils::check_conditions function verifies transaction conditions.

Steps

  1. Initialize Data: Prepare the data needed for the checks.
  2. Verify Conditions: Check if the conditions for NFT count, token amount, etc., are met.
int utils::check_conditions() inline_ref method_id {
    init_data();
    return ((db::right_nfts_count == db::right_nfts_received) & (db::left_nfts_count == db::left_nfts_received) &
            (db::left_coins_got >= db::left_commission) & (db::right_coins_got >= db::right_commission));
}

4. Sending TON Tokens

Function Definition

The utils::send_tons function is used to send TON tokens.

Parameters

  • to: The recipient’s address.
  • amount: The amount to be sent.
  • message: The message content.
  • mode: The sending mode.

Steps

  1. Construct Message: Create a message containing the recipient’s address, amount, and message.
  2. Send Message: Send the message via the send_raw_message function.

Supplementary Code: Handling Send Failure

() utils::send_tons(slice to, int amount, slice message, int mode) impure inline_ref {
    var msg = begin_cell()
        .store_uint(0x18, 6)
        .store_slice(to)
        .store_coins(amount)
        .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
        .store_uint(0, 32)
        .store_slice(message);
    send_raw_message(msg.end_cell(), mode);
}

Supplementary Code

The following are additional features to enhance the robustness and functionality of your smart contract.

Recording NFT Transfer History

(cell, int, int) utils::add_nft(cell dict, int nft_addr) inline_ref {
    int left_success = 0;
    int right_success = 0;
    (slice data, int found) = dict.udict_get?(256, nft_addr);
    if (found == 0) {
        return (dict, 0, 0);
    }
    if (data~load_uint(4) == 0) {
        dict~udict_set(256, nft_addr, begin_cell().store_uint(2, 4).end_cell().begin_parse());
        left_success = -1;
    } else {
        dict~udict_set(256, nft_addr, begin_cell().store_uint(3, 4).end_cell().begin_parse());
        right_success = -1;
    }
    return(dict, left_success, right_success);
}

Checking if NFT Has Been Sent

int utils::is_nft_sent(int nft_addr) inline_ref {
    // Check if NFT has been sent
}

Summary

Throughout this tutorial, we have delved into the key steps involved in handling NFTs and TON tokens within TON smart contracts. By implementing these supplementary codes, you can ensure the robustness of your contract and provide a richer user experience. In practical applications, adjust and optimize these code snippets according to your specific needs. Remember that security, scalability, user experience, compliance, legal considerations, testing, and deployment are all important factors to consider when designing smart contracts.

Extending the Contract

As your smart contract grows and evolves, you may find the need to extend its functionality. Ensure that your contract’s architecture allows for easy integration of new features without compromising existing ones. This could involve modular design, abstraction layers, or the use of libraries to manage complexity.

Community and Collaboration

Participating in the TON community can be invaluable for your contract’s success. Collaborate with other developers, share best practices, and learn from their experiences. Engaging with the community can help you stay up-to-date with the latest developments in the TON ecosystem and ensure that your contract remains relevant.

Monitoring and Maintenance

Once your smart contract is live, ongoing monitoring and maintenance are essential. Set up mechanisms to track the contract’s performance, handle any issues that arise, and apply updates as needed. This may involve setting up alerts for suspicious activity, implementing self-healing mechanisms, or periodic audits to ensure the contract’s integrity.

Conclusion

In conclusion, this tutorial has provided you with a detailed guide on how to handle NFTs and TON tokens within TON smart contracts. By following these steps and considering the additional factors mentioned, you can create a secure, scalable, and user-friendly contract that meets the needs of your application. Remember to continuously learn and adapt to the evolving landscape of smart contract development to stay ahead of the curve.