#35767 [SC-Critical] constanct value is used to check `price.confidence`
Was this helpful?
Was this helpful?
Submitted on Oct 7th 2024 at 09:07:06 UTC by @jasonxiale for
Report ID: #35767
Report Type: Smart Contract
Report severity: Critical
Target: https://github.com/Swaylend/swaylend-monorepo/blob/develop/contracts/market/src/main.sw
Impacts:
Protocol insolvency
In [Market.get_price_internal] (https://github.com/Swaylend/swaylend-monorepo/blob/34ada63c18efd163ef80694c404d0573d49d46b4/contracts/market/src/main.sw#L1017-L1050), while validating the Pyth's price, the function checks the `price.confidence` in .
The issue is that `get_price_internal` will be used to get price for different `price_fee_id`, but the returned price will be checked against the same constant value
As shown in , uses constant values to check `price.confidence`
```Rust 1017 #[storage(read)] 1018 fn get_price_internal(price_feed_id: PriceFeedId) -> Price { 1019 let contract_id = storage.pyth_contract_id.read(); 1020 require( 1021 contract_id != ContractId::zero(), 1022 Error::OracleContractIdNotSet, 1023 ); 1024 ... 1045 require( 1046 u256::from(price.confidence) <= (u256::from(price.price) * ORACLE_MAX_CONF_WIDTH / ORACLE_CONF_BASIS_POINTS), 1047 Error::OraclePriceValidationError, 1048 ); <<<--- constant value is checked here 1049 1050 price 1051 } ```
`Market.get_price_internal` is important, because it is used while borrow/liquidate assets:
if the constant value is too wide for some price-feeds, the user/protocol might execute the tx at a bad price
if the constant value is too restrict for some price-feeds, the tx might always revert
Add any relevant links to documentation or code
At the moment: >BTC/USD: price $63620, confidence: +- $16
>CBBTC/USD: price $63610, confidence: +- $509
Please put the following code into a new file named `check.rs` and run: ```bash root@4d98affa1474:/in/temp# rustc check.rs ; ./check BTC check: true CBBTC check: false ```
As we can see, BTC/USD can pass the check, and CBBTC/USD can't pass the check
```Rust pub const ORACLE_MAX_CONF_WIDTH: u64 = 20; pub const ORACLE_CONF_BASIS_POINTS: u64 = 10_000; fn main() { let btc_price : u64 = 63620; let btc_confidence: u64 = 16;
} ```
According to the technical walkthrough at , the derivate BTC might be used,
And from , we will take `BTC/USD` and `TBTC/USD` pair as an example
To prove the point, we'll use the following code to simulate the check in