Introduction

Decentralized Finance (DeFi) is transforming the financial industry by enabling decentralized, transparent financial services using blockchain technology. Unlike traditional systems that rely on central institutions, DeFi operates on smart contracts, giving users full control over their assets without intermediaries.

Overview

DeFi focuses on maximizing fund utilization and minimizing labor costs in smart contracts. Enhancing user experience by visualizing interactions between user wallets and smart contracts is crucial.

In this tutorial, you will learn how to:

This guide assumes you have a basic understanding of blockchain concepts such as accounts, transactions, and smart contracts. We will use the TONX API to interact with the TON blockchain, including querying and writing data.

Prerequisites

Before starting, ensure you have the following:

  1. TONX API Account: Sign up for a TONX API account.
  2. API Key: Obtain an API key from the TONX platform.

Note: The sample code provided is in Node.js and follow the repopsitory of @ton/ton to install the essential module.

Getting Started

Deploy Smart Contracts

Smart contracts are the foundation of any DeFi app, driving its logic and functionality. Most DeFi projects launch their fungible tokens and reward users through liquidity mining.

In this section, you will learn how to deploy a Jetton master or other types of smart contracts using the TONX API:

  1. Technical Approach:
    Use the blueprint SDK to compile your smart contract. Blueprint is a development environment for creating smart contracts in FunC and Tact. This method gives you full control over the deployment process.
  2. Simplified Approach:
    For a quicker setup, visit the TON Official Website and use the TON Minter. Simply connect your wallet, fill in the metadata fields, and mint your first Jetton effortlessly!

Get Balance

As a DeFi application, it's essential to display users' asset balances in real-time. This section will guide you on how to query balance information using the TONX API.

  1. Get TON Coin Balance:
    Easily retrieve the TON coin balance using the getAccountBalance method from the TONX API.
async function getTonBalance(address: string){
  const network = 'testnet';
  const version = 'v2';
  const apiKey = 'your api key which is compatible for the network'
  const endpoint = `https://${network}-rpc.tonxapi.com/${version}/json-rpc/${apiKey}`
  const response = await fetch(this.endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      id: "1",
      jsonrpc: "2.0",
      method: "getAccountBalance",
      params: {
        address: address
      }
    })
  })
  const data = await response.json()
  return data.result;
}
  
const balance = await getTonBalance(address) as string;
  1. Get Jetton (Fungible Token) Balance:
    To get the Jetton balance for a specific owner, use the getJettonWallets method.
async function getJettonWallets(params:{
  ownerAddress?: string,
  jettonWalletAddress?: string,
  jettonMasterAddress?: string,
  offset?: number,
  limit?: number,
}){
  const {
    ownerAddress,
    jettonWalletAddress,
    jettonMasterAddress,
    offset = 0,
    limit = 128,
  } = params;
  const network = 'testnet';
  const version = 'v2';
  const apiKey = 'your api key which is compatible for the network'
  const endpoint = `https://${network}-rpc.tonxapi.com/${version}/json-rpc/${apiKey}`
  
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      id: "1",
      jsonrpc: "2.0",
      method: "getJettonWallets",
      params: {
        address: jettonWalletAddress,
        jetton_address: jettonMasterAddress,
        limit: limit,
        offset: offset,
        owner_address: ownerAddress
      }
    })
  })
  const data = await response.json();

  return data.result;
}

const jettonWallets = await getJettonWallets(ownerAddress) as {
  address: string,  // jetton wallet address
  balance: string,  // jetton balance
  owner: string,    // owner address
  jetton: string,   // jetton master address
  last_transaction_lt: string,
  code_hash: string,
  data_hash: string
}[];
  1. Handle Jetton Info:
    Each Jetton (Fungible Token) has metadata such as decimals, symbol, icon, or total supply. This data, known as jetton_content, is managed by the Jetton master contract. To display this information, you need to handle the metadata, which can be complex as different Jetton deployers manage it in various ways.
