Powerful Honeysuckle Anteater
High
The volatility field for borrowing can be any arbitrary value and could be used to reduce option fees
The volatility
field can be arbitrarily passed into the deposit function in the borrowing.sol
contract, allowing borrowers to manipulate or impact the pricing of option fees.
The volatility
field used in option fee calculations measures the collateral's (e.g., ETH's) historical price fluctuations. Specifically, it represents the statistical standard deviation of the asset's historical returns over a chosen timeframe.
In this case, it should represent a 30-day timeframe, as noted in the NatSpec in Options.sol
:
/**
* @dev Function to calculate option fees
* @param _ethPrice ETH price
@>> * @param _ethVolatility ETH volatility for 30days
* @param _amount Depositing amount
* @param _strikePrice Strike price chosen by user
*/
function calculateOptionPrice(uint128 _ethPrice, uint256 _ethVolatility, uint256 _amount, StrikePrice _strikePrice)
public
view
returns (uint256)
{
The root cause is that, we could arbitrary specify that value in borrowing.sol
deposit() function:
function depositTokens(
@>> BorrowDepositParams memory depositParam
) external payable nonReentrant whenNotPaused(IMultiSign.Functions(0)) {
Definition of BorrowDepositParams struct:
struct BorrowDepositParams {
IOptions.StrikePrice strikePercent;
uint64 strikePrice;
@>> uint256 volatility;
AssetName assetName;
uint256 depositingAmount;
}
Then in BorrowingLib.sol:
function deposit(
IBorrowing.BorrowLibDeposit_Params memory libParams,
IBorrowing.BorrowDepositParams memory params,
IBorrowing.Interfaces memory interfaces,
mapping(IBorrowing.AssetName => address assetAddress) storage assetAddress
) public returns (uint256) {
........Skip Code....
// Call calculateOptionPrice in options contract to get options fees
uint256 optionFees = interfaces.options.calculateOptionPrice(
@>> libParams.ethPrice, params.volatility, params.depositingAmount, params.strikePercent
);
And in Options.sol
, we can see how it directly impacts the calculation, by directly affecting baseOptionPrice
and the optionPrice
variables.
function calculateOptionPrice(uint128 _ethPrice, uint256 _ethVolatility, uint256 _amount, StrikePrice _strikePrice)
public
view
returns (uint256)
{
@>> uint256 a = _ethVolatility;
uint256 ethPrice = _ethPrice; /*getLatestPrice();*/
// Get global omnichain data
IGlobalVariables.OmniChainData memory omniChainData = globalVariables.getOmniChainData();
// Calculate the current ETH vault value
uint256 E = omniChainData.totalVolumeOfBorrowersAmountinUSD + (_amount * _ethPrice);
require(E != 0, "No borrowers in protocol");
uint256 cdsVault;
if (omniChainData.noOfBorrowers == 0) {
cdsVault = omniChainData.totalCdsDepositedAmount * USDA_PRECISION;
} else {
// Else, get the cds vault current value from omnichain global data
cdsVault = omniChainData.cdsPoolValue * USDA_PRECISION;
}
require(cdsVault != 0, "CDS Vault is zero");
uint256 b = (cdsVault * 1e2 * OPTION_PRICE_PRECISION) / E; //1e18 * 1e2 * 1e5 / 1e8 = 1e17
@>> uint256 baseOptionPrice = ((sqrt(10 * a * ethPrice)) * PRECISION) / OPTION_PRICE_PRECISION
+ ((3 * PRECISION * OPTION_PRICE_PRECISION) / b);
uint256 optionPrice;
if (_strikePrice == StrikePrice.FIVE) {
// constant has extra 1e3 and volatility have 1e8
optionPrice = baseOptionPrice + (400 * OPTION_PRICE_PRECISION * baseOptionPrice) / (3 * a);
} else if (_strikePrice == StrikePrice.TEN) {
optionPrice = baseOptionPrice + (100 * OPTION_PRICE_PRECISION * baseOptionPrice) / (3 * a);
} else if (_strikePrice == StrikePrice.FIFTEEN) {
optionPrice = baseOptionPrice + (50 * OPTION_PRICE_PRECISION * baseOptionPrice) / (3 * a);
} else if (_strikePrice == StrikePrice.TWENTY) {
optionPrice = baseOptionPrice + (10 * OPTION_PRICE_PRECISION * baseOptionPrice) / (3 * a);
} else if (_strikePrice == StrikePrice.TWENTY_FIVE) {
optionPrice = baseOptionPrice + (5 * OPTION_PRICE_PRECISION * baseOptionPrice) / (3 * a);
} else {
revert("Incorrect Strike Price");
}
return ((optionPrice * _amount) / PRECISION) / USDA_PRECISION;
}
No response
No response
- User wants to create a deposit
- User specifies lower volatility value, such as 1, which is the lowest valid one. This leads to significantly less optionFees.
OptionFees are impacted and borrowers pay less, than they should.
Don't allow users to arbitrary pass that value, rather retrieve it from trusted source.