Lucene search

K
code423n4Code4renaCODE423N4:2023-05-VENUS-FINDINGS-ISSUES-523
HistoryMay 15, 2023 - 12:00 a.m.

Stale risk fund assets may make protocol loose funds

2023-05-1500:00:00
Code4rena
github.com
6
risk fund
protocol
auctions
bad debts
stale reserves

Lines of code
<https://github.com/code-423n4/2023-05-venus/blob/8be784ed9752b80e6f1b8b781e2e6251748d0d7e/contracts/Shortfall/Shortfall.sol#L381&gt;

Vulnerability details

Vulnerability Details

When swapping Risk funds in a pool swapPoolsAssets(address[],uint256[],address[][]) from one market underlying asset type to convertibleBaseAsset , only a limited selected markets are supplied as input parameter.

function swapPoolsAssets(
        address[] calldata markets,
        uint256[] calldata amountsOutMin,
        address[][] calldata paths
    ) external override returns (uint256) {
...

But when auctioning off pool bad debts, every market’s bad debt in the pools are calculated to form poolBadDebt which is a total of all bad debts in the pool. Additionally, when auctioning off bad debt in Shortfall contract, there is no check for pool reserves staleness:

function _startAuction(address comptroller) internal {
        ...
        uint256 riskFundBalance = riskFund.poolReserves(comptroller); // @audit pool reserves may be stale
        uint256 remainingRiskFundBalance = riskFundBalance;
        uint256 incentivizedRiskFundBalance = poolBadDebt + ((poolBadDebt * incentiveBps) / MAX_BPS);
        if (incentivizedRiskFundBalance &gt;= riskFundBalance) {
            auction.startBidBps =
                (MAX_BPS * MAX_BPS * remainingRiskFundBalance) /
                (poolBadDebt * (MAX_BPS + incentiveBps));
            remainingRiskFundBalance = 0;
            auction.auctionType = AuctionType.LARGE_POOL_DEBT;
        } else {
            uint256 maxSeizeableRiskFundBalance = incentivizedRiskFundBalance;

            remainingRiskFundBalance = remainingRiskFundBalance - maxSeizeableRiskFundBalance;
            auction.auctionType = AuctionType.LARGE_RISK_FUND;
            auction.startBidBps = MAX_BPS;
        }

This makes every auction using more or less stale pool reserves, which basically means looses for the protocol.

Impact

  1. Auctions are improperly priced as funds available in the RiskFund to a pool is what determines if an asset is considered a LARGE_POOL_DEBT or LARGE_RISK_FUND.
  2. Protocol is loosing value due to auctioning off the debt for fraction of price, when reserves can be used.

Proof of Concept

  1. Pool Apha has three markets only of combined 200M TVL, with a bad debt of 10M, the bad debt is spread across the three markets A,B and C respectively, 5M, 3M, 2M.
  2. The reserves from market A,B and C are 2M, 2M and 7M respectively (exclusive of protocol reserves).
  3. An authorized user calls swapPoolsAssets(address[],uint256[],address[][]) with market A and B as items in markets input. The Reserve is successfully calculated and converted with a pool reserve of 4M for the Risk fund to use to auction off bad debt on Pool Alpha.
  4. A week passes. An end user calls the startAuction(address) function on shortfall contract using Pool Alpha as the input param, and it calculates a total bad debts of pool Alpha to be 10M.
  5. Now since the bad debt as calculated in shortfall is 10M for pool alpha and the reserves in risk fund for pool Alpha is 4M, it therefore means that this auction will be auctioned off as a LARGE_POOL_DEBT type.

Tools Used

Manual analysis

Recommended Mitigation Steps

All assets reserved from each market in a pool should be used when swapping to convertibleBaseAsset, and validation should check that all markets in the pool is available in the markets input. So also meaning a comptroller address input should be passed as input to check against the markets own comptroller address to make sure they of all same pool in swapPoolsAssets(address[],uint256[],address[][]). Additionally, please consider adding stalessness check.

Assessed type

Other


The text was updated successfully, but these errors were encountered:

All reactions