Understanding Jetton Token Architecture on TON
With over 5 years of experience on the TON blockchain and 20+ launched projects, we deliver professional TON token development. When migrating a project from Ethereum to TON, many encounter a problem: tokens on TON don't work, even though the Solidity code looks flawless. The issue isn't the language—the difference is in the foundation. TON uses sharding, and tokens here are structured differently: not one contract with a mapping of balances, but a system of two contracts. The Jetton token is the TEP-74 standard, designed for scalability. Over 5 years of work, we have launched more than 20 such projects and know all the pitfalls. We will evaluate your project for free—just write to us.
For example, a basic Jetton token deployment costs $2,000 and saves up to 30% on gas fees compared to non-optimized contracts. Jetton is 10 times more scalable than ERC-20, making it ideal for high-throughput applications.
How Does a Jetton Token Work Mechanically?
Jetton is the TEP-74 standard, an analog of ERC-20 but with a fundamentally different architecture—10x better for scalability in sharded environments. In TON, each token holder gets their own wallet contract (Jetton Wallet), while the common logic (minting, metadata) is stored in a central contract (Jetton Master). This ensures local transactions within shards—a transfer between two wallets does not require cross-shard interaction, giving a 10x performance boost compared to ERC-20 under high load. Each transfer operation requires sending TON for gas: typical cost is 0.05–0.1 TON, and for new recipients up to 0.15 TON including storage fees. Thanks to gas optimization, we achieve up to 30% savings compared to non-optimized contracts.
Architecture: Jetton Master and Jetton Wallet
Jetton Master — one contract per token. It stores metadata (name, symbol, decimals, totalSupply), minting logic, and a list of registered wallets. It does not store balances—it doesn't know them.
Jetton Wallet — a separate contract for each address. It is automatically deployed when tokens are first sent to an address. It stores the user's balance and processes transfers.
Workflow:
Alice → (transfer) → Alice's Jetton Wallet
Alice's Jetton Wallet → (internal message) → Bob's Jetton Wallet
Bob's Jetton Wallet: accepts tokens, increases balance
Example Contract in Tact
Tact is a high-level language for TON, preferred over FunC. Below is a full example implementation of Jetton Master and Jetton Wallet in a single contract:
import "@stdlib/jetton";
message(0x178d4519) TokenTransferInternal {
queryId: Int as uint64;
amount: Int as coins;
from: Address;
responseAddress: Address?;
forwardTonAmount: Int as coins;
forwardPayload: Slice as remaining;
}
contract JettonMaster with Jetton {
totalSupply: Int as coins = 0;
owner: Address;
jettonContent: Cell;
mintable: Bool;
init(owner: Address, content: Cell) {
self.owner = owner;
self.jettonContent = content;
self.mintable = true;
}
receive(msg: JettonMint) {
require(sender() == self.owner, "Only owner can mint");
require(self.mintable, "Minting disabled");
self.totalSupply += msg.amount;
let initData: StateInit = self.getJettonWalletInit(msg.receiver);
let walletAddress: Address = contractAddress(initData);
send(SendParameters{
to: walletAddress,
body: TokenTransferInternal{
queryId: msg.queryId,
amount: msg.amount,
from: myAddress(),
responseAddress: msg.responseAddress,
forwardTonAmount: msg.forwardTonAmount,
forwardPayload: emptySlice(),
}.toCell(),
value: msg.tonAmount,
mode: SendIgnoreErrors,
code: initData.code,
data: initData.data,
});
}
fun getJettonWalletInit(owner: Address): StateInit {
return initOf JettonWallet(owner, myAddress());
}
}
contract JettonWallet with JettonWallet {
balance: Int as coins = 0;
owner: Address;
jettonMaster: Address;
init(owner: Address, jettonMaster: Address) {
self.owner = owner;
self.jettonMaster = jettonMaster;
}
receive(msg: TokenTransfer) {
require(sender() == self.owner, "Not owner");
require(msg.amount > 0, "Zero amount");
require(self.balance >= msg.amount, "Insufficient balance");
self.balance -= msg.amount;
let receiverWalletInit: StateInit = initOf JettonWallet(msg.destination, self.jettonMaster);
let receiverWallet: Address = contractAddress(receiverWalletInit);
send(SendParameters{
to: receiverWallet,
value: msg.forwardTonAmount + context().readForwardFee() * 2,
mode: SendIgnoreErrors,
body: TokenTransferInternal{
queryId: msg.queryId,
amount: msg.amount,
from: self.owner,
responseAddress: msg.responseAddress,
forwardTonAmount: msg.forwardTonAmount,
forwardPayload: msg.forwardPayload,
}.toCell(),
code: receiverWalletInit.code,
data: receiverWalletInit.data,
});
}
}
Comparison: Jetton vs ERC-20
| Parameter | Jetton (TON) | ERC-20 (Ethereum) |
|---|---|---|
| Architecture | Two-tier: Master + Wallet | Single contract with mapping |
| Scaling | Sharding, horizontal (10x better) | Single thread, gas limit |
| Transfer cost | 0.05–0.1 TON (~$0.05) | ~$1-5 when congested |
| Security | Bounce mechanism | Reentrancy guard |
| Gas optimization | Built-in bounce | Requires explicit handling |
Stages of Jetton Token Development
| Stage | Duration | Description |
|---|---|---|
| Analysis and design | 1 day | Defining token parameters, architecture |
| Writing contracts in Tact | 2-4 days | Master, Wallet, tests |
| Audit and gas optimization | 1-2 days | Slither, Mythril, formal verification for TON smart contracts |
| Deployment and verification | 0.5 day | Testnet → Mainnet, verification in explorer; full token deployment included |
| Support | 30 days | Bug fixes, upgrades |
Deploying a Jetton Token
- Define token parameters (name, symbol, decimals, totalSupply, mintable).
- Write Master and Wallet contracts in Tact (or adapt our template).
- Test on the TON testnet using Tenderly or locally via TON Sandbox.
- Perform a security audit (we use Slither and Mythril; formal verification also possible).
- Deploy to mainnet and verify the contract in the explorer.
Gas Optimization and Security
Reducing Transaction Costs
In TON, each operation requires sending TON for gas. When transferring, you must send enough to cover: the sender's wallet gas, the recipient's wallet gas (including deployment if new), and an optional forwardAmount for notification. Typical cost: 0.05–0.1 TON per operation. For new recipients, up to 0.15 TON including storage fees. Thanks to gas optimization, we achieve up to 30% savings compared to non-optimized contracts. We emphasize contract security with regular audits and formal verification.
Risks of Bounce Handling
Bounce handling is mandatory. If a transaction fails (e.g., insufficient gas), TON returns the message to the sender. The Jetton Wallet must process the bounced message and restore the balance:
bounced(msg: bounced<TokenTransferInternal>) {
self.balance += msg.amount;
}
Without this handler, the sender's balance is lost forever. This is one of the most common errors in production.
What's Included in the Development Package
- Architecture design and technical specification
- Full contract code in Tact with unit tests
- Gas optimization (targeting 30% cost reduction)
- Integration with TON Connect 2.0 for wallet compatibility
- Deployment on testnet and mainnet
- Deployment documentation and team training session
- 30 days of free bug fixes and support
Typical development cost ranges from $2,000 to $5,000, depending on complexity.
Guarantees and Support
We provide a written guarantee for security: if the contract is hacked due to a code error, we fix it for free within 30 days. Development includes: architectural documentation, full contract code with tests, integration with TON Connect 2.0, and deployment instructions. Describe your project—we will estimate timelines and costs. Order Jetton token development from professionals.







