Telegram Open Network (TON): Простое взаимодействие с блокчейном используя TypeScript

В данной статье научимся работать со смарт-контрактами в блокчейне TON через TypeScript.

Содержание
  1. Установка зависимостей для работы со смарт-контрактами TON используя TypeScript
  2. Установим модуль для запуска TypeScript файлов
  3. Установим кроссплатформенный компилятор func-js
  4. Установим библиотеки для развертывания и взаимодействия со смарт-контрактами
  5. Установим библиотеку для взаимодействия с блокчейном через HTTP RPC
  6. Работа с кошельком TON через TypeScript
  7. Запуск TypeScript файлов через терминал
  8. Запрос баланса и номера последней транзакции кошелька TON
  9. Отправка TON через TypeScript на другой адрес
  10. Разбираемся со смарт-контрактами TON
  11. Пишем простой смарт-контракт TON на FunC
  12. Компилируем смарт-контракт TON в boc (блок ячеек) с использованием стандартной библиотеки
  13. Подготовка смарт-контракта к публикации в блокчейне
  14. Деплой смарт-контракта TON через TypeScript
  15. Вызов get методов у смарт-контрактов
  16. Отправка сообщения в смарт-контракт с целью изменения его внутреннего состояния (изменение данных в хранилище)
  17. Тестирование смарт-контрактов TON
  18. Установка зависимостей для тестирования
  19. Настройка проекта для тестирования
  20. Подготовка к тестированию
  21. Тестирование get-метода смарт-контакта
  22. Тестирование отправки сообщения в смарт-контракт
  23. Отладка ошибок внутри самого смарт-контракта
  24. Тестирование в продакшне (в mainnet)
  25. Заключение

Установка зависимостей для работы со смарт-контрактами TON используя TypeScript

Первым делом создайте каталог для проекта и перейдите в него из консоли.

Предполагается, что nodenpm и npx у вас уже установлены (если это не так, установите их).
Версия node должна быть 18 и выше, а npm и npx рекомендовано 9.2.0 или выше.

Проверить установленные версии можно так:

node -v
npm -v
npx -v

Telegram Open Network (TON): Простое взаимодействие с блокчейном используя TypeScript

Установим модуль для запуска TypeScript файлов

$ npm install ts-node

Установим кроссплатформенный компилятор func-js

npm install @ton-community/func-js

Установим библиотеки для развертывания и взаимодействия со смарт-контрактами

npm install ton ton-crypto ton-core

Установим библиотеку для взаимодействия с блокчейном через HTTP RPC

npm install @orbs-network/ton-access

Работа с кошельком TON через TypeScript

Запуск TypeScript файлов через терминал

Код на TypeScript пишется внутри *.ts файлов, которые затем можно запускать следующим образом:

npx ts-node myscript.ts

Каркас для всех запускаемых далее скриптов на TypeScript в общем виде выглядит так:

import { getHttpEndpoint } from "@orbs-network/ton-access";
import { mnemonicToWalletKey } from "ton-crypto";
import { WalletContractV4, TonClient, fromNano } from "ton";

async function main() {
  
  // инициализация ton rpc клиента для тестовой сети testnet
  const endpoint = await getHttpEndpoint({ network: "testnet" }); // для mainnet достаточно вызвать getHttpEndpoint() без параметров
  const client = new TonClient({ endpoint });

  // ... здесь ваш код ...
}

main();

Запрос баланса и номера последней транзакции кошелька TON

Создадим файл test1.ts со следующим кодом используя код каркаса выше.

import { getHttpEndpoint } from "@orbs-network/ton-access";
import { mnemonicToWalletKey } from "ton-crypto";
import { WalletContractV4, TonClient, fromNano } from "ton";

async function main() {
  const mnemonic = "unfold sugar water ..."; // здесь через пробел ваша мнемоническая фраза из 24 секретных слов для доступа к кошельку (замените ... остальными словами)
  const key = await mnemonicToWalletKey(mnemonic.split(" ")); // мнемоническую фразу конвертируем в ключ доступа
  const wallet = WalletContractV4.create({ publicKey: key.publicKey, workchain: 0 }); // получаем адерс кошелька v4 (у каждой версии адреса отличаются)

  // выводим в консоль публичный адрес кошелька
  console.log(wallet.address.toString({ testOnly: true }));

  // выводим адрес воркчейна
  console.log("workchain:", wallet.address.workChain);

  // инициализация ton rpc клиента для тестовой сети testnet
  const endpoint = await getHttpEndpoint({ network: "testnet" });
  const client = new TonClient({ endpoint });

  // проверка что смарт-контракт кошелька опубликован
  if (!await client.isContractDeployed(wallet.address)) {
    return console.log("wallet is not deployed");
  }

  // запрос баланса кошелька из блокчейна
  const balance = await client.getBalance(wallet.address);
  console.log("balance:", fromNano(balance));

  // получаем seqno - порядковый номер последней транзакции, отправленной кошельком
  const walletContract = client.open(wallet);
  const seqno = await walletContract.getSeqno();
  console.log("seqno:", seqno);

}

