Перейти к основному содержимому

Чтение из сети

Введение

Это руководство показывает, как читать данные из блокчейна TON. Вы научитесь:

  • Получать информацию об аккаунте
  • Вызывать get-методы
  • Получать данные о транзакциях аккаунта

В итоге вы поймёте, как взаимодействовать с TON API на основе HTTP. В этом руководстве используется TON Center — быстрый и надёжный HTTP API для TON.

Настройка окружения

Сначала посетите страницы установки и установите Node.js и npm для вашей ОС. Проверьте, что установка корректна, выполнив следующие команды:

node -v
npm -v

Версии node и npm должны быть по меньшей мере v20 и v10 соответственно.

Настройка проекта

Давайте настроим структуру вашего проекта:

  1. Создайте новый каталог для вашего проекта и перейдите в него.
  2. Инициализируйте проект Node.js.
  3. Установите необходимые зависимости.
  4. Инициализируйте конфигурацию TypeScript.

Выполните эти команды в терминале:

mkdir reading-from-ton && cd reading-from-ton
npm init -y
npm install typescript ts-node @ton/ton @ton/core @ton/crypto
npx tsc --init

Для запуска скрипта на TypeScript в вашей текущей директории можно выполнить такую команду (если, например, он называется script.ts):

npx ts-node script.ts

Чтение информации об аккаунте

Информация об аккаунте включает составляющие balance, state, code и data.

  • balance: Сумма TON на счету.
  • state: Состояние может быть одним из следующих:
    • Nonexist: По адресу ещё нет никаких данных.
    • Uninit: У адреса есть баланс, но нет кода смарт-контракта.
    • Active: Адрес уже активен, у него есть и код, и баланс.
    • Frozen: Адрес заблокирован, поскольку баланс оказался недостаточным для расходов на хранение данных.
  • code: Код контракта в «сыром формате».
  • data: Сериализованные данные контракта, хранящиеся в ячейке.

Состояние аккаунта может быть получено с помощью метода getContractState.

Адрес аккаунта

Чтобы получить информацию об аккаунте, необходимо знать его адрес. В TON мы можем использовать формат «user-friendly address» — строку с форматом кодирования base64url, которая представляет аккаунт в блокчейне в человекочитаемом виде с защитой от ошибок.

Такие адреса также включают специальные флаги, определяющие, как этот адрес следует использовать. Например, некоторые адреса будут валидными только в тестнете, в то время как другие подходят любой сети. Эти флаги закодированы в первых нескольких битах, поэтому от них зависит первая буква адреса:

  • Адреса, которые начинаются с E или U, используются в мейннете
  • Адреса, которые начинаются с k или 0, используются в тестнете

Пример для мейннета:

  • EQDKbjIcfM6ezt8KjKJJLshZJJSqX7XOA4ff-W72r5gqPrHF
  • UQDKbjIcfM6ezt8KjKJJLshZJJSqX7XOA4ff-W72r5gqPuwA

Пример для тестнета:

  • kQDKbjIcfM6ezt8KjKJJLshZJJSqX7XOA4ff-W72r5gqPgpP
  • 0QDKbjIcfM6ezt8KjKJJLshZJJSqX7XOA4ff-W72r5gqPleK

Ваш адрес в последующих примерах

В приведённых примерах кода можете смело заменять используемый адрес на адрес вашего тестового кошелька.

 // Replace with any address
const accountAddress = Address.parse('0QD-SuoCHsCL2pIZfE8IAKsjc0aDpDUQAoo-ALHl2mje04A-');

Реализация

Создайте новый файл 1-get-account-state.ts:

1-get-account-state.ts
import { Address, TonClient } from "@ton/ton";

async function main() {
// Initializaing TON HTTP API Client
const tonClient = new TonClient({
endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC',
});

// Replace with any address
const accountAddress = Address.parse('0QD-SuoCHsCL2pIZfE8IAKsjc0aDpDUQAoo-ALHl2mje04A-');

// Calling method on http api
const state = await tonClient.getContractState(accountAddress);


console.log('State: ', state.state);
console.log('Balance: ', state.balance);
console.log('Data: ', state.data?.toString('hex'));
console.log('Code: ', state.code?.toString('hex'));
}

main();

Выполните этот пример, используя следующую команду:

npx ts-node 1-get-account-state.ts

Ожидаемый результат

State:  active
Balance: 3722511000883n
Data: b5ee9c7241010101002...fd1e976824402aa67b98
Code: b5ee9c7241021401000...c9ed54696225e5

Обратите внимание: баланс может отличаться от приведённого здесь, потому что кто угодно может отправить средства на кошелёк, изменив эту сумму.

Вызов get-методов

