Venus Protocol Isolated Pools - j4ld1na's results

Earn, Borrow & Lend on the #1 Decentralized Money Market on the BNB Chain

General Information

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

Venus Protocol

Findings Distribution

Researcher Performance

Rank: 102/102

Findings: 1

Award: $44.94

Gas:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

44.9387 USDC - $44.94

Labels

bug
G (Gas Optimization)
grade-b
G-17

External Links

IssuesInstances
G-01Use assembly to check for address(0). Save Gas.32
G-02It is not necessary to declare. No need to read amountLeft.1
G-03Consider using Assembly sometimes for Loops and If statements. Save gas.1
G-04When possible, use assembly instead of unchecked{++i}.37
G-05Consider use assembly for math (add, sub, mul, div).42

[G-01] Use assembly to check for address(0). Save Gas.

There are 32 instances:

Example:

function ownerNotZero(address _addr) public pure {
    require(_addr != address(0), "zero address)");
}

Gas: 258

function assemblyOwnerNotZero(address _addr) public pure {
    assembly {
        if iszero(_addr) {
            mstore(0x00, "zero address")
            revert(0x00, 0x20)
        }
    }
}

Gas: 252

Comptroller.sol#L128

require(poolRegistry_ != address(0), "invalid pool registry address");

Comptroller.sol#L962

require(address(newOracle) != address(0), "invalid price oracle address");

VToken.sol#L72

require(admin_ != address(0), "invalid admin address");

VToken.sol#L134

require(spender != address(0), "invalid spender address");

VToken.sol#L196

require(minter != address(0), "invalid minter address");

VToken.sol#L626

require(spender != address(0), "invalid spender address");

VToken.sol#L646

require(spender != address(0), "invalid spender address");

VToken.sol#L1399

if (shortfall_ == address(0)) {
            revert ZeroAddressNotAllowed();
        }

VToken.sol#L1408-L1410

if (protocolShareReserve_ == address(0)) {
             revert ZeroAddressNotAllowed();
        }

Shortfall/Shortfall.sol#L137

require(convertibleBaseAsset_ != address(0), "invalid base asset address");

Shortfall/Shortfall.sol#L349

require(_poolRegistry != address(0), "invalid address");

Pool/PoolRegistry.sol#L225-L226

require(beaconAddress != address(0), "PoolRegistry: Invalid Comptroller beacon address.");

require(priceOracle != address(0), "PoolRegistry: Invalid PriceOracle address.");

Pool/PoolRegistry.sol#L257-L260

require(input.comptroller != address(0), "PoolRegistry: Invalid comptroller address");

require(input.asset != address(0), "PoolRegistry: Invalid asset address");

require(input.beaconAddress != address(0), "PoolRegistry: Invalid beacon address");

require(input.vTokenReceiver != address(0), "PoolRegistry: Invalid vTokenReceiver address");

Pool/PoolRegistry.sol#L396

require(venusPool.creator == address(0), "PoolRegistry: Pool already exists in the directory.");

Pool/PoolRegistry.sol#L431-L433

if (protocolShareReserve_ == address(0)) {
            revert ZeroAddressNotAllowed();
        }

RiskFund/RiskFund.sol#L80-L81

require(pancakeSwapRouter_ != address(0), "Risk Fund: Pancake swap address invalid");

require(convertibleBaseAsset_ != address(0), "Risk Fund: Base asset address invalid");

RiskFund/RiskFund.sol#L100

require(_poolRegistry != address(0), "Risk Fund: Pool registry address invalid");

RiskFund/RiskFund.sol#L111

require(shortfallContractAddress_ != address(0), "Risk Fund: Shortfall contract address invalid");

RiskFund/RiskFund.sol#L127

require(pancakeSwapRouter_ != address(0), "Risk Fund: PancakeSwap address invalid");

RiskFund/RiskFund.sol#L157

require(poolRegistry != address(0), "Risk fund: Invalid pool registry.");

RiskFund/ProtocolShareReserve.sol#L40-L41

require(_protocolIncome != address(0), "ProtocolShareReserve: Protocol Income address invalid");

require(_riskFund != address(0), "ProtocolShareReserve: Risk Fund address invalid");

RiskFund/ProtocolShareReserve.sol#L54

require(_poolRegistry != address(0), "ProtocolShareReserve: Pool registry address invalid");

RiskFund/ProtocolShareReserve.sol#L71

require(asset != address(0), "ProtocolShareReserve: Asset address invalid");

