Skip to content

Commit

Permalink
feat(dispatcher_with_tests): Crypto router contract OK
Browse files Browse the repository at this point in the history
  • Loading branch information
akhercha committed Sep 16, 2024
1 parent a385f17 commit 1fab603
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 25 deletions.
2 changes: 1 addition & 1 deletion cairo/Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ dependencies = [
[[package]]
name = "pragma_lib"
version = "1.0.0"
source = "git+https://github.com/astraly-labs/pragma-lib?branch=chore%2Fbump_scarb#c36c0bad5661176a171d3988fb4235da4883343c"
source = "git+https://github.com/astraly-labs/pragma-lib?rev=86d7ccd#86d7ccdc15b349b8b48d9796fc8464c947bea6e1"

[[package]]
name = "pragma_maths"
Expand Down
2 changes: 1 addition & 1 deletion cairo/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ starknet = "2.8.2"
openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", branch = "upgrade-edition-2024-07" }

# Pragma Oracle
pragma_lib = { git = "https://github.com/astraly-labs/pragma-lib", branch = "chore/bump_scarb" }
pragma_lib = { git = "https://github.com/astraly-labs/pragma-lib", rev = "86d7ccd" }

# Alexandria (same version than Hyperlane)
alexandria_bytes = { git = "https://github.com/keep-starknet-strange/alexandria.git" }
Expand Down
22 changes: 11 additions & 11 deletions cairo/crates/pragma_dispatcher/src/dispatcher/contract.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub mod PragmaDispatcher {
pragma_feed_registry: IPragmaFeedsRegistryDispatcher,
// Hyperlane mailbox contract
hyperlane_mailbox: IMailboxDispatcher,
// Feed routers
// Feed routers for each asset class
routers: Map<AssetClass, IAssetClassRouterDispatcher>,
}

Expand Down Expand Up @@ -131,6 +131,9 @@ pub mod PragmaDispatcher {
///
/// The updates are dispatched through a Message, which format is:
/// - [u32] number of feeds updated,
/// - [X bytes] update per message. The number of bytes sent depends
/// for each type of asset_class->feed_type.
/// Check the Pragma documentation for more information.
///
/// Steps:
/// 1. Check that all feeds are valids. We are doing that because we need
Expand All @@ -152,11 +155,10 @@ pub mod PragmaDispatcher {
let nb_feeds_to_update: u32 = feed_ids.len();
update_message.append_u32(nb_feeds_to_update);

for i in 0
..nb_feeds_to_update {
// [Effect] Add the feed update to the message
self.add_feed_update_to_message(ref update_message, *feed_ids.at(i));
};
// [Effect] For each feed, add the update to the message
for feed_id in feed_ids {
self.add_feed_update_to_message(ref update_message, *feed_id);
};

// [Interaction] Send the complete message to Hyperlane's Mailbox
self.call_dispatch(update_message)
Expand Down Expand Up @@ -188,6 +190,7 @@ pub mod PragmaDispatcher {
contract_address: pragma_feed_registry_address
};
self.pragma_feed_registry.write(pragma_feeds_registry);

let hyperlane_mailbox = IMailboxDispatcher {
contract_address: hyperlane_mailbox_address
};
Expand All @@ -208,18 +211,15 @@ pub mod PragmaDispatcher {
// [Check] Feed id is valid
let feed: Feed = match FeedTrait::from_id(feed_id) {
Result::Ok(f) => f,
Result::Err(e) => {
// This should NEVER happen as we have a check in the Feeds Registry.
panic_with_felt252(e.into())
}
Result::Err(e) => { panic_with_felt252(e.into()) }
};

// [Check] Feed's asset class router is registered
let router = self.routers.entry(feed.asset_class).read();
assert(!router.is_zero(), errors::NO_ROUTER_REGISTERED);

// [Effect] Retrieve the feed update and add it to the message
let feed_update_message = router.routing(feed);
let feed_update_message = router.get_feed_update(feed);
message.concat(@feed_update_message);
}
}
Expand Down
2 changes: 1 addition & 1 deletion cairo/crates/pragma_dispatcher/src/dispatcher/errors.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pub const OWNER_IS_ZERO: felt252 = 'Owner cannot be 0';
pub const PRAGMA_FEED_REGISTRY_IS_ZERO: felt252 = 'Feed Registry cannot be 0';
pub const HYPERLANE_MAILBOX_IS_ZERO: felt252 = 'Hyperlane Mailbox cannot be 0';

pub const FEED_NOT_REGISTERED: felt252 = 'Feed ID not registered';
pub const FEED_NOT_REGISTERED: felt252 = 'One feed id is not registered';

pub const UNKNOWN_ASSET_CLASS: felt252 = 'Unknown asset class';
pub const NO_ROUTER_REGISTERED: felt252 = 'No router registered';
101 changes: 93 additions & 8 deletions cairo/crates/pragma_dispatcher/src/routers/crypto.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ pub mod CryptoRouter {
use pragma_dispatcher::routers::{
errors, interface::{IAssetClassRouter, IPragmaOracleWrapper, ISummaryStatsWrapper}
};
use pragma_dispatcher::types::pragma_oracle::{SummaryStatsComputation};
use pragma_feed_types::{Feed, FeedType};
use pragma_dispatcher::types::pragma_oracle::SummaryStatsComputation;
use pragma_feed_types::{Feed, FeedTrait, FeedType};
use pragma_lib::abi::{
IPragmaABIDispatcher, IPragmaABIDispatcherTrait, ISummaryStatsABIDispatcher,
ISummaryStatsABIDispatcherTrait
};
use pragma_lib::types::{PragmaPricesResponse, DataType, AggregationMode};
use pragma_lib::types::{PragmaPricesResponse, OptionsFeedData, DataType, AggregationMode};
use starknet::ContractAddress;
use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};

Expand Down Expand Up @@ -47,7 +47,7 @@ pub mod CryptoRouter {

#[abi(embed_v0)]
pub impl CryptoRouterImpl of IAssetClassRouter<ContractState> {
fn routing(self: @ContractState, feed: Feed) -> Bytes {
fn get_feed_update(self: @ContractState, feed: Feed) -> Bytes {
match feed.feed_type {
FeedType::SpotMedian => self.spot_median(feed),
FeedType::Twap => self.twap(feed),
Expand All @@ -64,19 +64,97 @@ pub mod CryptoRouter {
fn initializer(ref self: ContractState,) {}

fn spot_median(self: @ContractState, feed: Feed) -> Bytes {
BytesTrait::new_empty()
let data_type = DataType::SpotEntry(feed.pair_id);
let aggregation_mode = AggregationMode::Median;

let response = self.call_get_data(data_type, aggregation_mode);

let mut update = BytesTrait::new_empty();
update.append_u256(feed.id().into());
update.append_u64(response.last_updated_timestamp);
update.append_u16(response.num_sources_aggregated.try_into().unwrap());
update.append_u8(response.decimals.try_into().unwrap());
update.append_u256(response.price.into());
update.append_u256(0); // TODO: volume

update
}

fn twap(self: @ContractState, feed: Feed) -> Bytes {
BytesTrait::new_empty()
let data_type = DataType::SpotEntry(feed.pair_id);
let aggregation_mode = AggregationMode::Median;
let start_timestamp = 1;
let duration = 1;

let (twap_price, decimals) = self
.call_calculate_twap(data_type, aggregation_mode, start_timestamp, duration);

let mut update = BytesTrait::new_empty();
update.append_u256(feed.id().into());
update.append_u64(start_timestamp); // TODO: timestamp
update.append_u16(0); // TODO: number of sources
update.append_u8(decimals.try_into().unwrap());
update.append_u256(twap_price.into());
update.append_u256(duration.into()); // TODO: time period
update.append_u256(0); // TODO: start_price
update.append_u256(0); // TODO: end_price
update.append_u256(0); // TODO: total volume
update.append_u256(0); // TODO: number of data points

update
}

fn realized_volatility(self: @ContractState, feed: Feed) -> Bytes {
BytesTrait::new_empty()
let data_type = DataType::SpotEntry(feed.pair_id);
let aggregation_mode = AggregationMode::Median;
let start_timestamp = 1;
let end_timestamp = 2;
let num_samples = 10;

let (volatility, decimals) = self
.call_calculate_volatility(
data_type, aggregation_mode, start_timestamp, end_timestamp, num_samples
);

let mut update = BytesTrait::new_empty();
update.append_u256(feed.id().into());
update.append_u64(start_timestamp); // TODO: timestamp
update.append_u16(0); // TODO: number of sources
update.append_u8(decimals.try_into().unwrap());
update.append_u256(volatility.into());
update.append_u256(0); // TODO: time period
update.append_u256(0); // TODO: start price
update.append_u256(0); // TODO: end price
update.append_u256(0); // TODO: high price
update.append_u256(0); // TODO: low price
update.append_u256(0); // TODO: number of data points

update
}

fn option(self: @ContractState, feed: Feed) -> Bytes {
BytesTrait::new_empty()
let instrument_name = feed.pair_id;

let response = self.call_get_options_data(instrument_name);

let mut update = BytesTrait::new_empty();
update.append_u256(feed.id().into());
update.append_u64(response.current_timestamp);
update.append_u16(1);
update.append_u8(0); // TODO: decimals
update.append_u256(0); // TODO: strike price
update.append_u256(0); // TODO: implied volatility
update.append_u256(0); // TODO: time to expiry <- from instrument_name
update.append_u8(0); // TODO: is call <- from instrument_name
update.append_u256(0); // TODO: underlying price
update.append_u256(response.mark_price.into());
update.append_u256(0); // TODO: delta
update.append_u256(0); // TODO: gamma
update.append_u256(0); // TODO: vega
update.append_u256(0); // TODO: theta
update.append_u256(0); // TODO: rho

update
}

fn perp(self: @ContractState, feed: Feed) -> Bytes {
Expand Down Expand Up @@ -138,5 +216,12 @@ pub mod CryptoRouter {
.read()
.calculate_twap(data_type, aggregation_mode, duration, start_timestamp)
}

/// Calls get_options_data from the Summary Stats contract.
fn call_get_options_data(
self: @ContractState, instrument_name: felt252,
) -> OptionsFeedData {
self.summary_stats.read().get_options_data(instrument_name)
}
}
}
3 changes: 3 additions & 0 deletions cairo/crates/pragma_dispatcher/src/routers/errors.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
pub const OWNER_IS_ZERO: felt252 = 'Owner cannot be 0';

pub const FEED_ID_TOO_BIG: felt252 = 'Feed id should fit in u32';
pub const UNSUPPORTED_FEED_TYPE: felt252 = 'Unsupported feed type';

pub const PRAGMA_ORACLE_IS_ZERO: felt252 = 'Pragma Oracle cannot be 0';
pub const SUMMARY_STATS_IS_ZERO: felt252 = 'Summary Stats cannot be 0';
9 changes: 6 additions & 3 deletions cairo/crates/pragma_dispatcher/src/routers/interface.cairo
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use alexandria_bytes::Bytes;
use core::num::traits::Zero;
use pragma_dispatcher::types::pragma_oracle::{SummaryStatsComputation};
use pragma_dispatcher::types::pragma_oracle::SummaryStatsComputation;
use pragma_feed_types::Feed;
use pragma_lib::types::{PragmaPricesResponse, DataType, AggregationMode};
use pragma_lib::types::{PragmaPricesResponse, OptionsFeedData, DataType, AggregationMode};
use starknet::contract_address_const;

#[starknet::interface]
pub trait IAssetClassRouter<TContractState> {
fn routing(self: @TContractState, feed: Feed) -> Bytes;
fn get_feed_update(self: @TContractState, feed: Feed) -> Bytes;
}

#[starknet::interface]
Expand Down Expand Up @@ -47,6 +47,9 @@ pub trait ISummaryStatsWrapper<TContractState> {
start_timestamp: u64,
duration: u64,
) -> SummaryStatsComputation;

/// Calls get_options_data from the Summary Stats contract.
fn call_get_options_data(self: @TContractState, instrument_name: felt252,) -> OptionsFeedData;
}

impl IAssetClassRouterZero of Zero<IAssetClassRouterDispatcher> {
Expand Down

0 comments on commit 1fab603

Please sign in to comment.