Розробка Jetton-токенів на TON: архітектура, контракти та деплой

Розробка Jetton-токенів на TON: архітектура, контракти та деплой При перенесенні токенів з EVM на TON багато розробників стикаються з асинхронністю: баланс власника виявляється не в єдиному контракті, а в окремому Jetton Wallet. Це ламає звичні патерни — transfer стає ланцюжком повідомлень, а не

Напрямки блокчейн-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1450
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1309
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1005
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1270
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    719
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1011

Розробка Jetton-токенів на TON: архітектура, контракти та деплой

При перенесенні токенів з EVM на TON багато розробників стикаються з асинхронністю: баланс власника виявляється не в єдиному контракті, а в окремому Jetton Wallet. Це ламає звичні патерни — transfer стає ланцюжком повідомлень, а не атомарним викликом. Наша команда має понад 5 років досвіду в блокчейн-розробці та гарантує коректну реалізацію Jetton-стандарту під ключ. Ми успішно виконали 10+ проектів на TON, включаючи DeFi-протоколи та NFT-маркетплейси. Економія на gas-оптимізації досягає 30% при використанні Tact, що знижує вартість володіння токеном. Замовте розробку Jetton-токена під ключ — ми забезпечимо безпеку та оптимізацію газу.

Архітектура Jetton: два контракти

Jetton Master — центральний контракт, зберігає метадані токена (name, symbol, decimals, total_supply) і вміє минтити нові Jetton Wallet. Повна специфікація описана в TEP-74.

Jetton Wallet — один екземпляр на кожного власника. Зберігає баланс конкретної адреси. При transfer Jetton Wallet відправника шле повідомлення Jetton Wallet отримувача. Це не один атомарний виклик, а ланцюжок асинхронних повідомлень. Якщо Jetton Wallet отримувача ще не існує — він створюється в момент першого отримання токена, і відправник платить за деплой (приблизно 0.04 TON storage deposit). Зберігання даних на TON обкладається storage fee — близько 0.005 TON за кілобайт на місяць, тому для кожного гаманця потрібно підтримувати позитивний баланс TON. На практиці ми закладаємо мінімум 0.05 TON на гаманець — сума розраховується індивідуально, щоб уникнути заморозки.

Як працює Jetton-контракт?

Стандарт TEP-74 визначає структуру повідомлень і логіку transfer. Розглянемо обробку transfer у Jetton Wallet:

;; Jetton Wallet: обработка transfer сообщения () recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure { if (op == op::transfer()) { int query_id = in_msg_body~load_uint(64); int jetton_amount = in_msg_body~load_coins(); slice to_owner_address = in_msg_body~load_msg_addr(); slice response_address = in_msg_body~load_msg_addr(); cell custom_payload = in_msg_body~load_maybe_ref(); int forward_ton_amount = in_msg_body~load_coins(); slice forward_payload = in_msg_body; throw_unless(error::not_enough_jettons, jetton_amount <= balance); balance -= jetton_amount; save_data(); var msg_body = begin_cell() .store_uint(op::internal_transfer(), 32) .store_uint(query_id, 64) .store_coins(jetton_amount) .store_slice(my_address()) .store_slice(response_address) .store_coins(forward_ton_amount) .store_slice(forward_payload) .end_cell(); var to_wallet_address = calc_jetton_wallet_address(to_owner_address); send_raw_message( begin_cell() .store_uint(0x18, 6) .store_slice(to_wallet_address) .store_coins(forward_ton_amount + min_ton_for_storage) .store_uint(1, 107) .store_ref(msg_body) .end_cell(), 64 ); } } 

Код вище — основа стандартного Jetton Wallet. Зверніть увагу на виклик calc_jetton_wallet_address — адреса отримувача обчислюється детерміновано з адреси власника та коду гаманця.

Чому варто обирати Tact замість FunC?

Tact — високорівнева мова, що компілюється у FunC. Її синтаксис ближчий до TypeScript, що значно прискорює розробку. Tact у 5 разів швидший для створення Jetton-токенів порівняно з FunC, особливо для команд з EVM-досвідом. Приклад контракту на Tact:

