Platform: Code4rena
Start Date: 26/05/2022
Pot Size: $75,000 USDT
Total HM: 31
Participants: 71
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 18
Id: 126
League: ETH
Rank: 15/71
Findings: 3
Award: $1,168.41
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: SmartSek
Also found by: ch13fd357r0y3r
937.187 USDT - $937.19
Compromised owner
can withdraw()
entire balance of VeTokenMinter.sol
to any other account.
function withdraw(address _destination, uint256 _amount) external onlyOwner { veToken.safeTransfer(_destination, _amount); emit Withdraw(_destination, _amount); }
The owner
can choose any _destination
and _amount
to send funds to with no delay or limit.
These funds could be used to call Booster.deposit()
and then Booster.withdraw()
(withdraw) the equivalent in lptoken
.
Manual Review
Consider implementing a timelock on VeTokenMinter.withdraw()
and changing the destination
to an address that owner
has no control over.
Example of similar issues illustrating the severity of the finding can be found here (H-09).
#0 - solvetony
2022-06-15T15:21:06Z
Requires compromised owner.
#1 - GalloDaSballo
2022-07-05T22:37:08Z
Finding is valid, but contingent on a Malicious or Compromised Admin, Medium Severity is more appropriate
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x29A, 0xDjango, 0xNazgul, 0xf15ers, BouSalman, Chom, Deivitto, Dravee, ElKu, FSchmoede, Funen, GimelSec, Hawkeye, MiloTruck, Picodes, SecureZeroX, SmartSek, TerrierLover, WatchPug, _Adam, asutorufos, berndartmueller, c3phas, catchup, cccz, cogitoergosumsw, cryptphi, csanuragjain, delfin454000, dipp, ellahi, gzeon, hansfriese, horsefacts, hyh, kirk-baird, minhquanym, oyc_109, pauliax, reassor, robee, sashik_eth, shenwilly, simon135, sorrynotsorry, sseefried, unforgiven, xiaoming90, z3s
171.4663 USDT - $171.47
) { staker = _staker; minter = _minter; veAsset = _veAsset; escrow = _escrow; feeManager = msg.sender; maxTime = _maxTime; }
If any of the immutable variables above is accidentally set to zero the contract would have to be redeployed.
We recommend implementing a zero address check.
Other instances: Booster.sol#L41-L45
safeApprove
has been deprecatedWe recommend using safeIncreaseAllowance
and safeDecreaseAllowance
from SafeERC20
.
Verb is not conjugated correctly:
//can locking immediately or defer locking to someone else by paying a fee.
can lock
immediately.
require(!isShutdown, "shutdown"); PoolInfo storage pool = poolInfo[_pid]; require(pool.shutdown == false, "pool is closed");
For better readability please stick with one form of boolean check, either using !
or == false
.
Please have in mind that == false
is slightly more gas expensive.
//values must be within certain ranges
Comment above suggests variable still are bound to specific ranges, however these ranges have been removed from this implementation. Please remove comment.
SafeMath
inconsistencySome calculations redundantly use SafeMath
and some dont.
Please choose one method (preferably not SafeMath
) and stick with it.
No SafeMath
With SafeMath
veTokenMinter.sol
doesnt really mint
tokensveTokenMinter.sol
doesnt mint
tokens. It only really safeTransfer
it to another account.
Please use a naming convention that is in line with the functionality to speed up the auditing process.
#0 - GalloDaSballo
2022-07-09T18:14:05Z
Valid low
NC because of the usage in this codebase
NC
Nice find, valid Refactoring
Nice find, valid Refactoring
Valid Refactoring
Short and sweet and with interesting thoughts. 1L, 3R, 2NC
🌟 Selected for report: IllIllI
Also found by: 0x1f8b, 0x29A, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, Cityscape, Dravee, ElKu, FSchmoede, Funen, GalloDaSballo, Hawkeye, Kaiziron, MiloTruck, Randyyy, RoiEvenHaim, Ruhum, SecureZeroX, SmartSek, TerrierLover, TomJ, Tomio, WatchPug, Waze, _Adam, asutorufos, c3phas, catchup, cogitoergosumsw, delfin454000, ellahi, fatherOfBlocks, gzeon, hansfriese, horsefacts, jonatascm, minhquanym, oyc_109, pauliax, reassor, robee, sach1r0, saian, sashik_eth, simon135, z3s
59.7467 USDT - $59.75
SafeMath
Underflows/overflows cannot happen in solidity >=0.8.0
, therefore SafeMath
is redundant.
for
loop gas optimisationfor (uint256 i = 0; i < extraRewards.length; i++) { IRewards(extraRewards[i]).stake(_for, _amount); }
Gas could be saved by:
Example:
uint length = extraRewards.length; for (uint256 i; i < length;) { IRewards(extraRewards[i]).stake(_for, _amount); unchecked { ++i; } }
require(pool.shutdown == false, "pool is closed");
pool.shutdown == false
can be changed to !pool.shutdown
.
require(pool.shutdown == false, "pool is closed"); //send to proxy to stake address lptoken = pool.lptoken; IERC20(lptoken).safeTransferFrom(msg.sender, staker, _amount); //stake address gauge = pool.gauge; require(gauge != address(0), "!gauge setting");
require(gauge != address(0), "!gauge setting");
could be set prior to //send to proxy to stake
to save the gas used in safeTransferFrom
in case gauge == address(0)
.
Parameters such as totalCliffs
, reductionCliff
, veToken
and maxTime
could be made immutable to save gas.
#0 - GalloDaSballo
2022-07-18T23:31:49Z
4 * 2100 = 8400 from immutable
Rest is negligible