dApp development on TON blockchain

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
dApp development on TON blockchain
Complex
~2-4 weeks
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Developing dApps on TON Blockchain

TON is not "Ethereum with different syntax". It's a fundamentally different architectural model where most EVM patterns don't work or work in reverse. A developer transitioning from EVM will spend a week just relearning the paradigm. Asynchronous messages between contracts, cell-based storage, Actor model, absence of atomic transactions across multiple contracts—these aren't limitations, they're design.

TON Architectural Peculiarities

Actor Model and Asynchronous Messages

In EVM, a transaction can call N contracts synchronously and atomically. In TON, each smart contract is an Actor receiving messages. Calling another contract means sending an asynchronous message, processed in the next block (or later).

Development consequences:

  • No concept of "atomic composability" between multiple contracts
  • The "check → effect → interact" (CEI) pattern from EVM doesn't apply directly
  • Response from another contract arrives via recv_internal as an incoming message
  • An error in a nested contract doesn't rollback the entire chain—must explicitly handle bounce messages
;; Send internal message with bounce handling
send_raw_message(
  begin_cell()
    .store_uint(0x18, 6)    ;; bounce flag = 1
    .store_slice(destination_address)
    .store_coins(amount)
    .store_uint(0, 107)     ;; default message flags
    .store_ref(message_body)
  .end_cell(),
  64  ;; mode: carry remaining gas
);

Bounce messages are a TON-specific mechanism for returns: if the destination contract doesn't exist or returned an error, the sender receives a bounce with TON refund. Handling bounces is mandatory, otherwise TON just "disappear".

FunC and Tact: Language Choice

FunC — native TON contract language. Low-level, works with cells and slices directly. Necessary for maximum gas optimization or writing non-standard contracts. Syntax is unusual—lisp-style functions, global stack TVM.

Tact — high-level language, compiles to FunC. Appeared in 2023, actively developed. For most dApps today, Tact is the right choice: familiar syntax, type safety, built-in patterns for jetton/NFT.

// Tact: jetton transfer with callback
message JettonTransfer {
    queryId: Int as uint64;
    amount: Int as coins;
    destination: Address;
    responseDestination: Address?;
    forwardTonAmount: Int as coins;
    forwardPayload: Slice as remaining;
}

contract JettonWallet {
    receive(msg: JettonTransfer) {
        // Check sender - only master contract or other wallet
        require(sender() == self.master || sender() == self.owner, "Unauthorized");
        // Send notify to buyer
        if (msg.forwardTonAmount > 0) {
            send(SendParameters{
                to: msg.destination,
                value: msg.forwardTonAmount,
                body: JettonNotification{ amount: msg.amount }.toCell()
            });
        }
    }
}

Cell-Based Storage

In EVM, data is stored in storage slots (uint256 slots). In TON—in cells: a tree structure where each cell contains up to 1023 bits of data and up to 4 references to other cells. This allows storing arbitrary structures but requires explicit serialization/deserialization.

Standard contract storage pattern—through load_data() / save_data():

;; FunC: load state from cell
(slice owner, int balance, cell metadata) load_data() inline {
    slice ds = get_data().begin_parse();
    return (
        ds~load_msg_addr(),   ;; 267 bits - address
        ds~load_coins(),      ;; variable length - coins
        ds~load_ref()         ;; reference to metadata cell
    );
}

Important limitation: maximum contract state size is 65536 cells. For NFT collections or jettons with thousands of holders, data is stored in separate contracts for each user—a pattern where the master contract deploys child contracts (wallet contracts for jettons, item contracts for NFTs).

TEP Standards: Jetton and NFT

Jetton (TEP-74/TEP-89)

Jetton is the ERC-20 analog in TON. But architecture is fundamentally different. In EVM, one ERC-20 contract stores mapping(address → balance). In TON:

  • Jetton Master — stores general parameters (totalSupply, metadata, admin)
  • Jetton Wallet — separate contract for each holder, stores their balance

On transfer: sender sends transfer message to their Jetton Wallet → it sends internal_transfer to recipient's Jetton Wallet → it notifies recipient via transfer_notification.

Three contracts, three asynchronous messages, minimum three blocks. Gas is distributed among them—must send enough TON to cover gas at all levels.

NFT (TEP-62/TEP-64)

Similarly: NFT Collection contract + separate NFT Item contract for each token. Item stores owner, individual_content, collection_address. Minting is deploying a new Item contract.

// NFT Collection: mint new item
receive(msg: Mint) {
    let itemAddress = contractAddress(initOf NftItem(
        self.nextItemIndex,
        myAddress(),   // collection address
        msg.owner,
        msg.content
    ));
    // Deploy via StateInit
    send(SendParameters{
        to: itemAddress,
        value: ton("0.05"),   // gas for deploy and init
        code: codeOf NftItem,
        data: NftItem.init(self.nextItemIndex, myAddress(), msg.owner, msg.content),
        body: "Deploy".asComment()
    });
    self.nextItemIndex += 1;
}

