Level security record

Arbitrum, BNB Chainlevel.financeX

As of 3 Nov 2026, Level has 1 audit report on Trustblock, by Quantstamp, dated 29 Mar 2023. That report lists no open critical findings.

Critical findings
No open critical findings
In 1 report.
Open the latest report
Your label, live
Get the label for your site

Record last updated . It holds audits, findings and contracts up to Nov 2026, and incidents up to Oct 2026. Trustblock does not review code.

Audits1

Newest first

AuditSecurity firmDateScopeCritical findingsReport
Level FinanceSecurity firm: QuantstampDate: Scope: Files named in the reportNo open critical findingsOpen · certificate.quantstamp.com

Findings32

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

SeverityOpenAcknowledgedFixed
Critical000
High104
Medium212
Low0148
MediumOwnership Can Be RenouncedLevel Finance · Quantstamp · 29 Mar 2023Acknowledged

Contracts inheriting from `Ownable` contain a function called `renounceOwnership()` which allows the `owner` to leave the contract without an `owner`. This would leave every function guarded by the `onlyOwner` modifier unable to be executed. In the case of `Erc20Reserve`, the `transfer` function, guarded by `onlyOwner`, is the only way of retrieving funds from the contract. If ownership is renounced in this context, the funds in the contract would be lost forever.

Open the report
Low`LevelDevFund` Improper InitializationLevel Finance · Quantstamp · 29 Mar 2023Acknowledged

`LevelDevFund` inherits `Initializable`, a base contract used to "aid in writing upgradeable contracts, or any kind of contract that will be deployed behind a proxy". However, it is not written as an upgradeable contract and inherits from `Ownable`, which is not upgradeable. Therefore, when deployed, the contract will run the constructor from `Ownable`. At this point, it is possible for a malicious user to call `initialize`, setting `LEVEL_STAKE` to any desired value. Since the `owner` has no recourse to reset `LEVEL_STAKE`, the deployment would be a failure.

Open the report
Low`LyLevel` ERC-20 DiscrepancyLevel Finance · Quantstamp · 29 Mar 2023Acknowledged

