From 33329a2be193eb1bf82c2e5bb2cfe6259cda5ba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B1=E6=98=8A?= <qiuhao951@gmail.com> Date: Wed, 13 Nov 2019 08:18:06 +0800 Subject: [PATCH] feat: prices module (#23) * feat: prices module * fix: add check to avoid dividing by zero * fix: delete num_traits dependency --- Cargo.dev.toml | 1 + prices/Cargo.toml | 32 +++++++++++++++++ prices/src/lib.rs | 37 ++++++++++++++++++++ prices/src/mock.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++ prices/src/tests.rs | 30 ++++++++++++++++ 5 files changed, 183 insertions(+) create mode 100644 prices/Cargo.toml create mode 100644 prices/src/lib.rs create mode 100644 prices/src/mock.rs create mode 100644 prices/src/tests.rs diff --git a/Cargo.dev.toml b/Cargo.dev.toml index d3408d2..cbb1ce1 100644 --- a/Cargo.dev.toml +++ b/Cargo.dev.toml @@ -3,6 +3,7 @@ members = [ "oracle", "tokens", "traits", + "prices", "utilities", "auction", ] diff --git a/prices/Cargo.toml b/prices/Cargo.toml new file mode 100644 index 0000000..b8ae725 --- /dev/null +++ b/prices/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "orml-prices" +version = "0.1.0" +authors = ["Acala Developers"] +edition = "2018" + +[dependencies] +serde = { version = "1.0", optional = true } +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false } +sr-primitives = { git = "https://github.com/paritytech/substrate.git", default-features = false } +srml-support = { package = "srml-support", git = "https://github.com/paritytech/substrate.git", default-features = false } +srml-system = { package = "srml-system", git = "https://github.com/paritytech/substrate.git", default-features = false } +runtime_io = { package = "sr-io", git = "https://github.com/paritytech/substrate.git", default-features = false } + +traits = { package = "orml-traits", path = "../traits", default-features = false } +utilities = { package = "orml-utilities", path = "../utilities", default-features = false } + +[dev-dependencies] +primitives = { package = "substrate-primitives", git = "https://github.com/paritytech/substrate.git", default-features = false } + +[features] +default = ["std"] +std = [ + "serde", + "codec/std", + "sr-primitives/std", + "srml-support/std", + "srml-system/std", + "runtime_io/std", + "traits/std", + "utilities/std", +] diff --git a/prices/src/lib.rs b/prices/src/lib.rs new file mode 100644 index 0000000..645cafd --- /dev/null +++ b/prices/src/lib.rs @@ -0,0 +1,37 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use sr_primitives::traits::{MaybeSerializeDeserialize, Member, SimpleArithmetic, Zero}; +use srml_support::{decl_module, decl_storage, Parameter}; +use srml_system as system; +use traits::{DataProvider, PriceProvider}; + +pub trait Trait: system::Trait { + type CurrencyId: Parameter + Member + Default + Copy + MaybeSerializeDeserialize; + type Price: Parameter + Member + Zero + SimpleArithmetic + Copy + Ord; + type Source: DataProvider<Self::CurrencyId, Self::Price>; +} + +mod mock; +mod tests; + +decl_storage! { + trait Store for Module<T: Trait> as Prices { } +} + +decl_module! { + pub struct Module<T: Trait> for enum Call where origin: T::Origin { } +} + +impl<T: Trait> Module<T> {} + +impl<T: Trait> PriceProvider<T::CurrencyId, T::Price> for Module<T> { + fn get_price(base: T::CurrencyId, quote: T::CurrencyId) -> Option<T::Price> { + if let (Some(base_price), Some(quote_price)) = (T::Source::get(&base), (T::Source::get("e))) { + if !base_price.is_zero() { + return Some(quote_price / base_price); + } + } + + None + } +} diff --git a/prices/src/mock.rs b/prices/src/mock.rs new file mode 100644 index 0000000..5e86008 --- /dev/null +++ b/prices/src/mock.rs @@ -0,0 +1,83 @@ +//! Mocks for the prices module. + +#![cfg(test)] + +use primitives::H256; +use sr_primitives::{testing::Header, traits::IdentityLookup, Perbill}; +use srml_support::{impl_outer_origin, parameter_types}; + +use super::*; + +impl_outer_origin! { + pub enum Origin for Runtime {} +} + +// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Runtime; +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); +} + +pub type AccountId = u64; +pub type BlockNumber = u64; + +impl system::Trait for Runtime { + type Origin = Origin; + type Index = u64; + type BlockNumber = BlockNumber; + type Call = (); + type Hash = H256; + type Hashing = ::sr_primitives::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup<Self::AccountId>; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); +} + +type Price = u32; +type CurrencyId = u32; + +pub struct MockDataProvider; +impl DataProvider<CurrencyId, Price> for MockDataProvider { + fn get(currency: &CurrencyId) -> Option<Price> { + match currency { + 0 => Some(0), + 1 => Some(1), + 2 => Some(2), + _ => None, + } + } +} + +impl Trait for Runtime { + type CurrencyId = CurrencyId; + type Price = Price; + type Source = MockDataProvider; +} + +pub type PricesModule = Module<Runtime>; + +pub struct ExtBuilder; + +impl Default for ExtBuilder { + fn default() -> Self { + ExtBuilder + } +} + +impl ExtBuilder { + pub fn build(self) -> runtime_io::TestExternalities { + let t = system::GenesisConfig::default().build_storage::<Runtime>().unwrap(); + + t.into() + } +} diff --git a/prices/src/tests.rs b/prices/src/tests.rs new file mode 100644 index 0000000..ac07fc9 --- /dev/null +++ b/prices/src/tests.rs @@ -0,0 +1,30 @@ +//! Unit tests for the prices module. + +#![cfg(test)] + +use super::*; +use mock::{ExtBuilder, PricesModule}; + +#[test] +fn get_price_should_work() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(PricesModule::get_price(1, 2), Some(2)); + }); +} + +#[test] +fn price_is_none_should_not_panic() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(PricesModule::get_price(3, 3), None); + assert_eq!(PricesModule::get_price(3, 1), None); + assert_eq!(PricesModule::get_price(1, 3), None); + }); +} + +#[test] +fn price_is_zero_should_not_panic() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(PricesModule::get_price(0, 0), None); + assert_eq!(PricesModule::get_price(1, 0), Some(0)); + }); +} -- GitLab