import "@stdlib/deploy"; import "@stdlib/jetton"; contract JettonMaster with Deployable, Jetton { totalSupply: Int as coins; owner: Address; content: Cell; mintable: Bool; init(owner: Address, content: Cell) { self.totalSupply = 0; self.owner = owner; self.content = content; self.mintable = true; } receive(msg: TokenMint) { require(sender() == self.owner, "Not owner"); require(self.mintable, "Not mintable"); self.totalSupply += msg.amount; let winit: StateInit = self.getJettonWalletInit(msg.receiver); let walletAddress: Address = contractAddress(winit); send(SendParameters{ to: walletAddress, value: ton("0.05"), mode: SendIgnoreErrors, bounce: false, body: TokenTransferInternal{ queryId: 0, amount: msg.amount, from: myAddress(), responseAddress: msg.receiver, forwardTonAmount: 0, forwardPayload: emptySlice(), }.toCell(), code: winit.code, data: winit.data, }); } } 
Характеристика FunC Tact
Рівень абстракції Низький Високий
Синтаксис Специфічний Схожий на TypeScript
Швидкість розробки Низька Висока (в 5 разів швидше)
Контроль Повний Частковий (через вставки FunC)

Як гарантувати безпеку Jetton-токена?

Reentrancy — одна з головних загроз в асинхронному середовищі TON. На відміну від EVM, де стан блокується до кінця транзакції, в TON кожен виклик — окреме повідомлення. Якщо обробник transfer не перевіряє баланс до і після операцій, зловмисник може ініціювати повторний виклик до зміни стану. У наших проектах ми використовуємо патерн "check-effects-interactions" і додаємо захист від повторного входу через прапорці в даних гаманця. Також обов'язково тестуємо всі сценарії за допомогою fuzzing: Echidna для FunC та вбудовані фаззери в Blueprint.

Процес роботи: етапи

  1. Аналітика: обговорюємо вимоги до токена (стандартний чи кастомний), обираємо стек (Tact/FunC).
  2. Проектування: архітектура контрактів, визначення механік (transfer tax, whitelist, vesting).
  3. Реалізація: написання Jetton Master та Jetton Wallet, unit-тести через Blueprint sandbox.
  4. Тестування: симуляція всіх сценаріїв, перевірка на reentrancy та gas-оптимізацію.
  5. Деплой та верифікація: деплой у mainnet, верифікація коду на tonviewer.com, інтеграція з гаманцями.
Етап Тривалість Результат
Аналітика 1–2 дні Технічне завдання
Проектування 1–2 дні Архітектура контрактів
Реалізація 3–7 днів Вихідний код + тести
Тестування 1–2 дні Звіт про тестування
Деплой + верифікація 1–2 дні Робочий токен в мережі

Газ та storage: специфіка TON

У TON газ влаштований інакше, ніж у EVM. Ключові відмінності:

  • Storage fee — акаунти платять оренду за зберігання даних. Якщо баланс TON на Jetton Wallet падає до нуля, акаунт заморожується, дані втрачаються. Рекомендований мінімум депозиту для Jetton Wallet — 0.05 TON.
  • Forward TON — при відправці Jetton з forward_ton_amount > 0 отримувач-контракт отримує сповіщення з прикріпленими TON. Це аналог approve + transferFrom, але в TON-стилі.
  • Gas за транзакцію transfer становить близько 0.001 TON, що значно дешевше, ніж в Ethereum за поточними цінами.

Тестування

Офіційний фреймворк Sandbox (Blueprint) дозволяє тестувати контракти в TypeScript. Приклад тесту:

import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox'; import { JettonMaster } from '../wrappers/JettonMaster'; import { JettonWallet } from '../wrappers/JettonWallet'; 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, buildMetadataCell()) ); await jettonMaster.send(deployer.getSender(), { value: toNano('0.1') }, { $$type: 'Deploy', queryId: 0n, }); }); it('should mint tokens', async () => { const receiver = await blockchain.treasury('receiver'); const mintResult = await jettonMaster.send( deployer.getSender(), { value: toNano('0.2') }, { $$type: 'TokenMint', queryId: 0n, amount: toNano('1000'), receiver: receiver.address } ); expect(mintResult.transactions).toHaveTransaction({ from: jettonMaster.address, deploy: true, success: true, }); const walletAddress = await jettonMaster.getGetWalletAddress(receiver.address); const wallet = blockchain.openContract(JettonWallet.fromAddress(walletAddress)); const data = await wallet.getGetWalletData(); expect(data.balance).toBe(toNano('1000')); }); }); 

Що входить в роботу

Розробка Jetton Master та Jetton Wallet на Tact (або FunC на вимогу), тестування через Blueprint sandbox, деплой на TON mainnet, верифікація через tonviewer.com, wrapper-скрипти на TypeScript для інтеграції. Терміни: 5–10 днів для стандартного Jetton, 2–4 тижні для кастомних механік. Економія на розробці при використанні Tact може досягати 30% за рахунок швидшої реалізації.

Гарантуємо безпеку та оптимізацію газу. Якщо вам потрібна надійна реалізація Jetton-токена з гарантією безпеки, зв'яжіться з нами для попередньої оцінки. Отримайте консультацію щодо Jetton-токенів та оцініть можливості для вашого бізнесу.