Перейти к содержанию
Learning Platform
Глоссарий Troubleshooting
Урок 06.01 · 25 мин
Средний
JettonTEP-74ShardingToken StandardsTON

Архитектура Jetton 2.0

Jetton — это стандарт взаимозаменяемых токенов на TON, аналог ERC-20 в Ethereum, но с принципиально другой архитектурой. В отличие от ERC-20, где все балансы хранятся в одном контракте, в Jetton каждый держатель имеет свой отдельный контракт (Jetton Wallet). Это обеспечивает бесконечную масштабируемость, но требует понимания двухуровневой архитектуры для корректной интеграции.

В модулях M03 и M04 мы научились писать смарт-контракты на Tact и разобрали модель акторов. Теперь применим эти знания к токенам — одному из главных применений блокчейна. TON использует уникальную шардированную архитектуру токенов, принципиально отличающуюся от Ethereum.


ERC-20 vs Jetton: два разных подхода

В Ethereum токен стандарта ERC-20 — это один контракт с маппингом balances[address] => amount. Все балансы хранятся в одном месте:

ERC-20 (Ethereum) — ОДИН контракт
Token Contract
balances:
Alice => 500
Bob => 300
Carol => 200
totalSupply: 1000

В TON такой подход невозможен по архитектуре. Поскольку контракты распределены по шардчейнам и не имеют синхронного доступа к чужому состоянию, хранить все балансы в одном контракте — значит создать узкое место (bottleneck), нарушающее принцип параллелизма.

NOTE

ERC-20 vs Jetton 2.0

ERC-20 хранит все балансы в одном mapping внутри одного контракта. Это работает на Ethereum, потому что EVM обеспечивает синхронный доступ к любому состоянию. В TON каждый контракт изолирован в своём шардчейне — поэтому каждый баланс живёт в отдельном контракте.


Шардированная модель Jetton 2.0

Стандарт TEP-74 определяет архитектуру Jetton 2.0, состоящую из двух типов контрактов:

Jetton Master (мастер-контракт)

Один на весь токен. Хранит:

  • Metadata (TEP-64): имя токена, символ, описание, иконка
  • total_supply: общее количество выпущенных токенов
  • owner: адрес владельца (может минтить новые токены)
  • mintable: разрешено ли создание новых токенов

Jetton Master не хранит балансы пользователей. Его задача — управлять метаданными и создавать новые Jetton Wallet при минтинге.

Jetton Wallet (контракт баланса)

Один на каждого пользователя, владеющего токеном. Хранит:

  • balance: количество токенов пользователя
  • owner: адрес TON-кошелька владельца
  • jetton_master: адрес мастер-контракта

Jetton Wallet развёрнут в шардчейне своего владельца. Это ключевое свойство Jetton 2.0 — контракт баланса находится рядом с кошельком пользователя, обеспечивая максимальную скорость обработки.

Jetton 2.0 (TON) — МНОГО контрактов
Jetton Master
total_supply: 1000
metadata: {...}
deploys
Jetton Wallet Alice
balance: 500
owner: Alice
master: 0x..
шардчейн Alice
Jetton Wallet Bob
balance: 300
owner: Bob
master: 0x..
шардчейн Bob
Jetton Wallet Carol
balance: 200
owner: Carol
master: 0x..
шардчейн Carol
WARNING

Jetton Wallet — это НЕ TON Wallet

Не путайте Jetton Wallet (контракт баланса токенов) и TON Wallet (кошелёк пользователя типа v4/v5). Jetton Wallet — это отдельный смарт-контракт, который хранит баланс одного конкретного токена для одного пользователя. У пользователя может быть десятки Jetton Wallet — по одному на каждый токен.


Почему шардирование?

Шардированная архитектура Jetton 2.0 решает три ключевые проблемы:

1. Параллелизм

Каждый Jetton Wallet обрабатывается в шардчейне своего владельца. Когда Alice и Bob одновременно переводят токены разным получателям, их транзакции обрабатываются параллельно в разных шардах. Нет общего контракта, который стал бы узким местом.

2. Масштабируемость

