Highload-кошелёк: массовые рассылки транзакций

Поймёшь зачем Highload wallet вместо v4/v5 при массовых переводах: лимит seqno, query_id и каркас StateInit для highload v2.

Зачем Highload, если есть Wallet v4

Обычный кошелёк (v3/v4/v5) принимает external с одним seqno: следующую пачку нельзя отправить, пока сеть не подтвердит предыдущую. Для бирж, эйрдропов и сервисов с тысячами исходящих сообщений это узкое горлышко.

Highload wallet (классика — highload v2) допускает много внешних сообщений с разными query_id в окне времени и чистит старые id из словаря — параллельная отправка без ожидания одного seqno.


Адрес highload v2 из StateInit

typescript
// @ton/core ^0.59.0, @ton/crypto ^3.3.0
// codeCell — скомпилированный BoC highload-wallet-v2 (из репозитория
// ton-blockchain / сборки Blueprint). Без реального code хеш адреса учебный.
import { Address, beginCell, Cell } from "@ton/core";
import { mnemonicToWalletKey } from "@ton/crypto";

const words =
  "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about".split(
    " ",
  );
const { publicKey } = await mnemonicToWalletKey(words);

const SUBWALLET_ID = 698983191; // часто используемый default subwallet

const dataCell = beginCell()
  .storeUint(SUBWALLET_ID, 32)
  .storeUint(0, 64) // last_cleaned
  .storeBuffer(publicKey) // 256 bit
  .storeBit(0) // пустой dict обработанных query_id
  .endCell();

// Подставь code highload v2 (Cell из BoC), иначе адрес не совпадёт с mainnet-кодом
const codeCell = Cell.fromBase64("te6cckEBAQEAAgAAAA=="); // заглушка — замени на реальный code

const stateInit = beginCell()
  .storeBit(0) // split_depth
  .storeBit(0) // special
  .storeBit(1)
  .storeRef(codeCell)
  .storeBit(1)
  .storeRef(dataCell)
  .storeBit(0) // library
  .endCell();

const address = new Address(0, stateInit.hash());
console.log(address.toString({ bounceable: false, testOnly: true }));

Для продакшена бери проверенный code BoC и библиотеку/обёртку под highload (не копируй заглушку te6cck...). Тело batch-сообщения: словарь исходящих internal + уникальный query_id + подпись.

КошелёкReplay protectionТипичный use-case
v4 / v5seqno (строго по порядку)пользователь, dApp
highload v2query_id + окно очисткимассовые выплаты

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

  • Каждая внешняя операция помечается query_id; повтор того же id отклоняется.
  • Контракт хранит словарь недавних id и периодически чистит устаревшие (last_cleaned).
  • Можно слать несколько external «параллельно», не дожидаясь инкремента одного счётчика.
  • Адрес, как у любого контракта, = хеш StateInit (code + data с pubkey и subwallet).

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

Гонишь эйрдроп с Wallet v4 в цикле без ожидания seqno → часть сообщений отвалится с wrong seqno; используй highload или очередь с подтверждением seqno.

Переиспользуешь query_id → вторая отправка молча/явно отвергается; генерируй уникальные id (время + счётчик).

Путаешь highload с multisig → highload про throughput одного ключа; multisig про порог подписей. Это разные контракты.


Что дальше

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