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 |
In the contract `MUDUniswapV3Staker` the role `admin` has authority over the functions shown in the list and diagram below. * unstakeForMainnetMapping() - This function unstakes all liquidity NFT positions associated with a specified address, regardless of the contract's expiry time. * getContractCount() - The admin role can use this function to retrieve the total number of staking contracts associated with a specific address. * getContractInfo() - With this function, the admin role can obtain information about a particular staking contract. * getContractInfoByTokenId() - The admin role has the authority to retrieve information about a specific staking contract using the tokenId (liquidity NFT position ID). Any compromise to the `admin` account may allow the hacker to take advantage of this authority. They could potentially query the staking information of any account, which should be considered sensitive and only accessible to the staking owner. Furthermore, the hacker could also unstake the liquidity NFTs associated with any account. 
Open the report### MetaUserDAOToken In the contract `Ownable` the role `_owner` has authority over the functions shown in the list and diagram below. * renounceOwnership() - Renounce the ownership of the contract. * transferOwnership() - Transfer the ownership of the contract to a new account. Any compromise to the `_owner` account may allow the hacker to take advantage of this authority and transfer or renounce the ownership of `MetaUserDAOToken` contract.  --- ### MudAngelRoundReleaseBank In the contract `MudAngelRoundReleaseBank` the role `admin` has authority over the functions shown in the list below. * depositMapping() - Map the deposits of investors from Ethereum mainnet to Polygon by transferring the amounts mapped in Ethereum to this contract in Polygon from `admin` account. * depositMappingFinalised() - Finish the deposits mapping. * getDepositInfo() - Get deposit information of users for mapping purpose. Any compromise to the `admin` account may allow the hacker to take advantage of this authority over the functions listed, which would allow them to potentially perform malicious actions. Specifically, the hacker could use the `depositMapping()` function to map the deposits of users who are not int the Ethereum mainnet. Furthermore, if the hacker completes the deposit mapping process using the `depositMappingFinalised()` function, it would become impossible for admin to map investors' deposits since the mapping process would be considered complete and irreversible. --- ### MudMiningEscrow In the contract `MudMiningEscrow` the role `admin` has authority over the functions shown in the list below. * depositMapping() - Map the deposits of users from Ethereum mainnet to Polygon by transferring the amounts mapped in Ethereum to this contract in Polygon from `admin` account. * getDepositOrderInfo() - Get order information of users for mapping purpose. Any compromise to the `admin` account may allow the hacker to take advantage of this authority over the functions listed, which would allow them to potentially perform malicious actions. Specifically, the hacker could use the `depositMapping()` function to map the deposits of users who are not int the Ethereum mainnet. --- ### MudABRoundReleaseBank In the contract `MudABRoundReleaseBank` the role `admin` has authority over the functions shown in the list below. * depositMapping() - Map the deposits of investors from Ethereum mainnet to Polygon by transferring the amounts mapped in Ethereum to this contract in Polygon from `admin` account. * depositMappingFinalised() - Finish the deposits mapping. * getDepositInfo() - Get deposit information of users for mapping purpose. Any compromise to the `admin` account may allow the hacker to take advantage of this authority over the functions listed, which would allow them to potentially perform malicious actions. Specifically, the hacker could use the `depositMapping()` function to map the deposits of users who are not int the Ethereum mainnet. Furthermore, if the hacker completes the deposit mapping process using the `depositMappingFinalised()` function, it would become impossible for admin to map investors' deposits since the mapping process would be considered complete and irreversible. --- ### MudTeamReleaseBank In the contract `MudTeamReleaseBank` the role `admin` has authority over the functions shown in the list below. * teamMemberDeposit() - Distribute `MUD` tokens to team members and lock the tokens in the contract during ICO phrase. * icoFinalised() - Finish ICO phrase. Any compromise to the `admin` account may allow the hacker to take advantage of this authority over the functions listed, which would allow them to potentially perform malicious actions. Specifically, the hacker could use the `teamMemberDeposit()` function to distribute `MUD` tokens to team members and lock the tokens in the contract during the ICO phase. However, if the hacker could distribute the tokens to themselves or their own account instead of the actual team members, resulting in the theft of tokens. Additionally, the hacker could use the `icoFinalised()` function to prematurely finish the ICO phase, which would prevent admin from depositing `MUD` tokens to team members and potentially lead to a loss of confidence in the project. --- ### MudMiningPool In the contract `MudMiningPool` the role `admin` has authority over the functions shown in the list below. * poolInfoMappingDeposit() - Migrate the `MUD` balance of pool contract from Ethereum mainnet to Polygon by transferring the amounts mapped in Ethereum to this contract in Polygon from `admin` account. * poolInfoMapping() - Map the mined data from Ethereum mainnet to Polygon once the `MUD` token in Ethereum was frozen. * poolInfoMappingFinalized() - Set the migrating status finished. * getPoolInfo() - Get pool information
Open the reportAll of the `MUD` tokens will be sent to the contract deployer during deployment in `Polygon`. This is a centralization risk because the deployer can distribute tokens without obtaining the consensus of the community. Any compromise to these addresses may allow a hacker to steal and sell tokens on the market, resulting in severe damage to the project.
Open the reportIn the contract `MetaUserDAOToken`, the role `creator` has the authority to update the value of `_frozen` to true, which will irreversibly suspend all transfer functions of the token. ```solidity= function mainNetMappingFreeze() external { require(msg.sender == creator, "Not token creator!"); require(!_frozen, "Freezed for mainnet mapping !"); _frozen = true; } ``` Any compromise to the private key of the `creator` may allow hackers to take advantage of this authority and prevent token transfer functions.
Open the reportIn the contract `MudAngelRoundReleaseBank` the role `admin` has authority over the functions shown below: * icoDeposits(): deposit `MUD` tokens to investor. * icoFinalised(): mark the `ICO` finished flag, stop `icoDeposit`. Any compromise to the `admin` account may allow the hacker to take advantage of this authority and do the following: * Deposit `MUD` tokens to themselves or block `ICO`. In the contract `MudTeamReleaseBank` the role `admin` has authority over the functions shown below: * teamMemberDeposit(): deposit `MUD` tokens to team members, lock the team's `MUD` tokens to the contract and start to release after 365 days in daily release rate. * icoFinalised(): mark the `ICO` finished flag, stop `icoDeposit`. Any compromise to the `admin` account may allow the hacker to take advantage of this authority and do the following: * Deposit `MUD` tokens to themselves or block `ICO`. In the contract `MudMiningPool` the role `admin` has authority over the functions shown below: * icoDeposit(): deposit `MUD` tokens to the pool. Any compromise to the `admin` account may allow the hacker to take advantage of this authority and do the following: * Refuse deposit `MUD` tokens. In the contract `MudMiningPool` the role `miningDappAddress` has authority over the functions shown below: * miningStart(): start mining process. * miningSettlement(): settle mining tokens. Any compromise to the `miningDappAddress` may allow the hacker to take advantage of this authority and do the following: * Start mining process at any time as they want. * Settle tokens to themselves.
Open the reportThe team introduced a slippage mechanism in the commit [35ee42f3d5f86ca6abe4e66dcc80b00e7e71da93](https://github.com/MetaUserDAO/MUDUniswapV3Staker/tree/35ee42f3d5f86ca6abe4e66dcc80b00e7e71da93). This mechanism incorporates the `slippageFactor` parameter to ensure that the minimum liquidity tokens added surpass set thresholds, dictated by `usdtToStake` and `mudToStake`. ```solidity function createNewStakingContract(uint256 usdtToStake, uint256 mudToStake, uint8 duration, uint nodeId, uint256 slippageFactor) external returns ( uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1, uint startTime, uint endTime ) ``` The slippage threshold is derived as follows: ```solidity INonfungiblePositionManager.MintParams memory params = INonfungiblePositionManager.MintParams({ token0: usdtAddr, token1: mudAddr, fee: 3000, tickLower: -887220, //this will be adapted to reflect the actual MUD/USDT token pair on the polygon mainnet tickUpper: 887220, //this will be adapted to reflect the actual MUD/USDT token pair on the polygon mainnet amount0Desired: amount0ToMint, amount1Desired: amount1ToMint, amount0Min: SafeMath.mul(amount0ToMint, slippageFactor) / 1000, // slippage safeguard amount1Min: SafeMath.mul(amount1ToMint, slippageFactor) / 1000, // slippage safeguard recipient: address(this), deadline: block.timestamp }); ``` In the `createNewStakingContract()` function, the slippage factor used for calculating the minimum amounts (`amount0Min` and `amount1Min`) required for the liquidity minting is based on the user-provided token amounts (`amount0ToMint` and `amount1ToMint`), rather than the actual amounts needed for the liquidity. This approach can lead to transaction reverts if users stake a large number of `MUD` or `USDT` tokens without knowing the actual proportion between the two tokens. The slippage factor is applied to the user-provided amounts, which may result in unrealistically high minimum amounts. If the actual amounts needed for the liquidity are lower than the slippage-adjusted amounts, the transaction will fail. Additionally, the fix requires users carefully set the `usdtToStake`, `mudToStake` and `slippageFactor`. If those parameters are not properly set, it could still lead to a possible sandwich attack. For example, if the amount of `usdtToStake` and `mudToStake` deviate from the current ratio of usdt:mud in the pool, the threshold that is based on `usdtToStake` and `mudToStake` may be unable to protect from slippage and thus cause the potential loss due to slippage (as the above test case demonstrate).
Open the reportUpon completion of the mapping process from Ethereum to Polygon, the `MUD` token in Ethereum will be frozen, preventing users who hold `MUD` tokens in Ethereum from transferring or staking them. If there is any plan or process in place to compensate users for their `MUD` balance in Ethereum. Besides, the total number of `MUD` token deployed in Polygon will be `978118023075739`, what does this number come from? Does it mean the total supply number of `MUD` token mapped in Ethereum at a certain block?
Open the reportIn the function `miningSettlement()` of contract `MudMiningPool`, the `dailyMiningLimit` is just checked whether it should be halved only in the last settlement batch. If current settlement is divided into 5 batches (1,2,3,4,0), and it has been 4 years since the last `lastHalvingTime`, according to the logic, only in the last batch (batchNumber = 0) the `dailyMiningLimit` will be halved. In this case, it should be halved starting from batch #1. Besides, the half time could happen in any batch during a settlement.
Open the reportIn the function `createNewStakingContract()`, it passes the fixed values of `tickLower` and `tickUpper` while adding liquidity for a specific trading pair. There doesn't appear to be any immediate issue with the code snippet itself. However, it's important to note that these fixed values may not be suitable for all scenarios. The `tickLower` and `tickUpper` values may need to be adjusted based on the actual MUD/USDT token pair on the Polygon mainnet. It's crucial to ensure that the `tickLower` and `tickUpper` values align with the price range of the actual trading pair. Selecting inappropriate ranges for `tickLower` and `tickUpper` could result in insufficient liquidity provision or an inability to meet the trading demands. ```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); ```
Open the reportThe contract serves as the interface for interacting with the third-party protocol `Uniswap V3`, which involves the utilization of specific addresses associated with the protocol. These addresses include: - `IUniswapV3Pool`: Address related to the `Uniswap V3` pool. - `INonfungiblePositionManager`: Address associated with the non-fungible position manager of `Uniswap V3`. - `IUniswapV3Factory`: Address of the `Uniswap V3` factory. During the audit process, the third-party entities are treated as black boxes, assuming their functional correctness. However, it's important to acknowledge that in real-world scenarios, third-party entities can be compromised, potentially resulting in the loss or theft of assets. In addition to the third-party addresses, there are also addresses involved in the contract's business logic: - `daoFundAddress`: The address of the MUD DAO fund, which receives confiscated USDT. Currently, it is implemented as a Gnosis proxy address. - `usdtAddr`: The address of the USDT token. Currently, it is set as a testing token address. - `mudAddr`: The address of the MUD token deployed on the blockchain. Currently, it is set as a testing token address. It is assumed that these addresses are valid and secure actors, and appropriate logic has been implemented to facilitate collaboration with the current project.
Open the reportThere are some hardcode addresses in this codebase.
Open the reportThere is a hardcode init code hash in `PoolAddress` to calculate the pool address of `token0-token1`. ```solidity=6 bytes32 internal constant POOL_INIT_CODE_HASH = 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54; ```
Open the reportWhen transferring deflationary ERC20 tokens, it's important to consider that the amount received may not be equal to the amount sent due to transaction fees. For example, if a user sends 100 deflationary tokens with a 10% transaction fee, only 90 tokens may actually arrive at the contract. Failing to account for these fees can lead to issues where a user can withdraw more tokens from the contract than they have actually deposited. In the `MUDUniswapV3Staker` contract, users can stake liqudidity by first transferring tokens to the `MUDUniswapV3Staker` contract. The `MUDUniswapV3Staker` contract could probably transfer the same amount of tokens to `nonfungiblePositionManager` contract. If the pair tokens are deflationary tokens, the function call would potentially revert. ```solidity=166 // transfer tokens to contract usdt.transferFrom(msg.sender, address(this), amount0ToMint); mud.transferFrom(msg.sender, address(this), amount1ToMint); // Approve the position manager usdt.approve(address(nonfungiblePositionManager), amount0ToMint); mud.approve(address(nonfungiblePositionManager), amount1ToMint); 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); ```
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.
Open the reportThere are some hardcoded values in the codebase, especially those that may be used for testing purposes, for example, the `mudtTokenContractAddr` address. ```solidity library UtilityFunctions { address constant mudtTokenContractAddr = address(0x90a34C6ce471382c8d0296E84264d0aA85aac68a);//contrct address of the MUD token, should deploy the token contract first and set the contract address here function getMudToken() internal pure returns(MetaUserDAOToken){ MetaUserDAOToken token = MetaUserDAOToken(mudtTokenContractAddr); return token; } } ``` It is important to remind the client to review and check these hardcoded values carefully before deploying the contract to the Polygon mainnet. The concern with hardcoded values is that they are static and cannot be easily changed once the contracts are deployed. If these values are not properly reviewed and updated, they can lead to unintended behavior or security vulnerabilities in the deployed contract. Hardcoded values may include addresses, keys, or other configuration parameters that affect the contract's functionality.
Open the reportThe codebase contains multiple Solidity versions, which can lead to unexpected behavior, potential vulnerabilities, difficulties in maintaining the code, and inconsistencies in the execution of the smart contract. Using different versions may also result in increased complexity during code auditing, as different security features and bug fixes are present in different versions of the compiler. Versions used: `0.8.9`, `^0.8.0` `0.8.9` is used in polygonTeamRelease.sol file. ```solidity=2 pragma solidity 0.8.9; ``` `^0.8.0` is used in Token_flattened.sol file. ```solidity=736 pragma solidity ^0.8.0; ```
Open the reportThere is a potential issue in the functions listed which utilize a loop to iterate over arrays, 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.
Open the reportAccessing storage variables in a loop can be costly in terms of gas consumption. ```solidity=64 _icoDepositTotal = _icoDepositTotal + balanceArray[i]; ``` --- ```solidity=65 _icoDepositTotal = _icoDepositTotal + balanceArray[i]; ``` --- ```solidity=116 _totalSettlementAmount = _totalSettlementAmount + balanceArray[i]; ```
Open the reportPerforming integer division before multiplication truncates the low bits, losing the precision of calculation. ```solidity=102 dailyMiningLimit = dailyMiningLimit / 2; ``` ```solidity=110 uint256 settlementLimit = dailyMiningLimit * settlementPeriod; ```
Open the reportAccording to the `require` conditions in the functions `checkBalance()` and `withdraw()`, `miningDappAddress` is also excluded from this ico. Therefore, the mining address should be checked for `miningDappAddress` in the settlement loop. ```solidity for (uint i = 0; i < addressArray.length; i++) { require(addressArray[i] != admin && addressArray[i] != address(0), "invalid address"); require(balanceArray[i] > 0); _totalSettlementAmount = _totalSettlementAmount + balanceArray[i]; require(_totalSettlementAmount <= settlementLimit, "TotalAmount out of settlement limit!"); // > daily limit, trasaction failed. _minedToken[addressArray[i]] = _minedToken[addressArray[i]] + balanceArray[i]; } ```
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.
Open the reportIn the function `miningSettlement()` of contract `MudMiningPool`, the `batchNumber` is not validated. In the same settlement, `batchNumber` should be starting from 1 and increasing by 1 in subsequent batches, then ending at zero. But there is no logic to check whether the input `batchNumber` is passed correctly, for example, duplicate `batchNumber` for the same settlement in different batches.
Open the reportIn the contract `MudAngelRoundReleaseBank`, investors or admin are required to call function `checkBalance()` to check their locked `MUD` token amount after the `lastTIme`. ```solidity=88 require(block.timestamp > bank[addressToCheck].lastTime, "now time should > lastTime"); ``` If admin doesn't deposit MUD for `addressToCheck`, `bank[addressToCheck].lastTime` is equal to 0; once deposited, `bank[addressToCheck].lastTime` is just the time in the past, the condition in `require` statement can be true. The only timestamp it reverts is just the calling time is equal to depositing time, but this happens rarely. Even though it does, the remaining code can cover this and return `(0,0)`.
Open the reportState variables that never change should be declared as `constant` to save gas. --- ```solidity=22 uint256 settlementPeriod = 7; //7 days ``` - `settlementPeriod` should be declared `constant`.
Open the reportIn the function `miningSettlement` of contract `MudMiningPool`, it will call below two functions of `MUD` token. Here the `msg.sender` of both calls are just the contract itself equal to `address(this)`, it first increases allowance of `MUD` token for itself and then burns `MUD` token out if itself. ```solidity=138 require(token.increaseAllowance(address(this), amountToBurn), "increaseAllowance failed!"); token.burnFrom(address(this), amountToBurn); ```
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