async function getJettonMaster(params:{
	jettonMasterAddress?: string,
	adminAddress?: string,
	limit?: number,
	offset?: number
}){
  const network = 'testnet';
  const version = 'v2';
  const apiKey = 'your api key which is compatible for the network'
  const endpoint = `https://${network}-rpc.tonxapi.com/${version}/json-rpc/${apiKey}`
  const {
    jettonMasterAddress, 
    adminAddress,
    limit = 128,
    offset = 0,
  } = params;
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      id: "1",
      jsonrpc: "2.0",
      method: "getJettonMasters",
      params: {
        address: jettonMasterAddress,
        admin_address: adminAddress,
        limit: limit,
        offset: offset,
      }
    })
  })
  const data = await response.json();
  return data.result;
}

    
const jettons = new Map<string, any>();
const jettonMasterAddress = 'jettonMasterAddress' 
const jettonInfo = await getJettonMaster({jettonMasterAddress}) as {
      "address": string,
      "admin_address": string,
      "code_hash": string,
      "data_hash": string,
      "jetton_content": any,
      "jetton_wallet_code_hash": string,
      "last_transaction_lt": string,
      "mintable": true,
      "total_supply": string
    }[];
const jettonContent = jettonInfo[0].jetton_content;

if(jettonContent.symbol && jettonContent.decimals){
  jettons.set("jetton master address from getJettonWallets", {
    balance: "balance from getJettonWallets",
    meta: {
      symbol: jettonContent.symbol,
      decimals: jettonContent.decimals,
      image: jettonContent.image
    }
  });
}else if(jettonContent.uri){
  //USDT used this approach
  const resp = await fetch(jettonContent.uri);
  const jettonData = await resp.json();
  jettons.set("jetton master address from getJettonWallets", {
    balance: "balance from getJettonWallets",
    meta: {
      symbol: jettonData.symbol,
      decimals: jettonData.decimals | jettonContent.decimals,
      image: jettonData.image
    }
  });
}
  

Get Transaction History

In addition to displaying asset balances, providing transaction history is crucial for user experience. This section will show you how to query transaction histories for both TON and Jetton using the TONX API.

  1. Get TON transactions: Retrieve the transaction history for TON coins.
async function getTransactions(params:{
  address?: string,
  seqno?: number,
  shard?: string,
  workChainId?: number,
  hash?: string,
  startLt?: number,
  endLt?: number,
  startTimestamp?: number,
  endTimestamp?: number,
  offset?: number,
  limit?: number,
  sort?: 'ASC'|'DESC',
}){
  const network = 'testnet';
  const version = 'v2';
  const apiKey = 'your api key which is compatible for the network'
  const endpoint = `https://${network}-rpc.tonxapi.com/${version}/json-rpc/${apiKey}`
  const {
    address,
    seqno,
    shard,
    workChainId,
    hash,
    startLt,
    endLt,
    startTimestamp,
    endTimestamp,
    offset = 0,
    limit = 128,
    sort = 'ASC',
  } = params;
  const response = await fetch(this.endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      id: "1",
      jsonrpc: "2.0",
      method: "getTransactions",
      params: {
        seqno: seqno,
        shard: shard,
        workchain: workChainId,
        account: address,
        hash: hash,
        start_lt: startLt,
        end_lt: endLt,
        start_utime: startTimestamp,
        end_utime: endTimestamp,
        sort: sort,
        offset: offset,
        limit: limit

      }
    })
  })
  const data = await response.json()

  return data.result;
}

const transactions = await getTransactions({
  address: ownerAddress
})
 
  1. Get Jetton Transactions:
    Parsing Jetton transactions can be complex due to the different message types—external and internal—used in the TON design. The TONX API simplifies this process, making transaction data more readable and accessible.
