Как перейти на dAPI: руководство для разработчиков по переходу на Oracle

Как перейти на dAPI: руководство для разработчиков по переходу на Oracle

13 апреля 2023 г.

Оракулы обеспечивают смарт-контрактам безопасный и надежный способ доступа к рыночным данным в режиме реального времени, что необходимо для различных приложений DeFi.

API3 разработал узел оракула, которым управляет поставщик API, удалив промежуточный уровень узла или посредника. Это изменение в архитектуре оракула создает масштабируемое и прозрачное решение, которое позволяет агрегировать собственные оракулы в соответствии с требованиями пользователя. Протоколы DeFi, стремящиеся использовать собственные оракулы, делают это путем интеграции dAPI в свои смарт-контракты.

Для разработчиков dAPI были разработаны с простым процессом интеграции, который абстрагируется от технической реализации доступа к потокам данных. API3 Market предоставляет возможность управлять этими потоками данных, предоставляя пользователям доступ к целому ряду собственных каналов данных. В будущем после интеграции dAPI будут доступны дополнительные службы подачи данных, такие как сбор Oracle Extracted Value (OEV). .

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

Выбор контракта

Чтобы продемонстрировать, насколько легко выполнить перенос с Chainlink на API3, мы собираемся перенести контракт опционов DeFi из этого Cучебник по хайлинку.

Нам не нужно просматривать весь контракт, потому что мы будем изменять только небольшую часть контракта, чтобы перенести его, но в целом контракт позволяет пользователям создавать, покупать, исполнять и отменять опционы в рамках контракта, используя Токены Ethereum (ETH) и Chainlink (LINK). Он использует интерфейс агрегатора Chainlink для получения информации о ценах при исполнении опционов. Более подробное объяснение вы можете найти в полном руководстве.

Теперь давайте посмотрим на код, который мы хотим изменить:

pragma solidity ^0.8.17;

import "https://github.com/smartcontractkit/chainlink/blob/develop/evm-contracts/src/v0.6/interfaces/LinkTokenInterface.sol";
import "https://github.com/smartcontractkit/chainlink/blob/master/evm-contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";

contract chainlinkOptions {
    //Pricefeed interfaces
    AggregatorV3Interface internal ethFeed;
    AggregatorV3Interface internal linkFeed;
    //Interface for LINK token functions
    LinkTokenInterface internal LINK;
    uint ethPrice;
    uint linkPrice;
    //Precomputing hash of strings
    bytes32 ethHash = keccak256(abi.encodePacked("ETH"));
    bytes32 linkHash = keccak256(abi.encodePacked("LINK"));
    address payable contractAddr;

    //Options stored in arrays of structs
    struct option {
        uint strike; //Price in USD (18 decimal places) option allows buyer to purchase tokens at
        uint premium; //Fee in contract token that option writer charges
        uint expiry; //Unix timestamp of expiration time
        uint amount; //Amount of tokens the option contract is for
        bool exercised; //Has option been exercised
        bool canceled; //Has option been canceled
        uint id; //Unique ID of option, also array index
        uint latestCost; //Helper to show last updated cost to exercise
        address payable writer; //Issuer of option
        address payable buyer; //Buyer of option
    }
    option[] public ethOpts;
    option[] public linkOpts;

    //Kovan feeds: https://docs.chain.link/docs/reference-contracts
    constructor() public {
        //ETH/USD Kovan feed
        ethFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);
        //LINK/USD Kovan feed
        linkFeed = AggregatorV3Interface(0x396c5E36DD0a0F5a5D33dae44368D4193f69a1F0);
        //LINK token address on Kovan
        LINK = LinkTokenInterface(0xa36085F69e2889c224210F603D836748e7dC0088);
        contractAddr = payable(address(this));
    }

    //Returns the latest ETH price
    function getEthPrice() public view returns (uint) {
        (
            uint80 roundID, 
            int price,
            uint startedAt,
            uint timeStamp,
            uint80 answeredInRound
        ) = ethFeed.latestRoundData();
        // If the round is not complete yet, timestamp is 0
        require(timeStamp > 0, "Round not complete");
        //Price should never be negative thus cast int to unit is ok
        //Price is 8 decimal places and will require 1e10 correction later to 18 places
        return uint(price);
    }

    //Returns the latest LINK price
    function getLinkPrice() public view returns (uint) {
        (
            uint80 roundID, 
            int price,
            uint startedAt,
            uint timeStamp,
            uint80 answeredInRound
        ) = linkFeed.latestRoundData();
        // If the round is not complete yet, timestamp is 0
        require(timeStamp > 0, "Round not complete");
        //Price should never be negative thus cast int to unit is ok
        //Price is 8 decimal places and will require 1e10 correction later to 18 places
        return uint(price);
    }

    //Updates prices to latest
    function updatePrices() internal {
        ethPrice = getEthPrice();
        linkPrice = getLinkPrice();
    }

    -----------------------
    -----------------------


}

Контракт инициализирует AggregatorV3Interfaces через конструктор для каналов данных Eth и Link; позже их можно использовать для получения цены. Две функции getEthPrice() и getLinkPrice() используют AggregatorV3Interface для получения и возврата цены. Структура options определяет, как параметры сохраняются при их создании, а также массивы ethOpts и linkOpts для хранения созданных параметров.

Перенос

Перенос контракта на использование dAPI API3 в этом опционном контракте можно выполнить в три простых шага:

  1. Получение прокси-адреса dAPI «ETH/USD» и «LINK/USD» из API3 Market< /а>
  2. Импортируйте интерфейс прокси из репозитория API3 и задайте адреса прокси в конструкторе.
  3. Замените логику getEthPrice() и getLinkPrice() вызовом функции .read() для интерфейса прокси

Вот и все. Вам не нужно иметь какой-либо особый тип токена, чтобы иметь возможность читать из оракула, чтение совершенно бесплатно.

В настоящее время на рынке API3 доступно более 100+ dAPI, которые работают на основе самофинансирования, т. е. вы можете пополнить газовые кошельки, чтобы начать чтение из оракула. Если dAPI уже профинансирован, вам просто нужно скопировать адрес прокси, как показано ниже:

ETH/USD Feed on the market

Вот тот же опционный контракт DeFi, обновленный для использования dAPI API3

pragma solidity ^0.8.17;

import "@api3/contracts/v0.8/interfaces/IProxy.sol";

contract Api3Options {
    //Pricefeed proxies
    address public ethProxy;
    address public linkProxy;
    uint ethPrice;
    uint linkPrice;
    //Precomputing hash of strings
    bytes32 ethHash = keccak256(abi.encodePacked("ETH"));
    bytes32 linkHash = keccak256(abi.encodePacked("LINK"));
    address payable contractAddr;

    //Options stored in arrays of structs
    struct option {
        uint strike; //Price in USD (18 decimal places) option allows buyer to purchase tokens at
        uint premium; //Fee in contract token that option writer charges
        uint expiry; //Unix timestamp of expiration time
        uint amount; //Amount of tokens the option contract is for
        bool exercised; //Has option been exercised
        bool canceled; //Has option been canceled
        uint id; //Unique ID of option, also array index
        uint latestCost; //Helper to show last updated cost to exercise
        address payable writer; //Issuer of option
        address payable buyer; //Buyer of option
    }
    option[] public ethOpts;
    option[] public linkOpts;

    //Kovan feeds: https://docs.chain.link/docs/reference-contracts
    constructor(address _ethProxy, address _linkProxy) public {
        //ETH/USD Proxy on Goerli
        ethProxy = _ethProxy
        //LINK/USD Proxy on Goerli
        linkProxy = _linkProxy
        contractAddr = payable(address(this));
    }

    //Returns the latest ETH price
    function getEthPrice() public view returns (uint) {
        (int224 value,uint32 timestamp) = IProxy(ethProxy).read();
        // if the data feed is being updated with a one day-heartbeat
        // interval, you may want to check for that.
        require(
            timestamp + 1 days > block.timestamp,
            "Timestamp older than one day"
        );
        //Price should never be negative thus cast int to unit is ok
        //Price is 18 decimal places
        return uint(uint224(value));
    }

    //Returns the latest LINK price
    function getLinkPrice() public view returns (uint) {
        (int224 value,uint32 timestamp) = IProxy(linkProxy).read();
        // if the data feed is being updated with a one day-heartbeat
        // interval, you may want to check for that.
        require(
            timestamp + 1 days > block.timestamp,
            "Timestamp older than one day"
        );
        //Price should never be negative thus cast int to unit is ok
        //Price is 18 decimal places
        return uint(uint224(value));
    }

    //Updates prices to latest
    function updatePrices() internal {
        ethPrice = getEthPrice();
        linkPrice = getLinkPrice();
    }

    -----------------------
    -----------------------


}

Как видите, нам нужно было только вызвать .read() в интерфейсе IProxy(ethProxy), чтобы начать чтение из потока данных. В итоге мы получили меньше строк кода и гораздо более простой интерфейс для чтения. Вы можете попробовать запустить контракт самостоятельно на странице REMIX. (Примечание: версия ремикса позволяет открывать и закрывать параметры только в ETH для простоты).

Зачем использовать dAPI?

dAPI были разработаны, чтобы абстрагироваться от технической реализации фидов данных. После импорта dAPI в контракты оракула DAO API3 может перенаправить сопоставление dAPI по запросам пользователей. Это означает, что фиды данных могут быть переведены с самофинансируемых на управляемые dAPI или направлены на чтение альтернативных справочных данных без технической реализации.

Любое обновление каналов данных или их отсутствие может создать возможности для OEV, такие как арбитраж и ликвидация. Во время каждого из этих взаимодействий ценность утекает от пользователей dApp как к поисковикам, так и к валидаторам. После интеграции dAPI протоколы DeFi смогут получать Oracle Extractable Value без какой-либо дополнительной технической реализации.

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


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE