TLDR:
In this tutorial, we will discuss the standard implementation of fungible tokens on the TON blockchain and walk through the development steps using the Blueprint environment and Sandbox.
Start for free and get your app to production levels immediately. No credit card required. You can sign up with your GitHub, X, Google, or Microsoft account.
The suggested approach for fungible tokens on TON involves having a minter contract (also called a master contract) and a specific wallet contract for each user. This allows taking advantage of the TON blockchain architecture and its sharding feature.
The minter contract holds key token metrics and parameters, while the wallet contract maintains a balance of a specific user and allows transferring and burning tokens. This is described in more detail in the TON standards (TEPs). Let’s examine those related to fungible tokens.
TON fungible tokens are called Jettons. The Jetton standard is described in TEP74. The specification for metadata of all tokens on TON is in TEP64. The Jetton standard (TEP74) describes:
Jettons are organized as follows: each Jetton has a master smart contract used to mint new Jettons, account for circulating supply, and provide common information. At the same time, information about the amount of jettons owned by each user is stored in a decentralized manner in individual smart contracts (referred to as “Jetton-wallets”) for each owner.
An example of the Jetton minter and wallet contracts has been prepared by the TON core team. We will take these contracts as a starting point for our development.
Source: How to shard your TON smart contract and why - studying the anatomy of TON’s Jettons.
Let’s create an empty Blueprint project with FunC in the current folder:
After that, create the blueprint.config.ts
file and paste your Chainstack endpoint. In this tutorial, we work with the testnet:
Then, let’s copy the contracts from the standard implementation to our project’s contracts
folder. We need jetton-minter-discoverable.fc
, jetton-wallet.fc
and jetton-utils.fc
, discovery-params.fc
, op-codes.fc
, params.fc
. Let’s briefly walk through them.
The minter contract allows the admin (the contract owner) to manage the minting process and total tupply. Additionally, it implements the TEP89 feature for Jetton wallet discovery, which simplifies obtaining a Jetton wallet address by other smart contracts. Previously, this was challenging because contracts couldn’t use get methods on other contracts directly.
The wallet contract manages Jetton token transfers, storage, and burning for a specific user. It tracks the wallet balance, owner’s address, and Jetton master details, updating the data after transfers or burns.
The jetton-utils.fc
file contains functions that help in creating and managing a Jetton wallet, making sure that all the necessary data is packed and that the correct address for the wallet is calculated.
The discovery-params.fc
, op-code.fc
files contain the standard operational codes for the minter and wallet contracts. Additionally, the function is_resolvable
checks if a given address is within the same workchain as the contract. It extracts the workchain ID from the address and compares it with the current contract’s workchain ID. The params.fc
also contains the same check that is used by the wallet contract.
Before proceeding, please make sure your contracts include required imports.
jetton-minter-discoverable.fc
jetton-wallet.fc
jetton-utils.fc
params.fc
To check that everything is alright, please try to compile the contracts:
In the folder wrappers
create or update the compile files:
JettonMinter.compile.ts
JettonWallet.compile.ts
Run the command build
:
To test and run scripts for our smart contracts, we need to have TypeScript interfaces for them. The wrappers
folder contains such interface classes for all contracts (implementing Contract
from @ton/core
), including serialization primitives, getter wrappers and compilation functions.
Let’s copy the wrappers, JettonMinter.ts
, JettonWallet.ts
, JettonConstants.ts
and ui-utils.ts
, from the existing implementation to our project’s folder wrappers
. You can also copy the shortened versions of the same files from our repository. Additionally, ui-utils.ts
has a few adjustments there.
The Blueprint framework incorporates Sandbox. The package allows developers to emulate TON smart contracts behaviour as if they were deployed on a real network. Please copy the tests from our repository. As in the case with the wrappers, it’s a shortened version with a few adjustments based on examples prepared by the TON core team (here and here).
To test the contracts using Sandbox, run the command:
In the scripts
folder, create deployJettonMinter.ts
with the following code:
The metadata JSON must have the following format with the image data having base64-encoded value:
To deploy the contracts to the testnet, run the command:
We walked through the fungible token standard on the TON blockchain and its main development steps using Blueprint and Sandbox. In future tutorials, we will add custom behaviour for our token. Stay tuned!
Developer Advocate @ Chainstack
Multiple years of software development and Web3 expertise. Creator of the open-source Compare Dashboard for RPC provider performance benchmarking. Core contributor to the DevEx team’s pump.fun trading bot. Author of technical tutorials on EVM blockchains, Solana, TON and Subgraphs.
TLDR:
In this tutorial, we will discuss the standard implementation of fungible tokens on the TON blockchain and walk through the development steps using the Blueprint environment and Sandbox.
Start for free and get your app to production levels immediately. No credit card required. You can sign up with your GitHub, X, Google, or Microsoft account.
The suggested approach for fungible tokens on TON involves having a minter contract (also called a master contract) and a specific wallet contract for each user. This allows taking advantage of the TON blockchain architecture and its sharding feature.
The minter contract holds key token metrics and parameters, while the wallet contract maintains a balance of a specific user and allows transferring and burning tokens. This is described in more detail in the TON standards (TEPs). Let’s examine those related to fungible tokens.
TON fungible tokens are called Jettons. The Jetton standard is described in TEP74. The specification for metadata of all tokens on TON is in TEP64. The Jetton standard (TEP74) describes:
Jettons are organized as follows: each Jetton has a master smart contract used to mint new Jettons, account for circulating supply, and provide common information. At the same time, information about the amount of jettons owned by each user is stored in a decentralized manner in individual smart contracts (referred to as “Jetton-wallets”) for each owner.
An example of the Jetton minter and wallet contracts has been prepared by the TON core team. We will take these contracts as a starting point for our development.
Source: How to shard your TON smart contract and why - studying the anatomy of TON’s Jettons.
Let’s create an empty Blueprint project with FunC in the current folder:
After that, create the blueprint.config.ts
file and paste your Chainstack endpoint. In this tutorial, we work with the testnet:
Then, let’s copy the contracts from the standard implementation to our project’s contracts
folder. We need jetton-minter-discoverable.fc
, jetton-wallet.fc
and jetton-utils.fc
, discovery-params.fc
, op-codes.fc
, params.fc
. Let’s briefly walk through them.
The minter contract allows the admin (the contract owner) to manage the minting process and total tupply. Additionally, it implements the TEP89 feature for Jetton wallet discovery, which simplifies obtaining a Jetton wallet address by other smart contracts. Previously, this was challenging because contracts couldn’t use get methods on other contracts directly.
The wallet contract manages Jetton token transfers, storage, and burning for a specific user. It tracks the wallet balance, owner’s address, and Jetton master details, updating the data after transfers or burns.
The jetton-utils.fc
file contains functions that help in creating and managing a Jetton wallet, making sure that all the necessary data is packed and that the correct address for the wallet is calculated.
The discovery-params.fc
, op-code.fc
files contain the standard operational codes for the minter and wallet contracts. Additionally, the function is_resolvable
checks if a given address is within the same workchain as the contract. It extracts the workchain ID from the address and compares it with the current contract’s workchain ID. The params.fc
also contains the same check that is used by the wallet contract.
Before proceeding, please make sure your contracts include required imports.
jetton-minter-discoverable.fc
jetton-wallet.fc
jetton-utils.fc
params.fc
To check that everything is alright, please try to compile the contracts:
In the folder wrappers
create or update the compile files:
JettonMinter.compile.ts
JettonWallet.compile.ts
Run the command build
:
To test and run scripts for our smart contracts, we need to have TypeScript interfaces for them. The wrappers
folder contains such interface classes for all contracts (implementing Contract
from @ton/core
), including serialization primitives, getter wrappers and compilation functions.
Let’s copy the wrappers, JettonMinter.ts
, JettonWallet.ts
, JettonConstants.ts
and ui-utils.ts
, from the existing implementation to our project’s folder wrappers
. You can also copy the shortened versions of the same files from our repository. Additionally, ui-utils.ts
has a few adjustments there.
The Blueprint framework incorporates Sandbox. The package allows developers to emulate TON smart contracts behaviour as if they were deployed on a real network. Please copy the tests from our repository. As in the case with the wrappers, it’s a shortened version with a few adjustments based on examples prepared by the TON core team (here and here).
To test the contracts using Sandbox, run the command:
In the scripts
folder, create deployJettonMinter.ts
with the following code:
The metadata JSON must have the following format with the image data having base64-encoded value:
To deploy the contracts to the testnet, run the command:
We walked through the fungible token standard on the TON blockchain and its main development steps using Blueprint and Sandbox. In future tutorials, we will add custom behaviour for our token. Stay tuned!
Developer Advocate @ Chainstack
Multiple years of software development and Web3 expertise. Creator of the open-source Compare Dashboard for RPC provider performance benchmarking. Core contributor to the DevEx team’s pump.fun trading bot. Author of technical tutorials on EVM blockchains, Solana, TON and Subgraphs.