Venus Prime - orion's results

Earn, borrow & lend on the #1 Decentralized Money Market on the BNB chain.

General Information

Platform: Code4rena

Start Date: 28/09/2023

Pot Size: $36,500 USDC

Total HM: 5

Participants: 115

Period: 6 days

Judge: 0xDjango

Total Solo HM: 1

Id: 290

League: ETH

Venus Protocol

Findings Distribution

Researcher Performance

Rank: 93/115

Findings: 1

Award: $4.37

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2023-09-venus/blob/main/contracts/Tokens/Prime/PrimeLiquidityProvider.sol#L261

Vulnerability details

Impact

The accrueTokens function will always reverts when sweepToken is called with all balance of address(this), thus the contract will fails to work as intended

Proof of Concept

The accrueTokens function updates the tokenAmountAccrued state to uint256 tokenAccrued = (balanceDiff <= accruedSinceUpdate ? balanceDiff : accruedSinceUpdate);, where balanceDiff is the address(this) balance on the specified token - tokenAmountAccrued[token_]

The balance when the sweepToken function is called with all of the address(this) balance, will become 0, however tokenAmountAccrued will not,

function sweepToken(IERC20Upgradeable token_, address to_, uint256 amount_) external onlyOwner { uint256 balance = token_.balanceOf(address(this)); if (amount_ > balance) { revert InsufficientBalance(amount_, balance); } token_.safeTransfer(to_, amount_);

This will make the following line equation

uint256 balanceDiff = balance - tokenAmountAccrued[token_];

become alike "0 - (number higher than 0)", which will make it underflows and leads to the function call reverts every time, and the accrueToken function will reverts everytime (until someone sends and amount of the specified token that is higher than tokenAmountAccrued[token_] to PrimeLiquidityProvider, until balance - tokenAmountAccrued[token_] does not revert), scenario :

  • owner initialize tokenA
  • amount of tokens (1000) will be sent to PrimeLiquidityProvider, then calls to PrimeLiquidityProvider.accrueToken(tokenA)
  • owner calls PrimeLiquidityProvider.sweepToken
  • now tokenA.balanceOf(PrimeLiquidityProvider.address) is 0, and tokenAmountAccrued[tokenA] is 1000
  • the uint256 balanceDiff = balance - tokenAmountAccrued[token_]; will be 0 - 1000, thus always fails to deliver and reverts
  • the PrimeLiquidityProvider.accrueToken(tokenA) will always reverts

Note: in the following PoC, I removed the "if (deltaBlocks > 0)" condition in the solidity code to ensure the issue existence (instead of re-accruing on the next block)

PoC :

describe("Test Accrue failure", () => { it("check on transfer success", async () => { beforeEach(async () => { await accessControl.isAllowedToCall.returns(true); await tokenA.transfer(primeLiquidityProvider.address, tokenAInitialFund); await tokenB.transfer(primeLiquidityProvider.address, tokenBInitialFund); }); }); it("Transfer > Accrue > Seep > Re-Accrue", async () => { await mine(10); // Accrue const sweepAmount = 1000; await tokenA.transfer(primeLiquidityProvider.address, sweepAmount); const lastAccruedBlock = await primeLiquidityProvider.lastAccruedBlock(tokenA.address); await primeLiquidityProvider.accrueTokens(tokenA.address); const currentBlock = await primeLiquidityProvider.getBlockNumber(); const balanceA = await primeLiquidityProvider.tokenAmountAccrued(tokenA.address); const deltaBlocks = Number(currentBlock) - Number(lastAccruedBlock); const accrued = deltaBlocks * Number(tokenASpeed); // sweep const balanceAfter = await tokenA.balanceOf(primeLiquidityProvider.address); const tx = await primeLiquidityProvider.sweepToken(tokenA.address, signer.address, balanceAfter); tx.wait(); // Trying to accrue again await primeLiquidityProvider.accrueTokens(tokenA.address); }); });

Run :

npx hardhat test tests/hardhat/Prime/PrimeLiquidityProvider.ts

Log :

PrimeLiquidityProvider: tests Testing all initalized values The Hardhat Network tracing engine could not be initialized. Run Hardhat with --verbose to learn more. ✔ Tokens intialized ✔ Distribution Speed ... Test Accrue failure ✔ check on transfer success 1) Transfer > Accrue > Seep > Re-Accrue 23 passing (5s) 1 failing 1) PrimeLiquidityProvider: tests Test Accrue failure Transfer > Accrue > Seep > Re-Accrue: Error: VM Exception while processing transaction: reverted with panic code 0x11 (Arithmetic operation underflowed or overflowed outside of an unchecked block) at <UnrecognizedContract>.<unknown> (0x5fc8d32690cc91d4c39d9d3abcbd16989f875707)

Tools Used

Hardhat

In the token sweep function update the tokenAmountAccrued to be under or equal to token_.balanceOf(PrimeLiquidityProvider.address)

Assessed type

Error

#0 - c4-pre-sort

2023-10-06T23:36:12Z

0xRobocop marked the issue as duplicate of #42

#1 - c4-judge

2023-10-31T17:09:53Z

fatherGoose1 changed the severity to QA (Quality Assurance)

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