main();

Запускаем командой:

npx ts-node test1.ts

Отправка TON через TypeScript на другой адрес

Для реализации фукции отправки TON, допишем код в файле test1.ts следующим образом:

import { getHttpEndpoint } from "@orbs-network/ton-access";
import { mnemonicToWalletKey } from "ton-crypto";
import { TonClient, WalletContractV4, internal } from "ton";

async function main() {
  // ... здесь код инициализации клента и проверки опубликованного смарт-контракта кошелька из предыдущего примера

  // отправим 0.001 TON на кошелек EQDrjaLahLkMB-hMCmkzOyBuHJ139ZUYmPHu6RRBKnbdLIYI
  const walletContract = client.open(wallet);
  const seqno = await walletContract.getSeqno();
  await walletContract.sendTransfer({
    secretKey: key.secretKey,
    seqno: seqno,
    messages: [
      internal({
        to: "EQDrjaLahLkMB-hMCmkzOyBuHJ139ZUYmPHu6RRBKnbdLIYI",
        value: "0.001", // 0.001 TON
        body: "Hello", // (опционально) комментарий
        bounce: false,
      })
    ]
  });

  // ждем подтверждения транзакции
  let currentSeqno = seqno;
  while (currentSeqno == seqno) {
    console.log("waiting for transaction to confirm...");
    await sleep(1500);
    currentSeqno = await walletContract.getSeqno();
  }
  console.log("transaction confirmed!");
}

main();

function sleep(ms: number) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

Разбираемся со смарт-контрактами TON

Пишем простой смарт-контракт TON на FunC

Смарт-контракты в TON пишутся на языке FunC.

Создадим в нашем проекте файл counter.fc со следующим кодом:

(int) load_data() inline {                 ;; определяем функцию чтения из хранилища - возвращает int
  var ds = get_data().begin_parse();       ;; загружаем данные cell из хранилища и преобразуем их в slice
  return (ds~load_uint(64));               ;; читаем 64 bit unsigned int из slice и возвращаем его
}

() save_data(int counter) impure inline {  ;; пишем функцию сохранения данных в хранилище - используем int как аргумент
  set_data(begin_cell()                    ;; вызываем функцию сохраняем ячейки и передаем в нее билдер
    .store_uint(counter, 64)               ;; в билдер кладем 64 bit unsigned int
    .end_cell());                          ;; и конвертируем билдер в cell для возможности сохранения данных
}

;; int msg_value - баланс входящего сообещния в nanoTon
;; cell in_msg - ячейка с входящим сообщением
;; slice in_msg_body - тело входящего сообщения
() recv_internal(int msg_value, cell in_msg, slice in_msg_body) impure {  ;; функция обработки внутреннего сообщения, отправленного в смарт-контракт
  if (in_msg_body.slice_empty?()) {         ;; проверим, является ли входящее сообщение пустым (без тела)
    return ();                              ;; прекращаем дальнейшую обработку сообщения и сообщаем, что оно успешно обработано
  }
  int op = in_msg_body~load_uint(32);       ;; парсим тип операции закодированный в начале тела сообщения
  var (counter) = load_data();              ;; вызываем функцию загрузки данных из храналища смарт-контракта и передаем результат в переменную counter
  if (op == 1) {                            ;; обраобтка операции op #1 = увеличение счетчика
    save_data(counter + 1);                 ;; сохраняем новое значение счетчика = старое значение + 1
  }
}

int counter() method_id {        ;; объявляем метод для чтения значения счетчика - возвращаем int
  var (counter) = load_data();   ;; вытаскиваем данные значения счетчика из хранилища смарт-контакта
  return counter;
}

Компилируем смарт-контракт TON в boc (блок ячеек) с использованием стандартной библиотеки

