Level Finance

QuantstampFiles named in the report

Quantstamp reviewed Level (Level Finance) on 29 Mar 2023: 32 findings, 0 critical; 14 marked fixed, 15 acknowledged, 3 open.

No open critical findings
Open the reportOpen Level’s security record

Report hosted on certificate.quantstamp.com.

Trustblock does not review code.

Findings32

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

SeverityOpenAcknowledgedFixed
Critical000
High104
Medium212
Low0148
HighLGO is Vulnerable to Replay AttacksFixed

The `DOMAIN_SEPARATOR` value used in multiple functions to render signatures only usable for this specific protocol is never initialized. This effectively means that valid signatures can be reused with other applications that follow the same signature procedure.

HighLiquidity Can Be Drained Through Price ManipulationFixed

Level Finance allows traders to take leveraged long and short positions on various tokens, and the size of these positions is limited only by the amount of liquidity stored in the `Pool`. These trades can be executed with zero price impact. The same is the case for the swaps facilitated by the protocol between these tokens. The prices that are honoured by the protocol are produced by oracles referring to Coinbase and Binance, and validated against Chainlink's oracle. This opens the protocol to an economic attack whereby a trader can open positions on Level Finance, manipulate the oracle prices through action on centralized exchanges, and close the positions. Level Finance aims to correct for this issue by providing LPs tranches, whereby LPs can limit their exposure to trades conducted in assets with low liquidity on exchanges from which the oracles derive their prices. The underlying assumption is that the prices of certain tokens (e.g. BTC, ETH) are less manipulable than others. Currently, the token considered risky, CAKE, only has allocation within the mezzanine and junior tranches, and has only a 1% target weight across the entire pool. This single-faceted approach to dealing with the described attack vector is flawed on at least two counts: 1. The assumption that prices of assets like BTC and ETH will not be manipulated in the future may ultimately be proven false. If so, the up-to-30x leverage provided by Level Finance could allow the opening of positions that, when closed, could lead to serious losses for Level Finance LPs. 2. Although the target weight for CAKE liquidity is 1% (Level Finance's current CAKE holdings amount to $138,677), depending on the growth of Level Finance, this could lead to substantially larger amounts of CAKE being deposited.

HighPool Token Value Is Not Checked Against Total Short Size when Withdrawing, Potentially Resulting in Widespread Protocol ErrorFixed

When withdrawing from the pool via `removeLiquidity()`, an internal call is made to `_decreaseTranchePoolAmount()` which subtracts the withdrawn amount from `asset.poolAmount` and checks whether `asset.poolAmount < asset.reservedAmount`, reverting if this is the case. However, it does not check whether the value of the liquidity in the tranche can accommodate the total open short position size, `asset.totalShortSize`. If this is not the case, then it is possible for the short profits on a token to exceed the value of the new value of the token in the tranche. This would lead to a negative AUM, causing multiple functions to revert in the future. The same problem arises when `totalShortSize` increases above the value of the tranche's value for a given asset when opening or increasing a short position.

HighShort Positions Are Not Limited, Leading to Potential Protocol BreakFixed

Although the maximum global long position size of a token (i.e. the cumulative total size of all long positions on said token) is capped at the total amount of all holdings of the token in the vault, the maximum global short position size is in practice capped only by the amount of stablecoin that can be collateralized and borrowed in order to open short positions. However, the formula for calculating the total assets under management (in dollars) with respect to a given non-stablecoin token is defined by the formula ``` aum = SignedIntOps.wrap(_asset.poolAmount).sub(_asset.reservedAmount).mul(_price).add(_asset.guaranteedValue); aum = aum.sub(shortPnl); ``` where `poolAmount` is the amount of tokens deposited by LPs plus long position collateral, `reservedAmount` is the amount of tokens borrowed plus long position collateral, `guaranteedValue` is the value of the amount of tokens borrowed in USD, and `shortPnL` is the sum of all profits and losses of open short positions on the token. However, since the global short position size is not capped (except by the stablecoin reserves), with large enough amounts of stablecoins in the pools, it is in theory possible to open large enough short positions on a token such that, were the token to go down, the `shortPnL` value would exceed the amount of the tokens in the pool. This would cause the total assets under management to be a negative number, causing a reversion every time `_getTrancheValue()` is called. This is particularly concerning, as the function is called whenever a user decides to add or remove liquidity.

MediumTraders Can Prevent LPs From Removing Liquidity Through Denial of ServiceFixed

When calling `removeLiquidity()`, the amount of funds to which an LP is entitled is calculated with reference to the `poolValue` within a tranche, i.e. the `poolAmount` in dollars minus the `reservedAmount` in dollars plus the `guaranteedValue`. The `guaranteedValue` is the total amount borrowed (in USD) by traders. However, when removing liquidity, the only tokens that may be taken out are those counted by `poolAmount`; that is, when removing liquidity, `poolAmount` is decreased until it reaches zero and it cannot go lower. Thus, if traders collectively borrow enough tokens from the protocol, they may dramatically reduce the amount of funds that can be withdrawn from the protocol at a given time. This may even occur for long periods of time without malicious intent, say, in the event that some traders lose their keys and their trades move in their favour.

MediumUpgradeable Contracts Should Disable Initialization of the ImplementationFixed