TON Connect and Frontend

TON Connect 2.0

Analog of WalletConnect for TON. Supported by Tonkeeper, MyTonWallet, OpenMask. React implementation:

import { TonConnectUIProvider, TonConnectButton, useTonConnectUI, useTonAddress } from '@tonconnect/ui-react';

function App() {
  return (
    <TonConnectUIProvider manifestUrl="https://your-dapp.com/tonconnect-manifest.json">
      <DappContent />
    </TonConnectUIProvider>
  );
}

function DappContent() {
  const userAddress = useTonAddress();
  const [tonConnectUI] = useTonConnectUI();

  async function sendTransaction() {
    await tonConnectUI.sendTransaction({
      messages: [{
        address: CONTRACT_ADDRESS,
        amount: toNano('0.1').toString(),
        payload: beginCell()
          .storeUint(0x5fcc3d14, 32)  // op code transfer
          .storeUint(queryId, 64)
          .endCell()
          .toBoc()
          .toString('base64')
      }]
    });
  }
  // ...
}

tonconnect-manifest.json is a required file describing the dApp to the wallet. Must be accessible at a public URL.

Telegram Mini Apps Integration

For the TON ecosystem, Telegram Mini Apps are a first-class deployment target. Users don't install a wallet separately—Tonkeeper is built in. Telegram Web App API provides user context:

import WebApp from '@twa-dev/sdk';

// Initialize Telegram Mini App
WebApp.ready();
WebApp.expand(); // fullscreen mode

// User data from Telegram (doesn't require wallet connection for basic UX)
const user = WebApp.initDataUnsafe.user;

// MainButton for primary action
WebApp.MainButton.setText('Confirm Transaction');
WebApp.MainButton.onClick(() => sendTransaction());
WebApp.MainButton.show();

Mini App architecture: Vite + React + TON Connect UI React. Deploy on any HTTPS hosting. Bot created via @BotFather, Mini App registered via /newapp.

Testing and Infrastructure

Testnet and Local Environment

TON Testnet (testnet.toncenter.com) for integration tests. Testnet TON obtained via @testgiver_ton_bot. Important: mainnet and testnet addresses are incompatible (different workchain parameters).

For unit tests—@ton-community/sandbox (ton-core) allows running contracts locally without a node:

import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox';
import { JettonMaster } from '../wrappers/JettonMaster';

describe('Jetton', () => {
  let blockchain: Blockchain;
  let deployer: SandboxContract<TreasuryContract>;
  let jettonMaster: SandboxContract<JettonMaster>;

  beforeEach(async () => {
    blockchain = await Blockchain.create();
    deployer = await blockchain.treasury('deployer');
    jettonMaster = blockchain.openContract(
      await JettonMaster.fromInit(deployer.address, Cell.fromBase64(metadata))
    );
    await jettonMaster.send(deployer.getSender(), { value: toNano('0.5') }, 'Deploy');
  });

  it('should mint tokens', async () => {
    const result = await jettonMaster.send(deployer.getSender(), 
      { value: toNano('0.1') }, 
      { $$type: 'Mint', amount: toNano('1000'), receiver: deployer.address }
    );
    expect(result.transactions).toHaveTransaction({ success: true });
  });
});

Blueprint Framework

Blueprint is the official TON contract development tool. Analog to Hardhat/Foundry for TON:

npm create ton@latest
# Creates structure: contracts/, wrappers/, tests/, scripts/

Wrappers are TypeScript wrappers over contracts, generated from Tact or written manually for FunC. Used both in tests and frontend.

Development Stack

Contracts: Tact 1.x (preferred) or FunC. Blueprint for testing and deployment.

Frontend: React + Vite (for Mini Apps) or Next.js (for web dApp). TON Connect UI React, @ton/ton, @ton/core for blockchain interaction.

Backend (if needed): TON API (toncenter.com) or TON HTTP API v2. For production—own node via mytonctrl or use QuickNode/Tatum for TON.

Component Technology
Smart contracts Tact + Blueprint
Wallet connection TON Connect 2.0
Web frontend Next.js + TON Connect UI
Telegram Mini App Vite React + @twa-dev/sdk
Tests @ton/sandbox + Jest/Vitest
Contract deployment Blueprint deploy scripts

Timeline Estimates

Simple dApp: one contract (Tact) + web frontend with TON Connect—2-3 weeks (accounting for TON architecture learning curve if team has EVM background). Telegram Mini App with jetton integration, staking, and leaderboard—4-6 weeks. Full DeFi protocol (AMM or lending) on TON with audit—2-4 months. TON's asynchronous nature requires significantly more testing of message chains compared to EVM.