Borrowers can choose any volatility in order to pay less fees
*issue-contents*
0 CONTENTS
- 1................................................................................
- 2................................................................................
- 3................................................................................
- 4................................................................................
- 5................................................................................
- 6................................................................................
- 7................................................................................
- 8................................................................................
- 9................................................................................
1 METADATA
Number | 792 |
---|---|
Severity | Medium |
Author | John44 |
Contest | Autonomint |
Platform | Sherlock |
2 SUMMARY
When borrowers deposit into borrowing.sol they have to specify a volatility parameter. It is used when calculating how much option fees they will be charged. This is problematic as depositors can choose any value in order to be charged the lowest possible number of fees.
3 ROOT CAUSE
In Borrowing.depositTokens the volatility parameter is porvided by the user, thus users will always set it to an amount that results in less option fees.
4 INTERNAL PRE-CONDITIONS
No response
5 EXTERNAL PRE-CONDITIONS
No response
6 ATTACK PATH
- User deposits tokens into borrowing.sol.
- Before depositing they calculate which value of
volatility
will reduce their option fees the most. - They use that value and are charged less fees then they should have been.
For example, in the protocol’s tests the following value is used for the volatility: 50622665 https://github.com/sherlock-audit/2024-11-autonomint/blob/0d324e04d4c0ca306e1ae4d4c65f0cb9d681751b/Blockchain/Blockchian/test/foundry/Borrowing.t.sol#L47
However, we can test that by setting the volatility to 10000000 the fees are significantly less.
7 IMPACT
Users can reduce the number of option fees they have to pay.
8 POC
This is a mock-up function that calculates the option fee, exactly how it is
currently calculated in the protocol. Standard parameters are set in order to
isolate the effects of the volatility
variable. It can be ran in any
environment, just make sure to do the necessary imports.
By using the paramerter for volatility
used in the tests 50622665, we
receive 165738482. By using 10000000, we receive 101927611.
function calculateOptionPrice(uint256 _ethVolatility)
public
view
returns (uint256)
{
uint128 _ethPrice = 4000e2;
uint256 _amount = 10e18;
StrikePrice _strikePrice = StrikePrice(1);
uint256 a = _ethVolatility;
uint256 ethPrice = _ethPrice; /*getLatestPrice();*/
// Get global omnichain data
// Calculate the current ETH vault value
uint256 totalVolumeOfBorrowersAmountinUSD = 10e18 * _ethPrice / 1e14;
uint256 E = totalVolumeOfBorrowersAmountinUSD + (_amount * _ethPrice);
// Check the ETH vault is not zero
require(E != 0, "No borrowers in protocol");
uint256 cdsVault;
// If the there is no borrowers in borrowing, then the cdsVault value is deposited value itself
// Else, get the cds vault current value from omnichain global data
cdsVault = 1000e6 * USDA_PRECISION;
// Check cds vault is non zero
require(cdsVault != 0, "CDS Vault is zero");
// Calculate b, cdsvault to eth vault ratio
uint256 b = (cdsVault * 1e2 * OPTION_PRICE_PRECISION) / E;
uint256 baseOptionPrice = ((sqrt(10 * a * ethPrice)) * PRECISION) /
OPTION_PRICE_PRECISION +
((3 * PRECISION * OPTION_PRICE_PRECISION) / b); // 1e18 is used to handle division precision //18 * 5 /
uint256 optionPrice;
// Calculate option fees based on strike price chose by user
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) / //5 * x /
(3 * a);
} else {
revert("Incorrect Strike Price");
}
return ((optionPrice * _amount) / PRECISION) / USDA_PRECISION; //x*18/30 = 6 -> x = 18
}
function testCalculateOptionPrice(
uint256 _ethVolatility
) public view returns (uint256) {
//set up mockup omni chain data
uint256 noOfBorrowers = 1;
uint256 totalCdsDepositedAmount = 10000e6;
uint256 cdsPoolValue = 10000e6;
StrikePrice _strikePrice = StrikePrice(1);
uint256 _amount = 1e18;
uint256 ethPrice = 4000e2;
uint256 totalVolumeOfBorrowersAmountinUSD = 10e18 * ethPrice;
uint256 a = _ethVolatility;
// Calculate the current ETH vault value
uint256 E = totalVolumeOfBorrowersAmountinUSD + (_amount * ethPrice);
// Check the ETH vault is not zero
require(E != 0, "No borrowers in protocol");
uint256 cdsVault;
// If the there is no borrowers in borrowing, then the cdsVault value is deposited value itself
if (noOfBorrowers == 0) {
cdsVault = totalCdsDepositedAmount * USDA_PRECISION;
} else {
// Else, get the cds vault current value from omnichain global data
cdsVault = cdsPoolValue * USDA_PRECISION;
}
// Check cds vault is non zero
require(cdsVault != 0, "CDS Vault is zero");
// Calculate b, cdsvault to eth vault ratio
uint256 b = (cdsVault * 1e2 * OPTION_PRICE_PRECISION) / E;
uint256 baseOptionPrice = ((sqrt(10 * a * ethPrice)) * PRECISION) / OPTION_PRICE_PRECISION + ((3 * PRECISION * OPTION_PRICE_PRECISION) / b); // 1e18 is used to handle division precision
uint256 optionPrice;
// Calculate option fees based on strike price chose by user
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;
}
function sqrt(uint256 y) internal pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
}
9 MITIGATION
volatility
should not be derived from user-input, but instead be set by an
admin depending on the actual ETH volatility.
LINKS
*issue-links*
- 1.