Deep Sepia Gazelle
Medium
In the Numa protocol slot0
is used to receive the sqrtPriceX96
price. But this is not recommended, because slot0
can be manipulated very easy.
The Numa protocol is using slot0
to receive the sqrtPriceX96
and sqrtPriceX96Spot
variables in NumaOracle::getV3SpotPrice
, NumaOracle::getV3SqrtLowestPrice
and NumaOracle::getV3SqrtHighestPrice
. The problem is that the slot0
is the most recent data point and is therefore extremely easy to manipulate.
Price manipulation, the returned price can be higher and at the end swaps can result in users receiving less tokens than they intended.
No response
No response
No response
Let's consider the functions: getV3SpotPrice
, getV3SqrtLowestPrice
and getV3SqrtHighestPrice
:
function getV3SpotPrice(
address _numaPool,
uint _numaAmount
) external view returns (uint256) {
@> (uint160 sqrtPriceX96, , , , , , ) = IUniswapV3Pool(_numaPool).slot0();
uint256 numerator = (
IUniswapV3Pool(_numaPool).token0() == token
? sqrtPriceX96
: FixedPoint96.Q96
);
uint256 denominator = (
numerator == sqrtPriceX96 ? FixedPoint96.Q96 : sqrtPriceX96
);
uint256 TokenPerNumaMulAmount = FullMath.mulDivRoundingUp(
FullMath.mulDivRoundingUp(denominator, denominator, numerator),
_numaAmount,
numerator
);
return TokenPerNumaMulAmount;
}
function getV3SqrtLowestPrice(
address _uniswapV3Pool,
uint32 _intervalShort,
uint32 _intervalLong
) public view returns (uint160) {
require(
_intervalLong > _intervalShort,
"intervalLong must be longer than intervalShort"
);
uint160 sqrtPriceX96;
//Spot price of the token
(uint160 sqrtPriceX96Spot, , , , , , ) = IUniswapV3Pool(_uniswapV3Pool)
@> .slot0();
//TWAP prices for short and long intervals
uint160 sqrtPriceX96Short = getV3SqrtPriceAvg(
_uniswapV3Pool,
_intervalShort
);
uint160 sqrtPriceX96Long = getV3SqrtPriceAvg(
_uniswapV3Pool,
_intervalLong
);
.
.
.
}
function getV3SqrtHighestPrice(
address _uniswapV3Pool,
uint32 _intervalShort,
uint32 _intervalLong
) public view returns (uint160) {
require(
_intervalLong > _intervalShort,
"intervalLong must be longer than intervalShort"
);
uint160 sqrtPriceX96;
//Spot price of the token
(uint160 sqrtPriceX96Spot, , , , , , ) = IUniswapV3Pool(_uniswapV3Pool)
@> .slot0();
//TWAP prices for short and long intervals
uint160 sqrtPriceX96Short = getV3SqrtPriceAvg(
_uniswapV3Pool,
_intervalShort
);
uint160 sqrtPriceX96Long = getV3SqrtPriceAvg(
_uniswapV3Pool,
_intervalLong
);
.
.
.
}
These three functions get the sqrtPriceX96
and sqrtPriceX96Spot
from IUniswapV3Pool.slot0
. An attacker can simply manipulate the sqrtPriceX96
price and set a higher price than the intended one.
Use TWAP
to get the value of sqrtPriceX96
.