Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

price aggregator multi-query #809

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 66 additions & 16 deletions contracts/core/price-aggregator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

elrond_wasm::imports!();

mod events;
pub mod median;
pub mod price_aggregator_data;
pub mod staking;
mod events;

use price_aggregator_data::{OracleStatus, PriceFeed, TimestampedPrice, TokenPair};
use price_aggregator_data::{
OracleStatus, PriceFeed, PriceFeedMultiValue, TimestampedPrice, TokenPair,
};

const SUBMISSION_LIST_MAX_LEN: usize = 50;
const FIRST_SUBMISSION_TIMESTAMP_MAX_DIFF_SECONDS: u64 = 30;
Expand Down Expand Up @@ -264,40 +266,88 @@ pub trait PriceAggregator:
result
}

#[view(latestPriceFeed)]
fn latest_price_feed(
fn get_price_feed(
&self,
from: ManagedBuffer,
to: ManagedBuffer,
) -> SCResult<MultiValue6<u32, ManagedBuffer, ManagedBuffer, u64, BigUint, u8>> {
) -> SCResult<PriceFeed<Self::Api>> {
require_old!(self.not_paused(), PAUSED_ERROR_MSG);

let token_pair = TokenPair { from, to };
let round_values = self
.rounds()
.get(&token_pair)
.ok_or("token pair not found")?;
let feed = self.make_price_feed(token_pair, round_values);
Ok((
feed.round_id,
feed.from,
feed.to,
feed.timestamp,
feed.price,
feed.decimals,
)
.into())

Ok(self.make_price_feed(token_pair, round_values))
}

#[view(latestPriceFeed)]
fn latest_price_feed(
&self,
from: ManagedBuffer,
to: ManagedBuffer,
) -> SCResult<PriceFeedMultiValue<Self::Api>> {
let result_price_feed = self.get_price_feed(from, to);
match result_price_feed {
SCResult::Ok(feed) => Ok(feed.into_multi_value()),
SCResult::Err(err) => SCResult::Err(err),
}
}

#[view(latestPriceFeedOptional)]
fn latest_price_feed_optional(
&self,
from: ManagedBuffer,
to: ManagedBuffer,
) -> OptionalValue<MultiValue6<u32, ManagedBuffer, ManagedBuffer, u64, BigUint, u8>> {
) -> OptionalValue<PriceFeedMultiValue<Self::Api>> {
self.latest_price_feed(from, to).ok().into()
}

/// Receives pairs of (from, to) arguments,
/// where `from` is the token ticker which we query the price for,
/// and `to` is the token ticker in which we want the price to be denominated in.
///
/// For example, if we want the USDC price of EGLD, we would pass "(EGLD, USDC)",
/// even if the USDC full token ID would be something like USDC-abcdef. Only ticker is needed.
///
/// Returns all the prices. Will fail if one of the prices of not available.
/// If you want to do error handling yourself, use the `latestPriceFeedOptionalMulti` view.
#[view(latestPriceFeedMulti)]
fn latest_price_feed_multi(
&self,
from_to_pairs: MultiValueEncoded<MultiValue2<ManagedBuffer, ManagedBuffer>>,
) -> SCResult<MultiValueEncoded<PriceFeedMultiValue<Self::Api>>> {
let mut results = MultiValueEncoded::new();
for pair in from_to_pairs {
let (from, to) = pair.into_tuple();
let price_feed = self.latest_price_feed(from, to)?;
results.push(price_feed);
}

Ok(results)
}

/// Same as the `latestPriceFeedMulti` view, but instead,
/// returns Option<Price> instead of signalling an error if any prices are missing.
#[view(latestPriceFeedOptionalMulti)]
fn latest_price_feed_optional_multi(
&self,
from_to_pairs: MultiValueEncoded<MultiValue2<ManagedBuffer, ManagedBuffer>>,
) -> MultiValueEncoded<Option<PriceFeed<Self::Api>>> {
let mut results = MultiValueEncoded::new();
for pair in from_to_pairs {
let (from, to) = pair.into_tuple();
let result_price_feed = self.get_price_feed(from, to);
match result_price_feed {
SCResult::Ok(price_feed) => results.push(Some(price_feed)),
SCResult::Err(_) => results.push(None),
};
}

results
}

#[only_owner]
#[endpoint(setSubmissionCount)]
fn set_submission_count(&self, submission_count: usize) {
Expand Down
17 changes: 17 additions & 0 deletions contracts/core/price-aggregator/src/price_aggregator_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ pub struct TokenPair<M: ManagedTypeApi> {
pub to: ManagedBuffer<M>,
}

pub type PriceFeedMultiValue<M> =
MultiValue6<u32, ManagedBuffer<M>, ManagedBuffer<M>, u64, BigUint<M>, u8>;

#[derive(NestedEncode, NestedDecode, TopEncode, TopDecode, TypeAbi)]
pub struct PriceFeed<M: ManagedTypeApi> {
pub round_id: u32,
Expand All @@ -17,6 +20,20 @@ pub struct PriceFeed<M: ManagedTypeApi> {
pub decimals: u8,
}

impl<M: ManagedTypeApi> PriceFeed<M> {
pub fn into_multi_value(self) -> PriceFeedMultiValue<M> {
(
self.round_id,
self.from,
self.to,
self.timestamp,
self.price,
self.decimals,
)
.into()
}
}

#[derive(TopEncode, TopDecode, TypeAbi, Debug, PartialEq, Eq)]
pub struct TimestampedPrice<M: ManagedTypeApi> {
pub price: BigUint<M>,
Expand Down
2 changes: 2 additions & 0 deletions contracts/core/price-aggregator/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ elrond_wasm_node::wasm_endpoints! {
getPairDecimals
isPaused
latestPriceFeed
latestPriceFeedMulti
latestPriceFeedOptional
latestPriceFeedOptionalMulti
latestRoundData
pause
removeOracles
Expand Down