The implementation contracts behind a proxy can be initialized by any address. This is not a security problem in the sense that it impacts the system directly, as the attacker will not be able to cause any contract to self-destruct or modify any values in the proxy contracts. However, taking ownership of implementation contracts can open other attack vectors, like social engineering or phishing attacks.

Low`SignedInt` Poses an Unnecessary Gas BurdenFixed

In order to work with signed integers, Level Finance introduced a struct called `SignedIntOps`, consisting of a `uint256` sign and a `uint256` absolute value, together with a library, `SignedIntOps`, which contains functions that enable addition, multiplication, etc. However, Solidity comes prepackaged with `int256`, which enables working with signed integers with values between -2^<sup>255</sup> and 2^<sup>255</sup> - 1. We have confirmed through tests that many arithmetic operations can cost two-three times more gas when using `SignedInt` instead of `int256`.

Low`Timelock` Does Not Check Upper Bound for DelayFixed

The purpose of `Timelock.sol#26` is to check whether the input variable `_delay` is within the bounds set by `MINIMUM_DELAY` and `MAXIMUM_DELAY`. However, currently, this line erroneously checks the state variable `delay`, thus not enforcing the upper bound when setting `delay`. This also occurs in `setDelay()`.

LowDAO Fee Reduction Is ImpossibleFixed

The `withdrawFee()` function requires that the caller is the `feeDistributor` address, and this function is called from the `Treasury.withdrawFee()` function. This implies that the fee distributor is an instance of the `Treasury` contract; however the contract implementation doesn't have a mechanism that allows calling `reduceDaoFee()`, which means that this function cannot be called.

LowDuplicated ContractsFixed

`ETHUnwrapper.sol` and `LiquidityRouter.sol` are the same `LiquidityRouter` contract.

Show 4 more
LowFunctions in `OrderHook` Do NothingFixed

As of the audited commit, none of the functions in `OrderHook` do anything. They do not mutate or view the state of the blockchain, and they do not return any data. They simply impose a gas burden that is exacerbated by the fact that calls to the functions within this contract are `external`.

LowNo Cap on Oracle Price Feed TimeoutFixed

The `configToken()` function takes in a `chainlinkTimeout` value that is later used to validate if the price of the token returned from the oracle is stale or not. This value is not capped, which allows the contract owner to set arbitrary values to said timeout window, which would impact users' trading prices.

LowSignature MalleabilityFixed

The `LevelGovernance` contract allows users to use signatures to delegate voting and proposition power to other users. To verify these signatures, the contract calls `ecrecover`, vulnerable to signature malleability ([SWC-117](https://swcregistry.io/docs/SWC-117)). Although this is mitigated by using nonces, the best practice is to reject malleable signatures.

LowUnchecked Returned ValuesFixed

Multiple functions call `transfer()` without checking that the function returned `true`. This could lead to false calculations in case the `transfer()` function on the ERC20 token doesn't revert on failure.

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 (58)

  • src/interfaces/IRewarder.sol
  • src/lib/FixedPoint.sol
  • src/interfaces/ILevelMaster.sol
  • src/timelock/Timelock.sol
  • src/farm/LevelMasterV2.sol
  • src/interfaces/ILyLevelToken.sol
  • MathUtils.sol
  • src/lib/PairOracleTWAP.sol
  • src/interfaces/ILevelStake.sol
  • PoolErrors.sol
  • src/lockdrop/LockDrop.sol
  • PoolHook.sol
  • src/treasury/Treasury.sol
  • src/farm/LevelStake.sol
  • src/interfaces/IUniswapV2Pair.sol
  • ETHUnwrapper.sol
  • src/interfaces/ILPToken.sol
  • Pool.sol
  • src/fund/LevelDevFund.sol
  • src/lib/UniswapV2OracleLibrary.sol
  • src/interfaces/IWETH.sol
  • PositionUtils.sol
  • LPToken.sol
  • IOrderManager.sol
  • LiquidityRouter.sol
  • src/fund/Erc20Reserve.sol
  • src/lib/UQ112x112.sol
  • IPool.sol
  • ILPToken.sol
  • src/tokens/LyLevel.sol
  • src/referral/LevelReferralRegistry.sol
  • src/tokens/LevelGovernance.sol
  • IOracle.sol
  • PoolStorage.sol
  • src/referral/LevelReferralController.sol
  • IWETH.sol
  • IPoolHook.sol
  • IETHUnwrapper.sol
  • src/tokens/LevelToken.sol
  • AggregatorV3Interface.sol
  • OrderManager.sol
  • src/interfaces/ILVLOracle.sol
  • ILevelOracle.sol
  • src/lib/Babylonian.sol
  • SignedInt.sol
  • src/farm/LevelZap.sol
  • src/interfaces/IPool.sol
  • IReferralController.sol
  • src/fund/DaoVesting.sol
  • src/oracle/LVLOracle.sol
  • IOrderHook.sol
  • OrderHook.sol
  • IMintableErc20.sol
  • src/lib/GovernancePowerDelegationERC20.sol
  • LevelOracle.sol
  • src/farm/LevelMaster.sol
  • src/interfaces/IGovernancePowerDelegationToken.sol
  • src/interfaces/ILevelReferralRegistry.sol

Part of Level’s security record

Level
Audits1 audit by 1 firmLast audit Mar 2023, by Quantstamp.
Critical findingsNo open critical findingsIn 1 report.
Open Level’s security record

Security firm

Quantstamp

236 projects reviewed · 332 reports · latest Oct 2026

See Quantstamp’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