This repository contains an example Radix application which integrates the Religant Radix Oracle. The instructions here are intended for Radix developers who wish to integrate the Religant Oracle into their own applications.
The Religant Oracle protocol enables a decentralized feed of price data. A set of data nodes query exchanges for up-to-date transactions and submit feed updates to the contract, which employs a consensus mechanism to determine the aggregate price. Data nodes running the Religant node backend software submit feed updates either on a regular interval (if the price is stable), or as soon as the new aggregate price calculated by a node exceeds a specific divergence threshold.
At this time, the divergence threshold is set at 2%. This guarantees that the rate retrieved from the Religant oracle component's feed is always within 2% of the rates being used in real transactions on real exchanges.
The user-facing API of the Religant Oracle consists in a single method:
pub fn get_price(&self) -> Option<PriceData> which takes no arguments returns a data structure:
pub struct PriceData {
pub price: Decimal,
pub timestamp: i64,
}Where the price field is the current XRD/USD exchange rate, and the timestamp field is a POSIX timestamp that that identifies the moment at which the the exchange rate was calculated.
Note that the Option wrapper exists primarily for type safety. The get_price method will always return Some(_) after the first round of Oracle feed aggregation. Consequently, it should generally be safe to assume that you will never receive a None as a result of calling the method on an active Religant oracle component.
(You may, however, wish to check the timestamp. While we aim to provide high reliability, a major internet or cloud hosting outage could cause delays in feed updates, though this would be an extraordinary situation.)
NOTE: These instructions are current as of 11/13/2023. Some of the official documentation may refer to a different method (using different macros), but as of today the method illustrated below is the only one known to work.
Integrating with the Religant Oracle component requires a few small changes to your application's blueprint(s):
FIRST: You must define the PriceData struct outside of your blueprint. E.g., by adding:
#[derive(ScryptoSbor, PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone)]
pub struct PriceData {
pub price: USDValue,
pub timestamp: POSIXTime,
}at the top of the source file containing the component where you wish to use the Religant Oracle method.
SECOND: You must declare the component's API using an extern_blueprint! macro inside of your blueprint module:
#[blueprint]
mod oracle_client {
extern_blueprint! {
"package_rdx1phuhdg98xt90ygva6fgh357vtg20aps8mkmrdy6wn6mp4myn24rhyf",
Religant {
fn get_price(&self) -> Option<PriceData>;
}
}
...THIRD: You must instantiate a reference to the global Religant component as a const inside of your blueprint. It should be possible to instantiate this reference either at the top level of your blueprint module, or inside of a method or function. Here, we do it at the top level:
const RELIGANT: Global<Religant> =
global_component!(Religant, "component_rdx1czqqs4t8f62jeyp47ctyqwmtk3vnf9sffnqd9lu7tgtgtvshj6x9lp");FINALLY: You are free to use the methods of the instantiated component in your own method, for example:
pub fn cash_xrd(&self) -> Bucket {
match RELIGANT.get_price() {
None => {Bucket::new(self.price_token_resource_address)},
Some(price_data) => {
let resource_manager =
ResourceManager::from(self.price_token_resource_address);
resource_manager.mint(price_data.price)
}
}
}In this example, the cash_xrd method calls the Religant get_price method and mints a number of tokens equal to the current XRD/USD exchange rate.
The full integration example contract can be found in this repository's src/lib.rs module.