Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
18 changes: 9 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ format:
.PHONY: try-runtime
try-runtime:
$(cargo) build --release --features try-runtime
try-runtime --runtime ./target/release/wbuild/hydradx-runtime/hydradx_runtime.wasm on-runtime-upgrade --checks all live --uri wss://archive.rpc.hydration.cloud
try-runtime --runtime ./target/release/wbuild/hydradx-runtime/hydradx_runtime.wasm on-runtime-upgrade --blocktime 6000 --checks all live --uri wss://archive.rpc.hydration.cloud

.PHONY: build-docs
build-docs:
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "runtime-integration-tests"
version = "1.45.1"
version = "1.45.2"
description = "Integration tests"
authors = ["GalacticCouncil"]
edition = "2021"
Expand Down
7 changes: 6 additions & 1 deletion integration-tests/src/polkadot_test_net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub use primitives::{constants::chain::CORE_ASSET_ID, AssetId, Balance, Moment};

use cumulus_primitives_core::ParaId;
use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
use frame_support::traits::OnRuntimeUpgrade;
pub use frame_system::RawOrigin;
use hex_literal::hex;
use hydradx_runtime::{evm::WETH_ASSET_LOCATION, Referrals, RuntimeEvent, RuntimeOrigin};
Expand Down Expand Up @@ -843,7 +844,11 @@ pub fn hydra_live_ext(

let builder = Builder::<hydradx_runtime::Block>::new().mode(mode);

builder.build().await.unwrap()
let mut p = builder.build().await.unwrap();
p.execute_with(|| {
pallet_ema_oracle::migrations::v1::MigrateV0ToV1::<hydradx_runtime::Runtime>::on_runtime_upgrade();
});
p
});
ext
}
Expand Down
2 changes: 2 additions & 0 deletions integration-tests/src/stableswap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ fn peg_oracle_adapter_should_work_when_getting_price_from_mm_oracle() {
volume: Default::default(),
liquidity: Default::default(),
updated_at: current_block - blocks_diff as u32,
shares_issuance: Default::default(),
};
assert_eq!(peg, expected_peg)
});
Expand Down Expand Up @@ -174,6 +175,7 @@ fn peg_oracle_adapter_should_not_work_when_mm_oracle_price_was_updated_in_curren
volume: Default::default(),
liquidity: Default::default(),
updated_at: current_block,
shares_issuance: Default::default(),
};
assert_eq!(peg, expected_peg)
});
Expand Down
2 changes: 1 addition & 1 deletion math/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ license = 'Apache-2.0'
name = "hydra-dx-math"
description = "A collection of utilities to make performing liquidity pool calculations more convenient."
repository = 'https://github.com/galacticcouncil/hydradx-math'
version = "10.1.0"
version = "10.2.0"

[dependencies]
primitive-types = { workspace = true }
Expand Down
34 changes: 22 additions & 12 deletions math/src/ema/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,48 @@
pub type EmaPrice = Ratio;
pub type EmaVolume = (Balance, Balance, Balance, Balance);
pub type EmaLiquidity = (Balance, Balance);
pub type EmaSharesIssuance = Option<Balance>;

/// Calculate the new oracle values by integrating `incoming` values with the `previous` oracle.
/// Uses a weighted average based on the `smoothing` factor.
pub fn calculate_new_by_integrating_incoming(
previous: (EmaPrice, EmaVolume, EmaLiquidity),
incoming: (EmaPrice, EmaVolume, EmaLiquidity),
previous: (EmaPrice, EmaVolume, EmaLiquidity, EmaSharesIssuance),
incoming: (EmaPrice, EmaVolume, EmaLiquidity, EmaSharesIssuance),
smoothing: Fraction,
) -> (EmaPrice, EmaVolume, EmaLiquidity) {
let (prev_price, prev_volume, prev_liquidity) = previous;
let (incoming_price, incoming_volume, incoming_liquidity) = incoming;
) -> (EmaPrice, EmaVolume, EmaLiquidity, EmaSharesIssuance) {
let (prev_price, prev_volume, prev_liquidity, shares) = previous;
let (incoming_price, incoming_volume, incoming_liquidity, incoming_shares) = incoming;
let new_price = price_weighted_average(prev_price, incoming_price, smoothing);
let new_volume = volume_weighted_average(prev_volume, incoming_volume, smoothing);
let new_liquidity = liquidity_weighted_average(prev_liquidity, incoming_liquidity, smoothing);
(new_price, new_volume, new_liquidity)
let new_shares_issuance = incoming_shares

Check warning on line 28 in math/src/ema/math.rs

View workflow job for this annotation

GitHub Actions / build

using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`
.and_then(|incoming_s| Some(balance_weighted_average(shares.unwrap_or(0), incoming_s, smoothing)));
(new_price, new_volume, new_liquidity, new_shares_issuance)
}

/// Calculate the current oracle values from the `outdated` and `update_with` values using the `smoothing` factor with the old values being `iterations` out of date.
///
/// Note: The volume is always updated with zero values so it is not a parameter.
pub fn update_outdated_to_current(
iterations: u32,
outdated: (EmaPrice, EmaVolume, EmaLiquidity),
update_with: (EmaPrice, EmaLiquidity),
outdated: (EmaPrice, EmaVolume, EmaLiquidity, EmaSharesIssuance),
update_with: (EmaPrice, EmaLiquidity, EmaSharesIssuance),
smoothing: Fraction,
) -> (EmaPrice, EmaVolume, EmaLiquidity) {
let (prev_price, prev_volume, prev_liquidity) = outdated;
let (incoming_price, incoming_liquidity) = update_with;
) -> (EmaPrice, EmaVolume, EmaLiquidity, EmaSharesIssuance) {
let (prev_price, prev_volume, prev_liquidity, prev_shares) = outdated;
let (incoming_price, incoming_liquidity, incoming_shares) = update_with;
let smoothing = exp_smoothing(smoothing, iterations);
let new_price = price_weighted_average(prev_price, incoming_price, smoothing);
let new_volume = volume_weighted_average(prev_volume, (0, 0, 0, 0), smoothing);
let new_liquidity = liquidity_weighted_average(prev_liquidity, incoming_liquidity, smoothing);
(new_price, new_volume, new_liquidity)
let new_shares = incoming_shares.and_then(|incoming_s| {

Check warning on line 48 in math/src/ema/math.rs

View workflow job for this annotation

GitHub Actions / build

using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`
Some(balance_weighted_average(
prev_shares.unwrap_or(0),
incoming_s,
smoothing,
))
});
(new_price, new_volume, new_liquidity, new_shares)
}

