As of 3 Nov 2026, NFTCall has 1 audit report on Trustblock, by CertiK, dated 16 Mar 2023. That report lists no open critical findings.
Record last updated . It holds audits, findings and contracts up to Nov 2026, and incidents up to Oct 2026. Trustblock does not review code.
Newest first
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 0 |
| Medium | 0 | 0 | 1 |
| Low | 1 | 0 | 18 |
The exercise window of an option includes the `endTime`. The function `changePreference()` should only be able to be called after an option has ended, however, it makes the following check: ```solidity=462 require(block.timestamp >= uint256(nftStatus[tokenId].getEndTime()), Errors.CP_NFT_ON_MARKET_OR_UNABAILABLE); ``` This check allows the preferences to be changed if the `block.timestamp` equals the `endTime`. This allows the preferences to be changed and the call to be exercised in the same block. This scenario can cause confusion and have the user calling `changePreference()` spend gas unnecessarily.
Open the reportIn the function `createPool()`, the return variable `pool` is never assigned as there is a new temorary variable `pool` created in the following line of code: ```solidity=26 address pool = deploy(address(this), erc721token, oracle, premium); ```
Open the reportBoth contracts `NToken` and `CallToken` have the function `tokenURI()` return the `tokenURI` of the NFT and not a unique URI to the tokens.
Open the reportInside of the function `openCall()` the following line is returned but is not emitted. ```solidity vars.errorCode ``` This can cause confusion if the error code is nonzero. - In `openCall()` this will revert with the error message `Errors.CP_CAN_NOT_OPEN_CALL`. This can make it hard to determine the source of the revert.
Open the reportThe value of `minimumPremiumToOwner` should be the smallest premium that will be accepted, however, in the function `_previewOpenCall()` this will revert if the calculated `premiumToOwner` is equal to the `minimumPremiumToOwner`.
Open the reportWhen `createPool()` is called in the `CallFactory` contract it creates a new pool, but in addition creates new `NToken` and `CallToken` contracts. There is never an event emitted for the newly created `NToken` or `CallToken` contracts.
Open the reportThe **require** can be used to check for conditions and throw an exception if the condition is not met. It is better to provide a string message containing details about the error that will be passed back to the caller. --- In addition there is an error message that may be misleading. In `exerciseCall()` there is the following check: ```solidity require(remainValue == 0, Errors.CP_DID_NOT_SEND_ENOUGH_ETH); ``` A user may send more than the strike price in the `msg.value` and this will revert with an error stating they did not send enough ETH, however they sent too much ETH.
Open the reportThe function `collectProtocol()` should check if the `recipient` is the zero address.
Open the reportIf NFTs are accidentally sent directly to the `NToken` contract, then they will become locked and unable to be recovered. The contract implements the `onERC721Received()` function, so even if `safeTransferFrom()` is used a user will be able to send NFTs directly to the contract.
Open the reportThe `strikePrice` stored when opening a call is calculated using the oracles returned price. If this does not have 18 decimals, then in `exerciseCall` the `strikePrice` that is compared against the `msg.value` will not have 18 decimals.
Open the reportThe contract, `Premium` serves as the underlying entity to interact with the pricing of premiums on call options. However, the scope of the audit assumes the input `_premiumMesh` is functionally correct and treats it as a black box.
Open the reportIn the contract `NToken`, the functions `_beforeTokenTransfer()` and `supportsInterface()` override their respective functions from the `ERC721` contract. However, when overriding, they only call super on that function, which will simply call the function from the ERC721 contract.
Open the reportIn the batch functions that mint or transfer ERC721 tokens, the `onERC721Received()` hook can be used for reentrancy.
Open the reportA reentrancy attack can occur when the contract creates a function that makes an external call to another untrusted contract before resolving any effects. If the attacker manipulates the following contract by re-entering, they could potentially throw off any protocol listening for these events. Additionally, `exerciseCall()` does not conform to check effect interaction patterns by burning before all state changes have been completed. ### `withdrawETH()` can send ETH to an external contract which can trigger a re-entry on fallback which can cause events to be out of order: ```solidity=191 _safeTransferETH(to, amount); emit WithdrawETH(_msgSender(), to, amount); emit BalanceChangedETH(user, _balanceOf[user]); ``` ### `withdraw()` and `exerciseCall()` externally calls `Ntoken.burn()` which can cause events to be out of order: ```solidity=45 function burn(address user, address receiverOfUnderlying, uint256 tokenId) public override onlyOwner{ _burn(tokenId); IERC721(nft).safeTransferFrom(address(this), receiverOfUnderlying, tokenId); emit Burn(user, receiverOfUnderlying, tokenId); } ``` ### `deposit()` and `depositWithPreference()` externally calls `Ntoken.mint()` which can cause events to be out of order: ```solidity=40 function mint(address user, uint256 tokenId) public override onlyOwner{ _safeMint(user, tokenId); emit Mint(user, tokenId); } ```
Open the reportThe contract is serving as the underlying entity to interact with third-party `Oracles` and `NFT's` The scope of the audit treats third-party entities as black boxes and assumes their functional correctness. However, in the real world, third parties can be compromised and this may lead to lost or stolen assets.
Open the reportIn the contract, `CallPool` and `Errors`, the following typos were found: - `CP_NFT_ON_MARKET_OR_UNABAILABLE` should be corrected to `CP_NFT_ON_MARKET_OR_UNAVAILABLE`; - `CP_DID_NOT_SEND_ENOUGHT_ETH` should be corrected to `CP_DID_NOT_SEND_ENOUGH_ETH`. In the contract, `DataTypes`, the following typo was found: - bit 128-192: minimumStrikePrice should be corrected to bit 128-191: minimumStrikePrice. In the contract, `CallPool`, the following typos were found: - In the comments above `STRIKE_PRICE_SCALE`, it should use "greater" as opposed to "great"; - In the function `withdraw()`, the comment `// Burn NToken` should be moved to just before the `NToken` is burned; - In the function `exerciseCall()`, the comment `// Burn NToken and transfer underlying NFT` should be moved to just before the `NToken` is burned.
Open the report```solidity=7 event Activate(address account); ``` - `Activate` is declared in `ICallPoolEvents` but never emitted. --- ```solidity=8 event Deactivate(address account); ``` - `Deactivate` is declared in `ICallPoolEvents` but never emitted. --- ```solidity=18 event DepositETH(address indexed user, address indexed receiver, uint256 amount); ``` - `DepositETH` is declared in `ICallPoolEvents` but never emitted.
Open the report```solidity=9 interface IPriceOracleGetter { ``` - `IPriceOracleGetter` is declared but never used.
Open the reportThe `STRIKE_PRICE_SCALE` and `MAXIMUM_STRIKE_PRICE` are determine based on the decimals of the price returned by the oracle and the decimals of the strike price. The implementation assumes that the decimals of the price returned by the oracle is 18 and the decimals of the strike price is 9. In addition, the `MAXIMUM_STRIKE_PRICE` is the maximum `uint64` multiplied by the `STRIKE_PRICE_SCALE`.
Open the reportThe reports name a repository or files. Open a report to see its scope.
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.
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.
<head><script src="https://widget.trustblock.run/project-widget.min.js" defer></script></head><body><divdata-tb-project-widgetdata-tb-project-slug="nftcall"></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