Как создать оракул

Waves Platform предоставляет каталог для поиска и создания карточек оракулов — https://oracles.wavesexplorer.com. Используя сервис Waves Oracles, вы можете посмотреть, какие оракулы уже созданы другими разработчиками и какие данные они записывают в блокчейн. Если у вас уже есть оракул, вы можете опубликовать карточку своего оракула, чтобы другие пользователи знали о ее существовании и могли пользоваться его данными.

Создание самого оракула — микросервиса, который берет данные из какого-то источника и записывает их в блокчейн, остается за рамками сервиса Waves Oracles.

В этой статье мы на простом примере познакомим вас с полным циклом создания оракула, который состоит из регистрации карточки оракула в Waves Oracles, создания и развертывания программной части оракула, а также последующего использования данных оракула в тех или иных dApp.

Пример оракула

Примером может служить dApp, которому необходимы данные курса WAVES по отношению доллару США (USD) и по отношению к биткоину (BTC).

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

Для нашего dApp требуются данные котировок, записанные в блокчейне. Поэтому мы создадим новый оракул, который будет раз в час получать соответствующие данные о котировках из публичного API Waves Data Service и сохранять их в блокчейн, и кроме того создадим карточку оракула, чтобы другие пользователи могли также использовать эти данные в своих децентрализованных приложениях.

Реализация программной части оракула

Создадим главную часть оракула — программу, которая получит доступ к котировкам и запишет их в хранилище данных оракула. В примере, используем для этого TypeScript с Node.js. Вы можете использовать Python или любой другой язык программирования. Смотрите список клиентских библиотек.

Cron

Создадим cron, который будет запускать наш сервис для получения данных из API каждый час:

import * as cron from 'node-cron';
import { WavesPrice } from './WavesPrice';
​
// run WavesPrice class every 1 hour
cron.schedule('0 0 */1 * * *', () => {
  new WavesPrice(logger);
});

Получение данных и отправка транзакции

Создадим сам сервис, который будет запрашивать данные из API публичного Waves Data Services.

Получим параметр lastPrice из API, сдвинем точку на нужное количество знаков и присвоим значение соответствующему ключу:

lastPrice = await this.getLastprice('https://api.wavesplatform.com/v0/pairs/WAVES/Ft8X1v1LTa1ABafufpaCWyVj8KkaxUWE6xBhW6sNFJck');
dataParams.push({ key: 'waves_usd_2', value: lastPrice * Math.pow(10, 2) });

lastPrice = await this.getLastprice('https://api.wavesplatform.com/v0/pairs/WAVES/8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS');
dataParams.push({ key: 'waves_btc_8', value: lastPrice * Math.pow(10, 8) });

Самый простой способ создать новый оракул — зарегистрировать для него новый аккаунт. Как это сделать, читайте в разделе создание аккаунта.

Подпишем транзакцию данных при помощи SEED от аккаунта оракула:

const signerDataTX = DataTX(params,'YOU ORACLE SEED HERE');

Отправим подписанную транзакцию данных в блокчейн, Для тестовой сетиpool.testnet.wavesnodes.com, для основной сетиhttps://nodes.wavesnodes.com.

const result = await broadcast(signerDataTX, 'https://nodes.wavesnodes.com');

Помните, что создание карточки оракула, а также все остальные транзакции требуют уплаты комиссии, поэтому не забудьте пополнить баланс аккаунта. Чтобы не платить комиссию, вы можете попробовать создать оракул в тестовой сети.

Итоговый код выглядит следующим образом:

