<!-- canonical: https://0xsimao.com/reports/nftperp-ii -->

# Nftperp Matching Engine audit

Three Sigma · NFT perpetuals · 29th January 2024

A private security review of NFTPerp (NFT perpetuals), conducted with Three Sigma and completed on 29th January 2024 over 5 days. 0xSimao disclosed 15 findings: 6 medium and 9 informational.

## What NFTPerp is

Nftperp lets traders take leveraged long and short positions on NFT collection floor prices through perpetual futures settled entirely in ETH against a virtual AMM.

## Scope

The second round reviewed the rebuilt matching and pricing layer: mark-price updates, tick-based matching, index-flag heuristics for decreases, liquidity-notional constraints and share minting.

## Medium severity findings

- [Call _updateMarkPrice() whenever markPrice is changed](https://0xsimao.com/findings/nftperp-ii-mark-price-whenever-changed)
- [_match() always checks the trigger of the first order of a certain tick, instead of checking i order](https://0xsimao.com/findings/nftperp-ii-match-certain-tick-checking)
- [Use a flag to increase or decrease the index of the pool instead of a heuristic](https://0xsimao.com/findings/nftperp-ii-flag-decrease-index-heuristic)
- [Notional difference in AmmRouter:removeLiquidty() may revert in certain cases](https://0xsimao.com/findings/nftperp-ii-notional-difference-liquidty-revert)
- [It's possible to mint an infinite number of shares without increasing quote or base amounts, due to rounding down](https://0xsimao.com/findings/nftperp-ii-mint-infinite-shares-rounding)
- [Price deviation as is can be circumvented by making smaller trades in a loop](https://0xsimao.com/findings/nftperp-ii-price-deviation-circumvented-loop)

## Informational findings

- [PositionManager:_reversePosition() calculates the notional to reverse but could just use the exchangedQuote](https://0xsimao.com/findings/nftperp-ii-reverse-calculates-exchanged-quote)
- [Duplicate size to fill check in _staticFillToAmm()](https://0xsimao.com/findings/nftperp-ii-duplicate-size-fill-static)
- [gap is missing the private keyword](https://0xsimao.com/findings/nftperp-ii-gap-missing-private-keyword)
- [Index underflow is not protected against, although it has no impact as the pool with index type(uint256).max should not be registered](https://0xsimao.com/findings/nftperp-ii-index-underflow-impact-registered)
- [In AmmRouter:liquidateMaker(), the pools array can safely be deleted from storage](https://0xsimao.com/findings/nftperp-ii-liquidate-array-safely-storage)
- [trimDuplicatePools() is very expensive, having O(n^2) complexity and could be simplified](https://0xsimao.com/findings/nftperp-ii-trim-expensive-complexity-simplified)
- [Add a 0 address check on the pool when adding liquidity for greater verbosity](https://0xsimao.com/findings/nftperp-ii-add-adding-greater-verbosity)
- [setPools() could use more validation](https://0xsimao.com/findings/nftperp-ii-set-pools-validation)
- [Misleading error name](https://0xsimao.com/findings/nftperp-ii-misleading-error-name)

## The report

[Download the report (PDF)](https://0xsimao.com/reports/2024-01-29-nftperp-ii.pdf)