Токен с миллионом держателей = миллион отдельных контрактов, распределённых по шардчейнам. Нагрузка распределяется равномерно по всей сети, а не концентрируется на одном контракте.

3. Локальность данных

Jetton Wallet пользователя находится в том же шардчейне, что и его TON Wallet. Это минимизирует межшардовые сообщения при инициации транзакций.


Детерминистическое обнаружение адресов

Как Jetton Master “знает” адрес Jetton Wallet конкретного пользователя? Адрес вычисляется детерминистически из init-данных:

jetton_wallet_address = hash(
  code: jetton_wallet_code,
  data: init(owner_address, jetton_master_address)
)

Это означает, что:

  • Любой может вычислить адрес Jetton Wallet, зная адрес владельца и мастер-контракта
  • Jetton Wallet не нужно регистрировать — его адрес предсказуем
  • При первом переводе Jetton Wallet может быть развёрнут автоматически

Именно так кошельки и DEX определяют, где находится баланс пользователя: они вычисляют адрес Jetton Wallet и запрашивают его состояние.


TEP-89: Discoverable Jettons Wallets

Детерминистическая формула адреса Jetton Wallet элегантна, но создаёт проблему интеграции: чтобы вычислить адрес, dApp должен знать точный код Jetton Wallet мастер-контракта (он может отличаться от референсной реализации) и формат init-данных. Любое расхождение версий — и адрес получится “не тот”, сообщения уйдут в пустоту.

TEP-89 (Discoverable Jettons Wallets) — расширение TEP-74, которое решает проблему стандартизованным on-chain RPC: вместо ручного вычисления dApp просто спрашивает Jetton Master о адресе кошелька конкретного владельца.

Протокол: provide / take

TEP-89 определяет два opcode-сообщения:

OpcodeИмяНаправлениеНазначение
0x2c76b973provide_wallet_addressdApp -> Jetton Master”Дай адрес Jetton Wallet для этого владельца”
0xd1735400take_wallet_addressJetton Master -> dApp”Вот адрес Jetton Wallet” (ответ)

Поток выглядит так:

dApp (контракт) -> Jetton Master:
  op: 0x2c76b973 (provide_wallet_address)
  query_id: uint64
  owner_address: Address
  include_address: Bool   // включать ли owner_address в ответ?

Jetton Master -> dApp:
  op: 0xd1735400 (take_wallet_address)
  query_id: uint64
  jetton_wallet_address: Address
  owner_address: Address?  // если include_address = true

Зачем это нужно

Без TEP-89 dApp обязан сам реализовать вычисление адреса: хранить копию jetton_wallet_code, корректно собирать init-Cell, вызывать contractAddress(). Это:

  • Хрупко: при апгрейде кошелька (изменение кода) формула ломается.
  • Сложно для on-chain интеграции: смарт-контракту неудобно тащить с собой код всех Jetton Wallet, с которыми он работает.
  • Несовместимо с кастомными мастерами, у которых нестандартный init.

С TEP-89 dApp передаёт ответственность мастеру: тот знает свой код и сам вычисляет адрес. Это особенно важно для on-chain DEX, multisig и эскроу-контрактов, которые принимают произвольные Jetton.

NOTE

TEP-89 vs off-chain SDK

Off-chain SDK (например, @ton/ton, tonweb) обычно вычисляют адрес локально по жёстко зашитому коду референсного Jetton Wallet. Это работает для стандартных Jetton, но для on-chain контракта (где нет JS-runtime) TEP-89 — единственный способ получить адрес безопасно.

Реализация в Tact

Стандартный trait Jetton в @stdlib/jetton уже включает обработчик provide_wallet_address. Минимальный пример обработки на стороне Master:

message(0x2c76b973) ProvideWalletAddress {
    queryId: Int as uint64;
    ownerAddress: Address;
    includeAddress: Bool;
}

message(0xd1735400) TakeWalletAddress {
    queryId: Int as uint64;
    walletAddress: Address;
    ownerAddress: Slice as remaining;  // either<None, Address>
}

