Neutra - audit

CertiKFiles named in the report

CertiK reviewed Neutra Finance (Neutra - audit) on 10 Apr 2023: 27 findings, 0 critical; 13 marked fixed, 4 acknowledged, 10 open.

No open critical findings
Open the reportOpen Neutra Finance’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings27

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

SeverityOpenAcknowledgedFixed
Critical000
High002
Medium044
Low1007
LowClaimable `want` and `snGlp` Depend On `_dealAmouOpen

The function `__claimStakedNeuGlp()` or `__claimWant()` is used to calculate the claimable `want` or `snGlp` and transfer them to the users. ```solidity=248 uint256 totalBalance = totalSnGlpPerRound[round]; uint256 totalReceived = totalWantReceivedPerRound[round]; uint256 claimAmount = totalReceived * balance / totalBalance; ``` ```solidity=277 uint256 claimAmount = totalSnGlpReceivedPerRound[round] * balance / totalWantPerRound[round]; ``` ```solidity=306 function executeBatchPositions(bool _isWithdraw, bytes[] calldata _params, uint256 _dealAmount) external payable onlyHandlerAndAbove { require(msg.value >= executionFee * 2, "BatchRouter: not enough execution Fee"); uint256 amountIn = _isWithdraw ? totalSnGlpPerRound[currentWithdrawRound] : totalWantPerRound[currentDepositRound]; IRouter(router).executePositionsBeforeDealGlp{value: msg.value}(amountIn, _params, _isWithdraw); pendingDealAmount = _dealAmount; lastExecutionStatus = _isWithdraw; executed = true; emit ExecuteBatchPositions(_isWithdraw, amountIn); } ``` ```solidity=319 function confirmAndDealGlp() external onlyHandlerAndAbove { require(executed, "BatchRouter: executes positions first"); if (!lastExecutionStatus) { uint256 amountOut = IRouter(router).confirmAndBuy(pendingDealAmount, address(this)); _updateRewards(); totalSnGlpReceivedPerRound[currentDepositRound] = amountOut; ... } else { uint256 amountOut = IRouter(router).confirmAndSell(pendingDealAmount, address(this)); totalWantReceivedPerRound[currentWithdrawRound] = amountOut; ... } executed = false; } ``` As per the claimable amount calculation formula, the value of `totalWantReceivedPerRound[round]` or `totalSnGlpReceivedPerRound[round]` has a significant impact on the claimable amount. The amount of `totalWantReceivedPerRound[round]` or `totalSnGlpReceivedPerRound[round]` is ultimately determined by the `_dealAmount` parameter of the `executeBatchPositions` function. If the `_dealAmount` is insufficient, users may risk losing money, and it is essential to determine the appropriate quantity of `_dealAmount` to ensure that users can obtain the expected claimable tokens without any losses. Before proceeding, we would like to request confirmation from our customers on the correct approach for determining the right quantity of `_dealAmount`.

LowDivide Before MultiplyOpen

Performing integer division before multiplication truncates the low bits, losing the precision of the calculation. ```solidity=277 uint256 claimAmount = totalSnGlpReceivedPerRound[round] * balance / totalWantPerRound[round]; ``` ```solidity=284 uint256 esNeuClaimable = claimAmount * (cumulativeEsNeuRewardPerToken - cumulativeEsNeuRewardPerRound[round]) / PRECISION; ``` --- ```solidity=387 uint256 wbtcRatio = (aums[0] * MAX_BPS) / totalAum; ``` ```solidity=394 wbtcAmountIn = remainingAmount * wbtcRatio / (wbtcRatio + wethRatio); ``` --- ```solidity=404 uint256 sizeDelta = positionParam.size * _amount / _totalSupply; ``` ```solidity=408 uint256 usdOut = profitParam.hasProfit ? sizeDelta * profitParam.pnl / positionParam.size : 0; ```

LowEOA Receive `want` When Selling `glp`Open

The `StrategyVault` contract is responsible for using the `want` asset to purchase `glp` tokens for rebalancing. However, when `glp` tokens are sold, the `recipient` address that receives the `want` asset is specified by the input parameter instead of using the original address that paid for the `want` asset. Therefore, we would like to confirm with the client whether this current implementation aligns with the original project design.

LowIncompatibility with Deflationary TokensOpen

When transferring deflationary ERC20 tokens, the input amount may not be equal to the received amount due to the charged transaction fee. For example, if a user sends 100 deflationary tokens (with a 10% transaction fee), only 90 tokens actually arrived to the contract. However, a failure to discount such fees may allow the same user to withdraw 100 tokens from the contract, which causes the contract to lose 10 tokens in such a transaction.

LowLack of reasonable boundaryOpen

The variables `_executionFee`, `_fee`, and `_bps` do not have reasonable boundaries, so they can be given arbitrary values after deploying.

LowLack of Storage Gap in Upgradeable ContractOpen

There is no storage gap preserved in the logic contract. Any logic contract that acts as a base contract that needs to be inherited by another upgradeable child should have a reasonable size of storage gap preserved for the new state variable introduced by the future upgrades.

LowLack of Validation for Array LengthOpen

There is no validation to check whether the length of the array `_selectors` is the same length as each of the arrays `_params`. In the event that any of these lengths are less than the length of `_selectors`, there is no revert of the function.

LowState Variable Should Be Declared ConstantOpen

State variables that never change should be declared as `constant` to save gas.

LowUnchecked ERC-20 `transfer()`/`transferFrom()` CaOpen

The return value of the transfer()/transferFrom() call is not checked.

LowUnused Return ValueOpen

The return value of an external call is not stored in a local or state variable.

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

  • contracts/RouterV2.sol
  • contracts/StrategyVault.sol
  • contracts/StrategyVaultV2.sol
  • contracts/GmxHelper.sol
  • contracts/ExecutionCallbackTarget.sol
  • contracts/RepayCallbackTarget.sol
  • contracts/BatchRouter.sol

Part of Neutra Finance’s security record

Neutra Finance
Audits2 audits by 2 firmsLast audit Apr 2023, by CertiK.
Critical findingsNo open critical findingsAcross 2 reports.
Open Neutra Finance’s security record

Security firm

CertiK

1,044 projects reviewed · 1,375 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