import axios from 'axios';
import { data as DataTX, broadcast } from '@waves/waves-transactions';
​
​
export class WavesPrice {
​
  constructor() {
    this.start();
  }
​
  private async getLastprice(url: string): Promise<number> {
    const data = (await axios.get(url)).data.data;
    return data.lastPrice;
  }
​
  private async broadcastTX(dataParams) {
    const params = {
      data: dataParams
    };
​
    const signerDataTX = DataTX(params,'YOU ORACLE SEED HERE');
    const result = await broadcast(signerDataTX, 'https://nodes.wavesnodes.com');
  }
​
  public async start() {
    try {
      let dataParams = [];
      let lastPrice = 0;
​
      lastPrice = await this.getLastprice('https://api.wavesplatform.com/v0/pairs/WAVES/Ft8X1v1LTa1ABafufpaCWyVj8KkaxUWE6xBhW6sNFJck');
      dataParams.push({ key: 'waves_usd_2', value: lastPrice * Math.pow(10, 2) });
​
      lastPrice = await this.getLastprice('https://api.wavesplatform.com/v0/pairs/WAVES/8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS');
      dataParams.push({ key: 'waves_btc_8', value: lastPrice * Math.pow(10, 8) });
​
      await this.broadcastTX(dataParams);
    } catch(err) {
      console.log(err);
    }
  }
}

Зависимости проекта

Опишем зависимости проекта:

{
  "name": "balance-oracle",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "axios": "0.19.0",
    "node-cron": "2.0.3",
    "@waves/waves-transactions": "3.16.3"
  },
  "scripts": {
    "start": "tsc ./project/src/app.ts && node ./project/src/app.js"
  },
  "devDependencies": {
    "@types/node": "^11.11.3"
  }
}

Запуск оракула

Установите Node.js, если он ещё не установлен: https://nodejs.org/en.

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

$ npm install

Если TypeScript не установлен, следует установить его глобально:

$ npm install -g ts-node typescript

Теперь запустим наш оракул:

$ npm run start

В Waves Explorer мы увидим транзакцию с данными котировок в заданном нами формате (рис. 1):

Рисунок 1.

Создание карточки оракула

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

Waves Oracles использует расширение Waves Keeper.

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

Перейдите в Waves Oracles, авторизуйтесь в Waves Keeper и нажмите кнопку Create an oracle на боковой панели (рис.2).

Рисунок 2.

В появившейся форме заполните информацию об оракуле.

Назовем наш оракул "WAVES/USD and WAVES/BTC" и выберем соответствующую категорию "Market data & exchange rates", чтобы его можно было быстро найти. Укажем статус "Production", так как наш оракул уже работает и доступен. В поле About дадим небольшое описание оракула и принципов его работы. Так как оракул обновляет данные котировок каждый час, укажем это в поле Update frequency.

Верхняя часть формы показана на рис. 3.

Рисунок 3.

Заполним спецификацию и пример ниже.

В нашем случае оракул должен записывать два значения котировок: WAVES/USD и WAVES/BTC. Поэтому мы определим эти два параметра, как показано на рис. 4.

Здесь нужны некоторые пояснения. dApp на RIDE не может использовать значение с плавающей запятой (float), поэтому мы будем использовать целочисленный тип (integer) со сдвигом точки на необходимое количество знаков. В ключе укажем количество знаков, на которое смещается точка: для USD на два знака, для BTC на восемь знаков. В результате будет легко парсить такие ключи с помощью RIDE и видеть, на сколько именно символов необходимо смещать точку.

Также отметим, что такой ключ не является уникальным и в хранилище данных аккаунта всегда будет сохраняться только последнее значение. Вы можете добавить метку времени (timestamp), чтобы сделать каждый ключ уникальным, и таким образом сохранять исторические данные.

Рисунок 4.

После заполнения формы подтвердите транзакцию данных создания карточки оракула в Waves Keeper нажатием Approve. В результате новая карточка оракула успешно зарегистрирована в Waves Oracles. Протокол карточки оракула можно увидеть в Waves Explorer (см. рис. 5). Через некоторое время карточка появится в интерфейсе Waves Oracles.

Рисунок 5.

Использование данных оракула

Поздравляем, теперь наш оракул полностью готов. После сохранения данных в блокчейн, все dApp на RIDE могут получить к ним доступ при помощи методов getInteger(), getString(), getBinary() и getBoolean(). dApp смогут использовать эти данные для своих расчетов, например, для определения размера выплат, отправки транзакций, определения победителей конкурса и так далее.

В нашем случае, для получения из оракула данных по курсу пары WAVES/BTC, нужно в методе getInteger() указать адрес оракула и соответствующий ключ:

getInteger("3PPTrTo3AzR56N7ArzbU3Bpq9zYMgcf39Mk", "waves_btc_8")

results matching ""

    No results matching ""