Finding Description and Impact
The getNFTPrice function in the LendingPool contract relies on the RAACHousePrices contract to retrieve the latest price and timestamp for a given NFT. However, the RAACHousePrices contract uses a global lastUpdateTimestamp for all tokens instead of maintaining token-specific timestamps. This design flaw leads to the following issues:
Outdated Price Data:
The lastUpdateTimestamp returned by RAACHousePrices does not reflect the actual last update time for the specific token being queried. Instead, it reflects the latest update time for any token in the system.
As a result, the price returned by getNFTPrice could be outdated, even if the timestamp appears recent.
Incorrect Collateral Calculations:
The withdrawNFT function uses getNFTPrice to determine the value of the NFT being withdrawn. If the price is outdated, the collateral check (collateralValue - nftValue < userDebt.percentMul(liquidationThreshold)) could be bypassed or unfairly enforced.
This could allow users to withdraw NFTs even if it leaves them undercollateralized, or prevent users from withdrawing NFTs even if they are sufficiently collateralized.
Proof of Concept
getNFTPrice in LendingPool:
getLatestPrice in RAACHousePrices:
setHousePrice in RAACHousePrices:
Scenario
Suppose tokenA was last updated 30 days ago with a price of 100 ETH.
tokenB is updated today with a price of 200 ETH.
When querying the price of tokenA, the lastUpdateTimestamp returned will be today's timestamp (from tokenB's update), even though tokenA's price is outdated.
The getNFTPrice function will return the outdated price of tokenA (100 ETH) without any indication that the price is stale.
Impact
If a user tries to withdraw tokenA, the protocol will use the outdated price (100 ETH) to calculate collateralization. If the actual market value of tokenA has dropped to 50 ETH, the user could withdraw the NFT even though it leaves them undercollateralized, putting the protocol at risk of bad debt.
Recommended Mitigation Steps
Implement Token-Specific Timestamps:
Modify the RAACHousePrices contract to maintain a separate lastUpdateTimestamp for each token.
Update the setHousePrice function to set the token-specific timestamp:
Update the getLatestPrice function to return the token-specific timestamp:
Add Stale Price Check in getNFTPrice:
Add a check to ensure the price is not outdated before returning it.
By implementing these changes, the protocol can ensure that NFT prices are accurate and up-to-date, reducing the risk of financial losses and improving overall security.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.