contract MyJettonMaster {
    // ... остальные поля и receivers

    receive(msg: ProvideWalletAddress) {
        let walletInit: StateInit = initOf MyJettonWallet(msg.ownerAddress, myAddress());
        let walletAddress: Address = contractAddress(walletInit);

        let ownerSlice: Builder = beginCell();
        if (msg.includeAddress) {
            ownerSlice = ownerSlice.storeUint(0x400, 11).storeAddress(msg.ownerAddress);
        } else {
            ownerSlice = ownerSlice.storeUint(0, 2);  // None tag
        }

        send(SendParameters{
            to: sender(),
            value: 0,
            mode: SendRemainingValue,
            body: TakeWalletAddress{
                queryId: msg.queryId,
                walletAddress: walletAddress,
                ownerAddress: ownerSlice.endCell().asSlice(),
            }.toCell(),
        });
    }
}

DEX, агрегаторы и payment-процессоры обязаны реализовывать TEP-89 — иначе их Jetton не получится использовать в on-chain интеграциях. При написании собственного Jetton Master добавляйте этот receiver сразу.


Metadata по стандарту TEP-64

Jetton Master хранит метаданные токена в формате TEP-64. Существуют два подхода:

On-chain metadata — все данные в Cell контракта:

content_layout: 0x00
metadata:
  name: "My Token"
  symbol: "MTK"
  decimals: "9"
  description: "A sample Jetton 2.0 token"
  image: "https://example.com/token.png"

Off-chain metadata — ссылка на JSON-файл:

content_layout: 0x01
uri: "https://example.com/token-metadata.json"
TIP

Большинство токенов используют off-chain metadata для экономии газа. JSON-файл размещают на IPFS или HTTPS-сервере. Кошельки и эксплореры (Tonviewer, TonScan) автоматически загружают метаданные по URI.


Интерактивная визуализация

В следующем уроке мы детально разберём поток перевода Jetton и используем интерактивную диаграмму JettonFlowDiagram, которая показывает:

  1. Архитектуру — связь Master и Wallet контрактов
  2. Перевод — 4-шаговый поток сообщений между контрактами
  3. Минтинг — создание новых токенов через Master

Итоги

СвойствоERC-20 (Ethereum)Jetton 2.0 (TON)
Хранение балансовОдин mapping в одном контрактеОтдельный контракт на каждого пользователя
Количество контрактов11 + N (master + wallet на каждого держателя)
ПараллелизмОграничен одним контрактомПолный — каждый wallet в своём шарде
Обнаружение балансаbalanceOf(address)Вычислить адрес Jetton Wallet -> запросить состояние
СтандартERC-20 (EIP-20)TEP-74
МетаданныеERC-20 (name, symbol, decimals)TEP-64 (on-chain / off-chain JSON)

Частые ошибки

  1. Пытаются прочитать баланс пользователя из Jetton Master, хотя балансы хранятся в индивидуальных Jetton Wallet контрактах, а не централизованно.
  2. Путают Jetton Master (minter) и Jetton Wallet (balance holder): это два разных типа контрактов с разными интерфейсами.
  3. Не верифицируют, что Jetton Wallet действительно принадлежит заявленному Jetton Master, что позволяет фишинговым токенам подделывать метаданные.
  4. Забывают, что total_supply в Jetton Master обновляется асинхронно: в момент чтения он может не отражать все pending-операции mint/burn.

Jetton — частный случай более широкого паттерна “system design токена”: от выбора структуры (один master + N wallet vs альтернативы) до экономики и upgrade-стратегии. Системный взгляд на проектирование токенов на TON есть в курсе по System Design.

System Design: проектирование токена на TON
Проверка знанийKnowledge check
Почему в TON каждый пользователь имеет отдельный Jetton Wallet контракт, а не хранит баланс в общем контракте как в ERC-20?
ОтветAnswer
В TON контракты распределены по шардчейнам и не имеют синхронного доступа к чужому состоянию. Если бы все балансы хранились в одном контракте, он стал бы узким местом (bottleneck), нарушая принцип параллелизма. Jetton Wallet каждого пользователя находится в его шардчейне, что позволяет обрабатывать транзакции параллельно.

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 6