Platform: Code4rena
Start Date: 29/03/2024
Pot Size: $36,500 USDC
Total HM: 5
Participants: 72
Period: 5 days
Judge: 3docSec
Total Solo HM: 1
Id: 357
League: ETH
Rank: 11/72
Findings: 2
Award: $498.91
π Selected for report: 0
π Solo Findings: 0
490.6256 USDC - $490.63
https://github.com/code-423n4/2024-03-ondo-finance/blob/be2e9ebca6fca460c5b0253970ab280701a15ca1/contracts/ousg/ousgInstantManager.sol#L388 https://github.com/code-423n4/2024-03-ondo-finance/blob/be2e9ebca6fca460c5b0253970ab280701a15ca1/contracts/ousg/ousgInstantManager.sol#L599
The OUSGInstantManager contract implements a minimum redemption amount that is enforced in the _redeem function, dictating the minimum amount a user can redeem at one time. This limit can be modified at any time by an admin with the CONFIGURER_ROLE using the setMinimumRedemptionAmount function.
function _redeem(uint256 ousgAmountIn) internal returns (uint256 usdcAmountOut) { ... require( usdcAmountToRedeem >= minimumRedemptionAmount, "OUSGInstantManager::_redeem: Redemption amount too small" ); ... }
However, this can be problematic because users having deposited enough or left in an amount over the minimum could be forced to now make an extra deposit to be able to redeem their shares if the minimum is raised. Since there is a fee paid in deposits this will mean users will end up paying an extra amount to redeem their funds. This can also be abused by an admin to get users to pay more fees or be unable to redeem their shares.
function setMinimumRedemptionAmount(uint256 _minimumRedemptionAmount) external override onlyRole(CONFIGURER_ROLE) { require(_minimumRedemptionAmount >= FEE_GRANULARITY, "setMinimumRedemptionAmount: Amount too small"); emit MinimumRedemptionAmountSet(minimumRedemptionAmount, _minimumRedemptionAmount); minimumRedemptionAmount = _minimumRedemptionAmount; }
Set a reasonable ceiling for what the minimumRedemptionAmount can be set to, that way even if the minimum amount is increased users can have an idea of the maximum it can be set. Furthermore, this canβt be abused by an admin to get a user to pay more fees.
Other
#0 - c4-pre-sort
2024-04-04T23:51:25Z
0xRobocop marked the issue as duplicate of #142
#1 - c4-judge
2024-04-09T11:27:44Z
3docSec marked the issue as satisfactory
π Selected for report: immeas
Also found by: 0xAkira, 0xCiphky, 0xGreyWolf, 0xJaeger, 0xMosh, 0xabhay, 0xlemon, 0xmystery, 0xweb3boy, Aamir, Abdessamed, Aymen0909, Breeje, DanielArmstrong, DarkTower, Dots, EaglesSecurity, FastChecker, HChang26, Honour, IceBear, JC, K42, Krace, MaslarovK, Omik, OxTenma, SAQ, Shubham, Stormreckson, Tigerfrake, Tychai0s, VAD37, ZanyBonzy, albahaca, arnie, ast3ros, asui, b0g0, bareli, baz1ka, btk, caglankaan, carrotsmuggler, cheatc0d3, dd0x7e8, grearlake, igbinosuneric, jaydhales, kaden, kartik_giri_47538, m4ttm, ni8mare, niser93, nonn_ac, oualidpro, pfapostol, pkqs90, popeye, radev_sw, samuraii77, slvDev, zabihullahazadzoi
8.2807 USDC - $8.28
https://github.com/code-423n4/2024-03-ondo-finance/blob/be2e9ebca6fca460c5b0253970ab280701a15ca1/contracts/ousg/ousgInstantManager.sol#L278 https://github.com/code-423n4/2024-03-ondo-finance/blob/be2e9ebca6fca460c5b0253970ab280701a15ca1/contracts/ousg/ousgInstantManager.sol#L290
The OUSGInstantManager contract implements a mint limit that is enforced in the _mint function, dictating how much USDC can be transferred for minting in a specified duration. The function charges an instant mint fee that is deducted from the usdcAmountIn before minting, but the fee is not actually minted. Instead, it is directly transferred to the usdcReceiver address. When incrementing the mint limit through the _checkAndUpdateInstantMintLimit function the usdcAmountIn value is used.
function _mint(uint256 usdcAmountIn, address to) internal returns (uint256 ousgAmountOut) { ... _checkAndUpdateInstantMintLimit(usdcAmountIn); if (address(investorBasedRateLimiter) != address(0)) { investorBasedRateLimiter.checkAndUpdateMintLimit(msg.sender, usdcAmountIn); } ... uint256 usdcfees = _getInstantMintFees(usdcAmountIn); uint256 usdcAmountAfterFee = usdcAmountIn - usdcfees; ... // Transfer USDC if (usdcfees > 0) { usdc.transferFrom(msg.sender, feeReceiver, usdcfees); } usdc.transferFrom(msg.sender, usdcReceiver, usdcAmountAfterFee); ... ousg.mint(to, ousgAmountOut); }
This means that the mint limit is incorrectly being incremented by the fee amount as well, making it impossible for the minted tokens to reach the mint limit for a specific duration, even if there is enough demand.
Modify the _mint function to call the _checkAndUpdateInstantMintLimit function with the usdcAmountAfterFee instead of usdcAmountIn. This way, only the tokens being minted will be accounted for in the mint limit calculation.
function _mint(uint256 usdcAmountIn, address to) internal returns (uint256 ousgAmountOut) { ... uint256 usdcfees = _getInstantMintFees(usdcAmountIn); uint256 usdcAmountAfterFee = usdcAmountIn - usdcfees; _checkAndUpdateInstantMintLimit(usdcAmountAfterFee); // change here ... }
Other
#0 - c4-pre-sort
2024-04-04T05:18:12Z
0xRobocop marked the issue as duplicate of #47
#1 - c4-judge
2024-04-09T09:53:14Z
3docSec changed the severity to QA (Quality Assurance)
#2 - c4-judge
2024-04-09T09:53:29Z
3docSec marked the issue as grade-b