Розгортання смарт-контракту в тестовій мережі за допомогою Taquito

На минулому уроці ми вивчили базові та просунуті типи даних мови програмування LIGO. Цих знань вистачить, щоб написати код простого смарт-контракту. Але щоб інші користувачі могли взаємодіяти з контрактом, його потрібно розмістити в блокчейні.

Для розгортання смарт-контрактів в блокчейні розробники використовують спеціальні інструменти. У цьому уроці ми встановимо бібліотеку Taquito і з її допомогою опублікуємо контракт в тестовій мережі Tezos.

Установка і пробний запуск Taquito

Taquito — це TypeScript-бібліотека, яка спрощує взаємодію з блокчейном Tezos і смарт-контрактами. Наприклад, так виглядає розгортання контракту вручну через консоль клієнта Tezos:

tezos-client originate contract <назва контракту>
  for <user> transferring <кількість tez> from <from_user>
  running <шлях до файлу з кодом>
  --init '<стан сховища storage>'
  --burn-cap <максимальна комісія>

Скрипт Taquito для розгортання контракту виглядає простіше:

try {
  const op = await tezos.contract.originate ({
    // код смарт-контракту
    code: `{
          `,
    // значення сховища
    init: ``,
  });

Також за допомогою Taquito можна відправляти токени, перевіряти баланси адрес і розробити простий веб-інтерфейс для смарт-контракту.

Встановлення Taquito

Для роботи Taquito потрібна платформа nodeJS. Скачайте її з офіційного сайту і встановіть на свій комп'ютер.

Потім встановіть пакетний менеджер yarn. Він завантажить Taquito і автоматично пропише його в системі.

Для цього відкрийте консоль і виконайте команду:

sudo npm install --global yarn

1

Засоби для роботи Taquito готові, залишилося протестувати її роботу. Відкрийте Visual Studio Code, створіть папку taq-test, а в ній — два файли з назвами app.ts і main.ts.

У app.ts ми будемо записувати функції Taquito і основний код, а в main.ts — параметри і виклики функцій. Такий підхід дозволяє спростити структуру коду і не викликати функції до їх оголошення.

2

Відкрийте термінал в VS Code і за допомогою команди cd перейдіть в папку taq-test. Потім додайте в папку бібліотеку Taquito:

cd ~/Documents/taq-test

yarn add @taquito/taquito

3

Якщо ви правильно встановили NodeJS і yarn, термінал видасть довгий список встановлених файлів.

Відкрийте файл app.ts і додайте в нього код:

import { TezosToolkit } from '@taquito/taquito'
export class App {
  public async main() {}
}

У файл main.ts додайте:

import { App } from './app'

new App().main()

Не забудьте зберегти файли за допомогою ctrl+s або ⌘+s, інакше середовище виконання буде вважати їх порожніми.

Розширення .ts вказує на те, що в файлах міститься код TypeScript. Для його роботи потрібно встановити бібліотеку TypeScript. Для цього в терміналі VS Code виконайте:

sudo npm install typescript --save-dev

4

При успішній установці термінал видасть 3-4 попередження про відсутність ліцензії та опису проекту. Якщо в списку більше пунктів — ви забули додати sudo на початку команди або не перебуваєте в папці taq-test.

Останній крок — виконайте скрипт main.ts в віртуальному вузлі. Для цього введіть у терміналі команду:

npx ts-node main.ts

5

Термінал відзвітує про запуск npx одним рядком. Це означає, що npx вдало імпортував в додаток Taquito. Так як головна функція app.ts порожня, npx відразу її завершив. Інший результат при виконанні цього кроку означає, що ви допустили помилку під час установки TypeScript або Taquito.

При роботі над смарт-контрактами вам потрібно буде кожен раз встановлювати Taquito і TypeScript в папку проекту. На відміну від JavaScript, їх не можна встановити глобально.

Отримуємо дані з блокчейна Tezos через Taquito

За допомогою Taquito можна зчитувати баланси адрес в мережі Tezos, відправляти токени і публікувати смарт-контракти. Для цього не потрібно піднімати власний вузол Tezos: Taquito під’єднується до публічних вузлів через RPC (Remote Procedure Call або виклик віддалених процедур).

Давайте під’єднаємося до мейннету і запитаємо баланс адреси одного з бейкерів — валідаторів мережі Tezos. Для цього в файлі app.ts включимо бібліотеку TezosToolkit і підготуємо константу для RPC-посилання публічного вузла Tezos:

import { TezosToolkit } from '@taquito/taquito'
export class App {
  //оголошуємо приватний модифікатор tezos типу TezosToolkit
  private tezos: TezosToolkit
  //оголошуємо конструктор rpcUrl, який буде передавати адресу публічного вузла Tezos в TezosToolkit
  constructor(rpcUrl: string) {
    this.tezos = new TezosToolkit(rpcUrl)
  }
  public async main() {}
}

У файлі main.ts пропишемо RPC-посилання на публічний вузол Tezos Mainnet і передамо її класу App:

import { App } from './app'
//оголошуємо константу з адресою вузла
const RPC_URL = 'https://mainnet.smartpy.io'
//запускаємо App, який передає головної функції адреса вузла
new App(RPC_URL).main()

При виконанні команди npx ts-node main.ts Taquito отримає посилання на вузол, але нічого з ним не зробить, тому що в app.ts немає методів для взаємодії з мережею. Додамо в app.ts метод для отримання балансу адреси:

import { TezosToolkit } from '@taquito/taquito'
export class App {
  private tezos: TezosToolkit
  constructor(rpcUrl: string) {
    this.tezos = new TezosToolkit(rpcUrl)
  }
  //оголошуємо метод getBalance з вхідним параметром address
  public getBalance(address: string): void {
    //Taquito відправляє вузлу запит балансу зазначеної адреси. Якщо вузол виконав запит, скрипт виводить отримане значення в консоль. Якщо сталася помилка — видає «Address not found»
    this.tezos.rpc
      .getBalance(address)
      .then((balance) => console.log(balance))
      .catch((e) => console.log('Address not found'))
  }
  public async main() {}
}

Додамо адресу бейкера і викличемо метод getBalance в скрипті main.ts:

import { App } from './app'
const RPC_URL = 'https://mainnet.smartpy.io'
//оголошуємо константу з адресою бейкера Everstake
const ADDRESS = 'tz1aRoaRhSpRYvFdyvgWLL6TGyRoGF51wDjM'
// запускаємо App, передаємо йому посилання на вузол, викликаємо метод getBalance і передаємо йому адресу
new App(RPC_URL).getBalance(ADDRESS)

Запустимо скрипт за допомогою команди npx ts-node main.ts.

6

Taquito поверне кількість вільних tez на адресі Everstake.

7

Отриманий баланс збігається з даними оглядача tzStats.

Створюємо аккаунт в тестовій мережі Tezos за допомогою Taquito

Транзакції потрібно підписувати закритим ключем. Для цього Taquito використовує модуль signer, який працює з даними блокчейн-акаунтів.

Щоб не витрачати справжні tez, ми підключимося до Tezos Testnet. Спочатку потрібно отримати адресу і тестові tez на крані tzalpha. Перейдіть по посиланню, підтвердіть, що ви не робот, і натисніть кнопку Get Testnet tez.

8

Кран tzalpha створить нову адресу і видасть дані облікового запису: мнемонічну фразу, закритий ключ і публічний адресу.

9

Дані облікового запису потрібно зберегти в окремому файлі. Створіть в папці taq-test файл acc.json і вставте в нього код з tzalpha.

10

Тепер можна додати в проект модуль signer. В VS Code відкрийте термінал, перейдіть в папку taq-test і виконайте команду:

yarn add @taquito/signer

Як і при установці Taquito, термінал видасть попередження про відсутніх ліцензіях і список встановлених файлів.

11

Создадим новый файл tx.ts и добавим в него модуль signer:

import { TezosToolkit } from '@taquito/taquito'
//імпортуємо inMemorySigner. Він збереже приватний ключ в оперативній пам'яті і буде підписувати ним транзакції
import { InMemorySigner } from '@taquito/signer'
//оголошуємо константу acc, яка направить скрипт до файлу acc.json
const acc = require('./acc.json')
export class Tx {
  private tezos: TezosToolkit
  rpcUrl: string
  constructor(rpcUrl: string) {
    this.tezos = new TezosToolkit(rpcUrl)
    this.rpcUrl = rpcUrl

    //оголошуємо параметри за допомогою методу fromFundraiser: пошту, пароль і мнемонічну фразу, з якої можна отримати приватний ключ
    this.tezos.setSignerProvider(InMemorySigner.fromFundraiser(acc.email, acc.password, acc.mnemonic.join('')))
  }
  // отримуємо публічний і приватний ключі і активуємо аккаунт
  public async activateAccount() {
    const { pkh, secret } = acc
    try {
      const operation = await this.tezos.tz.activate(pkh, secret)
      await operation.confirmation()
    } catch (e) {
      console.log(e)
    }
  }
  public async main() {}
}

У файлі main.ts викликаємо метод activateAccount():

// імпортуємо Tx.ts
import { Tx } from './tx'
// міняємо RPC-посилання з мейннета на тестову мережу. Не лякайтеся smartpy в посиланні — це просто адреса сервера
const RPC_URL = 'https://florencenet.smartpy.io/'
const ADDRESS = 'tz1aRoaRhSpRYvFdyvgWLL6TGyRoGF51wDjM'
// викликаємо функцію Tx, передаємо їй посилання на тестову мережу і просимо активувати обліковий запис
new Tx(RPC_URL).activateAccount()

Залишилося виконати main.ts в терміналі:

npx ts-node main.ts

12

Якщо тестова мережа активує аккаунт, консоль відзвітує про запуск npx без повідомлень про помилки. Тепер можете перевірити активацію в браузері тестових мереж.

Відкрийте acc.json і скопіюйте публічний ключ з поля «pkh». Перейдіть на florence.tzstats і знайдіть свій аккаунт з публічного ключу. На балансі повинно бути близько сотні тестових tez, а в історії транзакцій — запис про активацію.

13

Ми налаштували Taquito і активували тестовий аккаунт. Для роботи в мейннеті потрібно буде зробити те ж саме: створити файл .json з даними облікового запису і під’єднати його за допомогою signer.

Публікуємо контракт в тестнеті

На минулому уроці ми запускали смарт-контракт з допомогою контейнера Docker і команди dry-run. Віртуальна машина з контрактом відразу закривалася, і при цьому не використовувала сховище storage.

Справжні смарт-контракти токенів і децентралізованих додатків постійно використовують storage для зберігання даних користувачів. Ми докладніше розповімо про це в наступному уроці. А поки опублікуємо контракт в тестовій мережі і подивимося, як storage зберігає інформацію.

Перейдіть в VS Code і створіть файл deploy.js. Вставте в нього наступний код:

import { TezosToolkit } from '@taquito/taquito';
import { importKey } from '@taquito/signer';

const provider = 'https://florencenet.smartpy.io/';

async function deploy () {
  const tezos = new TezosToolkit (provider);
  await importKey (
    tezos,
    "", // пошта
    "", // пароль
    [
      "", // мнемоніка
    ] .Join ( ''),
    "" // приватний ключ
  );

deploy ();

Впишіть в порожні місця дані облікового запису: пошту, пароль, слова мнемонічної фрази і приватний ключ з файлу acc.json.

14

Після даних аккаунта додайте код контракту. Ми будемо використовувати модифікований контракт з першого уроку:

​​function main (const num : int; const store : int) is
 ((nil : list (operation)),  store + num)

Цей смарт-контракт отримує від користувача параметр num типу int і підсумовує його з числом в сховищі.

Скомпілюйте код контракту на мову Michelson. Щоб не запускати Docker зайвий раз, скористайтеся онлайн середовищем розробки.

Вставте код в редактор, в випадаючому списку виберіть пункт Compile Contract і натисніть кнопку Run. Компілятор видасть код контракту на мові Michelson.

15

Вернитесь к файлу deploy.ts и после данных аккаунта вставьте следующий код:

try {
 const op = await tezos.contract.originate ({
   // код смарт-контракту
   code: `{parameter int;
     storage int;
     code {UNPAIR; ADD; NIL operation; PAIR}}
         `,
   // значення сховища
   init: `0`,
 });

Тепер опишіть процес розгортання контракту. Фінальний код буде виглядати так:

import { TezosToolkit } from '@taquito/taquito'
import { importKey } from '@taquito/signer'
const provider = 'https://florencenet.smartpy.io/'
async function deploy() {
  const tezos = new TezosToolkit(provider)
  await importKey(
    tezos,
    'Hoqfgsoy.qyisbhtk@tezos.example.org', // пошта
    'ZnnZLS0v6O', // пароль
    [
      'Able', // мнемоніка
      'Public',
      'Usual',
      'Hello',
      'October',
      'Owner',
      'Essence',
      'Old',
      'Author',
      'Original',
      'Various',
      'Gossip',
      'Core',
      'High',
      'Hire',
    ].Join(''),
    '2bed8dc244ee43a1e737096c4723263c269049d8' //приватний ключ
  )
  try {
    const op = await tezos.contract.originate({
      // код смарт-контракту
      code: `{parameter int;
      storage int;
      code {UNPAIR; ADD; NIL operation; PAIR}}
          `,
      // значення сховища
      init: `0`,
    })
    // початок розгортання
    console.log('Awaiting confirmation ...')
    const contract = await op.contract()
    // звіт про розгортання: кількість використаного газу, значення сховища
    console.log('Gas Used', op.consumedGas)
    console.log('Storage', await contract.storage())
    // хеш операції, за яким можна знайти контракт в блокчейн-браузері
    console.log('Operation hash:', op.hash)
  } catch (ex) {
    console.error(ex)
  }
}
deploy()

Відкрийте консоль і виконайте команду npx ts-node deploy.ts. Термінал видасть звіт про публікації контракту.

16

Скопіюйте хеш операції і знайдіть транзакцію розгортання контракту в оглядачі florence.tzstats. У ній буде вказана адреса смарт-контракту в тестовій мережі.

Спробуйте викликати опублікований контракт. Для цього створіть скрипт, який викличе головну функцію і передасть їй число.

Створіть файл call.ts і вставте в нього код:

import { TezosToolkit } from '@taquito/taquito'
import { InMemorySigner } from '@taquito/signer'
const acc = require('./acc.json')
export class Call {
  private tezos: TezosToolkit
  rpcUrl: string
  constructor(rpcUrl: string) {
    this.tezos = new TezosToolkit(rpcUrl)
    this.rpcUrl = rpcUrl

    // оголошуємо параметри за допомогою методу fromFundraiser: пошту, пароль і мнемонічну фразу, з якої можна отримати приватний ключ
    this.tezos.setSignerProvider(InMemorySigner.fromFundraiser(acc.email, acc.password, acc.mnemonic.join('')))
  }
  public add(add: number, contract: string) {
    this.tezos.contract
      .at(contract) // звертаємося до контракту, щоб отримати його точки входу
      .then((contract) => {
        console.log(`Adding ${add} to storage ...`)
        // звертаємося до головної функції. На відміну від синтаксису ligo, головна точка входу називається не main, а default
        return contract.methods.default(add).send()
      })
      .then((op) => {
        console.log(`Awaiting for ${op.hash} to be confirmed ...`)
        return op.confirmation(1).then(() => op.hash) // чекаємо одне підтвердження мережі, щоб швидше отримати результат
      })
      .then((hash) => console.log(`Call done}`)) // успішний виклик
      .catch((error) => console.log(`Error: ${JSON.stringify(error, null, 2)}`))
  }
}

Тепер зробіть окремий скрипт для виклику call.ts, передачі адреси контракту і значення аргументу. Для цього створіть файл maincall.ts і скопіюйте в нього код:

import { Call } from './call'
const RPC_URL = 'https://florencenet.smartpy.io/'
const CONTRACT = '' //адреса опублікованого контракту
const ADD = 5 // число, яке отримає головна функція. Можете змінити його на інше
new Call(RPC_URL).add(ADD, CONTRACT)

Присвойте константі CONTRACT адресу опублікованого тестового контракту. Відкрийте консоль і виконайте команду:

npx ts-node maincall.ts

Коли термінал видасть повідомлення про завершення операції, перейдіть за посиланням або знайдіть свій контракт за адресою. Як бачите, значення сховища змінилося.

17

Підбиваємо підсумки

Taquito — це інструмент для роботи з блокчейном Tezos через код на JavaScript і TypeScript. За допомогою Taquito розробники звертаються до точок входу смарт-контрактів і до мережі Tezos, як до звичайних JS-методів. Також Taquito дозволяє зберігати дані декількох акаунтів в різних файлах і виносити часто використовуваний код в окремі модулі.

Бібліотека Taquito потрібна для розробки DApp на Tezos. Розробникам простіше інтегрувати в веб-додаток JavaScript, ніж перекладати запити користувачів в консольні команди клієнта Tezos. У наступних уроках ми також будемо використовувати Taquito для створення взаємозамінного токена і NFT.

  • Автор — Павло Скоропляс
  • Продюсер — Світлана Коваль
  • Стилі — Дмитро Бойко
  • Ілюстрації — Кшиштоф Шпак
  • Верстка — Зара Аракелян
  • Розробка — Олександр Пупко
  • Керівник — Влад Ліхута