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
Rank: 93/115
Findings: 1
Award: $4.37
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Bauchibred
Also found by: 0x3b, 0xDetermination, 0xMosh, 0xScourgedev, 0xTheC0der, 0xTiwa, 0xWaitress, 0xdice91, 0xfusion, 0xpiken, 0xprinc, 0xweb3boy, ArmedGoose, Aymen0909, Breeje, Brenzee, Daniel526, DavidGiladi, DeFiHackLabs, Flora, Fulum, HChang26, Hama, IceBear, J4X, Krace, KrisApostolov, Maroutis, Mirror, MohammedRizwan, Norah, PwnStars, SPYBOY, TangYuanShen, Testerbot, ThreeSigma, Tricko, al88nsk, alexweb3, ast3ros, berlin-101, bin2chen, blutorque, btk, d3e4, deth, e0d1n, ether_sky, ge6a, gkrastenov, glcanvas, hals, imare, inzinko, jkoppel, jnforja, joaovwfreire, josephdara, kutugu, lotux, lsaudit, mahdirostami, merlin, n1punp, nadin, neumo, nisedo, nobody2018, oakcobalt, orion, peanuts, pep7siup, pina, ptsanev, rokinot, rvierdiiev, said, santipu_, sashik_eth, seerether, squeaky_cactus, terrancrypt, tonisives, twicek, vagrant, xAriextz, y4y
4.3669 USDC - $4.37
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
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 :
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)
Hardhat
In the token sweep function update the tokenAmountAccrued to be under or equal to token_.balanceOf(PrimeLiquidityProvider.address)
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)