Platform: Code4rena
Start Date: 08/05/2023
Pot Size: $90,500 USDC
Total HM: 17
Participants: 102
Period: 7 days
Judge: 0xean
Total Solo HM: 4
Id: 236
League: ETH
Rank: 39/102
Findings: 2
Award: $306.37
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: 0x73696d616f
Also found by: 0xadrii, 0xbepresent, 0xkazim, J4de, peanuts, pontifex, rvierdiiev, volodya
249.7365 USDC - $249.74
https://github.com/code-423n4/2023-05-venus/blob/main/contracts/Comptroller.sol#L199 https://github.com/code-423n4/2023-05-venus/blob/main/contracts/Comptroller.sol#L299 https://github.com/code-423n4/2023-05-venus/blob/main/contracts/Comptroller.sol#L324 https://github.com/code-423n4/2023-05-venus/blob/main/contracts/Comptroller.sol#L553 https://github.com/code-423n4/2023-05-venus/blob/main/contracts/Comptroller.sol#L1240 https://github.com/code-423n4/2023-05-venus/blob/main/contracts/Comptroller.sol#L1255 https://github.com/code-423n4/2023-05-venus/blob/main/contracts/Comptroller.sol#L578
Incorrect borrowBalance and token collateral values. Could lead to many different exploits, such has:
In the Comptroller
, the total collateral balance and borrow balance is calculated at _getHypotheticalLiquiditySnapshot(...)
. This function calculates these balances in the following loop:
for (uint256 i; i < assetsCount; ++i) { VToken asset = assets[i]; // Read the balances and exchange rate from the vToken (uint256 vTokenBalance, uint256 borrowBalance, uint256 exchangeRateMantissa) = _safeGetAccountSnapshot( asset, account ); // Get the normalized price of the asset Exp memory oraclePrice = Exp({ mantissa: _safeGetUnderlyingPrice(asset) }); // Pre-compute conversion factors from vTokens -> usd Exp memory vTokenPrice = mul_(Exp({ mantissa: exchangeRateMantissa }), oraclePrice); Exp memory weightedVTokenPrice = mul_(weight(asset), vTokenPrice); // weightedCollateral += weightedVTokenPrice * vTokenBalance snapshot.weightedCollateral = mul_ScalarTruncateAddUInt( weightedVTokenPrice, vTokenBalance, snapshot.weightedCollateral ); // totalCollateral += vTokenPrice * vTokenBalance snapshot.totalCollateral = mul_ScalarTruncateAddUInt(vTokenPrice, vTokenBalance, snapshot.totalCollateral); // borrows += oraclePrice * borrowBalance snapshot.borrows = mul_ScalarTruncateAddUInt(oraclePrice, borrowBalance, snapshot.borrows); // Calculate effects of interacting with vTokenModify if (asset == vTokenModify) { // redeem effect // effects += tokensToDenom * redeemTokens snapshot.effects = mul_ScalarTruncateAddUInt(weightedVTokenPrice, redeemTokens, snapshot.effects); // borrow effect // effects += oraclePrice * borrowAmount snapshot.effects = mul_ScalarTruncateAddUInt(oraclePrice, borrowAmount, snapshot.effects); } }
As can be seen, the oracle price is not updated via calling updatePrice(...)
, nor the borrow interest is updated by calling AccrueInterest(...)
. Only the corresponding VToken
that called the borrow(...)
, transfer(...)or
redeem(...)` has an updated price and interest, which could lead to critical inaccuracies for accounts with several VTokens.
Vscode, Hardhat
Update the price and interest of every collateral except the VToken that triggered the hook, which has already been updated. Similarly to what is being done on healAccount(...)
.
for (uint256 i; i < userAssetsCount; ++i) { userAssets[i].accrueInterest(); oracle.updatePrice(address(userAssets[i])); }
Oracle
#0 - c4-judge
2023-05-17T21:47:43Z
0xean marked the issue as duplicate of #88
#1 - c4-judge
2023-06-05T14:09:17Z
0xean changed the severity to 2 (Med Risk)
#2 - c4-judge
2023-06-05T14:09:45Z
0xean marked the issue as satisfactory
#3 - c4-judge
2023-06-05T16:32:01Z
0xean marked the issue as selected for report
#4 - chechu
2023-06-08T10:28:24Z
To share more info related to this topic:
oracle.updatePrice
is invoked. If no one invokes this update function for an asset later used indirectly by another user, and the difference between the price offered by the TWAP oracle and the rest of the oracles (i.e. Chainlink) is greater than a threshold configure in our Oracle system, the TX will be also reverted. Could this generate a DoS? I suppose that potentially it can do it, but as soon as a user interact with the "staled" asset in Venus the block will disappear#5 - 0xean
2023-06-08T12:45:59Z
@chechu - I believe I should mark #104 as a dupe of this as well. Since this issue talks about both prices updated and accruing interests.
we assume the prices in the rest of the markets will be updated frequently because they are updated every time other users interact directly with these other markets
This assumption I think has risks in which the wardens are calling out. Its hard to say how real these risks are apriori without making assumptions about usage of all the markets.
I think these issues should be batched together over concerns around accrueInterest and price updates into a single M issue.
#6 - chechu
2023-06-08T14:26:17Z
This assumption I think has risks in which the wardens are calling out. Its hard to say how real these risks are apriori without making assumptions about usage of all the markets.
@0xean IMHO I think the risk is low, but I could understand the concern and the lack of a guarantee in the code.
Regarding grouping this and #104, #104 only mentions the outdated interests and this mentions the outdated interest and the outdated prices. So, up to you, you are the judge :)
#7 - 0xean
2023-06-08T14:39:31Z
Sorry, I meant duping #104 against this. thanks for the response, will judge accordingly!
#8 - c4-judge
2023-06-08T14:39:54Z
0xean marked the issue as duplicate of #486
#9 - 0xean
2023-06-08T14:40:40Z
Issues mentioning both will receive 100% credit while issues mentioning one will receive 50%
#10 - c4-judge
2023-06-08T17:12:14Z
0xean marked the issue as not a duplicate
#11 - c4-judge
2023-06-08T17:12:33Z
0xean marked the issue as primary issue
🌟 Selected for report: brgltd
Also found by: 0x73696d616f, 0xAce, 0xSmartContract, 0xWaitress, 0xkazim, 0xnev, Aymen0909, BGSecurity, Bauchibred, Cayo, ChrisTina, Franfran, IceBear, Infect3d, Kose, Lilyjjo, PNS, RaymondFam, Sathish9098, Team_Rocket, Udsen, YakuzaKiawe, YoungWolves, berlin-101, bin2chen, btk, codeslide, fatherOfBlocks, frazerch, kodyvim, koxuan, lfzkoala, lukris02, matrix_0wl, nadin, naman1778, sashik_eth, tnevler, volodya, wonjun, yjrwkk
56.6347 USDC - $56.63
VToken
, transfer(...)
, missing 0x0
address checkVToken
, transferFrom(...)
allows the owner to be the spendertransferFrom(...)
This is different than what is stated on the EIP20, where a user would have to explicitly increase their balance. Thus, the function should revert if the owner is the spender and they haven't increased their balance.
Comptroller
, VToken
, It's possible to enter any number of markets by minting and then borrowing instead of calling enterMarkets(...)
VToken
, _initialize(...)
underlying no contract size check._initialize(...)
EOAs won't revert on IERC20Upgradeable(underlying).totalSupply();
PoolRegistry
, AddMarket(...)
, if the input.rateModel is wrong by mistake, the wrong parameters are set
.Consider creating 2 separate functions with different arguments.
VToken
, getAccountSnapshot(...)
, return variable error
confuses linter and marks it blueerror
at getAccountSnapshot(...)
BaseJumpRateMovelV2
, getBorrowRate(...)
calculate normal rate before the conditionsgetBorrowRate(...)
The normalRate
could be calculated before the conditions and reused.
RewardsDistributor
, _updateRewardTokenSupplyIndex(...)
, supplyState.block = blockNumber
out of if/else
_updateRewardTokenSupplyIndex
Avoids duplicate code.
#0 - c4-judge
2023-05-18T18:28:32Z
0xean marked the issue as grade-b