Platform: Code4rena
Start Date: 27/05/2022
Pot Size: $75,000 USDC
Total HM: 20
Participants: 58
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 15
Id: 131
League: ETH
Rank: 21/58
Findings: 2
Award: $352.96
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x29A, 0xNazgul, 0xf15ers, BowTiedWardens, Chom, Funen, Kaiziron, Kumpa, MiloTruck, Picodes, Ruhum, SecureZeroX, Sm4rty, SmartSek, StyxRave, WatchPug, Waze, asutorufos, bardamu, berndartmueller, c3phas, catchup, cccz, codexploder, cryptphi, defsec, delfin454000, dipp, fatherOfBlocks, gzeon, hake, hansfriese, hyh, masterchief, oyc_109, sach1r0, sashik_eth, shenwilly, simon135, unforgiven
268.1375 USDC - $268.14
There are ERC20 tokens that may make certain customizations to their ERC20 contracts.
One type of these tokens is deflationary tokens that charge a certain fee for every transfer()
or transferFrom()
.
The FeeBurner.burnToTarget
function will try to swap more of an ERC20 token than the contract actually received and due to transfering the token into the SwapperRouter
contract, the token balance is insufficient and the transfer will revert.
token_.safeTransferFrom(msg.sender, address(this), tokenBalance_); // @audit-info less tokens will be received in the contract when using fee-on transfer tokens if (address(token_) == targetUnderlying_) continue; _approve(address(token_), address(swapperRouter_)); swapperRouter_.swap(address(token_), _WETH, tokenBalance_); // @audit-info the swap function transfers the `token_` to itself and due to `tokenBalance_` not reflecting the correct token amount in the contract, the swap will revert
Manual review
As other contracts (e.g. AmmGauge.stakeFor
) already handle fee-on transfer tokens correctly, make sure also FeeBurner.burnToTarget
does so.
Compare the token balance before the transfer and after the transfer and use the delta as the actual swap amount to prevent the FeeBurner.burnToTarget
function reverting for fee-on transfer tokens:
function burnToTarget(address[] memory tokens_, address targetLpToken_) public payable override returns (uint256 received) { ... uint256 oldBal = token_.balanceOf(address(this)); token_.safeTransferFrom(msg.sender, address(this), tokenBalance_); uint256 swapAmount = token_.balanceOf(address(this)) - oldBal; if (address(token_) == targetUnderlying_) continue; _approve(address(token_), address(swapperRouter_)); swapperRouter_.swap(address(token_), _WETH, swapAmount); // @audit-info use `swapAmount` ... }
#0 - chase-manning
2022-06-06T11:27:52Z
We don't support fee-on-transfer tokens
#1 - GalloDaSballo
2022-06-19T21:16:06Z
I believe that the finding has validity, however in case of a revert, no funds would be loss nor stuck, for that reason QA is a more appropriate Severity
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x29A, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, Chom, Dravee, Fitraldys, Funen, Kaiziron, MiloTruck, Picodes, Randyyy, RoiEvenHaim, SecureZeroX, Sm4rty, SmartSek, StyxRave, Tadashi, Tomio, Waze, asutorufos, berndartmueller, c3phas, catchup, csanuragjain, defsec, delfin454000, djxploit, fatherOfBlocks, gzeon, hake, hansfriese, oyc_109, robee, sach1r0, sashik_eth, scaraven, simon135
84.8218 USDC - $84.82
A uint256
value can not be negative, hence there is no need to check for it.
tokenomics/InflationManager.sol#L589
totalLpPoolWeight = totalLpPoolWeight > 0 ? totalLpPoolWeight : 0;
tokenomics/InflationManager.sol#L602
totalAmmTokenWeight = totalAmmTokenWeight > 0 ? totalAmmTokenWeight : 0;
tokenomics/InflationManager.sol#L575
totalKeeperPoolWeight = totalKeeperPoolWeight > 0 ? totalKeeperPoolWeight : 0;
Remove the check and use the value directly to save gas.
poolCheckpoint
function callThe AmmGauge
and KeeperGauge
contracts call the function poolCheckpoint()
within the kill()
function. Therefore, functions which call this kill()
function do not have to additionally call the poolCheckpoint()
function.
A uint256
value can not be negative, hence there is no need to check for it.
tokenomics/InflationManager.sol#L427
tokenomics/InflationManager.sol#L461
Remove the call to poolCheckpoint()
to save gas.
#0 - GalloDaSballo
2022-06-17T23:21:49Z
I agree, because these are Storage value set to the same value, the gas saved is 100 per instance 300
I agree, but would have liked to see a POC with detailed gas savings, in lack of it will give it 200 gas (low estimate)
Total Gas Saved
500