Оракул Chainlink
Вступление
Теперь разработчики могут использовать децентрализованную сеть Оракулов Chainlink, для сбора данных в Moonbase Alpha TestNet. В этой инструкции рассматриваются два способа использования Оракулов Chainlink:
- Базовая модель запроса — конечный пользователь отправляет запрос провайдеру Оракулов, который извлекает данные по API и выполняет запрос, сохраняя эти данные on-chain.
- Price Feeds (Прайс-фиды) — данные постоянно обновляются операторами Оракулов в смарт-контракте так, чтобы другие смарт-контракты могли их получать.
Базовая Модель Запроса
Прежде чем мы перейдем к извлечению самих данных, важно понять основы “базовой модели запроса”.
Нода Оракула имеет набор job ID, каждый из которых соответствует задаче, выполнение которой пользователь может запросить, например, чтобы получить прайс-фид. Для этого пользователю необходимо отправить запрос через контракт, назовем его Клиентским контрактом, передав следующую информацию:
· Адрес Оракула: адрес контракта, размещенного нодой Оракула
· Job ID: задача, которая должна быть выполнена
· Оплата: оплата в LINK токенах, которые Оракул получит за выполнение запроса
Этот запрос фактически отправляет TransferAndCall в контракт LINK токена, который обрабатывает платеж и ретранслирует запрос в контракт Оракула. Здесь вместе с запросом выдается событие, которое подхватывается нодой Оракула. Затем нода извлекает необходимые данные и выполняет функцию fulfilOracleRequest, которая выполняет колбэк, хранящий запрошенную информацию в Клиентском контракте. Следующая диаграмма объясняет данный процесс.
Клиентский Контракт
Клиентский контракт — это элемент, который запускает интеграцию с Оракулом путем отправки запроса. Как показано на диаграмме, он вызывает метод TransferAndCall из контракта LINK токена, но для отслеживания запроса к Оракулу требуется дополнительная обработка. Для этого примера Вы можете использовать код из данного файла и разместить его на Remix в качестве теста. Давайте рассмотрим основные функции контракта:
- constructor: запускается при размещении контракта. Он устанавливает адрес LINK токена и владельца контракта.
- requestPrice: требует адрес контракта в Оракуле, job ID и токены оплаты (LINK) исполнителя запроса. Создает новый запрос, который отправляется с помощью функции sendChainlinkRequestTo из импорта ChainlinkClient.sol
- fulfill: колбэк, используемый нодой Оракула для выполнения запроса путем сохранения запрашиваемой информации в контракте.
pragma solidity ^0.6.6;
import "https://github.com/smartcontractkit/chainlink/evm-contracts/src/v0.6/ChainlinkClient.sol";
contract Client is ChainlinkClient {
//... there is mode code here
constructor(address _link) public {
// Set the address for the LINK token for the network
setChainlinkToken(_link);
owner = msg.sender;
}
function requestPrice(address _oracle, string memory _jobId, uint256 _payment)
public
onlyOwner
{
// newRequest takes a JobID, a callback address, and callback function as input
Chainlink.Request memory req = buildChainlinkRequest(stringToBytes32(_jobId), address(this), this.fulfill.selector);
// Sends the request with the amount of payment specified to the oracle
sendChainlinkRequestTo(_oracle, req, _payment);
}
function fulfill(bytes32 _requestId, uint256 _price)
public
recordChainlinkFulfillment(_requestId)
{
currentPrice = _price;
}
//... there is more code here
}
Обратите внимание, что Клиентский контракт должен иметь токены LINK на балансе, чтобы иметь возможность оплатить данный запрос. Однако при размещении сетапа можно установить значение LINK равным 0 в контракте ChainlinkClient.sol, но Вам все равно необходимо иметь размещенный в LINK токенах контракт.
Протестируйте это в Moonbase Alpha
Если Вы хотите минимизировать сложности, связанные с размещением контрактов, настройкой ноды Оракула, созданием job ID и т. д., то мы вам поможем.
Для вас доступен кастомный Клиентский контракт на Moonbase Alpha, который делает все запросы к нашему контракту в Оракуле с 0 оплатой. Эти запросы исполняются нодой Оракула, которую мы запускаем. Вы можете попробовать выполнить это на следующем Клиентском контракте, размещенном по адресу 0x6355D6E4f58fB96e859A89423B9d6A8F98aF1f4c
:
pragma solidity ^0.6.6;
/**
* @title Simple Interface to interact with Universal Client Contract
* @notice Client Address 0x6355D6E4f58fB96e859A89423B9d6A8F98aF1f4c
*/
interface ChainlinkInterface {
/**
* @notice Creates a Chainlink request with the job specification ID,
* @notice and sends it to the Oracle.
* @notice _oracle The address of the Oracle contract fixed top
* @notice _payment For this example the PAYMENT is set to zero
* @param _jobId The job spec ID that we want to call in string format
*/
function requestPrice(string calldata _jobId) external;
function currentPrice() external view returns (uint);
}
Это обеспечивает нам две функции:
- requestPrice() — функция, которой нужен только job ID данных, которые Вы хотите запросить. Эта функция запускает цепь событий, описанных ранее.
- currentPrice () — функция представления, которая возвращает последнюю цену, хранящуюся в контракте.
В настоящее время в ноде Оракула имеется набор Job ID для различных прайсов по следующим парам:
Далее используем интерфейсный контракт с Job ID BTC в USD в Remix.
После создания файла и компиляции контракта перейдите на вкладку “Deploy and Run Transactions”, введите адрес Клиентского контракта и нажмите кнопку “At Address”. Убедитесь, что Вы установили “Environment” в “Injected Web3” для подключения к Moonbase Alpha. Это создаст экземпляр Клиентского контракта, с которым Вы сможете взаимодействовать. Используйте функцию requestPrice() для запроса данных соответствующего Job ID. После подтверждения транзакции нужно подождать, пока не завершится весь процесс, указанный ранее. Мы можем проверить цену с помощью функции currentPrice().
Если у Вас есть какая-то конкретная пара, которую Вы хотите, чтобы мы включили в список, не стесняйтесь обращаться к нам через наш сервер в Discord.
Запуск собственного Клиентского контракта
Если Вы хотите запустить свой Клиентский контракт, но используете нашу ноду Оракула, Вы можете сделать это с помощью данных, указанных ниже:
Обратите внимание, что оплата в LINK токенах = 0.
Другие Запросы
Оракулы Chainlink могут предоставлять множество различных типов каналов данных с использованием внешних адаптеров. Однако для простоты наша нода Оракула настроена на предоставление только прайс-фидов.
Если вы заинтересованы в запуске собственной ноды Оракула в Moonbeam, пожалуйста, прочитайте этот гайд. Кроме того, мы рекомендуем ознакомиться с документацией Chainlink на сайте.
Прайс-фиды
Прежде чем мы перейдем к извлечению самих данных, важно понять основы прайс-фидов.
В стандартной конфигурации каждый прайс-фид обновляется децентрализованной сетью Оракула. Каждая нода Оракула получает вознаграждение за публикацию прайс-фидов в контракте Агрегатора. Однако информация обновляется только в том случае, если получено минимальное количество ответов от нод Оракулов (во время раунда агрегации).
Конечный пользователь может получать прайс-фиды с помощью read-only операций через Потребительский контракт, ссылаясь на правильный интерфейс агрегатора (Прокси-контракт). Прокси выступает в качестве промежуточного программного обеспечения для предоставления Потребителю наиболее актуального Агрегатора для конкретного прайс-фида.
Протестируйте это в Moonbase Alpha
Если вы хотите минимизировать сложности, связанные с размещением контрактов, настройкой ноды Оракула, созданием job ID и т. д., то мы Вам поможем.
Мы разместили все необходимые контракты на Moonbase Alpha, чтобы упростить процесс запроса прайс-фидов. В нашей текущей конфигурации мы запускаем только одну ноду Оракула, которая получает цену из одного источника по API. Данные по ценам проверяются каждую минуту и обновляются в смарт-контрактах каждый час, если только отклонение цены не составляет 1%.
Данные хранятся в серии смарт-контрактов (по одному на прайс-фид) и могут быть извлечены с помощью следующего интерфейса:
pragma solidity ^0.6.6;
interface ConsumerV3Interface {
/**
* Returns the latest price
*/
function getLatestPrice() external view returns (int);
/**
* Returns the decimals to offset on the getLatestPrice call
*/
function decimals() external view returns (uint8);
/**
* Returns the description of the underlying price feed aggregator
*/
function description() external view returns (string memory);
}
Это обеспечивает нам три функции:
- функции getLatestPrice(), которая будет считывать последние ценовые данные, доступные в контракте Агрегатора через Прокси;
- функции decimals(), которая возвращает количество десятичных знаков данных;
- функции description(), которая возвращает краткое описание прайс-фида, доступного в запрашиваемом контракте Агрегатора.
В настоящее время существует Потребительский контракт для следующих ценовых пар:
Далее используем интерфейсный контракт для получения прайс-фида BTC в USD с помощью Remix.
После создания файла и компиляции контракта перейдите на вкладку “Deploy and Run Transactions”, введите адрес Потребительского контракта, соответствующий BTC в USD, и нажмите кнопку “At Address”. Убедитесь, что Вы установили “Environment” в “Injected Web3”для подключения к Moonbase Alpha.
Это создаст экземпляр Потребительского контракта, с которым Вы сможете взаимодействовать. Используйте функцию getLatestPrice() для запроса данных соответствующего прайс-фида.
Обратите внимание, что для получения реальной цены необходимо учитывать десятичные дроби прайс-фида, доступные при вызове метода decimals()
.
Если у вас есть какая-то конкретная пара, которую Вы хотите, чтобы мы включили в список, не стесняйтесь обращаться к нам через наш сервер в Discord.
Обратная связь
Если у Вас есть фидбек относительно реализации Chainlink в вашем проекте или по любой другой теме, связанной с Moonbeam, не стесняйтесь обращаться к нам через наш официальный сервер в Discord.
Подготовлено при участии Oksana#9601, Lyn.