Категория

Pw85vttbO jMdre25 NBU7DAGaJ0jjLNfOK6yt5G8K 1o2 h QXRlkLGseZosyfnm39bOtIlKJFBJsYR8xK7QJnnJZYYc3GjCHr5pROCcq1dgvPmTJpelH9X6T55jbvcAslBbj2vC1tCvYvV8uruPJwmyfby5t4NU1I7aPD HOhe4z HK0dlkZfrNg • 🇷🇺 Блог Symbol

Японская версия 👉 здесь

Английская версия 👉 здесь

Что такое Node.js и NPM?

Node.js — это целая платформа для создания серверных приложений на языке программирования JavaScript. Node.js основан на модульной системе, позволяющей добавлять в приложение отдельные пакеты. 

Node.js использует диспетчер пакетов Node (npm) для управления зависимостями. Это позволяет загружать и устанавливать необходимые для проекта модули из сторонних источников.

TL;DR

1.Какова мотивация создания NEMTUS @nemtus/symbol-sdk-typescript?

  1. Мотивация состояла в том, чтобы использовать эквивалентную функциональность symbol-sdk v3, реализованную на JS в среде TypeScript, без стресса и без каких-либо специальных настроек.

2. Как @nemtus/symbol-sdk-typescript был создан из symbol-sdk v3, реализованного для JavaScript, в TypeScript самым простым способом?

  1. Он был создан путем сборки оригинального symbol-sdk v3 по следующей ссылке.

i.https://www.typescriptlang.org/docs/handbook/declaration-files/dts-from-js.html

b) Дополнительные сведения см. по следующим ссылкам на репозиторий SDK и пакет npm (Node Package Manager).  

i.https://github.com/nemtus/symbol/tree/dev/sdk/javascript

ii.https://www.npmjs.com/package/@nemtus/symbol-sdk-typescript

3. Как отправлять транзакции в блокчейне Symbol с помощью @nemtus/symbol-sdk-typescript

a.Пожалуйста, обратитесь к исходному коду по ссылке ниже.

i.https://zenn.dev/nemtus/articles/nemtus-symbol-sdk-typescript#samplecode

Бэкграунд

SDK версии 2 блокчейна Symbol для TypeScript/JavaScript устарел, и основная группа разработчиков (core-devs) работает над разработкой и обслуживанием версии 3 SDK для JavaScript, которая проще в работе.  

symbol-sdk v 2

symbol-sdk v2 — это SDK для JavaScript/TypeScript, который упростил разработку с использованием блокчейна Symbol, используя богатый набор функций.

Однако из-за различий в предпочтениях в отношении используемых rxjs, сложности богатой функциональности и организационных изменений было принято решение создать новый эталонный SDK, который больше соответствует основному протоколу. Было официально объявлено, что SDK v2 устарел.

symbol-sdk v 3

Новая версии SDK 3 написана на JavaScript, поэтому, если вы попытаетесь использовать ее в среде TypeScript, модуль выдаст ошибку “***”. В современной среде фронтенд-разработки, где язык программирования TypeScript очень популярен, поэтому ситуация не очень хорошая.

Поэтому, чтобы исправить эту ситуацию и попытаться каким-то образом преобразовать SDK в язык программирования в TypeScript, мы рассмотрели следующие 3 метода:

1. Создайте форк symbol-sdk v2 TypeScript SDK и продолжайте поддержку (обслуживание) независимо от разработчиков NEMTUS и разработчиков сообщества.

2. Японская организация NEMTUS и разработчики сообщества внедрят TypeScript SDK и продолжат разработку и обслуживание, ссылаясь на SDK версии 3, для JavaScript.

3. Разветвленная (Форк) версия SDK 3 для JavaScript используется как есть. Затем NEMTUS и разработчики из сообщества Symbol добавят или автоматически сгенерируют необходимые файлы TypeScript «.d.ts», чтобы упростить разработку и обслуживание.

__________

  • Хотелось бы отметить что обслуживание зависимых пакетов, является важным сложным моментом в этом вопросе.
  • Необходимо иметь точное понимание о том, как транзакции блокчейна NEM/Symbol, должны быть бинаризированы и обработаны в качестве “DSL” (Предметно-ориентированный язык), поэтому вероятно, это займет время и будет очень сложным фактором.

Мы получили совет от независимых разработчиков-добровольцев из сообщества Symbol и решили заняться методом номер 3, который описан выше в этой статье. 

Начиная с версии языка программирования TypeScript 3.7 или более поздней, вы можете создать файл «.d.ts» (который описывает синтаксис и структуру функций и свойств) из файлов «.js». Комментарии JSDoc были относительно хорошо написаны в официальном SDK (Software Development Kit), поэтому мы смогли выпустить обновленный SDK, который можно в некоторой степени использовать в среде TypeScript.

Комментарии JSDoc написаны к исходному коду JavaScript и используются инструментами разработки для предоставления разработчикам соответствующих подсказок и дополнений, а также для автоматического создания документации.

