As of 3 Nov 2026, nsurance has 4 audit reports by 2 security firms on Trustblock; the latest is by CertiK, dated 27 Feb 2024. Those reports list no open critical findings. It also holds 1 deployed contract on 1 chain.
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
| Audit | Security firm | Date | Scope | Critical findings | Report |
|---|---|---|---|---|---|
| nfa - staking/buyback/burn | Security firm: CertiK | Date: | Scope: Files named in the report | 1 critical finding, fixed | Open · skynet.certik.com |
| NFAI Buyback | Security firm: SolidProof | Date: | Scope: Not recorded (see the report) | No open critical findings | Open · IPFS |
| NFAIV2 | Security firm: CertiK | Date: | Scope: Files named in the report | No open critical findings | Open · skynet.certik.com |
| NFAi | Security firm: CertiK | Date: | Scope: 1 address on Ethereum | No open critical findings | Open · skynet.certik.com |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 1 |
| High | 6 | 0 | 1 |
| Medium | 2 | 0 | 1 |
| Low | 23 | 0 | 5 |
The `depositFutureRewards` function in the `AssetRewardContract` contains a flaw in its validation logic for the `availableFromTime` parameter. The contract incorrectly rejects deposits for future rewards intended for a time later than the current `block.timestamp`, due to a reversed conditional check. In `depositFutureRewards()` function, the below check is incorrectly added to make sure new future reward deposit's `availableFromTime` must be less than or equal to the `block.timestamp` at the time of the deposit. ```solidity=139 if(block.timestamp < availableFromTime) { revert InvalidFutureTime("Cannot set future rewards for a past time"); } ``` - By providing an `availableFromTime` greater than `block.timestamp`, the transaction is incorrectly reverted. This check implementation is against the logic in the function `distributiedReward()` shown below: ```solidity=223 if ((futureReward.availableFromTime <= block.timestamp && futureReward.availableFromTime != 0)) { totalRewards += futureReward.amount; delete futureRewards[i]; // Remove the future reward as it's now part of the total rewards } ``` The impact of this issue is critical because all of the deposited future reward will be used in distribution every time `distributeReward` is called, due to the failure of the "futureReward.availableFromTime <= block.timestamp" check in the function.
Open the reportThe `InfoAggregator` contract allows any external caller to update the `nFAiUserStakesContract` state variable via the `changeNFAiUserStakesContract` function. This function lacks access control mechanisms, making it possible for any user to change the address of the `nFAiUserStakesContract`. As a result, an unauthorized user could redirect functionalities dependent on this address, potentially leading to loss of funds or manipulation of the aggregated bucket information.
Open the reportThe `emergencyETHrecovery` uses `{value:}` structure and is designed to transfer native tokens from the contract to a `receiver`, but the `receive` function is missing, making it impossible for the contract to receive native tokens.
Open the reportThe current implementation of the `normalizeAmount` function only scales up the `stakeAmount` when the stake token's decimals are less than those of the reward token. There is no provision for scaling down when the stake token's decimals are equal to or greater. This finding seeks to discuss and confirm the intended behavior when `stakeTokenDecimals >= rewardTokenDecimals` to ensure the reward distributions are fair and aligned with the system's economic design. A stake token has the same or a greater number of decimals than the reward token. Stakeholders and developers need to confirm whether the intention is for the staked amounts to be adjusted downward or remain as is, which could potentially lead to higher rewards than intended.
Open the reportThe project design may not be compatible with non-standard ERC20 tokens, such as deflationary tokens or rebase tokens.
Open the reportThe constructor of the `NFAiRewardManager` contract does not validate whether the `_nuniAddress` parameter is the zero address. This omission could lead to scenarios where the `NUNI` token is inadvertently set to the zero address, causing the contract to fail to interact correctly with the `NUNI` token functions and potentially leading to loss of functionality or other unintended behaviors in the contract's operations.
Open the reportIn the `NFAiUserStakes` contract and `NFAiRewardManager` contract, we can observed that below 2 pairs of functions are very close in terms of logic: - NFAiUserStakes::removeRewardContractFromBucket vs. NFAiRewardManager::removeRewardContractFromBucket - NFAiUserStakes::addRewardContractToBucket vs. NFAiRewardManager::addRewardContractToBucket The only difference is actually additional security checks in functions of `NFAiUserStakes`, and `NFAiRewardManager` will update the `NFAiUserStakes` contract status with similar logic. ```solidity=83 function addRewardContractToBucket( uint256 bucketId, address rewardContractAddress ) external onlyRole(REWARD_MANAGER) { AssetRewardContract rewardContract = AssetRewardContract(rewardContractAddress); rewardBuckets[bucketId].rewardContracts.push(rewardContract); USER_STAKES_CONTRACT.addRewardContractToBucket(bucketId, rewardContractAddress); } ``` ```solidity=99 function removeRewardContractFromBucket( uint256 bucketId, address rewardContractAddress ) external onlyRole(REWARD_MANAGER) { RewardBucket storage bucket = rewardBuckets[bucketId]; uint256 rewardContractsLength = bucket.rewardContracts.length; for (uint256 i; i < rewardContractsLength; ++i) { if (address(bucket.rewardContracts[i]) == rewardContractAddress) { if (i != rewardContractsLength - 1) { bucket.rewardContracts[i] = bucket.rewardContracts[rewardContractsLength - 1]; } bucket.rewardContracts.pop(); break; } } USER_STAKES_CONTRACT.removeRewardContractFromBucket(bucketId, rewardContractAddress); } ``` ```solidity=235 function removeRewardContractFromBucket( uint256 bucketId, address rewardContractsAddress ) external onlyRole(ADMIN_ROLE) { if (buckets[bucketId].id == 0) { revert BucketDoesNotExist("Bucket does not exist"); } uint256 rewardContractsLength = buckets[bucketId].rewardContracts.length; for (uint256 i; i < rewardContractsLength; ++i) { if (address(buckets[bucketId].rewardContracts[i]) == rewardContractsAddress) { if (i != rewardContractsLength - 1) { buckets[bucketId].rewardContracts[i] = buckets[bucketId].rewardContracts[rewardContractsLength - 1]; } buckets[bucketId].rewardContracts.pop(); emit RewardContractRemovedFromBucket(bucketId, rewardContractsAddress); return; } } revert RewardContractNotAssociated("Reward contract not associated with bucket"); } ``` ```solidity=263 function addRewardContractToBucket( uint256 bucketId, address rewardContractsAddress ) external onlyRole(ADMIN_ROLE) { if (buckets[bucketId].id == 0) { revert BucketDoesNotExist("Bucket does not exist"); } if (rewardContractsAddress == address(0)) { revert TokenAddressZero("Token address is zero"); } AssetRewardContract rewardContract = AssetRewardContract(rewardContractsAddress); buckets[bucketId].rewardContracts.push(rewardContract); emit RewardContractAddedToBucket(bucketId, rewardContractsAddress); } ```
Open the reportThe `wNuni` contract includes a validation check `if(amount < 0) revert NegativeAmount();` in both the `mint` and `burn` functions. Given that the `amount` parameter is of type `uint256`, this check is unnecessary because unsigned integers cannot represent negative values in Solidity. This redundant check increases the gas cost for transactions unnecessarily and adds needless complexity to the contract code.
Open the report| Address | Chain | Source code |
|---|---|---|
| 0x8eec…79690x8eecaad83a1ea77bd88a818d4628fafc4cad7969 | Chain: Ethereum | Source code: Verified source |
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="nfa-labs"></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