BOC это блок, который включает в себя все cell (ячейки) входящие в смарт-контракт, которые связаны между собой через ссылки. Каждая ячейка (cell) может хранить до 1023 bit данных и 4 ссылки на другие ячейки.

Для того, чтобы смарт-контракт мог работать в блокчейне TON, его необходимо скомпилировать в байт-код TVM.

В первую очередь, скачайте файл стандартной библиотеки stdlib.fc и положите его рядом с файлом counter.fc.

Далее можете скомпилировать командой:

npx func-js stdlib.fc counter.fc --boc counter.cell

В результате у нас появится counter.cell – это двоичный файл, который содержит байт-код TVM в формате ячейки и который готов к развертыванию в сети.

Подготовка смарт-контракта к публикации в блокчейне

Рекомендуемый способ взаимодействия с контрактами, это создать небольшой TypeScript класс, который будет реализовывать интерфейс взаимодействия с контрактом.

Для этого создадим файл counter.ts со следующим содержимым и положим его рядом с counter.fc:

import { Contract, ContractProvider, Sender, Address, Cell, contractAddress, beginCell } from "ton-core";

export default class Counter implements Contract {

  static createForDeploy(code: Cell, initialCounterValue: number): Counter {
    // обратите внимание, что этот код имитирует создание ячейки в точности как API на FunC
    const data = beginCell()
      .storeUint(initialCounterValue, 64)
      .endCell();
    const workchain = 0; // деплой в workchain 0
    const address = contractAddress(workchain, { code, data }); // получение адреса контракта используя ячейку кода и ячейку данных
    return new Counter(address, { code, data });
  }

  constructor(readonly address: Address, readonly init?: { code: Cell, data: Cell }) {}
}

Смарт-контракт будет опубликован одновременно с передачей в него первого сообщения, что собственно и приводит к его публикации. Можно использовать любое сообщение или проще всего отправить несколько монет TON на смарт-контракт, что мы и сделаем.

Для этого добавьте функцию sendDeploy() в counter.ts — эта функция отправит сообщение о развертывании:

// export default class Counter implements Contract {

  async sendDeploy(provider: ContractProvider, via: Sender) {
    await provider.internal(via, {
      value: "0.01", // отправляем 0.01 TON на смарт-контракт в качестве комиссии
      bounce: false
    });
  }

// }

Деплой смарт-контракта TON через TypeScript

На этом этапе будем использовать ранее подготовленный интерфейс смарт-контракта counter.ts.

Создадим файл deploy.ts

import * as fs from "fs";
import { getHttpEndpoint } from "@orbs-network/ton-access";
import { mnemonicToWalletKey } from "ton-crypto";
import { TonClient, Cell, WalletContractV4 } from "ton";
import Counter from "./counter"; // тут подключаем наш интерфейс counter.ts

async function deploy() {
  // инициализация ton rpc клиента для тестовой сети testnet
  const endpoint = await getHttpEndpoint({ network: "testnet" });
  const client = new TonClient({ endpoint });

  // подготовка кода инициализации Counter и данные cells для публикации
  const counterCode = Cell.fromBoc(fs.readFileSync("counter.cell"))[0]; // берем код из того, что ранее мы скомпилировали
  const initialCounterValue = Date.now(); // в качестве начального значения счетчика, берем текущее время в милисекундах
  const counter = Counter.createForDeploy(counterCode, initialCounterValue); // выполняем публикацию

  // выходим если контракт уже опубликован
  console.log("contract address:", counter.address.toString());
  if (await client.isContractDeployed(counter.address)) {
    return console.log("Counter already deployed");
  }

  // подключаемся к смарт-контракту нашего кошелька TON
  const mnemonic = "unfold sugar water ..."; // тут ваша мнемоническая фраза из 24 секретных слов (замените ... вашими секретными словами из фразы)
  const key = await mnemonicToWalletKey(mnemonic.split(" "));
  const wallet = WalletContractV4.create({ publicKey: key.publicKey, workchain: 0 });
  if (!await client.isContractDeployed(wallet.address)) {
    return console.log("wallet is not deployed");
  }

  // читаем seqno последней транзакции в кошельке
  const walletContract = client.open(wallet);
  const walletSender = walletContract.sender(key.secretKey);
  const seqno = await walletContract.getSeqno();

  // отправляем транзакцию публикации (деплою)
  const counterContract = client.open(counter);
  await counterContract.sendDeploy(walletSender);

  // ждем подтверждения
  let currentSeqno = seqno;
  while (currentSeqno == seqno) {
    console.log("waiting for deploy transaction to confirm...");
    await sleep(1500);
    currentSeqno = await walletContract.getSeqno();
  }
  console.log("deploy transaction confirmed!");
}