Get-методы — это специальные функции в смарт-контрактах, позволяющие наблюдать текущее состояние смарт-контракта, сообщая лишь нужные вам конкретные данные — без необходимости читать полностью состояние аккаунта, как мы сделали в первом примере. Чтение аккаунта целиком предоставляет вам сразу всю информацию, включая баланс, код, данные и не только, а get-методы позволяют запрашивать точечную информацию, делая процесс эффективнее и проще для разработчика.

Их исполнение:

  • Не требует оплаты контрактами каких-либо комиссий.
  • Не может менять данные или состояние смарт-контракта.

Результат вызова get-метода через TON HTTP API приходит в стековом формате, и его можно десериализировать пошагово с помощью readNumber() или схожей функции, в зависимости от ожидаемого типа данных.

Зачем это требуется?

В TON управление токенами (также называемыми jettons) осуществляется с помощью отдельных контрактов, которые называются Jetton wallets и связаны с адресами основных кошельков пользователей. Чтобы взаимодействовать с токенами пользователя, сначала надо узнать адрес соответствующего контракта Jetton wallet.

В контракте Jetton master есть get-метод get_wallet_address, позволяющий нам получить верифицированный адрес контракта Jetton wallet для определённого адреса основного пользовательского кошелька.

В этом примере мы покажем, как вызвать метод, чтобы получить адрес Jetton wallet пользователя.

Реализация

Создайте новый файл 2-call-get-method.ts:

2-call-get-method.ts
import { Address, TonClient, TupleBuilder } from "@ton/ton";

async function main() {
// Initializaing TON HTTP API Client
const tonClient = new TonClient({
endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC',
});

// Building optional get method parameters list
const builder = new TupleBuilder();

// Replace with your address
builder.writeAddress(Address.parse('0QD-SuoCHsCL2pIZfE8IAKsjc0aDpDUQAoo-ALHl2mje04A-'));

const accountAddress = Address.parse('kQD0GKBM8ZbryVk2aESmzfU6b9b_8era_IkvBSELujFZPsyy')

// Calling http api to run get method on specific contract
const result = await tonClient.runMethod(
accountAddress, // address to call get method on
'get_wallet_address', // method name
builder.build(), // optional params list
);

// Deserializing get method result
const rawAddress = result.stack.readAddress();

console.log("Raw address:", rawAddress.toRawString());
console.log("User-friendly address:", rawAddress.toString({ bounceable: true, urlSafe: true, testOnly: true}));

}

main();

Запустите этот пример с помощью следующей команды:

npx ts-node 2-call-get-method.ts

Ожидаемый результат

Raw address: 0:25f2bf1ce8f83ed0c0fd73ea27aac77093cdcf900c750b071df7fb0288e019b2
User-friendly address: kQB11H0oDahylXlASZjiDtINlrS0PevVMsvtsbmKmvN5l9np

Вы можете увидеть адрес контракта, который вернул get-метод, в двух форматах:

  • «Сырой» формат raw address (шестнадцатеричный) — это то, как адреса представлены внутри блокчейна TON. Он точен, но не очень удобен для людей.
  • «Дружелюбный» формат user-friendly address — читаемый, более безопасный, разработан для его отправки другим людям и повседневного использования. С ним удобнее работать в кошельках и приложениях.

Оба адреса указывают на один и тот же контракт — в данном случае, контракт Jetton wallet, связанный с адресом кошелька пользователя.

Get-методы можно также вызвать с помощью Tonviewer:

  1. Перейдите в раздел get-методов.
  2. Выберите get_wallet_address.
  3. Вставьте адрес из примера 0QD-SuoCHsCL2pIZfE8IAKsjc0aDpDUQAoo-ALHl2mje04A- в поле Slice.
  4. Нажмите Выполнить.

Вы получите тот же адрес, который вы получили из консоли.

Использование обёрток для простоты

Обёртки — это классы, которые упрощают взаимодействие со смарт-контрактами, превращая сложные операции с блокчейном в простые вызовы функций. Вместо того, чтобы вручную сериализировать ячейки и транзакции, вы можете просто вызвать методы вроде jettonMaster.getWalletAddress(), который уже выполнил эти задачи для вас. Вот пример использования оболочки, функционально эквивалентной предыдущему фрагменту кода:

import { Address, JettonMaster, TonClient } from "@ton/ton";

async function main() {
// Initializaing TON HTTP API Client
const tonClient = new TonClient({
endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC',
});

// Initializing wrappers
const jettonMaster = tonClient.open(
JettonMaster.create(Address.parse('kQD0GKBM8ZbryVk2aESmzfU6b9b_8era_IkvBSELujFZPsyy')),
);

// Calling get method through wrapper
const address = await jettonMaster.getWalletAddress(Address.parse('0QD-SuoCHsCL2pIZfE8IAKsjc0aDpDUQAoo-ALHl2mje04A-'));
console.log(address);
}

main();

Получение транзакций аккаунта

