Деплойментт смарт-контрактів в TON
TON — це не EVM. Це принципово інша архітектура, та досвід деплойменту Ethereum не переносится сюди. Контракти пишуються на FunC (або Tact — більш високорівневі мові), компілюються в TVM bytecode та взаємодіють через асинхронні повідомлення. Синхронного виклику contract.someFunction() не існує — тільки відправлення сигналу та очікування вільного сигналу.
Мова та інструменти
FunC vs Tact
FunC — низькорівневі мова TON. Прямий контроль над TVM інструкціями, storage layout, gas. Складна у освоєнні, але всі оптимізації — у ваших руках. Стандартні контракти (Jetton, NFT) написані на FunC.
Tact — більш високорівневі, синтаксис ближче до TypeScript. Компілюється в FunC → TVM bytecode. Швидше розробляти, менше ймовірність помилок у storage serialization. Для нових контрактів — рекомендований вибір якщо немає специфічних вимог до оптимізації.
// Простий counter на Tact
contract Counter {
counter: Int as uint32;
init() {
self.counter = 0;
}
receive("increment") {
self.counter = self.counter + 1;
}
get fun value(): Int {
return self.counter;
}
}
Еквівалентний контракт на FunC займав би втрічі більше строк з явним управлінням storage через store_uint / load_uint.
Blueprint: стандартний toolchain
Blueprint — офіційний фреймворк розробки TON контрактів (аналог Hardhat для EVM):
npm create ton@latest my-project
cd my-project
npm install
Структура проекту:
contracts/ # .tact або .fc файли
tests/ # Jest-based тести
scripts/ # deploy скрипти
wrappers/ # TypeScript обгортки для контрактів
Компіляція та тести
npx blueprint build # компіляція
npx blueprint test # запуск тестів
Тести працюють на локальному TVM емуляторі (@ton/sandbox) — транзакції виконуються локально без звернення до мережі, тести швидкі:
import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox';
import { Counter } from '../wrappers/Counter';
describe('Counter', () => {
let blockchain: Blockchain;
let deployer: SandboxContract<TreasuryContract>;
let counter: SandboxContract<Counter>;
beforeEach(async () => {
blockchain = await Blockchain.create();
deployer = await blockchain.treasury('deployer');
counter = blockchain.openContract(await Counter.fromInit());
const deployResult = await counter.send(
deployer.getSender(),
{ value: toNano('0.05') },
{ $$type: 'Deploy', queryId: 0n }
);
expect(deployResult.transactions).toHaveTransaction({
from: deployer.address,
to: counter.address,
deploy: true,
});
});
it('should increment counter', async () => {
await counter.send(deployer.getSender(), { value: toNano('0.01') }, 'increment');
expect(await counter.getValue()).toBe(1n);
});
});
Деплойментт в testnet та mainnet
TON використовує концепцію StateInit для деплойменту: контракт деплоюється відправленням сигналу з init (code + initial data) на адресу контракту. Адреса вичислюється детерміновано з hash(code, data) — вам відома адреса до деплойменту.
// scripts/deployCounter.ts
import { toNano } from '@ton/core';
import { Counter } from '../wrappers/Counter';
import { NetworkProvider } from '@ton/blueprint';
export async function run(provider: NetworkProvider) {
const counter = provider.open(await Counter.fromInit());
await counter.send(
provider.sender(),
{ value: toNano('0.05') }, // TON для gas + storage rent
{ $$type: 'Deploy', queryId: 0n }
);
await provider.waitForDeploy(counter.address);
console.log('Deployed at:', counter.address.toString());
}
# Testnet
npx blueprint run --testnet
# Mainnet
npx blueprint run --mainnet
Blueprint запросить seed phrase або підключення Tonkeeper через QR.
Storage rent — важлива специфіка TON
На відміну від Ethereum, TON взимає аренду за зберігання даних у storage. Контракт з нульовим балансом буде «заморожений» (frozen) після ~6 місяців, та дані видалені за кілька років (uninit state). Для production контрактів потрібно:
- Закладати достатній баланс при деплойменті (для простого контракту — 0.1-0.5 TON)
- Реалізувати механізм поповнення балансу
- Моніторити баланс через TonAPI
Приблизна вартість зберігання: 1 bit даних на рік = 0.000000001 TON × 365 × ... Практично: контракт з 1KB storage потребує ~0.015 TON/рік.
Jetton (аналог ERC-20) та NFT
Стандартні токени в TON реалізовані через шаблонні контракти TEP-74 (Jetton) та TEP-62 (NFT). Архітектура радикально відрізняється від ERC-20:
У ERC-20 один контракт зберігає маппінг всіх балансів. У TON кожен holder має свій окремий контракт — JettonWallet. Основний JettonMaster контракт тільки мінтить токени та зберігає глобальну інформацію. Transfer — сигнал від JettonWallet відправника до JettonWallet отримувача.
Це означає: адресу Jetton гаманця для конкретного holder-а потрібно вичислювати через getWalletAddress(ownerAddress) на JettonMaster контракті. Неможливо просто використовувати адресу Jetton мастера для передач.
Blueprint надає готові обгортки для стандартних Jetton та NFT контрактів від TON Foundation — не потрібно писати з нуля.
Верифікація контракту
TON верифікатор — verifier.ton.org. Завантажуйте вихідники та proof-of-compilation, верифікатор підтверджує відповідність bytecode. Після верифікації tonviewer.com та tonscan.org показують вихідний код та дозволяють викликати getter функції.
Орієнтири по термінам
Деплойментт готового Tact/FunC контракту в testnet + mainnet з верифікацією — від кількох годин. Розробка кастомного контракту з нуля + тести + деплойментт: простий контракт — 1-2 дні, контракт зі складною бізнес-логікою (AMM, staking, NFT маркетплейс) — 1-2+ тижні.