/// Calculate the iterated exponential moving average for the given prices.
Expand Down
16 changes: 12 additions & 4 deletions math/src/ema/tests/invariants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ fn period_fraction() -> impl Strategy<Value = Fraction> {
(typical_period()).prop_map(smoothing_from_period)
}

fn any_shares_issuance() -> impl Strategy<Value = Balance> {
any::<Balance>()
}

prop_compose! {
fn period_and_iterations()(p in long_period())(
period in Just(p),
Expand Down Expand Up @@ -198,12 +202,14 @@ proptest! {
(prev_price, incoming_price) in (any_price(), any_price()),
(prev_volume, incoming_volume) in (any_volume(), any_volume()),
(prev_liquidity, incoming_liquidity) in (any_liquidity(), any_liquidity()),
(prev_shares_issuance, incoming_shares_issuance) in (any_shares_issuance(), any_shares_issuance()),
) {
let simple_price = price_weighted_average(prev_price, incoming_price, smoothing);
let simple_volume = volume_weighted_average(prev_volume, incoming_volume, smoothing);
let simple_liquidity = liquidity_weighted_average(prev_liquidity, incoming_liquidity, smoothing);
let new_oracle = calculate_new_by_integrating_incoming((prev_price, prev_volume, prev_liquidity), (incoming_price, incoming_volume, incoming_liquidity), smoothing);
prop_assert_eq!(new_oracle, (simple_price, simple_volume, simple_liquidity));
let simple_shares_issuance = balance_weighted_average(prev_shares_issuance, incoming_shares_issuance, smoothing);
let new_oracle = calculate_new_by_integrating_incoming((prev_price, prev_volume, prev_liquidity, Some(prev_shares_issuance)), (incoming_price, incoming_volume, incoming_liquidity, Some(incoming_shares_issuance)), smoothing);
prop_assert_eq!(new_oracle, (simple_price, simple_volume, simple_liquidity, Some(simple_shares_issuance)));
}
}

Expand All @@ -215,12 +221,14 @@ proptest! {
(prev_price, incoming_price) in (any_price(), any_price()),
prev_volume in any_volume(),
(prev_liquidity, incoming_liquidity) in (any_liquidity(), any_liquidity()),
(prev_shares_issuance, incoming_shares_issuance) in (any_shares_issuance(), any_shares_issuance()),
) {
let iterated_price = iterated_price_ema(iterations, prev_price, incoming_price, smoothing);
let iterated_volume = iterated_volume_ema(iterations, prev_volume, smoothing);
let iterated_liquidity = iterated_liquidity_ema(iterations, prev_liquidity, incoming_liquidity, smoothing);
let current_oracle = update_outdated_to_current(iterations, (prev_price, prev_volume, prev_liquidity), (incoming_price, incoming_liquidity), smoothing);
prop_assert_eq!(current_oracle, (iterated_price, iterated_volume, iterated_liquidity));
let iterated_shares = iterated_balance_ema(iterations, prev_shares_issuance, incoming_shares_issuance, smoothing);
let current_oracle = update_outdated_to_current(iterations, (prev_price, prev_volume, prev_liquidity, Some(prev_shares_issuance)), (incoming_price, incoming_liquidity, Some(incoming_shares_issuance)), smoothing);
prop_assert_eq!(current_oracle, (iterated_price, iterated_volume, iterated_liquidity, Some(iterated_shares)));
}
}