deploy();

function sleep(ms: number) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

Сохранив файл, можно выполнить деплой командой:

npx ts-node deploy.ts

После деплоя смарт-контракта можно проверить его наличие через explorer в блокчейне.

Запишите полученный адрес смарт-контракта, который у вас появится в консоли после деплоя. Он нам понадобится на следующем шаге.

Вызов get методов у смарт-контрактов

Для того чтобы иметь возможность дергать get-метод смарт контракта, нужно прописать соответствующую функцию в наш TypeScript интерфейс.

Изменим код файла counter.ts добавив в него следующую функцию:

// export default class Counter implements Contract {

  async getCounter(provider: ContractProvider) {
    const { stack } = await provider.get("counter", []);
    return stack.readBigNumber();
  }

// }

Обратите внимание, что когда вы создаете get-метод в интерфейсе TypeScript, то он всегда должен начинаться со слова “get”, так как это является требованием библиотеки ton.

Теперь, используя get-метод интерфейса, мы можем прочитать значение счетчика из блокчейна.

Для этого можно создать новый файл test2.ts со следующим кодом:

import { getHttpEndpoint } from "@orbs-network/ton-access";
import { TonClient, Address } from "ton";
import Counter from "./counter"; // тут подключаем наш интерфейс counter.ts

async function main() {
  // инициализация RPC клиента
  const endpoint = await getHttpEndpoint({ network: "testnet" });
  const client = new TonClient({ endpoint });

  // подключаемся к смарт-контракту Counter
  const counterAddress = Address.parse("<тут вставьте адрес вашего контракта, полученный ранее после запуска deploy.ts>");
  const counter = new Counter(counterAddress);
  const counterContract = client.open(counter);

  // вызываем get-метод и читаем значение счетчика
  const counterValue = await counterContract.getCounter();
  console.log("value:", counterValue.toString());
}

main();

Запускаем командой:

npx ts-node test3.ts

Важно отметить, что get-методы доступны только при обращении извне, через RPC клиент. Это означает, что смарт-контракты не могут вызывать эти методы. Взаимодействие смарт-контрактов возможно только при помощи их обмена внутренними сообщениями.

Отправка сообщения в смарт-контракт с целью изменения его внутреннего состояния (изменение данных в хранилище)

Смарт-контракты используют регистр c4 для хранения данных.

Мы можем отправить сообщение в смарт-контракт для увеличения счетчика counter в его внутреннем хранилище, но нам надо за это заплатить TON’ом, т.к. для изменения данных в блокчейне нужен косенсус валидаторов, которые берут за это комиссию.

Для этого создадим новый файл скрипта с названием test3.ts со следующим кодом:

import { getHttpEndpoint } from "@orbs-network/ton-access";
import { mnemonicToWalletKey } from "ton-crypto";
import { TonClient, WalletContractV4, Address } from "ton";
import Counter from "./counter"; // тут подключаем наш интерфейс counter.ts

async function main() {
  // инициализация RPC клиента
  const endpoint = await getHttpEndpoint({ network: "testnet" });
  const client = new TonClient({ endpoint });

  // open wallet v4 (notice the correct wallet version here)
  const mnemonic = "unfold sugar water ..."; // здесь через пробел ваша мнемоническая фраза из 24 секретных слов для доступа к кошельку (замените ... остальными словами) const key = await 
  const key = await mnemonicToWalletKey(mnemonic.split(" ")); // // мнемоническую фразу конвертируем в ключ доступа
  const wallet = WalletContractV4.create({ publicKey: key.publicKey, workchain: 0 }); // получаем адерс кошелька v4 (у каждой версии адреса отличаются)
  if (!await client.isContractDeployed(wallet.address)) {
    return console.log("wallet is not deployed");
  }

  // читаем seqno последней транзакции в кошельке
  const walletContract = client.open(wallet);
  const walletSender = walletContract.sender(key.secretKey);
  const seqno = await walletContract.getSeqno();

  // подключаемся к смарт-контракту Counter
  const counterAddress = Address.parse("<тут вставьте адрес вашего контракта, полученный ранее после запуска deploy.ts>");
  const counter = new Counter(counterAddress);
  const counterContract = client.open(counter);

  // отправка транзакции увеличения счетчика Counter в блокчейне
  await counterContract.sendIncrement(walletSender);

  // ждем подтверждения
  let currentSeqno = seqno;
  while (currentSeqno == seqno) {
    console.log("waiting for transaction to confirm...");
    await sleep(1500);
    currentSeqno = await walletContract.getSeqno();
  }
  console.log("transaction confirmed!");
}