Как сгенерировать файл d.ts из файла js ?

Подробнее можно ознакомиться в следующей статье:

https://www.typescriptlang.org/docs/handbook/declaration-files/dts-from-js.html

Пример кода для отправки транзакции с использованием @nemtus/symbol-sdk-typescript

Установка

  • Установите Node.js (Если вы это сделали, тогда пропустите этот шаг).
  • Создайте соответствующий каталог (в качестве примера здесь symbol-sdk-typescript-sample-1) и инициализируйте.
<!-- wp:paragraph -->
<p>~/$ mkdir symbol-sdk-typescript-sample-1</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>~/$ cd symbol-sdk-typescript-sample-1</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>~/symbol-sdk-typescript-sample-1$ npm init -y</p>
<!-- /wp:paragraph -->

Установите необходимые пакеты

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

  • typescript, ts-node… Язык программирования Typescript используется, для выполнения различных действий, позволяя (более полно описывать свойства и методы объектов и классов в Typescript), а ts-node необходим, для удобства выполнения этих задач.
  • С помощью REST API, можно получать информацию о блокчейне Symbol, а также реализовать отправку транзакции и многое другое. @nemtus/symbol-sdk-openapi-generator-typescript-axios
  • Комплект для разработки программного обеспечения (SDK) для TypeScript, созданный на этот раз (обработка информации об аккаунте, создание данных транзакции, подписание и т. д.). @nemtus/symbol-sdk-typescript
  • Для использования веб-сокетов. ws
  • Для использования REST API клиента. Axios
  • Для обработки приватного ключа в качестве переменной среды и при этом не записывать приватный ключ в исходный код. dotenv

Необходимо выполнить следующую команду:

<!-- wp:paragraph -->
<p><em>~/symbol-sdk-typescript-sample-1$ npm install -D typescript ts-node @types/ws</em></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><em>~/symbol-sdk-typescript-sample-1$ npm install @nemtus/symbol-sdk-typescript @nemtus/symbol-sdk-openapi-generator-typescript-axios axios ws dotenv</em></p>
<!-- /wp:paragraph -->

Создайте файл tsconfig.json

Выполните следующую команду, чтобы сгенерировать шаблон файла конфигурации tsconfig.json, для компиляции кода на TypeScript.

~/symbol-sdk-typescript-sample-1$ npx tsc --init

Измените «target»: «es2016» на «target»: «esnext», чтобы вы могли использовать более новый стиль написания для JavaScript, такой как модули ES и BigInt 

BigInt позволяет разработчикам иметь гораздо лучшее целочисленное представление и обработку данных для дальнейшей работы с этими данными, а ES добавляет в JavaScript официальную унифицированную модульную систему.

Создание тестового аккаунта и установка переменной среды

Загрузите официальный блокчейн-кошелек Symbol, создайте тестовый аккаунт в тестовой сети и получите тестовые токены в Symbol Faucet  👉

 https://testnet.symbol.tools . Затем сохраните свой приватный, публичный ключ, а также адрес своего кошелька.

Поэтому давайте добавим приватный ключ в файл .env следующим образом.

.env

SIGNER_1_PRIVATE_KEY =”PUT_YOUR_PRIVATE_KEY_HERE”

⚠️ В блокчейне приватный ключ имеет наибольшую и единственную возможность что-либо сделать с вашей крипто-учетной записью. Приватный ключ обеспечивает доступ к вашему крипто-аккаунту и позволяет управлять им и его следует держать в секрете. Если ваш приватный ключ будет скомпрометирован, вы потеряете все свои активы и конфиденциальную информацию в вашего аккаунта. На этот раз, мы создадим одноразовый аккаунт в тестовой сети Symbol и попробуем, использовать приватный ключ в виде простой переменной среды с помощью dotenv.

Модуль dotenv анализирует файл «.env» и делает установленные в нем переменные доступными из переменных среды.

Образец кода

Давайте создадим следующий файл и запустите его с помощью npx ts-node send-transfer-transaction.ts.

send-transfer-tx.ts
import { SymbolFacade } from "@nemtus/symbol-sdk-typescript/esm/facade/SymbolFacade";
import { PrivateKey } from "@nemtus/symbol-sdk-typescript/esm/CryptoTypes";
import { KeyPair } from "@nemtus/symbol-sdk-typescript/esm/symbol/KeyPair";
import { Signature } from "@nemtus/symbol-sdk-typescript/esm/symbol/models";
import {
  Configuration,
  NetworkRoutesApi,
  TransactionGroupEnum,
  TransactionRoutesApi,
  TransactionStatusDTO,
  TransactionStatusRoutesApi,
} from "@nemtus/symbol-sdk-openapi-generator-typescript-axios";
import WebSocket from "ws";
import "dotenv/config";

// Укажите узел в тестовой сети
const NODE_DOMAIN = "symbol-test.next-web-technology.com";

// Адрес назначения... На этот раз мы отправим его обратно на адрес Faucet.
const faucetAddressString = "TDMYLKCTEVPSRPTG4UXW47IQPCYNLW2OVWZMLGY";

