As of 14 Oct 2026, NetMind has 1 audit report on Trustblock, by Quantstamp, dated 4 Aug 2024. That report lists no open critical findings.
Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Statuses are the security firms’ own. Trustblock does not review code.
Newest first
| Audit | Security firm | Date | Scope | Critical findings | Report |
|---|---|---|---|---|---|
| NetMind | Security firm: Quantstamp | Date: | Scope: Repository at commit d52de61 | No open critical findings | Open · certificate.quantstamp.com |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 2 | 3 |
| Medium | 0 | 5 | 3 |
| Low | 1 | 7 | 4 |
Currently, `AccountManage.init()` does not assign a `signNum` for the contract, meaning that after initialization, the `signNum` has a zero value. This means that `withdrawComputingFee()` can be invoked without any signatures necessary, allowing any address to withdraw the accumulated `providerFeeSum` amount of NMT tokens from this contract. During the audit, we notified the team of their live contract with a `signNum` of zero with ~18 NMT at stake for withdrawal by any party. As of 12 pm ET on July 12th, the `signNum` has not been updated and remains at a zero value.
Open the reportThe function `FinanceToken.purchaseNMTWithToken()` intends to return any excess `_paymentToken` to the caller, but `nmtToken` is always returned instead. There is no need to refund any payment as only the `useAmount` is transferred from the caller, not the full `_paymentAmount`.
Open the reportThe functions `distribute()` and `agentDistribute()` are susceptible to signature replay since a nonce is not included in the digest. After either function is called, anyone can reuse the calldata, which consists of the authorized account signatures, to replay the distribute transaction. The transaction can be replayed continuously until the payment has no remaining funds or the `expir` time is reached.
Open the reportThe `vote(uint256 id)` function checks if a manager has already voted on a proposal using the `voteRecord` mapping. However, the voting record is not updated once a manager has voted. This allows a malicious manager to repeatedly vote on the same proposal, potentially reaching the threshold required to pass the proposal. Additionally, a malicious manager can propose any malicious proposal and ensure it passes, allowing them to drain funds from the contract.
Open the reportBoth the `purchaseNMTWithETH()` and `purchaseNMTWithToken()` functions may lead to unintended retention of excess ETH or tokens due to integer division during the calculation of `_purchaseNMTQuantity`. When `msg.value * finance.paymentPrice / 10**18` (for ETH) or `_paymentAmount * finance.paymentPrice / 10**decimals` (for tokens) results in a value that does not use the full `msg.value` or `_paymentAmount`, the remainder is not refunded to the user. Therefore, users can lose the excess ETH or tokens without receiving corresponding NMT tokens.
Open the reportIn the function `swapToken()`, USDC is swapped to NMT tokens through a DEX router. In the following calculation, precision loss occurs to the amount of NMT tokens received as division is executed before multiplication: ``` 181 | amounts[1] = amounts[1] / 100000000000 * 100000000000; ``` Since the `Purchase` contract does not contain any functionality to withdraw NMT tokens, the tokens lost to precision loss will be trapped in the contract.
Open the reportThe `_actuator()` function handles various proposal types, including adding nodes (`_typeIndex == 2`) and removing nodes (`_typeIndex == 3`). However, for general proposals (`_typeIndex == 6`), there is no guard preventing the execution of `addNodeAddr` or `removeNodeAddr` functions within the data payload of `excContractPropose`. This could allow unauthorized additions or removals of nodes through general proposals.
Open the reportThe `_obtainProposalMsg()` function constructs a `QueryProposalMsgData` object by iterating over proposal IDs and their corresponding proposers. However, the function assumes a fixed number of nodes (`_nodeNum`) to allocate space for all proposers. This assumption can lead to incorrect data retrieval and potential overflow if the number of nodes has changed over time. If the number of nodes has changed since the proposals were created, the function may map proposers incorrectly. If `_nodeNum` is larger than the number of proposers for a given proposal, the function will write past the allocated space and lead to incorrect proposers returned by `_obtainProposalMsg()`.
Open the report<br> 1. The `CommunityFund` contract can only release up to `1650e22` NMT tokens over its lifetime due to the logic in `calcRelease()`. Therefore, once the sum of all `CommunityFund` contract releases (tracked by the state variable `withdraw`) reaches `1650e22`, any remaining NMT would be trapped in the contract. Specifically, transaction execution will revert in the `vote()` function at the following check: ``` 267 | uint256 _allAmount = calcRelease(_time); 268 | require(_proposalMsg.amount <= _allAmount - withdraw, "withdraw error"); ``` 1. The `StrategicFund` contract can only release up to `750e22` NMT tokens over its lifetime due to the logic in `calcRelease()`. Therefore, once the sum of all `StrategicFund` contract releases (tracked by the state variable `withdrawSum`) reaches `750e22`, any remaining NMT would be trapped in the contract. Specifically, transaction execution will revert in the `vote()` function at the following check: ``` 263 | uint256 _allAmount = calcRelease(_time); 264 | require(_proposalMsg.amount <= _allAmount - withdrawSum, "withdraw error"); ``` 1. The `TechnologyFund` contract can only release up to `1000e22` NMT tokens over its lifetime due to the logic in `calcRelease()`. Therefore, once the sum of all `TechnologyFund` contract releases (tracked by the state variable `withdrawSum`) reaches `1000e22`, any remaining NMT would be trapped in the contract. Specifically, transaction execution will revert in the `vote()` function at the following check: ``` 265 | uint256 _allAmount = calcRelease(_time); 266 | require(_proposalMsg.amount <= _allAmount - withdrawSum, "withdraw error"); ```
Open the reportIn the `FixedLock` contract, the code in the `init()` function is commented out, and the function does not initialize any of the contract's state variables. Therefore, if the `FixedLock` contract is set as the implementation contract for a new proxy, the following state variables will remain unset without any way to update them: 1. `startTime` 2. `endTime` 3. `releaseStart` 4. `releaseEnd` 5. `releaseDuration` 6. `rewardPropotion` 7. `rewardDelay`
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="netmind"></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