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.
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.
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.
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"]
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 Testnet Proxy cx61a36e5d10412e03c907a507d1e8c6c3856d9964
- Band Testnet Bridge cxc79c2120992356eac409d5cf5ff650f2780a6995
- Band Testnet Relay cxb94de9090263f03c617d7e1ca767c23ca4efc6f2
- Band Mainnet Proxy cxe647e0af68a4661566f5e9861ad4ac854de808a2
- Band Mainnet Bridge cx087b4164a87fdfb7b714f3bafe9dfb050fd6b132
- Band Mainnet Relay cx3ba7f485dca73db634f116c21995eb89e3994f36