main();

function sleep(ms: number) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

Запускаем командой:

npx ts-node test3.ts

Тестирование смарт-контрактов TON

Существует широкий спектр подходов и инструментов для тестирования смарт-контрактов TON. Но мы не будем их все здесь рассматривать, а остановимся на одних из самых эффективных:

  1. Bare-bones TVM with Sandbox – это простая версия виртуальной машины TVM работающая на базе WebAssembly с болочкой на JavaScript, позволяющая производить тестовые взаимодействия используя TypeScript. На этот этап мы возлагаем 90% тестирования.
  2. Deploying beta contracts to mainnet – по сути это тестирование в продакшене (в сети mainnet). Это будет заключительный этап, на который будет приходится оставшиеся 10% тестирования.

Оба метода выбраны не случайно. На протяжении нескольких лет, наблюдая за широким спектром инструментов и методов тестирования в блокчейне Ethereum, наиболее удобным и сверхбыстрым оказался Hardhat. Это тонкая оболочка вокруг EthereumJs, которая представляет собой реализацию EVM в JavaScript.

Установка зависимостей для тестирования

Установим инструмент запуска тестов Jest:

npm install typescript jest @types/jest ts-jest

Установим Sandbox и его зависимости для запуска тестов:

npm install ton-core @ton-community/sandbox @ton-community/test-utils

Настройка проекта для тестирования

Будем использовать инструмент запуска тестов jest.

Чтобы настроить TypeScript для правильной работы, нам нужно создать файл tsconfig.json и поместить его в корень проекта.

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

Теперь настроим jest для корректной работы, для этого нужно создать файл jest.config.js и поместить его в корень проекта:

module.exports = {
  preset: "ts-jest",
  testEnvironment: "node",
};

Подготовка к тестированию

Первым делом убедитесь, что в корне проекта у вас лежат два файла counter.cell и counter.ts, подготовленные на предыдущих шагах.

Для тестирования мы развернем смарт-контракт в Sandbox аналогично тому, как мы разворачивали его в блокчейне.

Вот код, который за это отвечает:

const counterCode = Cell.fromBoc(fs.readFileSync("counter.cell"))[0]; // скомпилированный код смарт-контракта
const initialCounterValue = 17; // инициализация счетчика начальным значением
const counter = Counter.createForDeploy(counterCode, initialCounterValue);

Создадим новый файл test1.spec.ts для нашего теста со следующим кодом:

import * as fs from "fs";
import { Cell } from "ton-core";
import { Blockchain, SandboxContract, TreasuryContract } from "@ton-community/sandbox";
import Counter from "./counter"; // тут подключаем наш интерфейс counter.ts

describe("Counter tests", () => {
  let blockchain: Blockchain;
  let wallet1: SandboxContract<TreasuryContract>;
  let counterContract: SandboxContract<Counter>;

  beforeEach(async () =>  {
    // берем скомпилированный код смарт-контракта, устанавливаем начальное значение и готовим к деплою
    const counterCode = Cell.fromBoc(fs.readFileSync("counter.cell"))[0]; // скомпилированный код смарт-контракта
    const initialCounterValue = 17; // инициализация счетчика начальным значением
    const counter = Counter.createForDeploy(counterCode, initialCounterValue);

    // инициализация блокчейна sandbox
    blockchain = await Blockchain.create();
    wallet1 = await blockchain.treasury("user1");

    // деплой смарт-контракта в sandbox
    counterContract = blockchain.openContract(counter);
    await counterContract.sendDeploy(wallet1.getSender());
  }),

  it("заголовок первого теста", async () => {
    // тут место для описания логики теста
    // важно отметить, что блок it() независим и изолирован от других it()
    // это значит, что в каждом it() блокчейн инициализируется заново
  });
});

Как видите, тут мы используем тот же самый интерфейс Counter, который создавали ранее. Это преимущество TypeScript, – независимо от того, где мы используем наш контракт, мы всегда обращаемся к нему одним и тем же привычным способом.

