As of 24 Oct 2026, NetMind has 2 audit reports by 1 security firm on Trustblock; the latest is by CertiK, dated 13 Jan 2025. Those reports list no open critical findings.
Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Trustblock does not review code.
Newest first
| Audit | Security firm | Date | Scope | Critical findings | Report |
|---|---|---|---|---|---|
| NetMind XYZ | Security firm: CertiK | Date: | Scope: Files named in the report | No open critical findings | Open · skynet.certik.com |
| NetMind-Audit | Security firm: CertiK | Date: | Scope: Files named in the report | 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 | 0 |
| High | 0 | 6 | 5 |
| Medium | 0 | 4 | 10 |
| Low | 10 | 5 | 25 |
In function `check()`, the return parameter is used and assigned with a new value without initialization which causes an index "out of bounds" error. ```solidity function check(string memory paymentId, uint256 amt,uint256 expir, uint8[] calldata vs, bytes32[] calldata rs) public view returns(address[] memory signs){ bytes memory prefix = "\x19Ethereum Signed Message:\n32"; bytes32 digest = getDigest(paymentId, amt, expir); bytes32 hash = keccak256(abi.encodePacked(prefix, digest)); for (uint256 i = 0; i < vs.length; i++) { address signAddr = ecrecover(hash, vs[i], rs[i*2], rs[i*2+1]); signs[i] = signAddr; } } ```
Open the reportThe `claim()` function in the smart contract is intended for users to withdraw their staked rewards. However, it doesn't check whether the rewards being claimed include other users' principal amounts. ```solidity=207 IERC20(nmt).transfer(lf.owner, reward); ```
Open the reportBefore updating the new addresses and wallet address for a single node, the system will first verify whether the provided address has already been utilized. The existing code contains a flaw wherein incorrect index and state variables are employed for this verification process. ```solidity=210 require(!nodeAddrSta[_newAddr] && nodeIdByAddr[_newAddr] == address(0) && nodeAddrById[_newAddr] == address(0) , "node exist"); ``` ```solidity=216 require(!nodeAddrSta[_walAddr] && nodeIdByAddr[_walAddr] == address(0) && nodeAddrById[_walAddr] == address(0) , "walAddr exist"); ``` The third boolean expression in the statement at line 210/216, `nodeAddrById[_newAddr] == address(0)`/ `nodeAddrById[_walAddr] == address(0)`, should utilize `_nodeId` instead of `_newAddr` for indexing the node address.
Open the reportThe first field of the `DataMsg` struct is `dataId`; however, at line 124, it is assigned the value of `_dataHash`. ```solidity=58 struct DataMsg{ string dataId; string dataHash; } ``` ```solidity=124 DataMsg memory _dataMsg = DataMsg(_dataHash, _dataId); ```
Open the reportThe `vote` function is used to transfer funds once the number of votes exceeds half of the total node count. However, the contract increases the `withdrawSum` before the `if` conditions for a successful transfer are met. This can lead to inconsistencies in recorded withdrawals. ```solidity=253 withdrawSum = withdrawSum + _proposalMsg.amount; _proposalMsg.allProposers.push(_sender); _proposalMsg.voterSta[_sender] = true; uint256 length = _proposalMsg.allProposers.length; if(length> nodeNum/2 && !_proposalMsg.proposalSta){ require(address(this).balance >= _proposalMsg.amount, "Insufficient balance"); payable(_proposalMsg.targetAddr).transfer(_proposalMsg.amount); _proposalMsg.proposalSta = true; } ```
Open the reportWhen the remaining token amount in the pair drops below `gradThreshold`, the internal function `_addInitialLiquidity` is triggered to create a Uniswap V2 pair and add liquidity. However, due to the following condition: **contracts/AgentToken.sol** ```solidity=516 if (to_ == uniswapV2Pair && from_ != address(this) && fundedDate == 0) { revert InitialLiquidityNotYetAdded(); } ``` Since `from` is the `Bonding` contract rather than `address(this)` (token contract), the condition fails and the transaction reverts, preventing liquidity addition. **contracts/fun/Bonding.sol** ```solidity=305 function _addInitialLiquidity(IAgentToken token_, IERC20 _assetToken) internal returns(address){ address uniswapV2Pair_ = IUniswapV2Factory(uniswapRouter.factory()).createPair( address(token_), address(_assetToken) ); token_.addLiquidityPool(uniswapV2Pair_); token_.approve(address(uniswapRouter), type(uint256).max); _assetToken.approve(address(uniswapRouter), type(uint256).max); // Add the liquidity: (, , uint256 lpTokens) = uniswapRouter .addLiquidity( address(token_), address(_assetToken), token_.balanceOf(address(this)), _assetToken.balanceOf(address(this)), 0, 0, address(this), block.timestamp ); token_.setTokenSta(); IStakeVault stakeVault = IStakeVault(Clones.clone(stakeVaultImpl)); tokenStake[address(token_)] = address(stakeVault); IERC20(uniswapV2Pair_).approve(address(stakeVault), lpTokens); stakeVault.initialize(uniswapV2Pair_, lpTokens); return uniswapV2Pair_; } ```
Open the reportThe `addInitialLiquidity()` function, which is called by the `EXECUTOR_ROLE`, is responsible for adding liquidity to a pair. At line 93, tokenA is transferred to the pair, but tokenB is not. Then, at line 95, the function `mint` is invoked to initialize the amounts of both tokens. The omission of the tokenB transfer can lead to an imbalance in the liquidity provided, affecting the functionality of the pair initialization process. ```solidity=80 function addInitialLiquidity( address token_, uint256 amountToken_, uint256 amountAsset_ ) public onlyRole(EXECUTOR_ROLE) returns (uint256, uint256) { require(token_ != address(0), "Zero addresses are not allowed."); address pairAddress = factory.getPair(token_, assetToken); IFPair pair = IFPair(pairAddress); IERC20 token = IERC20(token_); token.safeTransferFrom(msg.sender, pairAddress, amountToken_); pair.mint(amountToken_, amountAsset_); return (amountToken_, amountAsset_); } ```
Open the reportThe `sellTax`, `buyTax` variables in the contract have no set limits, allowing fees to potentially reach 100%. If this occurs, users would receive no tokens from the contract, resulting in a complete loss of their investment.
Open the reportThe `approval()` function is invoked by the `Router` contract to approve token transfers from a pair to the user. However, the token utilizes the standard OpenZeppelin (OZ) library, which does not include a `forceApprove` function, causing compilation to fail. ```solidity=5 import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; ``` ```solidity=89 function approval( address _user, address _token, uint256 amount ) public onlyRouter returns (bool) { require(_user != address(0), "Zero addresses are not allowed."); require(_token != address(0), "Zero addresses are not allowed."); IERC20 token = IERC20(_token); token.forceApprove(_user, amount); return true; } ```
Open the reportThe `uniswapV2Pair` variable, representing the liquidity pool (LP) address for the token, is not initialized before being used in the AgentToken contract. This may lead to incorrect behavior when the contract interacts with Uniswap or other liquidity functions. ```solidity=137 function isLiquidityPool(address queryAddress_) public view returns (bool) { /** @dev We check the uniswapV2Pair address first as this is an immutable variable and therefore does not need * to be fetched from storage, saving gas if this address IS the uniswapV2Pool. We also add this address * to the enumerated set for ease of reference (for example it is returned in the getter), and it does * not add gas to any other calls, that still complete in 0(1) time. */ return (queryAddress_ == uniswapV2Pair || _liquidityPools.contains(queryAddress_)); } ``` ```solidity=516 if (to_ == uniswapV2Pair && from_ != address(this) && fundedDate == 0) { revert InitialLiquidityNotYetAdded(); } ```
Open the reportThe `buy()` function can be called by anyone to purchase tokens. When the token amount in the pair is less than the `gradThreshold`, it triggers an internal call to `_openTradingOnUniswap` to withdraw the remaining tokens in the pair. The function then proceeds to call `_addInitialLiquidity`, which creates a new Uniswap V2 pair and adds tokens for liquidity. However, if someone calls the createPair function and creates the Uniswap V2 pair ahead of time, the subsequent call to `_addInitialLiquidity` fails, causing the `buy` function to revert. ```solidity=305 function _addInitialLiquidity(IAgentToken token_, IERC20 _assetToken) internal returns(address){ address uniswapV2Pair_ = IUniswapV2Factory(uniswapRouter.factory()).createPair( address(token_), address(_assetToken) ); token_.addLiquidityPool(uniswapV2Pair_); token_.approve(address(uniswapRouter), type(uint256).max); _assetToken.approve(address(uniswapRouter), type(uint256).max); // Add the liquidity: (, , uint256 lpTokens) = uniswapRouter .addLiquidity( address(token_), address(_assetToken), token_.balanceOf(address(this)), _assetToken.balanceOf(address(this)), 0, 0, address(this), block.timestamp ); token_.setTokenSta(); IStakeVault stakeVault = IStakeVault(Clones.clone(stakeVaultImpl)); tokenStake[address(token_)] = address(stakeVault); IERC20(uniswapV2Pair_).approve(address(stakeVault), lpTokens); stakeVault.initialize(uniswapV2Pair_, lpTokens); return uniswapV2Pair_; } ```
Open the reportOn the main chain referred in the `CrossChain` contract, users have the ability to directly stake the native token. However, there is a current flaw in the code where users are allowed to stake any amount per day, and the owner does not receive the associated fees. In the process of staking with the native token, the provided `tokenAddr`, utilized in the `verfylimit()` function, lacks restrictions to a specific address. ```solidity=297 function stakeToken(string memory _chain, string memory receiveAddr, address tokenAddr, uint256 _amount) payable external onlyGuard { address _sender = msg.sender; require( chainSta[_chain], "Crosschain: The chain does not support transfer"); uint256 _sta = tokenSta[tokenAddr]; IERC20 token = IERC20(tokenAddr); if(mainChainSta){ _amount = msg.value; require(_amount > 0, "Value must be greater than 0"); }else { require(msg.value == 0, "Value must be equal to 0"); require(_sta > 0, "Incorrect token state setting"); require(token.transferFrom(_sender,address(this),_amount), "Token transfer failed"); } require(verfylimit(tokenAddr, _amount),"Extraction limit exceeded"); uint256 _fee = chargeRate[_chain][tokenAddr]; _amount = _amount - _fee; feeAmount[tokenAddr] = feeAmount[tokenAddr] + _fee; .... ``` In this scenario, users have the ability to invoke the `stakeToken()` function by providing an arbitrary and invalid value for the `tokenAddr` argument. Consequently, the boolean expression `threshold[token] > withdrawLimit[token][day];` will consistently evaluate to true. This is due to the invalidity of `tokenAddr`, resulting in an invalid fee being recorded by the `feeAmount` state variable, with the possibility of `feeAmount[address(0x00)]` being zero. ```solidity=410 function verfylimit(address token, uint256 amount) internal returns (bool) { uint256 day = block.timestamp/86400; withdrawLimit[token][day] += amount; return threshold[token] > withdrawLimit[token][day]; } ``` Otherwise, invoking the `withdrawChargeAmount()` function might result in zero fees, as the `feeAmount[address(0x00)]` is currently set to zero. ```solidity= function withdrawChargeAmount(address[] calldata tokenAddrs, address receiveAddr) external onlyOwner{ require( receiveAddr != address(0),"receiveAddr address cannot be 0"); for (uint256 i = 0; i< tokenAddrs.length; i++){ uint256 _feeAmount = feeAmount[tokenAddrs[i]]; if(tokenAddrs[i] == address(0x0)){ require(address(this).balance >= _feeAmount, "Insufficient amount of balance"); payable(receiveAddr).transfer(_feeAmount); }else{ IERC20 token = IERC20(tokenAddrs[i]); token.transfer(receiveAddr,_feeAmount); } feeAmount[tokenAddrs[i]] = 0; emit WithdrawChargeAmount(tokenAddrs[i], _feeAmount); } } ```
Open the reportThe provided code scans voting proposals from the most recent to the oldest, assuming that proposals are sorted in ascending order based on their expiration time. However, a flaw exists when the owner can update the `votingPeriod` using the `updateVotingPeriod()` function. This flaw can result in missing proposals under specific scenarios. ```solidity=310 for (uint256 i = proposalCount; i > 0; i--) { ProposalMsg storage _proposalMsg = proposalMsg[i]; if(_proposalMsg.expire > block.timestamp){ if(!_proposalMsg.proposalSta) { proposalIndexs[_num++] = i; } }else{ break; } } ``` In the current implementation, proposals are ordered based on the assumption that their expiration times are ascending when the `votingPeriod` is fixed. The expiration time (`_proposalMsg.expire`) is set as `_time + votingPeriod` when a new proposal is submitted. ```solidity=234 uint256 _time = block.timestamp; require(_time > LockTime + 31536000 * 5, "Not yet unlocked"); .... _proposalMsg.expire = _time + votingPeriod; ``` However, the owner has the ability to update the `votingPeriod` through the `updateVotingPeriod()` function. ```solidity=176 function updateVotingPeriod(uint256 _votingPeriod) external onlyOwner{ votingPeriod = _votingPeriod; emit UpdateVotingPeriod(_votingPeriod); } ``` For example, let's assume that current `votingPeriod` equals 5days, and consider a scenario: 1. A proposal (ID=1) is submitted with an expiration time of `α + 5 days`. 2. Another proposal (ID=2) is submitted 1 day later with an expiration time of `α + 1 day + 5 days`. 3. The owner then updates the `votingPeriod` to 1 day. 4. Another proposal (ID=3) is submitted 2 days later with an expiration time of `α + 2 days + 1 day`. 5. At this point, the expiration times in the `proposalMsg` state variable are as follows: 1. proposalMsg[0].expire = `α + 5 days` 2. proposalMsg[1].expire = `α + 6 days` 3. proposalMsg[2].expire = `α + 3 days` 6. When querying voting proposals at `α + 4 days`, only the last proposal (`proposalMsg[2]`) with an expiration time of `α + 3 days` is scanned because the condition `if(_proposalMsg.expire > block.timestamp)` at line 312 evaluates to false for the other proposals, leading to the `break` statement at line 317. 7. Consequently, the two unexpired proposals (`proposalMsg[0]` and `proposalMsg[1]`) are not returned. A similar issue also exists in `TechnologyFund` contract.
Open the reportthe `nodeAddrById` mapping is designed to trace the mapping between a node id and its corresponding node address. At line 500, the node address is incorrectly passed as an argument instead of the node id, which might result in the retrieval of a zero address (0x0), causing the subsequent `if` condition to false. ```solidity=498 function getNodeIdByAddr(address _nodeAddr) public view returns(address){ address _nodeId = nodeIdByAddr[_nodeAddr]; if(_nodeId == address(0) && nodeAddrSta[_nodeAddr] && nodeAddrById[_nodeAddr] == _nodeId){ return _nodeAddr; }else { return _nodeId; } } ```
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 can control the untrusted contract, they can make a recursive call back to the original function, repeating interactions that would have otherwise not run after the external call resolved the effects. ### External call(s) ```solidity=256 token.transfer(receiveAddr,_feeAmount); ``` ```solidity=253 payable(receiveAddr).transfer(_feeAmount); ``` ### State variables written after the call(s) ```solidity=258 feeAmount[tokenAddrs[i]] = 0; ```
Open the reportThe `_registerAgentEID()` function can be called by any user to register an `agentEID`. If the `agentEID` parameter is passed as an empty value, the condition at line 74 will not execute, allowing the registration process to proceed without proper validation of the `agentEID`. ```solidity=72 function _registerAgentEID(string memory agentEID) internal { bytes32 hash = keccak256(abi.encodePacked(agentEID)); if (hash != keccak256(abi.encodePacked(""))){ require(!_agentEIDs[hash], "Agent EID already registered"); _agentEIDs[hash] = true; } } ```
Open the reportPerforming integer division before multiplication truncates the low bits, losing the precision of calculation. ```solidity=608 uint256 swapThresholdInTokens = (_totalSupply * swapThresholdBasisPoints) / BP_DENOM; ``` ```solidity=618 swapBalance > swapThresholdInTokens * MAX_SWAP_THRESHOLD_MULTIPLE ``` ```solidity=608 uint256 swapThresholdInTokens = (_totalSupply * swapThresholdBasisPoints) / BP_DENOM; ``` ```solidity=621 swapBalance = swapThresholdInTokens * MAX_SWAP_THRESHOLD_MULTIPLE; ``` ```solidity=223 uint256 liquidity = (((k * 10000 ether) / supply) * 1 ether) / 10000; ```
Open the reportIn general, if we want to use Token-B to evaluate Token-A, the price of Token-A represents the amount of Token-B per Token-A. This can be calculated using the formula: $\frac{Token-B\_Amount}{Token-A\_Amount}$. From the implementation of the `createPair()` function, we can see that within a pair, `reserve0` represents the reserve amount of the agent token, while `reserve1` represents the reserve amount of the asset token. Therefore, the value returned by the `priceBLast()` function, which indicates the number of agent tokens per asset token, is the price of the asset token, not the agent token. As a result, in the following code block, the `price` field of `Data`, which contains attributes of the agent token, is incorrectly assigned the price of the asset token rather than the agent token. *contracts/fun/Bonding.sol* ```solidity=197 @> address _pair = factory.createPair(address(token), assetToken); .... Data memory _data = Data({ token: address(token), name: string.concat(_name, " by NetMind AI"), ticker: _ticker, supply: supply, marketCap: liquidity, @> price: IFPair(_pair).priceBLast() }); ``` ```solidity=131 function priceBLast() public view returns (uint256) { @> return _pool.reserve0 / _pool.reserve1; } ```
Open the reportUpon initialization, the `swapThresholdBasisPoints` variable is of `uint256`. However, in the `setSwapThresholdBasisPoints` function, `swapThresholdBasisPoints_` is assigned a `uint16`, which may be too small. This discrepancy can cause the `setSwapThresholdBasisPoints` to malfunction, leading to potential data loss or incorrect processing, compromising the system's reliability and accuracy.
Open the reportAddresses are not validated before assignment or external calls, potentially allowing the use of zero addresses and leading to unexpected behavior or vulnerabilities. For example, transferring tokens to a zero address can result in a permanent loss of those tokens.
Open the reportIn `Bonding.sol`, the `fee` state variable is initialized in the `initialize()` function and updated in the `setFee()` function; however, the calculation formulas for its value differ between the two functions. *contracts/fun/Bonding.sol* ```solidity=83 function initialize( address factory_, address router_, address feeTo_, uint256 fee_, .... ) external initializer { __Ownable_init(msg.sender); __ReentrancyGuard_init(); factory = FFactory(factory_); router = FRouter(router_); feeTo = feeTo_; @> fee = (fee_ * 1 ether) / 1000; .... } ``` ```solidity=133 function setFee(uint256 newFee, address newFeeTo) public onlyOwner { @> fee = newFee; feeTo = newFeeTo; } ```
Open the reportCurrent implementation is vulnerable to [a known ERC20 race condition issue](https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729), which could lead to token theft. When a user calls `approve()` for a second time on a spender that has already been allowed, the spender could call `transferFrom()` to transfer the previous value and still receive the authorization to transfer the new value. Exploit scenario: 1. Alice calls `approve(Bob, 100)` to allow Bob to spend 100 tokens. 2. Alice changes her mind and calls `approve(Bob, 50)`. 3. Bob observes the second `approve(Bob, 50)` function call and calls `transferFrom(Alice, Bob, 100)` before the second `approve(Bob, 50)` call. 4. The above scenario can be achieved by front-running. In this case, Bob can transfer another 50 tokens from Alice and in total, he transferred 150 tokens from Alice.
Open the reportThe `updateMapping()` function is responsible for updating node and wallet information. However, the previous mapping entry `nodeIdByAddr[_oldAddr]` remains uncleared, leading to outdated references. ```solidity=211 nodeIdByAddr[_newAddr] = _nodeId; ```
Open the reportAccording to the code logic, a data snapshot is considered valid and will be persisted if it receives votes from more than two individuals. This differs from the document content, which specifies that 12 votes are required.
Open the reportThe event triggered at line 98 enables the logging of the administrator's change operation. However, the code flaw is that the emitted event only reveals the new administrator's address. ```solidity=96 function changeAdmin(address newAdmin) external onlyAmdin returns(bool) { _setAdmin(newAdmin); emit AdminChanged(admin(), newAdmin); return true; } ``` After executing `_setAdmin(newAdmin)` at line 97, the `admin()` function returns the new admin address. Emitting the event after executing the code at line 97 results in the `AdminChanged` log displaying only the new admin address.
Open the reportBased on the [NetMind Official Doc](https://netmind-power.gitbook.io/white-paper/7.-netmind-token), > For the first 10 years, 1% (100 million) will be distributed annually, totaling 1 billion NMT. > For the following 30 years, 0.5% (50 million) will be distributed annually, totaling 1.5 billion NMT. > > The duration unit "year" in the reward rules is calculated as 365 days, regardless of leap years. ```solidity=135 uint256 i; if (block.timestamp < begin + 10 * 356 days) i = miner_awd_1; else if(block.timestamp < begin + 40 * 365 days) i = miner_awd_2; else i = miner_awd_3; ``` The hardcoded `356 days` should be replaced by `365 days`, otherwise, `miner_awd_2` is returned if the `block.timestamp` is greater than `10 * 356 days` and less than 10 years. A similar issue also exists in `getAwradMSG(uint256 time)` function.
Open the reportIt is unsafe to assume that, when `addr.code.length` equals zero, an address is an externally-owned account (EOA) and not a contract. Among the following types of addresses, `addr.code.length` is zero: 1. an externally-owned account 2. a contract in construction 3. an address where a contract will be created. Before deploying contract, user can construct that contract address by himself. 4. an address where a contract lived, but was destroyed
Open the report```solidity=109 function lock(uint256 amt) public payable notContract returns(uint256 id){ require(block.timestamp > startTime, "activit not start"); require(block.timestamp < endTime, "activit end"); ... ``` The state variables `startTime` and `endTime` represent the valid time period for the NMT lock service. However, there is a potential service blocking issue when `endTime` is less than `startTime` because the boolean expressions at L110 and L111 cannot be true at the same time. The input validation within the `init()` function is lack, and the values of `startTime` and `endTime` cannot be updated after contract initialization. In this case, `endTime` may be less than `startTime`. ```solidity=84 function init(uint256 _endTime, uint256 _lockDuration, uint256 _rewardPropotion, uint256 _rewardDelay, bool _isMainNet) public initializer{ startTime = block.timestamp; endTime = _endTime; ... ```
Open the reportThe state variable `SigNum` is used to check if valid signatures are enough. Its value should be greater than zero. Because its value cannot be changed after calling `init()` function, it is better to check its value when initializing. ```solidity=185 require(counter >= SigNum, "lack of signature"); ```
Open the reportAddresses are not validated before assignment or external calls, potentially allowing the use of zero addresses and leading to unexpected behavior or vulnerabilities. For example, transferring tokens to a zero address can result in a permanent loss of those tokens. ```solidity=267 payable(sender).transfer(value); ``` - `sender` is not zero-checked before being used. --- ```solidity=90 if (what == "WNMT") WNMT = dst; ``` ```solidity=91 else if (what == "Training") Training = dst; ``` ```solidity=92 else if (what == "Inference") Inference = dst; ``` ```solidity=93 else if (what == "Price") Price = dst; ``` ```solidity=94 else if (what == "Credit") Credit = dst; ``` ```solidity=95 else if (what == "Staking") Staking = dst; ``` ```solidity=96 else if (what == "Award") Award = dst; ``` ```solidity=97 else if (what == "AccountManageExecutor") accountManageExecutor = dst; ``` ```solidity=98 else if (what == "PriceServiceExecutor") priceServiceExecutor = dst; ``` ```solidity=99 else if (what == "TrainingTaskExecutor") trainingTaskExecutor = dst; ``` - `dst` is not zero-checked before being used. --- ```solidity=199 trader = _trader; ``` - `_trader` is not zero-checked before being used. --- ```solidity=203 exector = _exector; ``` - `_exector` is not zero-checked before being used. --- ```solidity=130 conf = _conf; ``` - `_conf` is not zero-checked before being used. --- ```solidity=136 blacker = guy; ``` - `guy` is not zero-checked before being used. --- ```solidity=198 exector = _exector; ``` - `_exector` is not zero-checked before being used. --- ```solidity=140 conf = _conf; ``` - `_conf` is not zero-checked before being used. --- ```solidity=141 Rewardcontract = _reward; ``` - `_reward` is not zero-checked before being used. --- ```solidity=178 minter = _minter; ``` - `_minter` is not zero-checked before being used. --- ```solidity=173 require(!nodeAddrSta[_nodeAddr], "This node is already a node address"); nodeAddrSta[_nodeAddr] = true; ``` - `_nodeAddr` is not zero-checked before being used. --- ```solidity=114 _proposalMsg.addr = _addr; ``` - `_addr` is not zero-checked before being used.
Open the reportSigned messages are not properly verified with the current chain ID, thus allowing attackers to perform replay attacks across chains. Hardcoded or cached chain ID values are also vulnerable since a hard fork may occur and change the chain ID in the future. ```solidity=379 abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(_data.userAddr, _data.amount, _data.expiration, _nonce)) ) ``` - Reading a state variable `DOMAIN_SEPARATOR`, which seems to use a cached chain ID value. - Encoding the cached chain ID value `DOMAIN_SEPARATOR`. ```solidity=317 bytes32 digest = getDigest(Data( addr, uints[0], uints[1]), _nonce); ``` - `getDigest(Data(addr,uints[0],uints[1]),_nonce)` returns the cached chain ID. ```solidity=368 bytes32 hash = keccak256(abi.encodePacked(prefix, _digest)); ``` - Encoding data using `abi.encodePacked()`. ```solidity=369 address signer = ecrecover(hash, _sig.v, _sig.r, _sig.s); ``` - Calling `ecrecover` with a hash that does not properly include the chain ID. --- ```solidity=429 abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(_data.userAddr, _data.contractAddr, _data.amount, _data.expiration, _data.chain, _data.txid)) ) ``` - Reading a state variable `DOMAIN_SEPARATOR`, which seems to use a cached chain ID value. - Encoding the cached chain ID value `DOMAIN_SEPARATOR`. ```solidity=340 bytes32 digest = getDigest(Data( addrs[0], addrs[1], uints[0], uints[1], strs[0], strs[1])); ``` - `getDigest(Data(addrs[0],addrs[1],uints[0],uints[1],strs[0],strs[1]))` returns the cached chain ID. ```solidity=404 bytes32 hash = keccak256(abi.encodePacked(prefix, _digest)); ``` - Encoding data using `abi.encodePacked()`. ```solidity=405 address _nodeAddr = ecrecover(hash, _sig.v, _sig.r, _sig.s); ``` - Calling `ecrecover` with a hash that does not properly include the chain ID. --- ```solidity=224 abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(paymentId, amt, expir))) ``` - Reading a state variable `DOMAIN_SEPARATOR`, which seems to use a cached chain ID value. - Encoding the cached chain ID value `DOMAIN_SEPARATOR`. ```solidity=173 bytes32 digest = getDigest(paymentId, amt, expir); ``` - `getDigest(paymentId,amt,expir)` returns the cached chain ID. ```solidity=216 bytes32 hash = keccak256(abi.encodePacked(prefix, _digest)); ``` - Encoding data using `abi.encodePacked()`. ```solidity=217 address signer = ecrecover(hash, _sig.v, _sig.r, _sig.s); ``` - Calling `ecrecover` with a hash that does not properly include the chain ID. --- ```solidity=224 abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(paymentId, amt, expir))) ``` - Reading a state variable `DOMAIN_SEPARATOR`, which seems to use a cached chain ID value. - Encoding the cached chain ID value `DOMAIN_SEPARATOR`. ```solidity=194 bytes32 digest = getDigest(paymentId, amt, expir); ``` - `getDigest(paymentId,amt,expir)` returns the cached chain ID. ```solidity=195 bytes32 hash = keccak256(abi.encodePacked(prefix, digest)); ``` - Encoding data using `abi.encodePacked()`. ```solidity=198 address signAddr = ecrecover(hash, vs[i], rs[i*2], rs[i*2+1]); ``` - Calling `ecrecover` with a hash that does not properly include the chain ID. --- ```solidity=296 abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(_data.userAddr, _data.contractAddr, _data.amount, _data.expiration, _nonce)) ) ``` - Reading a state variable `DOMAIN_SEPARATOR`, which seems to use a cached chain ID value. - Encoding the cached chain ID value `DOMAIN_SEPARATOR`. ```solidity=237 bytes32 digest = getDigest(Data( addrs[0], addrs[1], uints[0], uints[1]), _nonce); ``` - `getDigest(Data(addrs[0],addrs[1],uints[0],uints[1]),_nonce)` returns the cached chain ID. ```solidity=271 bytes32 hash = keccak256(abi.encodePacked(prefix, _digest)); ``` - Encoding data using `abi.encodePacked()`. ```solidity=272 address _accessAccount = ecrecover(hash, _sig.v, _sig.r, _sig.s); ``` - Calling `ecrecover` with a hash that does not properly include the chain ID. --- ```solidity=223 abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(nonce, amt, expir))) ``` - Reading a state variable `DOMAIN_SEPARATOR`, which seems to use a cached chain ID value. - Encoding the cached chain ID value `DOMAIN_SEPARATOR`. ```solidity=169 bytes32 digest = getDigest(nonce, amt, expir); ``` - `getDigest(nonce,amt,expir)` returns the cached chain ID. ```solidity=215 bytes32 has
Open the reportIn the `claimReward()` function, designed for users to claim rewards, a logic flaw is present at line 173. It imposes a condition `block.timestamp > lf.lockTime + rewardDelay`, indicating that rewards can only be claimed after a specific time. ```solidity=168 function claimReward(uint256 id) public notContract{ LockInfo storage lf = lockInfo[id]; require(lf.locked > 0, "lockId unexsit"); require(lf.owner == msg.sender, "only owner can call"); require(lf.rewardsEarned == 0, "already claim"); require(block.timestamp > lf.lockTime + rewardDelay, "unarrived claim time"); //claim reward uint256 reward = lf.locked * rewardPropotion / 1000; require(address(this).balance - reward >= totalLocked, "reward used up"); lf.rewardsEarned = reward; payable(msg.sender).transfer(reward); emit ClaimReward(id, msg.sender, reward); } ``` However, the `checkReward()` function, which assesses the available rewards, considers the condition `block.timestamp = lf.lockTime + rewardDelay` as eligible for rewards. This inconsistency causes transactions invoking `claimReward()` to revert even when users should be entitled to rewards. ```solidity=160 function checkReward(uint256 id) public view returns(uint256){ LockInfo memory lf = lockInfo[id]; if (block.timestamp < lf.lockTime + rewardDelay || lf.rewardsEarned > 0){ return 0; } return lf.locked * rewardPropotion / 1000; } ```
Open the reportAccording to the document, there are only three states of `Job`, ```bat 1: running, 2: finish,3: abort, ``` ```solidity=189 require(_jobMsg.state == 1 || _jobMsg.state == 4, "task status error"); ```
Open the reportThe `Conf` contract initializer is the default account with the authority to update state variables. This initializer can delegate such rights to other accounts. However, a current flaw in the code allows newly authorized accounts to delegate the ability to update state variables to other new accounts. ```solidity=17 mapping (address => uint) public wards; function rely(address guy) external auth { wards[guy] = 1; } function deny(address guy) external auth { wards[guy] = 0; } modifier auth { require(wards[msg.sender] == 1); _; } ``` ```solidity=62 function files(string[] calldata whats, address[] calldata dstas) external auth { .... ```
Open the reportIn the `stake()` function for the user to deposit assets into the contract, the existence of `nodeAddr` is verified on line 267, which means that `_nodeAddrIndex` will hold a non-zero value.
Open the reportThe `ecrecover()` function is subject to signature malleability. The signature malleability is possible within the Elliptic Curve cryptographic system. An Elliptic Curve is symmetric on the `X`-axis, meaning two points can exist with the same `X` value. In the `r`, `s` and `v` representation this permits us to carefully adjust `s` to produce a second valid signature for the same `r`, thus breaking the assumption that a signature cannot be replayed in what is known as a replay-attack. ```solidity=320 (bool result, address signAddr) = verifySign( digest, Sig(vs[i], rssMetadata[i*2], rssMetadata[i*2+1]) ); ``` - `verifySign` called. ```solidity=369 address _nodeAddr = ecrecover(hash, _sig.v, _sig.r, _sig.s); ``` - `ecrecover` called without proper checks. --- ```solidity=343 (bool result, address signAddr) = verifySign( digest, Sig(vs[i], rssMetadata[i*2], rssMetadata[i*2+1]) ); ``` - `verifySign` called. ```solidity=405 address _nodeAddr = ecrecover(hash, _sig.v, _sig.r, _sig.s); ``` - `ecrecover` called without proper checks. --- ```solidity=176 (bool result, address signAddr) = verifySign(digest, Sig(vs[i], rs[i*2], rs[i*2+1])); ``` - `verifySign` called. ```solidity=217 address signer = ecrecover(hash, _sig.v, _sig.r, _sig.s); ``` - `ecrecover` called without proper checks. --- ```solidity=198 address signAddr = ecrecover(hash, vs[i], rs[i*2], rs[i*2+1]); ``` - `ecrecover` called without proper checks. --- ```solidity=197 address signAddr = ecrecover(hash, vs[i], rs[i*2], rs[i*2+1]); ``` - `ecrecover` called without proper checks.
Open the reportThe function `vote()` is designed to vote for specific proposals identified by `_proposalId`. The function does not verify that the proposal has been executed, which means that it does not check whether the associated `_proposalMsg.proposalSta` variable is `true`.
Open the reportThe `SafeMath` library is used unnecessarily. With Solidity compiler versions 0.8.0 or newer, arithmetic operations will automatically revert in case of integer overflow or underflow. ```solidity=140 using SafeMath for uint256; ``` - `SafeMath` library is used for `uint256` type in `AccountManage` contract. ```solidity=256 _userAccountMsg.balance = _userAccountMsg.balance.add(msg.value); ``` - `SafeMath.add` is called in `tokenCharge` function of `AccountManage` contract. *Note: Only a sample of 2 `SafeMath` library usage in this contract (out of 14) are shown above.* --- ```solidity=22 using SafeMath for uint256; ``` - `SafeMath` library is used for `uint256` type in `Management` contract. ```solidity=116 _proposalMsg.expire = _time.add(86400*3); ``` - `SafeMath.add` is called in `_propose` function of `Management` contract. --- ```solidity=112 using SafeMath for uint256; ``` - `SafeMath` library is used for `uint256` type in `TrainingTask` contract. ```solidity=193 _jobMsg.freezeAmount = _jobMsg.freezeAmount.add(freezeAmount); ``` - `SafeMath.add` is called in `updateJob` function of `TrainingTask` contract. *Note: Only a sample of 2 `SafeMath` library usage in this contract (out of 6) are shown above.* --- ```solidity=103 using SafeMath for uint256; ``` - `SafeMath` library is used for `uint256` type in `ERC20` contract. --- ```solidity=103 using SafeMath for uint256; ``` - `SafeMath` library is used for `uint256` type in `ERC20` contract. ```solidity=136 allowances[owner][msg.sender] = allowances[owner][msg.sender].sub(amount); ``` - `SafeMath.sub` is called in `transferFrom` function of `ERC20` contract. *Note: Only a sample of 2 `SafeMath` library usage in this contract (out of 8) are shown above.* --- ```solidity=193 library SafeMath { ``` - An implementation of `SafeMath` library is found.
Open the reportOne or more logic contracts do not protect their initializers. An attacker can call the initializer and assume ownership of the logic contract, whereby she can perform privileged operations that trick unsuspecting users into believing that she is the owner of the upgradeable contract. ```solidity=139 contract AccountManage is Ownable{ ``` - `AccountManage` is an upgradeable contract that does not protect its initializer. ```solidity=193 function init(address _conf) external ``` - `init` is an unprotected initializer function. --- ```solidity=109 contract CommunityFund is ICommunityFund,Ownable{ ``` - `CommunityFund` is an upgradeable contract that does not protect its initializer. ```solidity=156 function init(address[] calldata _nodeAddrs) external initializer{ ``` - `init` is an unprotected initializer function. --- ```solidity=109 contract Crosschain is Initializable,Ownable { ``` - `Crosschain` is an upgradeable contract that does not protect its initializer. ```solidity=167 function init( ``` - `init` is an unprotected initializer function. --- ```solidity=107 contract Payment is Initializable, Ownable { ``` - `Payment` is an upgradeable contract that does not protect its initializer. ```solidity=129 function init(address _conf, uint256 _signum) public initializer{ ``` - `init` is an unprotected initializer function. --- ```solidity=113 contract Pledge is Initializable,Ownable,IPledge{ ``` - `Pledge` is an upgradeable contract that does not protect its initializer. ```solidity=154 function init() external initializer{ ``` - `init` is an unprotected initializer function. --- ```solidity=105 contract PriceService is Ownable{ ``` - `PriceService` is an upgradeable contract that does not protect its initializer. ```solidity=116 function init( ``` - `init` is an unprotected initializer function. --- ```solidity=118 contract RewardContract is Initializable,Ownable,IRewardContract { ``` - `RewardContract` is an upgradeable contract that does not protect its initializer. ```solidity=172 function init(address _conf) external initializer{ ``` - `init` is an unprotected initializer function. --- ```solidity=107 contract RewardPool is Initializable, Ownable { ``` - `RewardPool` is an upgradeable contract that does not protect its initializer. ```solidity=139 function init(address _conf, address _reward, uint256 _dailymaxmove, uint256 _signum, uint256 _moveable) public initializer{ ``` - `init` is an unprotected initializer function. --- ```solidity=109 contract TechnologyFund is ITechnologyFund,Ownable{ ``` - `TechnologyFund` is an upgradeable contract that does not protect its initializer. ```solidity=155 function init(address[] calldata _nodeAddrs) external initializer{ ``` - `init` is an unprotected initializer function. --- ```solidity=111 contract TrainingTask is Ownable{ ``` - `TrainingTask` is an upgradeable contract that does not protect its initializer. ```solidity=147 function init( ``` - `init` is an unprotected initializer function. --- ```solidity=162 contract WrapToken is Initializable,Ownable,ERC20{ ``` - `WrapToken` is an upgradeable contract that does not protect its initializer. ```solidity=165 function init( address _minter) external initializer{ ``` - `init` is an unprotected initializer function.
Open the reportThe smart contract contains one or more values that are not used, which can lead to unnecessary complexity and reduced maintainability. --- ```solidity=277 uint256 _nodeNum = nodeNum; ``` - The variable `_nodeNum` is never used after this assignment. --- ```solidity=281 _nodeNum = _nodeAddrIndex; ``` - The variable `_nodeNum` is never used after this assignment.
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-xyz"></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