FNCY Chain

CertiKFiles named in the report

CertiK reviewed FNCY (FNCY Chain) on 22 Mar 2024: 43 findings, 0 critical; 30 marked fixed, 6 acknowledged, 7 open.

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

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings43

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

SeverityOpenAcknowledgedFixed
Critical000
High032
Medium034
Low7024
LowIncompatibility With Deflationary TokensOpen

When transferring standard ERC20 deflationary tokens, the input amount may not be equal to the received amount due to the charged transaction fee. As a result, an inconsistency in the amount will occur. For example, if a user locks 100 deflationary tokens (with a 10% transaction fee) to the bridge contract, only 90 tokens actually arrive to the bridge. ```solidity if (paymentAmount > 0) { if (paymentToken != address(0)) { ... TransferHelper.safeTransferFrom(paymentToken, msg.sender, launchpadFeeInterceptor, paymentAmount); } else if (paymentToken == address(0)) { ... } ILaunchpadFeeInterceptor(launchpadFeeInterceptor).executeFundsTransfer(projectId, paymentAmount, paymentToken); } ```

LowInsufficient Checks For Input ParametersOpen

For the functions `addProject()` and `updateProject()`, there is a lack of sufficient checks around the input parameters. - For address variables like `settlement` and `paymentTokens`, there are no checks that the addresses are zero addresses. - For timestamp variables like `startTimestamp` and `endTimestamp` there are no checks in relation to the current time `block.timestamp`, therefore they could be set to times in the past. - For numeric values like `price` or `total` it might be helpful to include checks on the lower and/or upper values. - Specifically for the `updateProject()` function, there are no checks on the updated values in comparison to their original values. Changes to values like `total` and `endTimestamp` during the course of the project could lead to unexpected behavior. ```solidity function updateProject( uint256 projectId, INFT nft, uint8 limitPerWallet, uint112 total, uint256 price, uint256 startTimestamp, uint256 endTimestamp, address payable settlement, address[] memory paymentTokens ) public onlyAdmin { Project storage project = projects[projectId]; project.nft = nft; project.limitPerWallet = limitPerWallet; project.total = total; project.price = price; project.startTimestamp = startTimestamp; project.endTimestamp = endTimestamp; project.settlement = settlement; ... ```

LowPossibility of duplicate NFTs created during bulkOpen

There is a potential issue that occurs if a user provides an array `nftIds` with duplicate `nftId` values to a function (such as the `bulkMint()` function) that uses the `_checkHasMinted(address collection, uint256[] memory nftIds)` method, which could bypass the "Already Minted" check for duplicates since all checks are completed before any NFTs are minted in bulk. It is also uncertain the relationship between `nftId` (which is a server generated value) and the parameter input `tokenId` which is used to identify the minted tokens. In the current implementation there could hypothetically be the case where duplicate NFTs that are processed in bulk and have passed the `_checkHasMinted` verification are assigned different tokenIds. This would mean that they will be identified as unique NFTs in the contract even though they were initially duplicates.

LowPotential Unexpected Revert in Fee Distribution DOpen

Within function `_transferFee()`, transfers to `fee.recipients` in ETH could potentially fail especially if there are any recipients that are smart contract that do not contain an appropriate fallback function. ```solidity=122 require(_transferTo(fee.recipient, payout), "Transfer Fail"); ``` This failure would cause all the transfers to the set fee recipients to fail. If one of the `fee.recipient` addresses is controlled by a malicious actor, they can craft their smart contract's `fallback` function in a way that will always cause it to revert. This would effectively cause the `_transferFee()` function to revert every time, leading to a Denial of Service (DoS) for the functionality of transferring fees.

LowPotential Unexpected Revert in NFT Distribution DOpen

