As of 9 Nov 2026, Metaverse User DAO has 4 audit reports by 1 security firm on Trustblock; the latest is by CertiK, dated 7 Sep 2023. Those reports list no open critical findings.
Record last updated . It holds audits and findings, contracts and incidents up to Nov 2026. Trustblock does not review code.
Newest first
| Report | Security firm | Date | Scope | Critical findings | Source |
|---|---|---|---|---|---|
| metaverse-user-dao-addendum III | Security firm: CertiK | Date: | Scope: Files listed | None open | skynet.certik.com ↗ |
| metaverse-user-dao---addendum II | Security firm: CertiK | Date: | Scope: Files listed | None open | skynet.certik.com ↗ |
| Metaverse User DAO - Addendum | Security firm: CertiK | Date: | Scope: Files listed | None open | skynet.certik.com ↗ |
| MUD | Security firm: CertiK | Date: | Scope: Files listed | 2 critical findings, fixed | skynet.certik.com ↗ |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 5 | 0 | 1 |
| Medium | 3 | 0 | 0 |
| Low | 18 | 0 | 23 |
There is a potential issue in the `depositMapping()` function of the `MudMiningEscrow` contract, where it could overwrite deposits made by users who called the `deposit()` function. This is because the function `depositMapping()` does not verify whether a user has already made a deposit at a particular index in the `_logbook`, but instead directly writes the mapped amounts from Ethereum to the `_logbook` storage. Consequently, the user's deposit amounts could be replaced, causing potential losses to users. ```solidity=80 if (_cursors[depositAddress].start == 0) { _cursors[depositAddress].start = orderIdArray[i]; _cursors[depositAddress].end = orderIdArray[i]; } else { if (orderIdArray[i] < _cursors[depositAddress].start) { _cursors[depositAddress].start = orderIdArray[i]; } if (orderIdArray[i] > _cursors[depositAddress].end) { _cursors[depositAddress].end = orderIdArray[i]; } } _logbook[depositAddress][orderIdArray[i]].startTime = starttimeArray[i]; _logbook[depositAddress][orderIdArray[i]].endTime = endtimeArray[i]; _logbook[depositAddress][orderIdArray[i]].amount = amountArray[i]; ```
Open the reportBoolean variables can be used directly and do not need to be compared to true or false.
Open the reportIn the `MUDUniswapV3Staker` contract, function `unstake()` violates the Check-Effects-Interactions pattern. This pattern is a best practice for writing secure smart contracts that involves performing all state changes before making any external function calls. ### External call(s) ```solidity=247 (usdtReleased, mudReleased) = releaseLiquidity(tokenId); ``` ```solidity=335 function releaseLiquidity(uint256 tokenId) private returns (uint256 amount0collected, uint256 amount1collected) { (, , , uint128 liquidity) = getPositionInfo(tokenId); INonfungiblePositionManager.DecreaseLiquidityParams memory params = INonfungiblePositionManager.DecreaseLiquidityParams({ tokenId: tokenId, liquidity: liquidity, amount0Min: 0, amount1Min: 0, deadline: block.timestamp }); nonfungiblePositionManager.decreaseLiquidity(params); (amount0collected, amount1collected) = collectAllFees(tokenId); //return tokens to the owner usdt.transfer(tokenOwner[tokenId], amount0collected); mud.transfer(tokenOwner[tokenId], amount1collected); } ``` ```solidity=316 function collectAllFees(uint256 tokenId) private returns (uint256 amount0, uint256 amount1) { // set amount0Max and amount1Max to uint256.max to collect all fees INonfungiblePositionManager.CollectParams memory params = INonfungiblePositionManager.CollectParams({ tokenId: tokenId, recipient: address(this), amount0Max: type(uint128).max, amount1Max: type(uint128).max }); (amount0, amount1) = nonfungiblePositionManager.collect(params); } ``` ### State variables removed after the call(s) ```solidity=249 delete tokenOwner[tokenId]; ``` An external function call to the `nonfungiblePositionManager.decreaseLiquidity()` and `nonfungiblePositionManager.collect()` functions are made before the state changes are made. This may create a potential vulnerability where an attacker could manipulate the contract's state during the external function call, which could lead to loss of funds or other malicious actions. To prevent such potential issue, it is important to ensure that all external function calls are made after the state changes have been made.
Open the reportIn the `onERC721Received()` function, there is no need to modify the contract state or receive Ether. However, these functions are not explicitly labeled with the `pure` or `view` modifiers. The `pure` modifier indicates that a function does not read or modify the contract's storage or state variables. It is used when a function performs computations based solely on its input parameters and does not have any side effects. The `view` modifier is used for functions that do not modify the contract's state but may read the contract's storage or state variables. It is used when a function provides a read-only view of the contract's data.
Open the reportIn the function `createNewStakingContract()`, there is a `duration` validation check in which the comment mentions "Duration should be 3/6/9 !", but the valid options for the duration variable are actually 3, 6, or 12. The value 9 is not a valid option according to the condition specified in the `require` statement. ```solidity=161 require(duration == 3 || duration == 6 || duration == 12, "Duration should be 3/6/9 !"); ``` In the codebase, there is inconsistent comment regarding the `duration`. ```solidity=85 struct StakingContractInfo { uint256 tokenId; //UNISWAP V3 liquidity NFT position id uint8 duration; //staking period, 3,6,12 in months(every months 30 days) uint startTime;//staking start block time uint endTime;//staking end time uint256 startMUD; //initial MUD staked uint256 startUSDT; //initial USDT staked } ``` ```solidity=138 // Parameters: // usdtToStake: USDT to be staked // mudToStake: MUD to be staked // duration: stake period (3/6/9 months, each month 30 days) // nodeId: DAPP to use, must return in events ```
Open the reportIn the contract `unstakeForMainnetMapping()`, the `contractInfoArray` variable is declared as `storage`, but it is only used for read-only purposes. When a variable is declared as `storage`, any modifications made to it will directly update the state of the contract storage. However, in this function, the `contractInfoArray` is only being read from, and no modifications are being made to it. Declaring a variable as storage is useful when modifying the variable and having those changes persist in the contract's storage. However, if the function just needs to read the data from the variable and doesn't intend to modify it, declaring it as `storage` incurs unnecessary gas costs. ```solidity=361 StakingContractInfo[] storage contractInfoArray = stakingContractInfoMap[addr]; ``` Similarly, the same code exists in the function `getContractInfoByTokenId()`. ```solidity=448 StakingContractInfo[] storage contractInfoArray = stakingContractInfoMap[addressToCheck]; ```
Open the reportThe `createNewStakingContract()` function does not include a check to verify if the `usdtToStake` and `mudToStake` inputs are not zero. This can lead to unintended behavior and potential issues if either of these inputs is mistakenly set to zero. ```solidity=150 function createNewStakingContract(uint256 usdtToStake, uint256 mudToStake, uint8 duration, uint nodeId) external returns ( uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1, uint startTime, uint endTime ) { require(duration == 3 || duration == 6 || duration == 12, "Duration should be 3/6/9 !"); uint256 amount0ToMint = usdtToStake; uint256 amount1ToMint = mudToStake; ```
Open the reportIn the `createNewStakingContract()` function, both `amount0Min` and `amount1Min` are specified with a value of zero when calling the `mint()` function of the `nonfungiblePositionManager`. These parameters are used to enforce price slippage checks in the DEX pair. By setting them to zero, there is no explicit requirement for a minimum amount of tokens to be received in return for the staking transaction. This omission can lead to potential issues with price slippage and unexpected outcomes for the staking operation. ```solidity=174 INonfungiblePositionManager.MintParams memory params = INonfungiblePositionManager.MintParams({ token0: usdtAddr, token1: mudAddr, fee: 3000, tickLower: -887220,//this will be modified to the actual token pair MUD/USDT of polygon mainnet tickUpper: 887220,//this will be modified to the actual token pair MUD/USDT of polygon mainnet amount0Desired: amount0ToMint, amount1Desired: amount1ToMint, amount0Min: 0, amount1Min: 0, recipient: address(this), deadline: block.timestamp }); // Note that the pool defined by MUD/USDT and fee tier 0.3% must already be created and initialized in order to mint (tokenId, liquidity, amount0, amount1) = nonfungiblePositionManager.mint(params); ``` Additionally, the same issue also exists in `prematureUnstake()` and `releaseLiquidity()` functions. ```solidity=288 INonfungiblePositionManager.DecreaseLiquidityParams memory params = INonfungiblePositionManager.DecreaseLiquidityParams({ tokenId: tokenId, liquidity: liquidityOff, amount0Min: 0, amount1Min: 0, deadline: block.timestamp }); (amount0, amount1) = nonfungiblePositionManager.decreaseLiquidity(params); ``` ```solidity=338 INonfungiblePositionManager.DecreaseLiquidityParams memory params = INonfungiblePositionManager.DecreaseLiquidityParams({ tokenId: tokenId, liquidity: liquidity, amount0Min: 0, amount1Min: 0, deadline: block.timestamp }); nonfungiblePositionManager.decreaseLiquidity(params); ``` Therefore, it could be vulnerable to sandwich attacks.
Open the reportThere is a potential issue in the function `unstakeForMainnetMapping()` which uses a loop to iterate over an array, and could potentially result in a high amount of gas consumption. If the array contains an exceedingly large number of elements, the loop may consume more gas than is available in a single block. This would cause the transaction to fail with the "out of gas" error. ```solidity=364 for (uint i=0; i < contractInfoArray.length; i++) { uint256 tokenId = contractInfoArray[i].tokenId; require(tokenOwner[tokenId] == addr, "The addr is not the owner of the token !"); (uint256 usdtReleased, uint256 mudReleased) = releaseLiquidity(tokenId); delete tokenOwner[tokenId]; //delete the nft position from owner map emit mudLPUnstaked(addr, tokenId, usdtReleased, mudReleased); } ```
Open the reportThe `createNewStakingContract()` function allows users to specify arbitrary values for the `nodeId` parameter. However, since the function is public, there is a risk that users may provide unexpected or incorrect values for `nodeId`. This may result in events not being processed correctly by the intended DAPP, potentially causing issues with the expected functionality and data processing.
Open the reportThe linked `transfer()`/`transferFrom()` invocations do not check the return value of the function call, which should yield `true` in the case of a proper `ERC-20` implementation.
Open the reportSome events are never emitted, which can lead to confusion and code maintainability issues. ```solidity=104 event mudLPTransferredUSDTToDAOFund(address daoFundAddress, uint256 usdtBalance); event mudLPBurntMUDOfPrematureContracts(uint256 mudBalance); ```
Open the reportIn the `MudAngelRoundReleaseBank` contract, function `depositMapping()` violates the Check-Effects-Interactions pattern. This pattern is a best practice for writing secure smart contracts that involves performing all state changes before making any external function calls. ### External call(s) ```solidity=72 require(token.transferFrom(msg.sender, address(this), totalDepositToBeTransferred), "transferFrom failed!"); //check the return value, it should be true ``` ### State variables written after the call(s) ```solidity=73 _depositMappingTotal = _depositMappingTotal + totalDepositToBeTransferred;//to save gas ``` The same issue exists in the function `depositMapping()` of contract `MudABRoundReleaseBank()`. An external function call to the `token.transferFrom()` function is made before the state changes are made. This creates a potential vulnerability where an attacker could manipulate the contract's state during the external function call, which could lead to loss of funds or other malicious actions. To prevent such potential issue, it is important to ensure that all external function calls are made after the state changes have been made.
Open the reportExternal calls are made inside a `for` loop. This might lead to a denial-of-service attack. If any of the calls fail, it will cause the entire loop to revert. ```solidity=71 require(token.transferFrom(msg.sender, address(this), balanceArray[i]), "transferFrom failed!"); //check the return value, it should be true ``` --- ```solidity=72 require(token.transferFrom(msg.sender, address(this), balanceArray[i]), "transferFrom failed!"); //check the return value, it should be true ``` Moreover, the code is to transfer `MUD` tokens from the sender to the contract multiple times inside a loop, this will also consume much more gas.
Open the reportThe `withdraw()` function logic restricts both the `admin` and `miningDappAddress` from withdrawing tokens from the current contract. However, the `poolInfoMapping()` function does not include a check to verify whether the `addressArray[i]` is equal to either the `admin` or `miningDappAddress`. This omission means that the `admin` and `miningDappAddress` could potentially be included in the withdrawal process, which may not be intended.
Open the reportAccording to the code, variable `lastHalvingTime` was assigned an initial value during the construct process and reassigned a new value every 4 years. Therefore, the value of it always greater than 0. Condition `lastHalvingTime > 0` always true and hence that related check are meaningless.
Open the reportThe comment for the `depositMapping()` function of the `MudABRoundReleaseBank` contract in line#43 is misleading regarding the `icoBalanceArray` parameter. The comment states that it is an array of amounts of MUD coins received from the `Angel round`, which seems to be a leftover when copying from other code. ```solidity=39 /* only the contractor creator could deposit mapping to investor * map the MUD AB round from eth mainnet contract * parameters: * addressArray: Angel round investor addresses * icoBalanceArray: array of amount of MUD coin received from Angel round * balanceArray: array of amount of MUD coin mapped from eth mainnet contract * lasttimeArray: lasttime mapped from eth mainnet contract * return: (block time, total coins deposited in the contract) */ function depositMapping(address[] calldata addressArray, uint256[] calldata icoBalanceArray, uint256[] calldata balanceArray, uint[] calldata lasttimeArray) external returns (uint256, uint256){ require(msg.sender == admin, "Only admin can deposit."); require(!_depositMappingFinished, "Deposit Mapping finished!"); require(addressArray.length == balanceArray.length && icoBalanceArray.length == balanceArray.length && balanceArray.length == lasttimeArray.length, "Array length not match"); ``` However, based on the code implementation and context, it appears that the intended meaning of `icoBalanceArray` is the mapping amounts of the `AB round`, not the `Angel round`. This discrepancy between the comment and the actual usage of `icoBalanceArray` could potentially cause confusion for developers or auditors trying to understand the code.
Open the reportThere should always be events emitted in the sensitive functions that are controlled by centralization roles.
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. ```solidity=147 require(balanceArray[i] > 0); ```
Open the reportThe issue with the current implementation is that although the owner of the token contract has the ability to freeze the token to prevent transfers, the token can still be burned even while it is frozen. This means that the total supply of the token can be decreased while it is still under frozen, which can impact the value of the token and the expectations of the token holders. If the token is frozen, the `_burn()` function should revert and not allow the tokens to be burned. This will ensure that the total supply of the token remains unchanged while it is under frozen and prevent any potential issues with token holders and the value of the token.
Open the reportIn the `checkBalance()` function of `MudABRoundReleaseBank` contract, the `require` statement in L#94 is unnecessary. ```solidity-94 require(block.timestamp > bank[addressToCheck].lastTime, "now time < lastTime"); ``` The `bank[addressToCheck].lastTime` is zero or a timestamp in the past.
Open the reportIn the function `breakContract()` of contract `MudMiningEscrow`, it is using the `increaseAllowance()` and `burnFrom()` functions to burn tokens from the contract itself. This is an unnecessary step, as the contract can burn tokens directly using the `burn()` function provided by the token contract. ```solidity=126 require(token.increaseAllowance(address(this), burnAmount), "increaseAllowance failed!"); token.burnFrom(address(this), burnAmount); ```
Open the reportThe project contains one or more contract or library definitions that are not used, which can lead to unnecessary complexity and reduced maintainability. ```solidity=132 abstract contract Pausable is Context { ``` - The abstract contract `Pausable` is declared but never implemented.
Open the reportSome events are never emitted, which can lead to confusion and code maintainability issues. ```solidity=37 event miningstart(uint lastHalvingTime); ``` - `miningstart` is declared in `MudMiningPool` but never emitted.
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="metaverse-user-dao"></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