Native v2 (Security Review)

QuantstampFiles named in the report

Audit · firm’s term: security review

Quantstamp reviewed Native v2 (Native v2 (Security Review)) on 6 Jan 2025: 18 findings, 0 critical; 6 marked fixed, 9 acknowledged, 3 open.

No open critical findings
Open the reportOpen Native v2’s security record

Report hosted on certificate.quantstamp.com.

Trustblock does not review code.

Findings18

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

SeverityOpenAcknowledgedFixed
Critical000
High012
Medium033
Low351
HighAny Whitelisted Trader Can Settle Trades and Remove Collateral on Behalf of Another TraderFixed

In the `CreditVault.sol` contract, the operations `settle()` and `removeCollateral()` are protected by the modifier `onlyTraderOrSettler`, which has the following code: ``` modifier onlyTraderOrSettler(address trader) { if (!isTraders[msg.sender] && !(isTraders[trader] && msg.sender == settlers[trader])) { revert ErrorsLib.OnlyTrader(); } _; } ``` We can observe that having `isTraders[msg.sender] == true` is enough to bypass this condition.

HighIncorrect Updates of `fundingFees`Fixed

In `CreditVault.sol`, the storage variable `fundingFees` is used as an accounting variable for the funding fees accumulated when the function `epochUpdate()` is executed. However, the same variable is used to keep track of funding fees accumulated through different assets. This causes two problems (i) there is information loss on how much fee is available for each token, and (ii) there is a high risk of miscalculation due to the precision mismatch in the tokens. As an example, if `1e18 ETH` and `1e6 USDC` are accounted for in the contract as funding fees (with `fundingFees == 1e18 + 1e6`) that also owns `1e18 USDC`, it is possible for `feeWithdrawer` to withdraw `1e18 USDC` from the contract via `withdrawFundingFees()`. In addition, the address `feeWithdrawer` can withdraw any amount of underlying asset to any arbitrary recipient address via the function `withdrawFundingFees()`. However, there is no mechanism to make sure that the underlying token is supported by the contract (which could result in incorrectly reducing the value of `fundingFees`, resulting in the loss of these fees).

MediumAdding Collateral to Non-Trader Addresses Is PossibleFixed

In the `CreditVault.sol` contract, anyone can call the function `addCollateral()` to add collateral for another address. However, there is no check to make sure that the receiver address is a whitelisted trader in the system. If this is not the case, tokens sent as collateral may remain locked in the contract.

MediumAn Address Gets Added to the `poolArray` Every Time `setNativePool()` Is CalledFixed

`CreditVault.sol` contract has a function `setNativePool()` that is used to toggle the whitelist status of an instance of `NativeRFQPool.sol` contract. However, every call to the function, whether it's activating, de-activating, or no-op, would push the pool address in the function argument to the `poolArray`, which is the storage list used to keep track of the whitelisted addresses for the `NativeRFQPool.sol` instances. This does not seem aligned with the expected behavior.

MediumUnclear Specifications of Fee Accounting and Associated InvariantsFixed

The documentation and code comments indicate that the protocol is supposed to generate revenue by accumulating funding fees and also be able to distribute this to holders of LP tokens. The mechanisms by which this happens is not obvious from the code and in some cases the solvency of the fee mechanism is unclear. As an example, the mechanism by which LP Token gains fees is through `LPToken.distributeYield()` external call that is made on each `CreditVault.epochUpdate()` function call. However, the `distributeYield()` function simply updates the total underlying token amount of the LP token without actually transferring token. In addition, the auditors suspect that there may need to be some sort of invariant between `lpFee` and `fundingFee` such as `lpFee` < `fundingFee` because the LP fee actually originates from the funding fee accumulated. No such check takes place on-chain, and it is assumed that `accruedFees` input must be correct.

LowSome Important Updates of the System Do Not Emit EventsFixed

The following updates of the contract's state do not result in emitting an event, making it harder for observers (team or users) to track important contract state changes (intended or not) and react fast if something unexpected is identified: 1. Updates to privileged addresses in `CreditVault.sol` (`liquidator`, `signer`, `epochUpdated`, and `feeWithdrawer`); 2. Execution of the functions `NativeRouter.refundERC20()` and `NativeRouter.unwrapWETH9()`; 3. Adding routers to the whitelist in `NativeRouter.setWhitelistRouter()`;

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

  • src/libraries/TStorage.sol
  • src/NativeRouter.sol
  • src/libraries/ConstantsLib.sol
  • src/NativeRFQPool.sol
  • src/libraries/ReentrancyGuardTransient.sol
  • src/LPToken.sol
  • src/CreditVault.sol
  • src/libraries/ErrorsLib.sol

Part of Native v2’s security record

Native v2
Audits1 audit by 1 firmLast audit Jan 2025, by Quantstamp.
Critical findingsNo open critical findingsIn 1 report.
Open Native v2’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