(async () => {
  // Вызовите NetworkRoutesApi.getNetworkProperties, чтобы получить epochAdjustment, networkCurrencyMosaicId
  const configurationParameters = {
    basePath: `http://${NODE_DOMAIN}:3000`,
  };
  const configuration = new Configuration(configurationParameters);
  const networkRoutesApi = new NetworkRoutesApi(configuration);
  const networkPropertiesDTO = (await networkRoutesApi.getNetworkProperties())
    .data;

  // Поскольку значение ответа epochAdjustment представляет собой строку и содержит s в конце, удалите его и преобразуйте в число.
  const epochAdjustmentOriginal = networkPropertiesDTO.network.epochAdjustment!;
  const epochAdjustment = parseInt(epochAdjustmentOriginal.replace(/s/g, ""));

  // Поскольку ответное значение networkCurrencyMosaicId представляет собой шестнадцатеричную строку и содержит ' в середине, удалите ее и преобразуйте в BigInt.
  const networkCurrencyMosaicIdOriginal =
    networkPropertiesDTO.chain.currencyMosaicId!;
  const networkCurrencyMosaicId = BigInt(
    networkCurrencyMosaicIdOriginal.replace(/'/g, "")
  );

  // Сделайте Вызов NetworkRoutesApi.getNetworkType, чтобы получить имя сети, такое как testnet, указанное в фасаде.
  const networkTypeDTO = (await networkRoutesApi.getNetworkType()).data!;
  const networkName = networkTypeDTO.name;

  // Необходимо инициализировать SDK с сетевым именем
  const facade = new SymbolFacade(networkName);

  // Создание данных, связанных с учетной записью, для отправки транзакций
  const signer1PrivateKeyString = process.env.SIGNER_1_PRIVATE_KEY!;
  const signer1PrivateKey = new PrivateKey(signer1PrivateKeyString);
  const signer1KeyPair = new KeyPair(signer1PrivateKey);
  const signer1PublicKeyString = signer1KeyPair.publicKey.toString();
  const signer1AddressString = facade.network
    .publicKeyToAddress(signer1KeyPair.publicKey)
    .toString();

  // Расчет крайнего срока (установлен на 2 часа, но может быть изменен, но произойдет ошибка, если он будет слишком большим)
  const now = Date.now();
  const deadline = BigInt(now - epochAdjustment * 1000 + 2 * 60 * 60 * 1000);

  // Сгенерировать данные транзакции... (Пример) Отправить 1XYM = 1000000μXYM от SIGNER_1 на FAUCET
  const transaction = facade.transactionFactory.create({
    type: "transfer_transaction",
    signerPublicKey: signer1PublicKeyString,
    deadline,
    recipientAddress: faucetAddressString,
    mosaics: [{ mosaicId: networkCurrencyMosaicId, amount: 1000000n }],
  });

  // Настройка оплаты ... Это зависит от настройки узла назначения, но я думаю, что значение настройки по умолчанию 100 для узла в основном достаточно.
  const feeMultiplier = 100;
  (transaction as any).fee.value = BigInt(
    (transaction as any).size * feeMultiplier
  );

  //подпись
  const signature = facade.signTransaction(signer1KeyPair, transaction);
  (transaction as any).signature = new Signature(signature.bytes);

  // Установите для каждой сети конкретное поколение HashSeed
  (transaction as any).network.generationHashSeed = facade.network;

  // Вычислить хэш транзакции ... Необходимо при последующем подтверждении статуса утверждения транзакции с помощью WebSocket
  const hash = facade.hashTransaction(transaction);
  console.log(hash.toString());
  console.log(`https://testnet.symbol.fyi/transactions/${hash.toString()}`); // Отображение соответствующей страницы обозревателя блоков, чтобы ее было легко проверить при отладке

  // Используйте эти данные при отправке транзакций
  const transactionPayload = (
    facade.transactionFactory.constructor as any
  ).attachSignature(transaction, signature);

  // 1 Настройки для случаев, отличных от подтверждения
  const confirmationHeight = 6; // 6confで確認と見なす場合
  let transactionHeight = 0;
  let blockHeight = 0;
  let finalizedBlockHeight = 0;

  //Необходимо предопределить обработку по различным событиям при отправке транзакций с WebSocket
  const ws = new WebSocket(`wss://${NODE_DOMAIN}:3001/ws`);

  ws.on("open", () => {
    console.log("connection open");
  });

  ws.on("close", () => {
    console.log("connection closed");
  });

  ws.on("message", async (msg: any) => {
    const res = JSON.parse(msg);
    if ("uid" in res) {
      console.log(`uid : ${res.uid}`);

      // Отслеживайте, когда транзакция целевого адреса переходит в неподтвержденное состояние
      const unconfirmedBody = `{"uid": "${res.uid}", "subscribe": "unconfirmedAdded/${signer1AddressString}"}`;
      console.log(unconfirmedBody);
      ws.send(unconfirmedBody);

      // Мониторинг одобренных транзакций по целевому адресу
      const confirmedBody = `{"uid": "${res.uid}", "subscribe": "confirmedAdded/${signer1AddressString}"}`;
      console.log(confirmedBody);
      ws.send(confirmedBody);

      // Мониторинг ошибки транзакции целевого адреса
      const statusBody = `{"uid": "${res.uid}", "subscribe": "status/${signer1AddressString}"}`;
      console.log(statusBody);
      ws.send(statusBody);

      // Следите за новыми блоками
      const blockBody = `{"uid": "${res.uid}", "subscribe": "block"}`;
      console.log(blockBody);
      ws.send(blockBody);

      // Смотреть готовые блоки
      const finalizedBlockBody = `{"uid": "${res.uid}", "subscribe": "finalizedBlock"}`;
      console.log(finalizedBlockBody);
      ws.send(finalizedBlockBody);
    }

    // Запускается, когда транзакция не подтверждена
    if (
      res.topic === `unconfirmedAdded/${signer1AddressString}` &&
      res.data.meta.hash === hash.toString()
    ) {
      console.log("transaction unconfirmed");
    }

    // Запускается, когда транзакция одобрена
    if (
      res.topic === `confirmedAdded/${signer1AddressString}` &&
      res.data.meta.hash === hash.toString()
    ) {
      console.log("transaction confirmed");
      transactionHeight = parseInt(res.data.meta.height);
    }

    // Срабатывает при создании блока
    if (res.topic === `block`) {
      console.log("block");
      blockHeight = parseInt(res.data.block.height);
    }

    // Срабатывает, когда блок завершен
    if (res.topic === `finalizedBlock`) {
      console.log("finalizedBlock");
      console.log(res);
      finalizedBlockHeight = parseInt(res.data.height);
    }

    // Запускается при сбое транзакции
    if (
      res.topic === `status/${signer1AddressString}` &&
      res.data.hash === hash.toString()
    ) {
      console.log(res.data.code);
      ws.close();
    } else {
      console.log(res);
    }

    // confirmationHeightブロック後に監視終了
    if (
      transactionHeight !== 0 &&
      transactionHeight + confirmationHeight - 1 <= blockHeight
    ) {
      console.log(
        `${confirmationHeight} blocks confirmed. transactionHeight is ${transactionHeight} blockHeight is ${blockHeight}.`
      );

      // Проверить статус транзакции и завершить мониторинг
      try {
        const transactionStatusRoutesApi = new TransactionStatusRoutesApi(
          configuration
        );
        const transactionStatusDTO: TransactionStatusDTO = (
          await transactionStatusRoutesApi.getTransactionStatus({
            hash: hash.toString(),
          })
        ).data;
        if (transactionStatusDTO.group === TransactionGroupEnum.Confirmed) {
          // Обработка подтверждения транзакции здесь
          ws.close();
        } else if (
          transactionStatusDTO.group === TransactionGroupEnum.Unconfirmed
        ) {
          // Если он снова становится неутвержденным, продолжайте отслеживать как есть.
          console.log("rollback detected. transaction is unconfirmed.");
        } else {
          // Напишите сюда обработку, когда транзакция исчезает без одобрения... Например, проверить статус и повторно объявить и т.д.
          console.log("rollback detected. transaction disappeared.");
          ws.close();
        }
      } catch (err) {
        console.error(err);
        ws.close();
      }
    } else {
      console.log(
        `wait for ${confirmationHeight} blocks. transactionHeight is ${transactionHeight} blockHeight is ${blockHeight}.`
      );
    }

    // Мониторинг заканчивается после того, как finalizedBlockHeight проходит целевой блок
    if (transactionHeight !== 0 && transactionHeight <= finalizedBlockHeight) {
      console.log(
        `${finalizedBlockHeight} block finalized. transactionHeight is ${transactionHeight} blockHeight is ${blockHeight}.`
      );

      // Проверить статус транзакции и завершить мониторинг
      try {
        const transactionStatusRoutesApi = new TransactionStatusRoutesApi(
          configuration
        );
        const transactionStatusDTO: TransactionStatusDTO = (
          await transactionStatusRoutesApi.getTransactionStatus({
            hash: hash.toString(),
          })
        ).data;
        if (transactionStatusDTO.group === TransactionGroupEnum.Confirmed) {
          // Обработка подтверждения транзакции здесь
          ws.close();
        } else if (
          transactionStatusDTO.group === TransactionGroupEnum.Unconfirmed
        ) {
          // Обработка подтверждения транзакции здесь
          console.log("rollback detected. transaction is unconfirmed.");
        } else {
          // Напишите сюда обработку, когда транзакция исчезает без одобрения... Например, проверить статус и повторно объявить и т.д.
          console.log("rollback detected. transaction disappeared.");
          ws.close();
        }
      } catch (err) {
        console.error(err);
        ws.close();
      }
    } else {
      console.log(
        `wait for finalized block. transactionHeight is ${transactionHeight} blockHeight is ${blockHeight}.`
      );
    }
  });

  // Объявление транзакций
  try {
    const transactionRoutesApi = new TransactionRoutesApi(configuration);
    console.log(transactionPayload);
    const response = await transactionRoutesApi.announceTransaction({
      transactionPayload,
    });
    console.log(response.data);
  } catch (err) {
    console.error(err);
  }
})();

При инициализации такой транзакции, если вы откроете кошелек, транзакция будет отправлена и вы услышите звук «цзин». В коде примера написано большое количество комментариев, чтобы вы могли видеть, где и что вы делаете. Если у вас есть какие-либо проблемы, не стесняйтесь обращаться к нашему GitHub или Discord.

Пример журнала времени выполнения (log)

~/symbol-sdk-typescript-sample-1$ npx ts-node send-transfer-transaction.ts 

40EED5433899E2EB1FB33A864CCEDB9D7F5F42A59561F1B4341DE3751030B85F
https://testnet.symbol.fyi/transactions/40EED5433899E2EB1FB33A864CCEDB9D7F5F42A59561F1B4341DE3751030B85F
{"payload": "B00000000000000008B788D279A618F169687225327E5721D0D6A2738F10F53A82347310E6CCD4928AA6C8705E6219BCE50E76D1BD5D499567C97E2390C6398689DEFE60EB90A506ECF3FF68E017A83528A0A361F1F1EE91D761B5E34008AD9474870D54F5C4D0680000000001985441C044000000000000F64B73920500000098D985A853255F28BE66E52F6E7D1078B0D5DB4EADB2C59B0000010000000000C8B6532DDB16843A40420F0000000000"}
{ message: 'packet 9 was pushed to the network via /transactions' }
connection open
uid : PE56L7DT7UFEV4ZUZM6JEB373PJNCLUL
{"uid": "PE56L7DT7UFEV4ZUZM6JEB373PJNCLUL", "subscribe": "unconfirmedAdded/TBFVGBN5XKVFWF3PKWRQRPH6SHSOTXJMXKYSTEQ"}
{"uid": "PE56L7DT7UFEV4ZUZM6JEB373PJNCLUL", "subscribe": "confirmedAdded/TBFVGBN5XKVFWF3PKWRQRPH6SHSOTXJMXKYSTEQ"}
{"uid": "PE56L7DT7UFEV4ZUZM6JEB373PJNCLUL", "subscribe": "status/TBFVGBN5XKVFWF3PKWRQRPH6SHSOTXJMXKYSTEQ"}
{"uid": "PE56L7DT7UFEV4ZUZM6JEB373PJNCLUL", "subscribe": "block"}
{"uid": "PE56L7DT7UFEV4ZUZM6JEB373PJNCLUL", "subscribe": "finalizedBlock"}
{ uid: 'PE56L7DT7UFEV4ZUZM6JEB373PJNCLUL' }
wait for 6 blocks. transactionHeight is 0 blockHeight is 0.
wait for finalized block. transactionHeight is 0 blockHeight is 0.
transaction unconfirmed
{
  topic: 'unconfirmedAdded/TBFVGBN5XKVFWF3PKWRQRPH6SHSOTXJMXKYSTEQ',
  data: {
    transaction: {
      signature: '08B788D279A618F169687225327E5721D0D6A2738F10F53A82347310E6CCD4928AA6C8705E6219BCE50E76D1BD5D499567C97E2390C6398689DEFE60EB90A506',
      signerPublicKey: 'ECF3FF68E017A83528A0A361F1F1EE91D761B5E34008AD9474870D54F5C4D068',
      version: 1,
      network: 152,
      type: 16724,
      maxFee: '17600',
      deadline: '23931866102',
      recipientAddress: '98D985A853255F28BE66E52F6E7D1078B0D5DB4EADB2C59B',
      mosaics: [Array]
    },
    meta: {
      hash: '40EED5433899E2EB1FB33A864CCEDB9D7F5F42A59561F1B4341DE3751030B85F',
      merkleComponentHash: '40EED5433899E2EB1FB33A864CCEDB9D7F5F42A59561F1B4341DE3751030B85F',
      height: '0'
    }
  }
}
wait for 6 blocks. transactionHeight is 0 blockHeight is 0.
wait for finalized block. transactionHeight is 0 blockHeight is 0.
block
{
  topic: 'block',
  data: {
    block: {
      signature: '27C609DDBD9E552425B736A1222B32C2E1ABD9431E4B59FD68705460799F4A95E5B39625D7461A7F780DF1108E85B80D37EF966D34567CE1342C8D273DF27D05',
      signerPublicKey: 'CD96C6830906530C4BCD7C45453F5D55A5FA5BAF098CFC4E512B18CC763D9573',
      version: 1,
      network: 152,
      type: 33091,
      height: '653699',
      timestamp: '23924697359',
      difficulty: '10000000000000',
      proofGamma: '14987781C5471F99EE0A168007E8F1E0AF204FC351057178071B73D9923CD4B3',
      proofVerificationHash: '5A494A1E9335148507B7C58162249217',
      proofScalar: 'A086226451E081BABC25619348E2FC5026F2688C0742D375B66F73BF580B6E02',
      previousBlockHash: 'C6DF5E1406BF16CB0FBD421AE524016E2FD16DFF1AF56D72F2AF0B871A908E21',
      transactionsHash: '40EED5433899E2EB1FB33A864CCEDB9D7F5F42A59561F1B4341DE3751030B85F',
      receiptsHash: '0E12701813430073FDFA2E524C5AA182950DB5C2931FB0A015D260D6A54939C3',
      stateHash: '978B0BCAC574548EF5C28F15F6791ACAAE40A16A326C9C236D041335981E5B1D',
      beneficiaryAddress: '980F30859E6AB05706FD93188B39A42B42A44AC8DA115053',
      feeMultiplier: 100
    },
    meta: {
      hash: '5B09B4DC5B58B277FB74745FF5C9483467BE8ECB10FF61384184B5F82EE9C666',
      generationHash: 'F8084B2C740931EF6C84430E33B30248E90458AD4EE266111BE797E7AD1C5329'
    }
  }
}
wait for 6 blocks. transactionHeight is 0 blockHeight is 653699.
wait for finalized block. transactionHeight is 0 blockHeight is 653699.
transaction confirmed
{
  topic: 'confirmedAdded/TBFVGBN5XKVFWF3PKWRQRPH6SHSOTXJMXKYSTEQ',
  data: {
    transaction: {
      signature: '08B788D279A618F169687225327E5721D0D6A2738F10F53A82347310E6CCD4928AA6C8705E6219BCE50E76D1BD5D499567C97E2390C6398689DEFE60EB90A506',
      signerPublicKey: 'ECF3FF68E017A83528A0A361F1F1EE91D761B5E34008AD9474870D54F5C4D068',
      version: 1,
      network: 152,
      type: 16724,
      maxFee: '17600',
      deadline: '23931866102',
      recipientAddress: '98D985A853255F28BE66E52F6E7D1078B0D5DB4EADB2C59B',
      mosaics: [Array]
    },
    meta: {
      hash: '40EED5433899E2EB1FB33A864CCEDB9D7F5F42A59561F1B4341DE3751030B85F',
      merkleComponentHash: '40EED5433899E2EB1FB33A864CCEDB9D7F5F42A59561F1B4341DE3751030B85F',
      height: '653699'
    }
  }
}
wait for 6 blocks. transactionHeight is 653699 blockHeight is 653699.
wait for finalized block. transactionHeight is 653699 blockHeight is 653699.
block
{
  topic: 'block',
  data: {
    block: {
      signature: '300C88C9BDDBF04C4F81A80917FE058CFC9458B84E08D509ADF243693D94D27E0098DDC3FB8BA226435ACA4DE9BE95FDC692B0C683F95EF5883CA69193A44906',
      signerPublicKey: 'BF2EAFD7C2B1E84C814B797332CA10E82CC3E3C1E7BC8ACC4640E7FD33C90A2C',
      version: 1,
      network: 152,
      type: 33091,
      height: '653700',
      timestamp: '23924741192',
      difficulty: '10000000000000',
      proofGamma: '0953D5657183B9F500871FDF9BB83EDCDBF5D9B931BF32D1783FD9BCDC38F1A2',
      proofVerificationHash: 'A5192E49F1E794737D3C831D5585B401',
      proofScalar: 'DF1929D97CD80E0F0C085524840F0009FBCAF1683AE86B77E55C03DD2561FA0F',
      previousBlockHash: '5B09B4DC5B58B277FB74745FF5C9483467BE8ECB10FF61384184B5F82EE9C666',
      transactionsHash: '0000000000000000000000000000000000000000000000000000000000000000',
      receiptsHash: '55917278DD7CA2D0BAEF12D5DD072CC929A2187AAC78E239E043A1F4198AC5DF',
      stateHash: '2FB6BE644C3CC1186CD737C39E14EDB24D90DBEEF87DF779136F88AA2C9003D7',
      beneficiaryAddress: '985F693ED8D58BC10F3E428E600E17F704BE042B03198B2A',
      feeMultiplier: 0
    },
    meta: {
      hash: 'D36D50647F1F41EA75FAB503F8F0795F5762C2198268EC9FB4F4013D577F7815',
      generationHash: 'D67B01773A8B6BC9E2FF7BBB0423DB4D8C843478B4556391062512687CC42DCE'
    }
  }
}
wait for 6 blocks. transactionHeight is 653699 blockHeight is 653700.
wait for finalized block. transactionHeight is 653699 blockHeight is 653700.
block
{
  topic: 'block',
  data: {
    block: {
      signature: '64B0A8BAFA35F1D2A7F8D00475D4ACB8BA3AC546CB3445BA190A123A706CCADFC89B102396BABDA49803298B987206F49C97164DACBEDAFE63DA430954923800',
      signerPublicKey: '21CF6E21A73CB4CEBD32BA0AE2C7059D19B1A7827DF6C8D10FF33C3F1A2BF0E8',
      version: 1,
      network: 152,
      type: 33091,
      height: '653701',
      timestamp: '23924771171',
      difficulty: '10000000000000',
      proofGamma: '414F99CCF2115DC10CF761D3D4E335884ADCA8A74D9479FD67EAF38D61915D12',
      proofVerificationHash: '523DF3CEE73CA1F1684EF22599BF8B58',
      proofScalar: 'FE12167FE39A1EEA8FFD7B18D35F847B1D42BE696EA16534D9F669A0910A270C',
      previousBlockHash: 'D36D50647F1F41EA75FAB503F8F0795F5762C2198268EC9FB4F4013D577F7815',
      transactionsHash: '0000000000000000000000000000000000000000000000000000000000000000',
      receiptsHash: 'BFC94F3C268EA1D531DEE62CCF388CCB85746D368DAC775171A904B5897C0566',
      stateHash: 'B199DE8B7A60975EE9549075FF821F83289196564FF0A52C5354BDEC138D5DD2',
      beneficiaryAddress: '98FFA418508A3B022EF3491FC8254DEB7EC3EBA65B52DE1D',
      feeMultiplier: 0
    },
    meta: {
      hash: '0D5F10306D3F7E63158E1581C96EB1D636BD7787FACE35CADCD1D8A8E2AA7D1D',
      generationHash: 'F8210DAC0163CB037F3ABC73E59FE86C070DDC827E5922AAB4208FCE7666F824'
    }
  }
}
wait for 6 blocks. transactionHeight is 653699 blockHeight is 653701.
wait for finalized block. transactionHeight is 653699 blockHeight is 653701.
block
{
  topic: 'block',
  data: {
    block: {
      signature: '12118E9565A88F932FE89D3595E01EE991CB4A803F375D9A1CCEF0D667C9C180F4F1DB8A6438C3626BF87E9278FA0601B88EF03DA807DE9C4220BA92A926D002',
      signerPublicKey: 'BF2EAFD7C2B1E84C814B797332CA10E82CC3E3C1E7BC8ACC4640E7FD33C90A2C',
      version: 1,
      network: 152,
      type: 33091,
      height: '653702',
      timestamp: '23924792232',
      difficulty: '10000000000000',
      proofGamma: 'B6B4EAFCAC77DFBFE42BEC7BC41E9B1D65C0A27EEE97E94F55AB08E9FF9910D9',
      proofVerificationHash: 'A8A8244A0EB6AC01E18A228DC44865E7',
      proofScalar: '67147B2A8C4B73F8CF31E98CE48DB95A76CF0DD9C24F3AF23094A86D5CCE930D',
      previousBlockHash: '0D5F10306D3F7E63158E1581C96EB1D636BD7787FACE35CADCD1D8A8E2AA7D1D',
      transactionsHash: '0000000000000000000000000000000000000000000000000000000000000000',
      receiptsHash: '55917278DD7CA2D0BAEF12D5DD072CC929A2187AAC78E239E043A1F4198AC5DF',
      stateHash: 'DCE2463E6D9D10F758F1904718539329890DE030447C37511910C50DF1D34A34',
      beneficiaryAddress: '985F693ED8D58BC10F3E428E600E17F704BE042B03198B2A',
      feeMultiplier: 0
    },
    meta: {
      hash: 'CC4DF75939F1ED540890EA97688055CC686AA9B2D1FA1998A82B05FF094E35FA',
      generationHash: 'FDB798D4ACBCC9B60F4A35BCD9F5D80152909D51B5FF9A7236DD7BF0325D1723'
    }
  }
}
wait for 6 blocks. transactionHeight is 653699 blockHeight is 653702.
wait for finalized block. transactionHeight is 653699 blockHeight is 653702.
block
{
  topic: 'block',
  data: {
    block: {
      signature: '48011E2F4DE712B135B59FE782375730882B01D8D66B5A01BAB0B89D05E66673EDEF24E25B609835E54D1D3957E942C1BF620988DF231F44AEA0810557433A08',
      signerPublicKey: 'F9A5A66EBE9AD5EAAAF07AF208BF33FB0B24C2049EFF99B65AD1BB46809852DE',
      version: 1,
      network: 152,
      type: 33091,
      height: '653703',
      timestamp: '23924824521',
      difficulty: '10000000000000',
      proofGamma: 'D0E1CDB0F05EF355CB4C3150233A6F69063F0F1641DAA48A2710136909857B01',
      proofVerificationHash: 'A5755D01A57F5CE9305FFF84DAEAFB5B',
      proofScalar: 'F4167D2CAC137C7E8B50F0C3786E012F191CB7CEFF6E85A9999F0F9B2432320C',
      previousBlockHash: 'CC4DF75939F1ED540890EA97688055CC686AA9B2D1FA1998A82B05FF094E35FA',
      transactionsHash: '0000000000000000000000000000000000000000000000000000000000000000',
      receiptsHash: 'F426FEC961E15E6F1A76117DA8363DE4064391816B024B5134F6BA19DCAF5DC0',
      stateHash: 'DF1C0EEEAACA2E966B3ECA891234482315C7057C1628E5C0CBECBD91D0ABCEF7',
      beneficiaryAddress: '98D3970759CB13CD9E6BD7FBEBD7F909F34ADA4E079B1A4D',
      feeMultiplier: 0
    },
    meta: {
      hash: '661392D9004B85260818CF03AA16AF05F987EB7ED700DB37D574059E258BB3CE',
      generationHash: 'F473AEDD8F5183A4C497ADA2C4F7798B73C06BF7DAB6D6E5C19628A267913F9A'
    }
  }
}
wait for 6 blocks. transactionHeight is 653699 blockHeight is 653703.
wait for finalized block. transactionHeight is 653699 blockHeight is 653703.
block
{
  topic: 'block',
  data: {
    block: {
      signature: '43417AF8B7CEDC9D359EF4B17745523968EF0287F835C8D5A758E919B53970B11FC2894E1953185E577FA6B442982FE051719EBAE8B9A2771FC36DACC213940E',
      signerPublicKey: '88A7993C2478345E3B86A98A2D8AC47739F7A95620238018958E3961C153E263',
      version: 1,
      network: 152,
      type: 33091,
      height: '653704',
      timestamp: '23924861796',
      difficulty: '10000000000000',
      proofGamma: '60F4CA9CD7AFBD3F5BE8ED42A40B5CE3A90F2EAD4969F0F719A12516F24D67D6',
      proofVerificationHash: '525BB53255B1A900B29D85E3564E56F3',
      proofScalar: '8214A6B61FD2BD2FE53F465DAEC6E3B2540B62EBACF083E92D6A323D78B03A03',
      previousBlockHash: '661392D9004B85260818CF03AA16AF05F987EB7ED700DB37D574059E258BB3CE',
      transactionsHash: '0000000000000000000000000000000000000000000000000000000000000000',
      receiptsHash: '987E011A37AC36B4D5524D846515B7580B33B41360083578BD721C85D07AD753',
      stateHash: 'A7E06767E5BDD277A82F472000E18038E5BAEDACB87CCE28F186BAED438BA0CE',
      beneficiaryAddress: '98258E9856A612C5346D3C0B318DCB654257BD9DD86E6481',
      feeMultiplier: 0
    },
    meta: {
      hash: '2DB314AD386B94F413F627A0370D175E846A572CD3D62DBF92175166437AC3ED',
      generationHash: 'F49E42593C78FCE7FBE9D211F3AAA4DED5E8EBCDE82F1613B54D41D93AD62A1E'
    }
  }
}
6 blocks confirmed. transactionHeight is 653699 blockHeight is 653704.
wait for finalized block. transactionHeight is 653699 blockHeight is 653704.
connection closed

Резюме

Теперь, когда у нас есть клиент TypeScript REST API и npm-пакет TypeScript (для отправки транзакций), мы можем начать фронтенд-разработку в среде TypeScript, используя инструменты, соответствующие концепции нового официального SDK.

Однако если вы посмотрите на пример кода, то увидите, что есть места, где проблем можно избежать с помощью некоторых обходных путей. Таким образом, некоторые части кода могут быть улучшены путем написания комментариев в комментариях JSDoc (они помогут улучшить файлы определения типов, автоматически сгенерированные), поэтому, если я могу, я хочу отправить запрос на извлечение, чтобы улучшить их напрямую. к новому официальному SDK Symbol.

С момента запуска Symbol прошло около полутора лет, но еще много неизвестного о том, как будет развиваться экосистема Symbol и NEM. Также на данный момент не известно, какое место в экосистеме Symbol займут SDK от NEMTUS. (Может быть будет другой SDK, лучший, чем этот и это было бы здорово).

Про NEMTUS

Если у вас есть что добавить к статьям от NEMTUS, связанных с NEM или Symbol или SDK, пожалуйста, не стесняйтесь сотрудничать с нами. Мы будем очень признательны за это. 

https://github.com/nemtus/

Японская некоммерческая организация NEMTUS, будет рада продолжать улучшать техническую информацию о NEM и Symbol и вносить свой вклад в экосистему.

Автор Статьи

Имя Автора: Ясунори Мацуока (松岡靖典)

Организация: NEMTUS

Биография: 

  • Принимал участие в веб-разработке блокчейна в CauchyE Co., Ltd.
  • С августа 2022 года Ясунори работает на постоянной основе в качестве заместителя председателя некоммерческой организации NEMTUS по продвижению технологии блокчейна NEM/Symbol.

Социальные сети:

Твиттер: https://twitter.com/salaryman_tousi

GitHub: https://github.com/YasunoriMATSUOKA

___

Перевод: SymbolTimes