From 62fa31de07a512d1af57eed1a7fda988147e03dc Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Tue, 5 Dec 2023 12:29:36 -0500 Subject: [PATCH] If the pool has yet to start, insert a price of 0 The test failures were caused by not inserting any price, causing the first price to immediately become the oraclized price. While that's not inherently invalid, suggesting the tests should've been the ones updated, it opens an exploit where whoever first adds liquidity has the opportunity to set a ridiculous price and DoS the set. Not oraclizing until we have an entire period, achieved by inserting 0s during the initial blocks, ensures an open launch for such discovery. --- substrate/dex/pallet/src/lib.rs | 35 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/substrate/dex/pallet/src/lib.rs b/substrate/dex/pallet/src/lib.rs index 099a99851..e26ca0af8 100644 --- a/substrate/dex/pallet/src/lib.rs +++ b/substrate/dex/pallet/src/lib.rs @@ -360,22 +360,23 @@ pub mod pallet { for coin in Pools::::iter_keys() { // insert the new price to our oracle window // The spot price for 1 coin, in atomic units, to SRI is used - let Ok((sri_balance, coin_balance)) = Self::get_reserves(&Coin::native(), &coin) else { - continue; - }; - - // We use 1 coin to handle rounding errors which may occur with atomic units - // If we used atomic units, any coin whose atomic unit is worth less than SRI's atomic unit - // would cause a 'price' of 0 - // If the decimals aren't large enough to provide sufficient buffer, use 10,000 - let coin_decimals = coin.decimals().max(5); - let accuracy_increase = - HigherPrecisionBalance::from(SubstrateAmount::pow(10, coin_decimals)); - let sri_per_coin = u64::try_from( - accuracy_increase * HigherPrecisionBalance::from(sri_balance) / - HigherPrecisionBalance::from(coin_balance), - ) - .unwrap_or(u64::MAX); + let sri_per_coin = + if let Ok((sri_balance, coin_balance)) = Self::get_reserves(&Coin::native(), &coin) { + // We use 1 coin to handle rounding errors which may occur with atomic units + // If we used atomic units, any coin whose atomic unit is worth less than SRI's atomic + // unit would cause a 'price' of 0 + // If the decimals aren't large enough to provide sufficient buffer, use 10,000 + let coin_decimals = coin.decimals().max(5); + let accuracy_increase = + HigherPrecisionBalance::from(SubstrateAmount::pow(10, coin_decimals)); + u64::try_from( + accuracy_increase * HigherPrecisionBalance::from(sri_balance) / + HigherPrecisionBalance::from(coin_balance), + ) + .unwrap_or(u64::MAX) + } else { + 0 + }; let sri_per_coin = sri_per_coin.to_be_bytes(); SpotPriceForBlock::::set(n, coin, sri_per_coin); @@ -393,7 +394,7 @@ pub mod pallet { SpotPriceForBlock::::remove(start_of_window, coin); // Remove this price from the multiset OraclePrices::::mutate_exists(coin, start_spot_price, |v| { - *v = Some(v.unwrap() - 1); + *v = Some(v.unwrap_or(1) - 1); if *v == Some(0) { *v = None; }