Expand Down
2 changes: 1 addition & 1 deletion pallets/ema-oracle/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pallet-ema-oracle"
version = "1.7.1"
version = "1.8.0"
description = "Exponential moving average oracle for AMM pools"
authors = ["GalacticCouncil"]
edition = "2021"
Expand Down
15 changes: 12 additions & 3 deletions pallets/ema-oracle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ mod tests;
mod types;
pub use types::*;

pub mod migrations;
#[allow(clippy::all)]
pub mod weights;
pub use weights::WeightInfo;
Expand Down Expand Up @@ -121,6 +122,7 @@ pub mod pallet {
use frame_system::pallet_prelude::{BlockNumberFor, OriginFor};

#[pallet::pallet]
#[pallet::storage_version(migrations::STORAGE_VERSION)]
pub struct Pallet<T>(_);

#[pallet::config]
Expand Down Expand Up @@ -214,20 +216,21 @@ pub mod pallet {
#[pallet::genesis_config]
#[derive(frame_support::DefaultNoBound)]
pub struct GenesisConfig<T: Config> {
pub initial_data: Vec<(Source, (AssetId, AssetId), Price, Liquidity<Balance>)>,
pub initial_data: Vec<(Source, (AssetId, AssetId), Price, Liquidity<Balance>, Option<Balance>)>,
#[serde(skip)]
pub _marker: PhantomData<T>,
}

#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
for &(source, (asset_a, asset_b), price, liquidity) in self.initial_data.iter() {
for &(source, (asset_a, asset_b), price, liquidity, shares_issuance) in self.initial_data.iter() {
let entry: OracleEntry<BlockNumberFor<T>> = {
let e = OracleEntry {
price,
volume: Volume::default(),
liquidity,
shares_issuance,
updated_at: BlockNumberFor::<T>::zero(),
};
if ordered_pair(asset_a, asset_b) == (asset_a, asset_b) {
Expand Down Expand Up @@ -329,6 +332,7 @@ pub mod pallet {
EmaPrice::new(price.0, price.1),
Volume::default(),
Liquidity::default(),
None,
T::BlockNumberProvider::current_block_number(),
);
if ordered_pair == (asset_a, asset_b) {
Expand All @@ -342,7 +346,7 @@ pub mod pallet {
if !Self::is_within_range(reference_entry.0.price.into(), price) {
log::error!(
target: LOG_TARGET,
"Updating biforst oracle failed as the price is outside the allowed range"
"Updating bifrost oracle failed as the price is outside the allowed range"
);
return Err(Error::<T>::PriceOutsideAllowedRange.into());
}
Expand Down Expand Up @@ -565,6 +569,7 @@ impl<T: Config> OnTradeHandler<AssetId, Balance, Price> for OnActivityHandler<T>
liquidity_a: Balance,
liquidity_b: Balance,
price: Price,
shares_issuance: Option<Balance>,
) -> Result<Weight, (Weight, DispatchError)> {
// We assume that zero liquidity values are not valid and can be ignored.
if liquidity_a.is_zero() || liquidity_b.is_zero() {
Expand All @@ -584,6 +589,7 @@ impl<T: Config> OnTradeHandler<AssetId, Balance, Price> for OnActivityHandler<T>
price,
volume,
liquidity,
shares_issuance,
updated_at,
};
Pallet::<T>::on_trade(source, ordered_pair(asset_a, asset_b), entry)
Expand All @@ -607,6 +613,7 @@ impl<T: Config> OnLiquidityChangedHandler<AssetId, Balance, Price> for OnActivit
liquidity_a: Balance,
liquidity_b: Balance,
price: Price,
shares_issuance: Option<Balance>,
) -> Result<Weight, (Weight, DispatchError)> {
if liquidity_a.is_zero() || liquidity_b.is_zero() {
log::trace!(
Expand All @@ -623,6 +630,7 @@ impl<T: Config> OnLiquidityChangedHandler<AssetId, Balance, Price> for OnActivit
// liquidity provision does not count as trade volume
volume: Volume::default(),
liquidity,
shares_issuance,
updated_at,
};
Pallet::<T>::on_liquidity_changed(source, ordered_pair(asset_a, asset_b), entry)
Expand Down Expand Up @@ -775,6 +783,7 @@ impl<T: Config> RawOracle<AssetId, Balance, BlockNumberFor<T>> for Pallet<T> {
price: (entry.price.n, entry.price.d),
volume: entry.volume,
liquidity: entry.liquidity,
shares_issuance: entry.shares_issuance,
updated_at: entry.updated_at,
})
}
Expand Down
6 changes: 6 additions & 0 deletions pallets/ema-oracle/src/migrations/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use frame_support::traits::StorageVersion;

pub mod v1;

/// The in-code storage version.
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
Loading
Loading