async function getJettonTransfer(params:{
  ownerAddress?: string,
  jettonMasterAddress?: string,
  startTimestamp?: number,
  endTimestamp?: number,
  limit?: number,
}){

const network = 'testnet';
const version = 'v2';
const apiKey = 'your api key which is compatible for the network'
const endpoint = `https://${network}-rpc.tonxapi.com/${version}/json-rpc/${apiKey}`

const {    
  ownerAddress,
  jettonMasterAddress,
  startTimestamp,
  endTimestamp,
  limit = 128
  } = params
const response = await fetch(endpoint, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    id: "1",
    jsonrpc: "2.0",
    method: "getJettonTransfers",
    params: {
      address: ownerAddress,
      jetton_master: jettonMasterAddress,
      limit: limit,
      start_timestamp: startTimestamp,
      end_timestamp: endTimestamp
    }
  })
})
const data = await response.json()

return data.result;

}

const transfers = await getJettonTransfer(ownerAddress, jettonMasterAddress);



Manage deposit and withdraw

Building on the previous section where we learned how to retrieve transfer information using the TONX API, this section will cover how to manage deposit and withdrawal actions.

  1. Handle Jetton Deposits and Withdrawals: Learn how to manage Jetton deposits and withdrawals efficiently.
import { address } from "@ton/core";

const transfers = await getJettonTransfer({
  ownerAddress: contractAddress,
  jettonMasterAddress: jettonMasterAddress,
});
const transferMap = new Map<string, any>();
const info = jettons.get(jettonMasterAddress);
transfers.forEach(tx => {
  const {source, destination, amount, transaction_hash: hash, transaction_now: now} = tx;
  const {symbol, decimals} = info.meta;
  const transfer = {
    hash: hash,
    source: source,
    dest: destination,
    transferType: '',
    value: amount,
    fwdFee: '',
    ihrFee: '',
    symbol: symbol,
    decimals: decimals,
    createdAt: now,
  }
  if(address(tx.source).equals(address(ownerAddress))){
    transfer.transferType = 'send';
  }else{
    transfer.transferType = 'receive';
  }
  transferMap.set(hash, transfer);
})


  1. Handle TON Coin Deposits and Withdrawals: Understand the process for handling deposits and withdrawals of TON coins.
const transactions = await getTransactions({
  address: contractAddress,
})


const transferMap = new Map<string, any>();
transactions.forEach(tx => {	
  const inMsg = tx.in_msg;
  const outMsgs = tx.out_msgs.out_msgs;

  const isExternal = inMsg.source === '';
  if(!isExternal){
    const {value, fwd_fee, ihr_fee, hash, source, destination} = inMsg
    const transfer = {
      hash: hash,
      source: source,
      dest: destination,
      transferType: 'receive',
      value: value,
      fwdFee: fwd_fee,
      ihrFee: ihr_fee,
      symbol: 'ton',
      decimals: 9,
      createdAt: tx.now,
    }
    transferMap.set(hash, transfer);
  }
  if(outMsgs && outMsgs.length !== 0){
    outMsgs.forEach((om) => {
      const {hash, value, fwd_fee, ihr_fee, source, destination} = om;
      const transfer = {
        hash: hash,
        source: source,
        dest: destination,
        transferType: 'send',
        value: value,
        fwdFee: fwd_fee,
        ihrFee: ihr_fee,
        symbol: 'ton',
        decimals: 9,
        createdAt: tx.now,
      }
      transferMap.set(hash, transfer);
    })
  }
})

Conclusion

Congratulations! You've taken the first steps towards building your own DeFi application. By following this guide, you’ve learned how to:

  • Deploy smart contracts on the TON blockchain.
  • Retrieve account balances and transaction history for both TON coins and Jettons.
  • Manage deposits and withdrawals effectively.

With this foundational knowledge, you're now equipped to create powerful DeFi solutions using the TONX API. Keep exploring and building to unlock the full potential of decentralized finance.

Ready for your next challenge? Dive into our Build Your First GameFi App guide to learn how to create engaging blockchain-based gaming experiences. Let’s bring your GameFi ideas to life!