RiskFund/ReserveHelpers.sol#L52-L53

require(asset != address(0), "ReserveHelpers: Asset address invalid");

require(poolRegistry != address(0), "ReserveHelpers: Pool Registry address is not set");

Proxy/UpgradeableBeacon.sol#L8

require(implementation_ != address(0), "Invalid implementation address");

Recommended Mitigations Steps:

  • Use Assembly for this check

[G-02] It is not necessary to declare. No need to read amountLeft.

The an instance:

Rewards/RewardsDistributor.sol#L182-L183

uint256 amountLeft = _grantRewardToken(recipient, amount);
require(amountLeft == 0, "insufficient rewardToken for grant");

Recommended Mitigations Steps:

change to:

require(_grantRewardToken(recipient, amount) ==
    0, 'insufficient rewardToken for grant');

[G-03] Consider using Assembly sometimes for Loops and If statements. Save gas.

There an instance:

Example:

function howManyEvens(uint256 startNum, uint256 endNum) external pure returns(uint256) {
    // the value we will return
    uint256 ans;
    assembly {
        // syntax for for loop
        for { let i := startNum } lt( i, add(endNum, 1)  ) { i := add(i,1) }
        {
            // if i == 0 skip this iteration
            if iszero(i) {
                continue
            }
            // checks if i % 2 == 0
            // we could of used iszero, but I wanted to show you eq()
            if  eq( mod( i, 2 ), 0 ) {
                ans := add(ans, 1)
            }
        }
    }
    return ans;
}

Comptroller.sol#L216-L222

uint256 assetIndex = len;
for (uint256 i; i < len; ++i) {
    if (userAssetList[i] == vToken) {
        assetIndex = i;
        break;
    }
}

Recommended Mitigations Steps:

  • See the example

[G-04] When possible, use assembly instead of unchecked{++i}.

You can also use unchecked{++i;} for even more gas savings but this will not check to see if i overflows. For best gas savings, use inline assembly, however this limits the functionality you can achieve.

Example:

//loop with unchecked{++i}
function uncheckedPlusPlusI() public pure {
    uint256 j = 0;
    for (uint256 i; i < 10; ) {
        j++;
        unchecked {
            ++i;
        }
    }
}

Gas: 1329

//loop with inline assembly
function inlineAssemblyLoop() public pure {
    assembly {
        let j := 0
        for {
            let i := 0
        } lt(i, 10) {
            i := add(i, 0x01)
        } {
            j := add(j, 0x01)
        }
    }
}

Gas: 709

Recommended Mitigations Steps:

  • See the example. Implement whenever possible

[G-05] Consider use assembly for math (add, sub, mul, div).

Use assembly for math instead of Solidity. You can check for overflow/underflow in assembly to ensure safety.

There are 42 instances:

Example Addition:

//addition in Solidity
function addTest(uint256 a, uint256 b) public pure {
    uint256 c = a + b;
}

Gas: 303

//addition in assembly
function addAssemblyTest(uint256 a, uint256 b) public pure {
    assembly {
        let c := add(a, b)
        if lt(c, a) {
            mstore(0x00, "overflow")
            revert(0x00, 0x20)
        }
    }
}

Gas: 263

ExponentialNoError.sol#L81-L83

