Boost _ Folks Finance 33787 - [Smart Contract - Low] Function PythNodeprocess doesnt handle correctl
Submitted on Mon Jul 29 2024 11:43:04 GMT-0400 (Atlantic Standard Time) by @Paludo0x for Boost | Folks Finance
Report ID: #33787
Report type: Smart Contract
Report severity: Low
Target: https://testnet.snowtrace.io/address/0xA758c321DF6Cd949A8E074B22362a4366DB1b725
Impacts:
Temporary freezing of funds of at least 24h
Description
Vulnerability Details
Function PythNode::process()
is called to return the Pyth price. The factor pythData.expo
is adjusted as written it the comment inside the function /// @dev adjust the price to 18 d.p., exponent is a int32 so it could be negative or positive
int256 factor = PRECISION + pythData.expo;
uint256 price = factor > 0
? pythData.price.toUint256() * (10 ** factor.toUint256())
: pythData.price.toUint256() / (10 ** factor.toUint256());
The issue is that function SafeCast::toUint256()
reverts if the value passed is < 0, as per following snippet:
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
Therefore whenever factor < 0
the call to this function will revert.
The function process()
should be rewritten as follows:
uint256 price = factor > 0
? pythData.price.toUint256() * (10 ** factor.toUint256())
: pythData.price.toUint256() / (10 ** (-factor).toUint256());
Impact Details
PythNode::process()
is called by OracleManager::processPriceFeed()
OracleManager::processPriceFeed()
is called by several functions of the protocol, these are 3 examples:
HubPool::updatePoolWithDeposit()
: in this case the call toBridgeMessenger::receiveMessage()
will fails and received messagge will be catched infailedMessages[adapterId][message.messageId]
variable of BridgeRouterHubPool::preparePoolForBorrow()
: same beahviour as perHubPool::updatePoolWithDeposit()
LiquidationLogic::calcLiquidationAmounts()
: in this case the full call toHub::directOperation()
withLiquidate
action will fail
In my opinion this bug shall be considered high because in case of HubPool::updatePoolWithDeposit()
user funds would be temporary frozen until someone with MANAGER_ROLE will change the node manager by calling OracleManager::setNodeManager(address nodeManager) external onlyRole(MANAGER_ROLE)
.
Proof of concept
POC
The following POC is a simplified version of function PythNode::process
and shall be copied in remix IDE.
The aim is to demonstarate that if exponent is < 18 the function will revert.
pragma solidity >=0.7.0 <0.9.0;
library SafeCast {
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert();
}
return uint256(value);
}
}
contract Test {
using SafeCast for int256;
int256 public constant PRECISION = 18;
function process(int256 exponent) public view returns (uint256) {
int256 factor = PRECISION + exponent;
uint256 priceFromPyth = 1e6;
uint256 price = factor > 0
? priceFromPyth * (10 ** factor.toUint256())
: priceFromPyth / (10 ** factor.toUint256());
return price;
}
}
Last updated
Was this helpful?