Взаимодействие с аккаунтом в блокчейне происходит с помощью сообщений и транзакций.

Что такое транзакция?

Транзакция в TON состоит из таких вещей:

  • Входящее сообщение, которое изначально обращается к контракту (существуют специальные способы обратиться)
  • Действия контракта, вызванные входящим сообщением, такие как обновление хранимых им данных (опционально)
  • Исходящие сообщения, которые генерируются и отправляются другим акторам (опционально)

Ключевые поля транзакций

Транзакция, полученная из API, имеет следующую структуру:

{
"address": {
"account_address": "EQD-SuoCHsCL2pIZfE8IAKsjc0aDpDUQAoo-ALHl2mje02Zx"
},
"utime": 1738588970,
...
"in_msg": {
...
},
"out_msgs": [...]
}
  • address: Адрес аккаунта, где осуществлялась транзакция.
  • utime: UNIX-время транзакции.
  • in_msg: Входящее сообщение, которое инициировало транзакцию.
  • out_msgs: Исходящие сообщения, отправленные в ходе транзакции.

Что такое сообщение?

Сообщение представляет собой пакет данных, отправляемых между акторами (пользователями, приложениями или смарт-контрактами). Обычно оно содержит информацию, указывающую получателю на то, какие действия выполнять: например, обновить сохранённые данные или отправить новое сообщение.

Ключевые поля сообщений

{
"hash": "mcHdqltDAB8ODQHqtedtYQIS6MQL7x4ut+nf9tXWGqg=",
"source": "EQAJTegD8OO-HksHfI4KVDqb7vW9Dlqi5C1FTcL1dECeosTf",
"destination": "EQD-SuoCHsCL2pIZfE8IAKsjc0aDpDUQAoo-ALHl2mje02Zx",
"value": "20000000",
...
"msg_data": {
"body": "te6cckEBAQEAAgAAAEysuc0=",
...
},
...
}
  • hash (хеш): криптографический идентификатор сообщение, который вычисляется после того, как сообщение включено в транзакцию и получило значение logical time (lt), которое определяет, в каком порядке оно будет обработано. Хеш не является частью исходного сообщения, и он позволяет уникально идентифицировать финализированное сообщение для проверки целостности.
  • source (источник): Адрес отправителя (аккаунт, который инициировал сообщение).
  • destination: Адрес получателя (аккаунт, который будет обрабатывать сообщение).
  • value: Количество TON (указывается в nanoTON), прикреплённое к сообщению.
  • msg_data: Содержит тело сообщения и состояние инициализации.

Реализация

Давайте попробуем получить транзакции принадлежащего нам аккаунта.

До исполнения этого кода:

  • Откройте в Tonviewer адрес своего кошелька в тестнете, который мы ранее создали в секции Getting Started.
  • Отправьте себе тестовые TON с помощью Testgiver Ton Bot.
  • Подождите несколько секунд и убедитесь, что транзакция отобразилась в Tonviewer.
important

Make sure you're working in the Testnet, not the Mainnet.

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

  • Затем создайте новый файл 3-fetch-account-transaction.ts:
3-fetch-account-transaction.ts
import { Address, TonClient } from "@ton/ton";

async function main() {
// Initializaing TON HTTP API Client
const tonClient = new TonClient({
endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC',
});

// Calling method on http api
// full api: https://testnet.toncenter.com/api/v2/#/accounts/get_transactions_getTransactions_get
const transactions = await tonClient.getTransactions(
// Replace with your Testnet address to fetch transactions
Address.parse('0QD-SuoCHsCL2pIZfE8IAKsjc0aDpDUQAoo-ALHl2mje04A-'),
{
limit: 10, //maximum ammount of recieved transactions
archival: true, //search in all history
},
);

const firstTx = transactions[0];
const { inMessage } = firstTx;

console.log('Timestamp:', firstTx.now);
if (inMessage?.info?.type === 'internal') {
console.log('Value:', inMessage.info.value.coins);
console.log('Sender:', inMessage.info.src.toString({ testOnly: true }));
}
}

main();
  • В строке Address.parse('0QD-SuoCHsCL2pIZfE8IAKsjc0aDpDUQAoo-ALHl2mje04A-') замените предложенный адрес на свой в тестнете.

Запустите этот пример, используя следующую команду:

npx ts-node 3-fetch-account-transaction.ts

Ожидаемый результат

Timestamp: 1748338158
Value: 48526800n
Sender: kQDhJ2Kx7dD6FLzAXcqiI4Xsu4ioY6JlE24m9Tx86eGkq0OF
к сведению

Более сложный пример обхода графа транзакций можно увидеть здесь.

Следующий шаг

Теперь, когда вы научились читать данные из блокчейна TON, пришло время изучить, как писать данные в сеть.

Нажмите кнопку ниже для продолжения:

Запись в сеть

Was this article useful?