Jetton-токены на TON: разработка, контракты, деплой

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

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

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1451
  • 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 Wallets. Полная спецификация описана в 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 на кошелёк — это примерно 0.1 USD по текущему курсу, чтобы избежать заморозки.

Как работает 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-токенам и оцените возможности для вашего бизнеса.