function add_(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

Example Subtraction:

//subtraction in Solidity
function subTest(uint256 a, uint256 b) public pure {
  uint256 c = a - b;
}

Gas: 300

//subtraction in assembly
function subAssemblyTest(uint256 a, uint256 b) public pure {
    assembly {
        let c := sub(a, b)
        if gt(c, a) {
            mstore(0x00, "underflow")
            revert(0x00, 0x20)
        }
    }
}

Gas: 263

ExponentialNoError.sol#L93-L95

function sub_(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

Example Multiplication:

//multiplication in Solidity
function mulTest(uint256 a, uint256 b) public pure {
    uint256 c = a * b;
}

Gas: 325

//multiplication in assembly
function mulAssemblyTest(uint256 a, uint256 b) public pure {
    assembly {
        let c := mul(a, b)
        if lt(c, a) {
            mstore(0x00, "overflow")
            revert(0x00, 0x20)
        }
    }
}

Gas: 265

ExponentialNoError.sol#L121-L123

function mul_(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

Example Division:

//division in Solidity
function divTest(uint256 a, uint256 b) public pure {
    uint256 c = a * b;
}

Gas: 325

//division in assembly
function divAssemblyTest(uint256 a, uint256 b) public pure {
    assembly {
        let c := div(a, b)
        if gt(c, a) {
            mstore(0x00, "underflow")
            revert(0x00, 0x20)
        }
    }
}

Gas: 265

ExponentialNoError.sol#L149-L151

function div_(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

BaseJumpRateModelV2.sol#L118

uint256 oneMinusReserveFactor = BASE - reserveFactorMantissa;

BaseJumpRateModelV2.sol#L120

uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / BASE;

BaseJumpRateModelV2.sol#L141

return (borrows * BASE) / (cash + borrows - reserves);

BaseJumpRateModelV2.sol#L157-L159

baseRatePerBlock = baseRatePerYear / blocksPerYear;
multiplierPerBlock = (multiplierPerYear * BASE) / (blocksPerYear * kink_);
jumpMultiplierPerBlock = jumpMultiplierPerYear / blocksPerYear;

BaseJumpRateModelV2.sol#L180

return (util * multiplierPerBlock) / BASE + baseRatePerBlock;

BaseJumpRateModelV2.sol#L182

uint256 normalRate = ((kink * multiplierPerBlock) / BASE) + baseRatePerBlock;

BaseJumpRateModelV2.sol#L185

excessUtil = util - kink;

BaseJumpRateModelV2.sol#L187

return (excessUtil * jumpMultiplierPerBlock) / BASE + normalRate;

WhitePaperInterestRateModel.sol#L37-L38

baseRatePerBlock = baseRatePerYear / blocksPerYear;
multiplierPerBlock = multiplierPerYear / blocksPerYear;

WhitePaperInterestRateModel.sol#L56

return (ur * multiplierPerBlock) / BASE + baseRatePerBlock;

WhitePaperInterestRateModel.sol#L73

uint256 oneMinusReserveFactor = BASE - reserveFactorMantissa;

WhitePaperInterestRateModel.sol#L75

uint256 rateToPool = (borrowRate * oneMinusReserveFactor) / BASE;

WhitePaperInterestRateModel.sol#L96

return (borrows * BASE) / (cash + borrows - reserves);

RiskFund/ReserveHelpers.sol#L64

balanceDifference = currentBalance - assetReserve;

Shortfall/Shortfall.sol#L244

riskFundBidAmount = (auction.seizedRiskFund * auction.highestBidBps) / MAX_BPS;

VToken.sol#L784

totalSupply = totalSupply + mintTokens;

VToken.sol#L857

totalSupply = totalSupply - redeemTokens;

VToken.sol#L897-L898

uint256 accountBorrowsNew = accountBorrowsPrev + borrowAmount;
uint256 totalBorrowsNew = totalBorrows + borrowAmount;

VToken.sol#L965-L966

uint256 accountBorrowsNew = accountBorrowsPrev - actualRepayAmount;
uint256 totalBorrowsNew = totalBorrows - actualRepayAmount;

VToken.sol#L1117

uint256 liquidatorSeizeTokens = seizeTokens - protocolSeizeTokens;

VToken.sol#L1120

uint256 totalReservesNew = totalReserves + protocolSeizeAmount;

VToken.sol#L1128

totalSupply = totalSupply - protocolSeizeTokens;

VToken.sol#L1188

totalReservesNew = totalReserves + actualAddAmount;

VToken.sol#L1278

return balanceAfter - balanceBefore;

VToken.sol#L1320

uint256 allowanceNew = startingAllowance - tokens;

VToken.sol#L1453-L1455

uint256 principalTimesIndex = borrowSnapshot.principal * borrowIndex;

        return principalTimesIndex / borrowSnapshot.interestIndex;

VToken.sol#L1477-L1478

uint256 cashPlusBorrowsMinusReserves = totalCash + totalBorrows + badDebt - totalReserves;
uint256 exchangeRate = (cashPlusBorrowsMinusReserves * expScale) / _totalSupply;

Comptroller.sol#L353

uint256 nextTotalBorrows = totalBorrows + borrowAmount;

Comptroller.sol#L1348

uint256 borrowPlusEffects = snapshot.borrows + snapshot.effects;

Comptroller.sol#L1352

snapshot.liquidity = snapshot.weightedCollateral - borrowPlusEffects;

Comptroller.sol#L1356

snapshot.shortfall = borrowPlusEffects - snapshot.weightedCollateral;

Recommended Mitigations Steps:

  • See the example above

#0 - c4-judge

2023-05-18T17:42:01Z

0xean marked the issue as grade-b

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter