Метаданные jetton: off-chain и on-chain

Задашь метаданные Jetton по TEP-64: off-chain JSON по URL и on-chain словарь — name, symbol, decimals, image.

Два способа хранить content

Метаданные Jetton (TEP-64) лежат в cell content master-контракта. Два формата:

  1. Off-chain — в content URL на JSON (https://.../meta.json).
  2. On-chain — словарь ключ→значение прямо в cell (без внешнего хоста).

Кошельки и эксплореры читают get_jetton_data() → поле content и рендерят имя/тикер/иконку.


Off-chain и on-chain в коде

typescript
// @ton/core ^0.59.0
import { beginCell, Dictionary, Cell } from "@ton/core";
import { sha256_sync } from "@ton/crypto";

// ——— Off-chain (TEP-64): первый байт 0x01 + URL ———
function buildOffchainContent(url: string): Cell {
  return beginCell()
    .storeUint(0x01, 8)
    .storeStringTail(url)
    .endCell();
}

// JSON по URL (пример). Хостинг: IPFS / свой HTTPS с CORS.
// {
//   "name": "Demo Jetton",
//   "symbol": "DEMO",
//   "description": "Учебный токен",
//   "decimals": "9",
//   "image": "https://example.com/demo.png"
// }

const offchain = buildOffchainContent(
  "https://example.com/jettons/demo/meta.json",
);

// ——— On-chain: первый байт 0x00 + Dictionary(key=sha256(name)) ———
function toSha256Key(key: string): bigint {
  return BigInt("0x" + sha256_sync(key).toString("hex"));
}

function storeOnchainValue(value: string): Cell {
  return beginCell().storeUint(0, 8).storeStringTail(value).endCell();
}

function buildOnchainContent(meta: {
  name: string;
  symbol: string;
  description: string;
  decimals: string;
  image: string;
}): Cell {
  const dict = Dictionary.empty(
    Dictionary.Keys.BigUint(256),
    Dictionary.Values.Cell(),
  );
  dict.set(toSha256Key("name"), storeOnchainValue(meta.name));
  dict.set(toSha256Key("symbol"), storeOnchainValue(meta.symbol));
  dict.set(toSha256Key("description"), storeOnchainValue(meta.description));
  dict.set(toSha256Key("decimals"), storeOnchainValue(meta.decimals));
  dict.set(toSha256Key("image"), storeOnchainValue(meta.image));

  return beginCell().storeUint(0x00, 8).storeDict(dict).endCell();
}

const onchain = buildOnchainContent({
  name: "Demo Jetton",
  symbol: "DEMO",
  description: "Учебный токен",
  decimals: "9",
  image: "https://example.com/demo.png",
});

void offchain;
void onchain;

При деплое master передаёшь один из cell в init-данные / config. Смена content после деплоя — только если master поддерживает change_content и ты admin.

Как это работает

  • 0x01 + URL — off-chain: дешёвый деплой, но зависаешь от хоста JSON.
  • 0x00 + dict — on-chain: данные в блокчейне, дороже по storage/gas.
  • Ключи on-chain — sha256 от имени поля (name, symbol, …), не UTF-8 строки напрямую.
  • decimals в JSON/on-chain — строка/значение для UI; on-chain баланс всегда в минимальных единицах.

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

Только off-chain без рабочего HTTPS/IPFS → кошельки показывают «Unknown token».

Забыл decimals или указал не то → UI рисует 1000000000 вместо 1.0.

Сменил JSON, а content-URL тот же с CDN-кэшем → эксплореры долго отдают старые метаданные. Меняй URL или кэш-заголовки.


Что дальше

Материалы gramdocs.tech носят образовательный характер и не являются финансовой, юридической или инвестиционной рекомендацией. Работа с блокчейном TON и токеном Gram связана с рисками потери средств. Правовая информация