The `LyLevel` contract implements a token by attempting to follow ERC-20. However, the constant `decimals` is declared as `uint256` instead of `uint8` (see [EIP-20](https://eips.ethereum.org/EIPS/eip-20#token)). This is potentially a result of trying to clone-and-own the OpenZeppelin ERC20 code. This is generally considered poor practice, as it obfuscates the intentions of the developer, and neglects the benefits of using time-tested libraries such as OpenZeppelin's resulting in errors like the above.

Open the report
LowAccounting Errors when Dealing with Deflationary TokensLevel Finance · Quantstamp · 29 Mar 2023Acknowledged

When placing a swap order via `OrderManager` with a deflationary token, the `executeSwapOrder()` function attempts to use the same amount used when calling the `transfer()` function of the token. This will lead to the `OrderManager` attempting to swap more tokens than actually received during placement of the order. If there are not enough tokens in `OrderManager`, then the transaction will revert. Moreover, returning funds via `cancelOrder()` may fail due to insufficient token balance in `OrderManager`. In `LevelMasterV2`, `addLiquidity()` calculates ``` IERC20(assetToken).safeTransferFrom(msg.sender, address(this), assetAmount); IERC20(assetToken).safeIncreaseAllowance(address(levelPool), assetAmount); levelPool.addLiquidity(tranche, assetToken, assetAmount, minLpAmount, address(this)); ``` After the transfer from `msg.sender` to the `LevelMasterV2` contract, the actual transferred amount might be lower than the suppose `assetAmount`. This means we are potentially giving more allowance to the `levelPool` contract than it should have access to. However, this is not an issue in `levelPool.addLiquidity()` as it uses the actual balance changed through the call `_transferIn(_token, _amountIn)`.

Open the report
LowAssets Cannot Be Removed From the PoolLevel Finance · Quantstamp · 29 Mar 2023Acknowledged

When `addToken()` is called, the token's address is added to the `allAssets` array. However, there is no way for the protocol to remove added tokens, which means that once the `MAX_ASSETS` threshold is reached (currently set at 10 total assets), the protocol will not be able to add any new tokens or remove existing ones.

Open the report
LowLax Assumptions for `LyLevel.sol`Level Finance · Quantstamp · 29 Mar 2023Acknowledged

In `claimable()`, it is required that `_batchId <= currentBatchId`. However, it doesn't make sense to allow claiming at `currentBatchId` since `rewardPerShare` for the current batch would not have been set yet. This is only set in `allocateReward()`, but by calling it, `currentBatchId` will be incremented.

Open the report
LowLoss of Precision Due to Division before MultiplicationLevel Finance · Quantstamp · 29 Mar 2023Acknowledged

Division before multiplication may result in a loss of precision when the operations are carried over integer numbers. This was noticed in the following instances: * `LevelOracle` * #194 -- `lowerBound` * #195 -- `minLowerBound` * #196 -- `upperBound` * #197 -- `maxUpperBound` * `Pool` * #828 -- `tokenInfo.lastAccrualTimestamp` * #835 -- `tokenInfo.borrowIndex` * #836 -- `tokenInfo.lastAccrualTimestamp` * #888 -- `feeAdjust_scope_0`

Open the report
LowMissing Interface Inheritance for `OrderManager`Level Finance · Quantstamp · 29 Mar 2023Acknowledged

`OrderManager` is currently not inheriting from the `IOrderManager` interface. It is generally recommended for Solidity contracts to inherit interfaces in order to define an abstract behavior for the extending contract. This helps to ensure that the contract implements the required functions and adheres to the specified behavior.

Open the report
LowPool Asset Amount Increase Is Not Reflected in Check in `_reservePoolAsset()`Level Finance · Quantstamp · 29 Mar 2023Acknowledged

In `_reservePoolAsset()`, the `if` statement checks whether the asset's new reserved amount is greater than the pool amount. If this is not true, the logic is allowed to continue and `_reserveTrancheAsset()` is called. This check is being made because there should never be a situation where the pool amount is less than the reserved amount. However, `_reserveTrancheAsset()` increases not just the reserved amount, but also the pool amount. Therefore, the check is validating the wrong amounts. This may occasionally cause certain position increases to be blocked.

Open the report
LowPotential User Error Using `setRiskFactor()`Level Finance · Quantstamp · 29 Mar 2023Acknowledged

`setRiskFactor()` loops through an array of `RiskConfig` objects, one for each tranche with a risk factor to be modified. However, this leaves room for the user to mistakenly input a tranche twice, leading to an incorrect risk configuration.

Open the report
Show 5 more
LowPrivileged Roles and OwnershipLevel Finance · Quantstamp · 29 Mar 2023Acknowledged

Smart contracts will often have variables designating users with special privileges. This phenomenon occurs in numerous contracts throughout the Level Finance codebase. * `Pool.sol` * Functions using `onlyOrderManager` * Functions using `onlyOwner` * Functions using `_validateFeeDistributor` * `OrderManager.sol` * Functions using `onlyExecutor` * Functions using `onlyOwner` * `LPToken.sol` * `_mint()` requires the caller to be `minter` * `LevelOracle.sol` * Functions using `onlyOwner` * `LevelStake.sol` * `setRewardPerSecond()` uses `onlyOwner` * `LevelZap.sol` * `addZap()` and `removeZap()` use `onlyOwner` * `LevelMasterV2.sol` * Functions using `onlyOwner` * `Erc20Reserve.sol` * `transfer()` uses `onlyOwner` * `LevelDevFund.sol` * Functions using `onlyOwner` * `LVLOracle.sol` * `update()` requires `msg.sender` to be `updater` * `LevelReferralController.sol` * Functions using `onlyOwner` * `LevelReferralRegistry.sol` * `setController()` uses `onlyOwner` * `LyLevel.sol` * Functions using `onlyOwner`

Open the report
LowStaking Rewards AccountingLevel Finance · Quantstamp · 29 Mar 2023Acknowledged

`LevelStake` gives `LGO` rewards to users that stake `LVL` tokens in it. It transfers the reward (if any) when staking, unstaking, or when the user claims it (`claimRewards()`). `LevelStake._safeTransferLGO()` sanitizes the number of tokens to not send more than the contract balance. In case there are not enough tokens, the user's `rewardDebt` is updated as if the full amount was transferred.

Open the report
LowUnderconstrained Assumptions for OracleLevel Finance · Quantstamp · 29 Mar 2023Acknowledged

In`_getReferencePrice()`, we calculate the following formula: `minLowerBound = refPrice * (PRECISION - 3 * config.chainlinkDeviation) / PRECISION`. However, in `configToken()`, it is only required that `chainlinkDeviation != 0 && chainlinkDeviation < PRECISION / 2`. Consequently, if the owner misconfigures the token by setting `chainlinkDeviation` to somewhere between `PRECISION / 3` and `PRECISION / 2`, calls to `_getReferencePrice()` will revert due to underflow. This means any call to get the price of the token from the oracle will fail. However, this can be fixed by having the `owner` call `configToken()` again with the correct parameters.

Open the report
LowUnexpected EventLevel Finance · Quantstamp · 29 Mar 2023Acknowledged

`LevelReferralController.setEnableStake()` will always emit an `EnableStakeSet` event, even if the new value is equal to the old value of `enableStaking`.

Open the report
LowWhitelisted Tokens Cannot Be RemovedLevel Finance · Quantstamp · 29 Mar 2023Acknowledged

When `configToken()` is called, the token address is pushed to `whitelistedTokens` if the token's `baseUnits` is equal to zero, and the token's properties are configured. The function doesn't allow the owner to remove a whitelisted token since the `baseUnits` cannot be reset back to zero as passing `tokenDecimals` as a zero value would make the function revert.

Open the report

Contracts

No deployed address is recorded for these audits.

The reports name a repository or files. Open a report to see its scope.

The repositories and files the reports name

Show this on your site

Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.

Content

Facts

Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.

Fixed as
Language

Style

Layout
Theme
Accent
Corners

Format

Size
Date
Embed as
HTML
<head>
<script src="https://widget.trustblock.run/project-widget.min.js" defer></script>
</head>
<body>
<div
data-tb-project-widget
data-tb-project-slug="level-1"
></div>
</body>

Paste the code where the label should appear. It uses no API credit and updates by itself.

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