Onyx Protocol - Audit

CertiKFiles named in the report

CertiK reviewed Onyx Protocol (Onyx Protocol - Audit) on 28 Feb 2023: 25 findings, 0 critical; 11 marked fixed, 14 open.

No open critical findings
Open the reportOpen Onyx Protocol’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings25

Statuses are the security firm’s own, from its report.

SeverityOpenAcknowledgedFixed
Critical000
High301
Medium203
Low907
High`_addReserves` function is not disabled in OErc7Fixed

The `_addReserves()` function accrues interest and adds reserves by transferring assets from the sender. The formula for the calculation of `exchangeRate` is as follows: $$ exchangeRate = {totalCash + totalBorrows - totalReserves \over totalSupply } $$ ```solidity=342 function exchangeRateStoredInternal() internal view returns (MathError, uint) { uint _totalSupply = totalSupply; if (_totalSupply == 0) { /* * If there are no tokens minted: * exchangeRate = initialExchangeRate */ return (MathError.NO_ERROR, initialExchangeRateMantissa); } else { /* * Otherwise: * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply */ uint totalCash = getCashPrior(); uint cashPlusBorrowsMinusReserves; Exp memory exchangeRate; MathError mathErr; (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } (mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, _totalSupply); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } return (MathError.NO_ERROR, exchangeRate.mantissa); } } ``` The `getCashPrior()` function returns `totalSupply`, the NFT can not be borrowed, so the `totalBorrows` is always 0. Based on the logic of functions `mintFresh()` and `redeemFreshOToken()`, it can be inferred that the exchange rate between the underlying asset and the token is 1:1. If the `_addReserves()` function is not disabled, the exchange rate will decrease, the return value `redeemAmount` at line 633 in the `OTokenEx` contract may be 0 when the sender redeems underlying asset using the function `redeem()`/`redeems()`. Worse, if `totalReserves` equals `totalCash`, the exchange rate will be 0 and the sender will not be able to mint/redeem.

MediumArray Index Not CheckFixed

The input parameter `tokenIndex` is not checked for a valid array index. If the `tokenIndex` is not correct, the `doTransferOut()` function will revert and the user can not redeem the underlying asset.

MediumLack Of Access ControlFixed

The functions `setUnderlyingPrice()` and `setDirectPrice()` can be called by anyone as it has no access restriction. This enables anyone to call this and update the `prices` configuration.

MediumPotential Reentrancy AttackFixed

The following codes in the function `redeemFresh()/borrowFresh()` do not meet the Checks-Effects-Interactions pattern. ```solidity=787 doTransferOut(borrower, borrowAmount); /* We write the previously calculated values into storage */ accountBorrows[borrower].principal = vars.accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = vars.totalBorrowsNew; ``` It only has a reentrancy lock as there is no lock at the Controller level, only the OToken level. If the `OToken` is an ERC777/ERC677 protocol, the reentrancy can happen in function levels of an ERC777/ERC677-based contract, i.e. multiple function calls that are triggered by the hook mechanism of ERC777/ERC677. This issue is possible to happen with all compound forks, but Compound is not affected as they do not list tokens with callback functionality.

Low`totalReserves` Update errorFixed

The `_reduceReservesFresh()` function reduces reserves by transferring to admin. However, the second argument of `doTransferOut()` function is the index of the token, not the reduction amount. Additionally, the `doTransferOut()` function can only transfer one NFT at a time. As a result, the reduction amount should always be 1, and the admin can only transfer their own tokens.

LowInclude unlisted tokensFixed

The `claimXcn()` function of the `Comptroller` contract requires that the token must be listed. However, the `pendingXcn()` function does not exclude the unlisted token. The same issue exists with the function `getDailyXCN()`.

LowInconsistent with the logic of the `distributeSupFixed

In the `distributeSupplierXcn()` function of the `Comptroller` contract, line 1276 covers the case where users supplied tokens before the market's supply state index was set. Rewards the user with `xcnInitialIndex` accrued from the start of when supplier rewards were first set for the market. So the `distributeSupplierXcn()` function of the `OnyxLens` contract should use the same comparison conditions.

LowMissing Zero Address ValidationFixed

Addresses should be checked before assignment or external call to make sure they are not zero addresses. ```solidity=51 admin = admin_; ``` - `admin_` is not zero-checked before being used. --- ```solidity=68 implementation = implementation_; ``` - `implementation_` is not zero-checked before being used. --- ```solidity=52 admin = admin_; ``` - `admin_` is not zero-checked before being used. --- ```solidity=69 implementation = implementation_; ``` - `implementation_` is not zero-checked before being used. --- ```solidity=36 target = target_; ``` - `target_` is not zero-checked before being used. --- ```solidity=415 MINT_BASE_TOKEN = mintBaseToken; ``` - `mintBaseToken` is not zero-checked before being used.

LowRedundant CodeFixed

In the `oErc721` contract, the sender cannot borrow the assets, so the aforementioned lines are redundant since the `totalBorrows` is always 0.

LowReturn a different XCN token addressFixed

In the `Comptroller` contract, the function `getXcnAddress()` returns the address `0xc03Fa5e041BE9C8deD030D6dec7936cE67D78ae8` as the XCN token address. However, in the `ComptrollerG3`, `ComptrollerG4`, and `ComptrollerG5` contracts, this function returns the address `0xA2cd3D43c775978A96BdBf12d733D5A1ED94fb18`.

Show 1 more
LowUnimplemented function `_setMigration()`Fixed

The function `_setMigration()` is not implemented in the implementation contract `OErc721`.

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (47)

  • contracts/Reservoir.sol
  • contracts/LegacyInterestRateModel.sol
  • contracts/ComptrollerExInterface.sol
  • contracts/JumpRateModelV2.sol
  • contracts/OErc721Delegate.sol
  • contracts/OEther.sol
  • contracts/EIP20Interface.sol
  • contracts/ComptrollerG5.sol
  • contracts/BaseJumpRateModelV2.sol
  • contracts/ErrorReporter.sol
  • contracts/InterestRateModel.sol
  • contracts/SimplePriceOracle.sol
  • contracts/PriceOracle.sol
  • contracts/SafeMath.sol
  • contracts/XCNInterface.sol
  • contracts/WhitePaperInterestRateModel.sol
  • contracts/Lens/OnyxLens.sol
  • contracts/OErc20.sol
  • contracts/ExponentialNoError.sol
  • contracts/JumpRateModel.sol
  • contracts/ComptrollerG2.sol
  • contracts/ComptrollerInterface.sol
  • contracts/EIP20NonStandardInterface.sol
  • contracts/DAIInterestRateModelV3.sol
  • contracts/OErc20Delegator.sol
  • contracts/OErc20Immutable.sol
  • contracts/OTokenEx.sol
  • contracts/Exponential.sol
  • contracts/Maximillion.sol
  • contracts/XCN.sol
  • contracts/EIP721Interface.sol
  • contracts/ChainlinkOracle/AggregatorV2V3Interface.sol
  • contracts/Unitroller.sol
  • contracts/ComptrollerG1.sol
  • contracts/LegacyJumpRateModelV2.sol
  • contracts/ComptrollerG4.sol
  • contracts/OErc721.sol
  • contracts/OErc721Delegator.sol
  • contracts/ComptrollerG3.sol
  • contracts/OToken.sol
  • contracts/ChainlinkOracle/ChainlinkOracle.sol
  • contracts/Comptroller.sol
  • contracts/OTokenInterfaces.sol
  • contracts/CarefulMath.sol
  • contracts/ODaiDelegate.sol
  • contracts/OErc20Delegate.sol
  • contracts/ComptrollerStorage.sol

Part of Onyx Protocol’s security record

Onyx Protocol
Audits9 audits by 2 firmsLast audit Sep 2025, by PeckShield.
Critical findingsNo open critical findingsAcross 9 reports.
IncidentIncident 31 Oct 2023Source: De.Fi incident database.
Open Onyx Protocol’s security record

Security firm

CertiK

1,044 projects reviewed · 1,393 reports · latest May 2025

See CertiK’s audits

Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.

Tell us