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: 19/72
Findings: 2
Award: $72.43
🌟 Selected for report: 0
🚀 Solo Findings: 0
64.1515 USDC - $64.15
Admin's can't burn rOUSG of non-KYC'd users.
rOUSG.burn is documented as, "Admin burn function to burn rOUSG tokens from any account". However, it's not possible to burn shares from an account which has been removed from the KYC list or sanctioned.
As we can see, we execute _burnShares
on the provided account:
_burnShares(_account, ousgSharesAmount);
_burnShares
executes _beforeTokenTransfer
with the _account
as the from
address. As we can see, if the from
address is non-zero and doesn't pass KYC, we revert:
if (from != address(0)) { // If not minting require(_getKYCStatus(from), "rOUSG: 'from' address not KYC'd"); }
As a result, it's impossible to burn the shares of a non-KYC'd user, even as an admin.
Note that having KYC/sanctioned funds DoS is documented as a known issue, however this prevents even the admin from accessing those funds via a method which is intended to work on "any account".
Create and call a specialized function to burn shares without validating KYC status which is only executable by the admin-only burn function.
Other
#0 - c4-pre-sort
2024-04-04T05:11:31Z
0xRobocop marked the issue as duplicate of #237
#1 - c4-judge
2024-04-09T08:32:53Z
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/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/rOUSG.sol#L276-L287 https://github.com/code-423n4/2024-03-ondo-finance/blob/78779c30bebfd46e6f416b03066c55d587e8b30b/contracts/ousg/rOUSG.sol#L638
Fails to comply to ERC20 spec in two ways as stated below.
Note that under EIP Compliance Checklist, it states: "We strive to keep rOUSG as ERC20 compliant as possible."
There are two ways in which the contract fails to adhere to the ERC20 spec:
function transferFrom( address _sender, address _recipient, uint256 _amount ) public returns (bool) { uint256 currentAllowance = allowances[_sender][msg.sender]; // @audit will succeed if _amount is 0 require(currentAllowance >= _amount, "TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE"); _transfer(_sender, _recipient, _amount); _approve(_sender, msg.sender, currentAllowance - _amount); return true; }
This is in defiance of the ERC20 spec where it states: "The function SHOULD throw
unless the _from
account has deliberately authorized the sender of the message via some mechanism."
function burn( address _account, uint256 _amount ) external onlyRole(BURNER_ROLE) { uint256 ousgSharesAmount = getSharesByROUSG(_amount); if (ousgSharesAmount < OUSG_TO_ROUSG_SHARES_MULTIPLIER) revert UnwrapTooSmall(); _burnShares(_account, ousgSharesAmount); ousg.transfer( msg.sender, ousgSharesAmount / OUSG_TO_ROUSG_SHARES_MULTIPLIER ); // @audit emits transfer from address(0) to sender, // should be from _account to address(0) emit Transfer(address(0), msg.sender, getROUSGByShares(ousgSharesAmount)); emit TransferShares(_account, address(0), ousgSharesAmount); }
This incorrect usage of the Transfer event results in indexing logic failing to properly track balances and totalSupply.
ERC20
#0 - 0xRobocop
2024-04-04T06:20:29Z
QA
#1 - c4-pre-sort
2024-04-04T06:20:33Z
0xRobocop marked the issue as insufficient quality report
#2 - 3docSec
2024-04-09T06:42:18Z
Point 1: invalid (inconsequential, and common practice), Point 2: QA
#3 - c4-judge
2024-04-09T06:42:32Z
3docSec changed the severity to QA (Quality Assurance)
#4 - c4-judge
2024-04-09T06:42:35Z
3docSec marked the issue as grade-b