Единственная странная часть здесь, это blockchain.treasury(“user1”). Но на самом деле это аналог контракта кошелька v4 в Sandbox, у которого инициализирован большой баланс для наших тестов.

Теперь можно запустить тест следующей командой:

npx jest test1

Обратите внимание, что все файлы тестов именуются по шаблону <название>.spec.ts, причем при запуске нужно указать только название.

Тестирование get-метода смарт-контакта

Замените конструкцию it() из предыдущего шага, на следующий код с реальным тестом, который будет тестировать get-метод нашего контракта и затем запустите тест снова:

it("should get counter value", async () => {
    const value = await counterContract.getCounter();  // тут контракт возвращает нам значение счетчика TVM с типом int (257 bit)
    expect(value).toEqual(17n);  // т.к. тип number в JavaScript ограничен 64-bit, мы вынуждены засчет символа 'n' конвертировать его в BigInt, чтобы обойти это ограничение
  });

Тестирование отправки сообщения в смарт-контракт

После предыдущей конструкции it() вставьте еще одну конструкцию it, которая будет тестировать отправку сообщения в смарт-контракт и заново запустите тест.

it("should increment the counter value", async () =>  {
  await counterContract.sendIncrement(wallet1.getSender()); // вызываем функцию увеличения счетчика в смарт-контракте
  const counterValue = await counterContract.getCounter();  // получаем значение счетчика
  expect(counterValue).toEqual(18n);                        // сравниваем, что значение счетчика увеличилось на 1
})

Отладка ошибок внутри самого смарт-контракта

Когда в тесте что-то идет не так, часто возникает необходимость посмотреть на значения некоторых переменных в коде самого смарт-контракта, по аналогии с console.log(variable).

Для этого в языке FunC есть две полезные функции:

  • ~dump(variable_name); – так можно узнать значения переменных в различных участках кода, а также расставлять цифровые метки, чтобы убедиться, что функция при своей работе достигла определенных участков кода.
  • ~strdump(string_value); – ей можно делать отладку строк.

Пример дебага в FunC:

() recv_internal(int msg_value, cell in_msg, slice in_msg_body) impure {
  ~dump(msg_value);                         ;; first debug print
  if (in_msg_body.slice_empty?()) { 
    return (); 
  }
  int op = in_msg_body~load_uint(32);
  var (counter) = load_data();
  if (op == 1) {
    ~strdump("increment received");         ;; second debug print
    save_data(counter + 1);
  }
}

После любых изменений в коде смарт-контракта, не забудьте заново его скомпилировать в counter.cell.

Пример дебага в файле теста:

it("should send ton coin to the contract", async () => {
  console.log("sending 7.123 TON");
  await wallet1.send({
    to: counterContract.address,
    value: toNano("7.123")
  });
});

it("should increment the counter value", async () =>  {
  console.log("sending increment message");
  await counterContract.sendIncrement(wallet1.getSender());
})

После повторного запуска теста, вы увидите отладочные сообщения, что-то вроде этого:

console.log
  sending 7.123 TON

console.log
  #DEBUG#: s0 = 7123000000

console.log
  sending increment message

console.log
  #DEBUG#: s0 = 2000000

console.log
  #DEBUG#: increment received

Тестирование в продакшне (в mainnet)

Финальное тестирование рекомендуется делать в mainnet.

На этот счет есть несколько заблуждений, которые вам будут говорить обратное:

  • Тестовая сеть работает точно также, как основная. Это не верно. Она менее надежна и не соответствует стандартам. Это будет вам стоить времени, которое понадобится чтобы разобраться во всем этом.
  • Тестирование в mainnet выйдет дороже, так как там придется тратить реальные TON. Это неверно. Да, вы тратите TON, но вы экономите время, которое в итоге обходится дороже.
  • Тестовая сеть это аналог mainnet. Это не верно. Там могут быть уже неактуальные версии узлов, конфигураций и прочего, так как за этим особо никто не следит.
  • Не хочу загрязнять mainnet тестовыми контрактами. Не беспокойтесь об этом. Всем все равно. Кроме того, контракт со временем удалится если на его балансе не будет TON для оплаты нахождения в блокчейне (так устроен TON).

Заключение

В данном руководстве мы создали проект вручную, пройдясь по различным его этапам, чтобы понимать, что происходит “под капотом”.

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

Данная статья является результатом перевода этих трех туториалов: один, два и три, с последующей выжимкой и дополнениями.

 

Рейтинг
( 1 оценка, среднее 5 из 5 )
Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: