Skip to content

Latest commit

 

History

History
159 lines (115 loc) · 9.34 KB

band-protocol.md

File metadata and controls

159 lines (115 loc) · 9.34 KB

Band Protocol

In addition to data native to the ICON blockchain, ICON developers also have access to various cryptocurrency price data provided by Band Protocol’s oracle.

Standard Reference Dataset Contract Info

Data Available

The price data originates from data requests made on BandChain. Band’s std_reference SCORE on ICON then retrieves and stores the results of those requests. Specifically, the following price pairs are available to be read from the std_reference_proxy contract:

  • BTC/USD
  • ETH/USD
  • ICX/USD

These prices are automatically updated every 5 minutes. The std_reference_proxy itself is currently deployed on ICON Yeouido testnet at cx61a36e5d10412e03c907a507d1e8c6c3856d9964.

The prices themselves are the median of the values retrieved by BandChain’s validators from many sources including CoinGecko, CryptoCompare, Binance, CoinMarketcap, HuobiPro, CoinBasePro, Kraken, Bitfinex, Bittrex, BITSTAMP, OKEX, FTX, HitBTC, ItBit, Bithumb, CoinOne. The data request is then made by executing Band’s aggregator oracle script, the code of which you can view on Band’s proof-of-authority mainnet. Along with the price data, developers will also have access to the latest timestamp the price was updated.

These parameters are intended to act as security parameters to help anyone using the data to verify that the data they are using is what they expect and, perhaps more importantly, actually valid.

Standard Reference Dataset Contract Price Update Process

For the ease of development, the Band Foundation will be maintaining and updating the std_reference contract with the latest price data. In the near future, we will be releasing guides on how developers can create similar contracts themselves to retrieve data from Band’s oracle.

Retrieving the Price Data

The code below shows an example of a relatively simple price database SCORE on ICON which retrieve price data from Band’s std_reference_proxy contract and store it in the contract’s state.

===================
|                 |
| simple price db |
|                 |
===================
 |               ^
 |(1)            |(4)
 |Asking for     |Return
 |price data     |result
 |               |
 v               |
===================   (2) Ask     ===================
|                 |-------------->|                 |
|  std ref proxy  |               |     std ref     |
|                 |<--------------|                 |
===================   (3) Result  ===================

The contract is able to store exchange rate of any price pair that available on the std_reference contract. For more information on what oracle scripts are and how data requests work on BandChain in general, please see their wiki and developer documentation

from iconservice import *

TAG = "SimplePriceDB"

# Interface of StdReferenceProxy
class IStdReferenceProxy(InterfaceScore):
    @interface
    def get_reference_data(self, _base: str, _quote: str) -> dict:
        pass

    @interface
    def get_reference_data_bulk(self, _bases: str, _quotes: str) -> list:
        pass


# SimplePriceDB contract
class SimplePriceDB(IconScoreBase):
    def __init__(self, db: IconScoreDatabase) -> None:
        super().__init__(db)
        self.std_reference_proxy_address = VarDB(
            "std_reference_proxy_address", db, value_type=Address
        )
        self.prices = DictDB("prices", db, value_type=int)

    def on_install(self, _proxy: Address) -> None:
        super().on_install()
        self.set_proxy(_proxy)

    def on_update(self) -> None:
        super().on_update()

    # Get price of the given pair multiply by 1e18.
    # For example "BTC/ETH" -> 30.09 * 1e18.
    @external(readonly=True)
    def get_price(self, _pair: str) -> int:
        return self.prices[_pair]

    # Sets the proxy contract address, which can only be set by the owner.
    @external
    def set_proxy(self, _proxy: Address) -> None:
        if self.msg.sender != self.owner:
            self.revert("NOT_AUTHORIZED")

        self.std_reference_proxy_address.set(_proxy)

    # This function accepts the string coin pairs such as "BTC/ETH".
    # And then pass it to the std_reference_proxy. After receiving the output
    # from the std_reference_proxy, the exchange rate of the input pair
    # is recorded into the state.
    @external
    def set_single(self, _pair: str) -> None:
        proxy = self.create_interface_score(
            self.std_reference_proxy_address.get(), IStdReferenceProxy
        )
        base, quote = _pair.split("/")
        result = proxy.get_reference_data(base, quote)

        self.prices[_pair] = result["rate"]

    # This function accepts the string of the encoding of an array of coin pairs
    # such as '["BTC/ETH", "ETH/USD", "USDT/USD"]'. And then transform the format
    # of the input to pass it to the std_reference_proxy. After receiving the output
    # from the std_reference_proxy, each pair's rate is recorded into the state.
    @external
    def set_multiple(self, _json_pairs: str) -> None:
        proxy = self.create_interface_score(
            self.std_reference_proxy_address.get(), IStdReferenceProxy
        )

        pairs = json_loads(_json_pairs)
        bases, quotes = [json_dumps(x) for x in zip(*[pair.split("/") for pair in pairs])]
        results = proxy.get_reference_data_bulk(bases, quotes)

        if len(pairs) != len(results):
            self.revert("LEN_PAIRS_MUST_EQUAL_TO_LEN_RESULTS")

        for pair, result in zip(pairs, results):
            self.prices[pair] = result["rate"]

Code Breakdown

The example code above can be broken down into two sections: defining the interface for the IStdReferenceProxy and the actual SimplePriceDB SCORE code itself.

IStdReferenceProxy Interface

This section consists of two functions, get_reference_data and get_reference_data_bulk. This is the interface that we’ll use to query price from Band oracle for the latest price of a token or a bunch of tokens.

SimplePriceDB class

The SimplePriceDB then contains the main logic of our SCORE. It’s purpose will be to store the latest price of tokens.

The actual price data query can then be called through the get_price function. Before we can call the method, however, we need to first set the address of the std_reference_proxy. This is done by calling the set_proxy method or constructor. After that the price should be set by calling set_single or set_multiple.

The set_single function will simply calling get_reference_data from std_reference_proxy with base symbol and quote symbol. It then extract the exchange rate from the result and save to the state.

The set_multiple function converts the input into an array of base symbol and quote symbol arrays. After that it will call get_reference_data_bulk from std_reference_proxy with base symbols and quote symbols. It then extract the exchange rates from the results and save all of them to the state.

The full source code for the SimplePriceDB score can be found in this repo along with the JSON for sending the set_proxy, set_single, set_multiple. The score itself is also deployed to the testnet at address cxd8b7e45dad9a111254f1d3168931e9ca562bc534.

Band Contracts

  • Band Testnet Proxy cx61a36e5d10412e03c907a507d1e8c6c3856d9964
  • Band Testnet Bridge cxc79c2120992356eac409d5cf5ff650f2780a6995
  • Band Testnet Relay cxb94de9090263f03c617d7e1ca767c23ca4efc6f2
  • Band Mainnet Proxy cxe647e0af68a4661566f5e9861ad4ac854de808a2
  • Band Mainnet Bridge cx087b4164a87fdfb7b714f3bafe9dfb050fd6b132
  • Band Mainnet Relay cx3ba7f485dca73db634f116c21995eb89e3994f36