Platform: Code4rena
Start Date: 24/10/2023
Pot Size: $36,500 USDC
Total HM: 4
Participants: 147
Period: 6 days
Judge: 0xDjango
Id: 299
League: ETH
Rank: 120/147
Findings: 1
Award: $4.52
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0xmystery
Also found by: 0x11singh99, 0xAadi, 0xAlix2, 0xG0P1, 0xStalin, 0xWaitress, 0x_Scar, 0xhacksmithh, 0xhunter, 0xpiken, Al-Qa-qa, Arz, Avci, Bauchibred, BeliSesir, Breeje, Bughunter101, DarkTower, Eeyore, Fitro, HChang26, Imlazy0ne, J4X, JCK, Kaysoft, Kral01, Madalad, Mike_Bello90, Noro, PASCAL, PENGUN, Proxy, Rickard, Shubham, SovaSlava, Strausses, Team_Rocket, ThreeSigma, Topmark, Udsen, Walter, Yanchuan, Zach_166, ZanyBonzy, adam-idarrha, adeolu, almurhasan, arjun16, ast3ros, asui, ayden, btk, cartlex_, castle_chain, cccz, chainsnake, codynhat, critical-or-high, cryptonue, csanuragjain, deepkin, degensec, dirk_y, erebus, foxb868, ge6a, hunter_w3b, jasonxiale, kkkmmmsk, lanrebayode77, lsaudit, marchev, matrix_0wl, max10afternoon, nuthan2x, oakcobalt, oxchsyston, pavankv, peanuts, pep7siup, pipidu83, pontifex, ptsanev, qpzm, radev_sw, rokinot, rotcivegaf, rvierdiiev, sorrynotsorry, squeaky_cactus, supersizer0x, tnquanghuy0512, twcctop, twicek, young, zhaojie, ziyou-
4.5226 USDC - $4.52
Total Low Risk Issues | 1 |
---|
Count | Title | Instances |
---|---|---|
L-01 | Wrong accounting in StakedUSDe in variable vestingAmount | 1 |
Total Non-Critical Issues | 1 |
---|
Count | Title | Instances |
---|---|---|
NC-01 | Unnecessary if-revert statement | 4 |
StakedUSDe
contract in variable vestingAmount
According to the description of vestingAmount
in the comments vestingAmount
is:
/// @notice The amount of the last asset distribution from the controller contract into this /// contract + any unvested remainder at that time uint256 public vestingAmount;
vestingAmount
is updated in transferInRewards()
but it will never be the input amount + any unvested remainder at that time, only the input amount.
This is because the line if (getUnvestedAmount() > 0) revert StillVesting();
reverts if getUnvestedAmount()
returns anything greater than 0.
function transferInRewards(uint256 amount) external nonReentrant onlyRole(REWARDER_ROLE) notZero(amount) { if (getUnvestedAmount() > 0) revert StillVesting(); uint256 newVestingAmount = amount + getUnvestedAmount(); // @audit `getUnvestedAmount()` will always return 0 vestingAmount = newVestingAmount; // @audit `vestingAmount` will not be updated correctly lastDistributionTimestamp = block.timestamp; // transfer assets from rewarder to this contract IERC20(asset()).safeTransferFrom(msg.sender, address(this), amount); emit RewardsReceived(amount, newVestingAmount); }
First two instances
In EthenaMinting
contract, functions mint()
and redeem()
use an unneccessary if-revert statement while calling _deduplicateOrder()
if (!_deduplicateOrder(order.benefactor, order.nonce)) revert Duplicate();
The _deduplicateOrder()
function only returns true or reverts before returning anything. Thus the revert Duplicate()
will never be executed.
function _deduplicateOrder(address sender, uint256 nonce) private returns (bool) { (bool valid, uint256 invalidatorSlot, uint256 invalidator, uint256 invalidatorBit) = verifyNonce(sender, nonce); mapping(uint256 => uint256) storage invalidatorStorage = _orderBitmaps[sender]; invalidatorStorage[invalidatorSlot] = invalidator | invalidatorBit; return valid; // @audit returns true, otherwise reverts before returning anything }
verifyNonce()
function used in _deduplicateOrder()
function verifyNonce(address sender, uint256 nonce) public view override returns (bool, uint256, uint256, uint256) { if (nonce == 0) revert InvalidNonce(); uint256 invalidatorSlot = uint64(nonce) >> 8; uint256 invalidatorBit = 1 << uint8(nonce); mapping(uint256 => uint256) storage invalidatorStorage = _orderBitmaps[sender]; uint256 invalidator = invalidatorStorage[invalidatorSlot]; if (invalidator & invalidatorBit != 0) revert InvalidNonce(); return (true, invalidatorSlot, invalidator, invalidatorBit); }
Second two instances
In EthenaMinting
contract, functions transferToCustody()
and verifyRoute()
don't need to check for address(0)
.
if (wallet == address(0) || !_custodianAddresses.contains(wallet)) revert InvalidAddress();
if (!_custodianAddresses.contains(route.addresses[i]) || route.addresses[i] == address(0) || route.ratios[i] == 0)
Because these functions only allow usage of _custodianAddresses
there is no need to check for address(0)
because the function addCustodianAddress()
that is used to add addresses to the variable already checks for address(0)
/// @notice Adds an custodian to the supported custodians list. function addCustodianAddress(address custodian) public onlyRole(DEFAULT_ADMIN_ROLE) { if (custodian == address(0) || custodian == address(usde) || !_custodianAddresses.add(custodian)) { revert InvalidCustodianAddress(); } emit CustodianAddressAdded(custodian); }
#0 - c4-pre-sort
2023-11-02T02:51:48Z
raymondfam marked the issue as sufficient quality report
#1 - c4-judge
2023-11-14T17:00:07Z
fatherGoose1 marked the issue as grade-b