Within function `_bulkMint,` NFT transfers to `recipients` could potentially fail, especially if any recipients are contracts that do not contain an appropriate `onERC721Received` function. ```solidity=122 if (CallType.MINT == callType) { for (uint256 i = 0; i < _size; i++) { (uint256 rTokenId) = _callMint(collectionConfig.collection, recipients[i], tokenIds[i], uris[i]); rTokenIds[i]=rTokenId; } } else if (CallType.SAFE_TRANSFER_FROM == callType) { for (uint256 i = 0; i < _size; i++) { _callSafeTransferFrom(collectionConfig.collection, collectionConfig.merchant, recipients[i], tokenIds[i]); // Error handling exists in ERC721 } } ``` This failure would cause all the transfers to the recipients to fail. If one of the `recipients` addresses is controlled by a malicious actor, they can craft their smart contract's `onERC721Received` function in a way that will always cause it to revert. This would effectively cause the `_bulkMint` function to revert every time, leading to a Denial of Service (DoS) for the functionality of distributing NFTs.

LowPotential Zero Payout Due to Rounding IssueOpen

In function `_transferFee()` the `payout` could potentially be zero due to the division truncation of integers, if the value of `_price.mul(fee.feeRate)` is less than the `FEE_BASIS_POINT`. ```solidity=124 uint256 payout = _price.mul(fee.feeRate).div(FEE_BASIS_POINT); ``` Especially, if the token has a small number of decimals, like 6, then the _price value will tend to be smaller, and it will exacerbate this truncation issue.

LowThird-Party Dependency UsageOpen

The contract is serving as the underlying entity to interact with one or more third-party protocols. 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. In addition, upgrades of third parties can possibly create severe impacts, such as increasing fees of third parties, migrating to new LP pools, etc. ```solidity=38 mapping(address => address) public interceptors; ``` - The contract `NFTExchange` interacts with third-party contracts with `IExchangeFeeInterceptor` interface via `interceptors`. --- ```solidity=27 address public launchpadFeeInterceptor; ``` - The contract `NFTLaunchpad` interacts with third-party contracts with `ILaunchpadFeeInterceptor` interface via `launchpadFeeInterceptor`. --- ```solidity interface INFT { function safeMint(address to, uint256 tokenId, string memory uri) external returns(uint256); } ``` ```solidity struct Project { INFT nft; uint8 limitPerWallet; uint112 total; uint256 price; uint256 startTimestamp; uint256 endTimestamp; uint256 soldCount; address payable settlement; bool fundraising; } ``` - The `NFTLaunchpad` contract interacts with third-party contracts with `INFT` interface via `Project.nft` --- ```solidity function buyFromAnotherChain(address user, uint256 projectId, uint8 count, string memory receipt, uint256 chainId) public onlySpecial onlyAvailable(projectId) ``` - The `NFTLaunchpad` contract may interact with the off-chain bridge server to perform the purchase from another chain. --- ```solidity interface IBaseNFT { function safeMint(address to, uint256 tokenId, string memory uri) external returns(uint256); } ``` ```solidity struct CollectionConfig { address collection; address merchant; bool enabled; CallType callType; } ``` - The `TransferManagement` contract interacts with third-party contracts with `IBaseNFT` interface via `CollectionConfig.collection`. --- ```solidity function sell(address _nftAddress, uint256 _tokenId, uint256 _price, uint256 _deadline) public nonReentrant whenNotPaused ``` - The `NFTExchange` contract interacts with third-party contracts with `IERC721Upgradeable` interface via `_nftAddress`.

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

  • contracts/market/NFTLaunchpad.sol
  • contracts/market/LaunchpadFeeInterceptor.sol
  • contracts/market/TransferManagement.sol
  • contracts/base/TransferHelper.sol
  • contracts/market/NFTExchange.sol
  • contracts/market/ExchangeFeeInterceptor.sol

Part of FNCY’s security record

FNCY
Audits1 audit by 1 firmLast audit Mar 2024, by CertiK.
Critical findingsNo open critical findingsIn 1 report.
Open FNCY’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