Часто Web3 приложения или Dapps выглядят архитектурно выглядят как Фронтенд, который вызывает методы смарт-контрактов. Соответственно нужно уметь делать запросы на JS в блокчейн. В TON мало примеров на JS, поэтому я решил сделать небольшой наглядный туториал.
Web 3 приложения часто строятся вокруг стандартов, существующих в блокчейне, в TON это NFT и Jetton. Для стандарта NFT распространенной задачей является получение адресов NFT конкретной коллекции. Поэтому в данном туториале:
- мы достаем данные об NFT коллекции
- получим адрес NFT по индексу
и все это на JS.
Для запросов в TON нам понадобиться typescript
и модулями для работы с TON.
Для работы с Typescript нам понадобятся:
- Node.js — среда, в которой вы будете запускать компилятор TypeScript.
- Компилятор TypeScript — модуль Node.js, который компилирует TypeScript в JavaScript.
Глубоко погружаться в Node.js мы не будем, инструкции по его установке есть здесь:
Для удобства работы с модулями создадим файл package.json
c помощью пакетного менеджера npm
:
-
В консоли перейдите в папку вашего проекта (где будем писать скрипты)
-
Введите в консоли
npm init
-
Ответьте на вопросы в консоли и убедитесь, что файл
package.json
создан
Теперь установим typescript
. В командной строке вводим следующую команду:
npm install typescript
После установки вы можете ввести следующую команду, чтобы проверить текущую версию компилятора TypeScript:
tsc --v
Также установим пакет ts-node для выполнения TypeScript в консоли и REPL для node.js.
npm install ts-node
Осталось установить модули для работы c TON:
npm install ton ton-core ton-crypto
Отлично, теперь можно приступать к скриптам.
Чтобы получить информацию об NFT коллекции нам нужно вызвать GET-метод смарт-контракта коллекции, для этого надо:
- использовать некий API сервис, который взаимодействует с Лайт серверами блокчейна TON
- через этот клиент вызвать нужный GET-метод
- преобразовать полученные данные в читаемый вид
В данном туториале мы воспользуемся toncenter API, для запроса воспользуемся клиентом на js, библиотеки ton.js.
Создадим скрипт collection.ts
. Импортируем из библиотеки клиент:
import { TonClient } from 'ton';
И подключаемся к toncenter:
import { TonClient } from 'ton';
export const toncenter = new TonClient({
endpoint: 'https://toncenter.com/api/v2/jsonRPC',
});
Для простоты примера мы не используем API ключ, поэтому мы будем лимитированы одним запросом в минуту, для создания ключа можете воспользоваться ботом https://t.me/tonapibot
Теперь посмотрим в стандарт NFT коллекций на TON для того, чтобы понять какой GET-метод нужно вызвать. По стандарту видно, что нам нужна функция get_collection_data()
, которая вернет нам:
next_item_index
— количество развернутых в данный момент элементов NFT в коллекции.collection_content
— содержимое коллекции в формате, соответствующем стандарту TEP-64.owner_address
- адрес владельца коллекции, нулевой адрес, если нет владельца.
Воспользуемся синтаксическим сахаром async/await
и вызовем данный метод для какой-нибудь коллекции в TON:
import { TonClient } from 'ton';
export const toncenter = new TonClient({
endpoint: 'https://toncenter.com/api/v2/jsonRPC',
});
export const nftCollectionAddress = Address.parse('UQApA79Qt8VEOeTfHu9yKRPdJ_dADvspqh5BqV87PgWD998f');
(async () => {
let { stack } = await toncenter.callGetMethod(
nftCollectionAddress,
'get_collection_data'
);
})().catch(e => console.error(e));
Для преобразования данных в читаемый вид, воспользуемся библиотекой ton-core
:
import { Address } from 'ton-core';
Преобразуем nextItemIndex в строку, вычитаем ячейку с контентом и преобразуем адрес:
import { TonClient } from 'ton';
import { Address } from 'ton-core';
export const toncenter = new TonClient({
endpoint: 'https://toncenter.com/api/v2/jsonRPC',
});
export const nftCollectionAddress = Address.parse('UQApA79Qt8VEOeTfHu9yKRPdJ_dADvspqh5BqV87PgWD998f');
(async () => {
let { stack } = await toncenter.callGetMethod(
nftCollectionAddress,
'get_collection_data'
);
let nextItemIndex = stack.readBigNumber();
let contentRoot = stack.readCell();
let owner = stack.readAddress();
console.log('nextItemIndex', nextItemIndex.toString());
console.log('contentRoot', contentRoot);
console.log('owner', owner);
})().catch(e => console.error(e));
Запустим скрипт с помощью ts-node
. Должно получиться следующее:
Теперь решим задачу по получению адреса по индексу, мы опять будем вызывать GET-метод смарт-контракта коллекции. В соответствии со стандартом, для этой задачи подходит метод get_nft_address_by_index(int index)
, который возвращает slice address
.
Данный метод принимает параметр int index
и на первый взгляд выглядит так, как будто нужно просто передать значение с типом int
в смарт-контракт. Это конечно так, но так как виртуальная машина TON использует регистры то значение с типом int
нужно будет передать в кортеже. Для этого в библиотеке ton.js
есть TupleBuilder
.
import { TupleBuilder } from 'ton';
Запишем в кортеж значение 0:
import { TonClient } from 'ton';
import { Address } from 'ton-core';
import { TupleBuilder } from 'ton';
export const toncenter = new TonClient({
endpoint: 'https://toncenter.com/api/v2/jsonRPC',
});
export const nftCollectionAddress = Address.parse('EQDvRFMYLdxmvY3Tk-cfWMLqDnXF_EclO2Fp4wwj33WhlNFT');
(async () => {
let args = new TupleBuilder();
args.writeNumber(0);
})().catch(e => console.error(e));
Остается сделать запрос и преобразовать адрес с помощью readAddress()
:
import { TonClient } from 'ton';
import { Address } from 'ton-core';
import { TupleBuilder } from 'ton';
export const toncenter = new TonClient({
endpoint: 'https://toncenter.com/api/v2/jsonRPC',
});
export const nftCollectionAddress = Address.parse('EQDvRFMYLdxmvY3Tk-cfWMLqDnXF_EclO2Fp4wwj33WhlNFT');
(async () => {
let args = new TupleBuilder();
args.writeNumber(0);
let { stack } = await toncenter.callGetMethod(
nftCollectionAddress,
'get_nft_address_by_index',
args.build(),
);
let nftAddress = stack.readAddress();
console.log('nftAddress', nftAddress.toString());
})().catch(e => console.error(e));
Запустим скрипт с помощью ts-node
. Должно получиться следующее:
Подобные разборы и туториалы я публикую в телеграм канале https://t.me/ton_learn буду рад вашей подписке.