Mundus Security is thrilled to announce the release of Final Security Audit Report for ARTH Value Token of MahaDAO project. If you want to increase trust for your users, we are here to talk (Calendly).
Check out our website and please join our community!
About MahaDAO
MahaDAO is a mission to create a decentralized and stable economy. That is driven by the people, for the people.
MahaDAO is a community-powered, decentralized organization on a mission to empower billions with a stable economy through the world’s first valuecoin, ARTH.
To do this, MahaDAO uses two tokens to achieve this vision - the governance token MAHA, and the valuecoin ARTH.
About ARTH value token and Governance Model
ARTH is a stablecoin that is designed to appreciate overtime against the US dollar while at the same time it remains relatively stable.
ARTH is minted/burnt using decentralized smart contracts that use ETH as collateral to maintain its peg. The interest rate charged to mint ARTH using ETH is 0%, which makes it very cost-effective for borrowing/lending.
ARTH is fully collateralized with mechanisms that give it a backing of at least 110% in ETH.
You can find more information about ARTH token here
We also have finished audit for ARTH Value token.
MahaDAO's governance model is designed to keep malicious attackers out of the way and ensure that the project is kept as decentralized as possible. Read more about MahaDAO Governance.
MahaDAO's governance has various components, each of them briefly explained below.
- MAHA NFT Locker: Locks MAHA to create NFTs with voting power based on how much and long the MAHA tokens were locked for. (Read: Locking Maha)
- NFT Staker: A staking contract that stakes a MAHA NFT to be used for various aspects of the governance. (Read Staking NFTs)
- Governance Portal: A web portal that allows users to create and vote on proposals that change various aspects of the DAO. (Read: Voting Portal)
- Time-locks: A smart contract that puts all transactions into a queue before they are committed onto the blockchain.
- Emergency DAO: A community-owned multi-sig wallet that has the ability to veto any malicious votes. (Read Emergency DAO)
- Pool Voter: A voting contract that votes and determines how much MAHA goes to what gauge. (Read Pool Voting)
- Pool Gauge: A contract that stakes liquidity pool tokens and determines how much MAHA rewards should be given out. (Read Uniswap Staking)
Summary of the Governance Security Audit Report
During the audit process, our security team has identified 29 potential vulnerabilities. In which 3 Medium vulnerabilities. The MahaDAO team fixed 2 vulnerabilities, all other vulnerabilities are acknowledged by the MahaDAO team.
You can find our classification in the Appendix of this announcement.
Vulnerabilities found during the audit -> after fixing (left as acknowledged):
- High 0 -> 0
- Medium 3 -> 1
- Low 5 -> 5
- Informational 13 -> 12
- Gas 9 -> 9
You can find a full smart contract security audit report here (Github).
Scope of Work
You could find the Audit Scope below:
- BaseV2Bribes
- BaseV2Voter Proxy
- EmissionController
- FeesSplitter
- GaugeLP Proxy
- GaugeUniswapV3 Proxy
- MAHATimelockController-14
- MAHATimelockController-30
- MahaToken
- MAHAXGovernor
- MAHAXLocker
- MAHAXStaker
- MAHAXVetoGovernor
- Registry
- RenderingContract
High and Medium Vulnerabilities Description
ID-01. Medium: Potential DoS in getReward of GaugeLP.sol
Description:
The getReward method of GaugeLP.sol performs calls the distribute method of the BaseV2Voter contract (see @audit_1), which in turn calls back the notifyRewardAmount method of the GaugeLP contract, if specific criteria are met (see @audit_2).
The getReward method of GaugeLP.sol performs calls the distribute method of the BaseV2Voter contract (see @audit_1), which in turn calls back the notifyRewardAmount method of the GaugeLP contract, if specific criteria are met (see @audit_2).
// @audit_1 GaugeLP.sol getReward call to BaseV2Voter
_unlocked = 1;
IGaugeVoterV2(registry.gaugeVoter()).distribute(address(this));
_unlocked = 2;
// @audit_2 BaseV2Voter.sol distribute call to GaugeLP
claimable[_gauge] = 0;
IGauge(_gauge).notifyRewardAmount(registry.maha(), _claimable);
emit DistributeReward(msg.sender, _gauge, _claimable);
The getReward method is protected against reentrancy with the require(_unlocked == 0, "reentrancy"); requirement of the lock modifier. Thus, the BaseV2Voter contract's call to GaugeLP will revert due to _unlocked local variable not being set to 0 (see @audit_1).
Recommendation:
Modify the getReward method of GaugeLP.sol in the following way
Modify the getReward method of GaugeLP.sol in the following way
_unlocked = 0;
IGaugeVoterV2(registry.gaugeVoter()).distribute(address(this));
_unlocked = 1;
Alleviation:
This issue is acknowledged by the MahaDAO team.
This issue is acknowledged by the MahaDAO team.
ID-02. Medium: distributeETH should be non- reentrant in FeesSplitter.sol
Description:
The distributeETH method of FeesSplitter.sol performs low-level calls to addresses in a for-loop to distribute ETH. This pattern is prone to reentrancy, e.g. a CREATE2 address with predefined malicious logic could be provided to accounts state variable which later drains out the FeesSplitter contract.
The distributeETH method of FeesSplitter.sol performs low-level calls to addresses in a for-loop to distribute ETH. This pattern is prone to reentrancy, e.g. a CREATE2 address with predefined malicious logic could be provided to accounts state variable which later drains out the FeesSplitter contract.
Recommendation:
Add nonReentrant modifier to the distributeETH method of FeesSplitter.sol.
Add nonReentrant modifier to the distributeETH method of FeesSplitter.sol.
Alleviation:
The issue fix was introduced in commit ce2036f053f68fd48ed043f572e6aeb952b3f33d.
The distributeETH function now has nonReentrant modifier.
The issue fix was introduced in commit ce2036f053f68fd48ed043f572e6aeb952b3f33d.
The distributeETH function now has nonReentrant modifier.
ID-03. Medium: Arbitrary IERC20 in distributeERC20 public of FeesSplitter.sol
Description:
The distributeERC20 method of FeesSplitter.sol has no access control and takes arbitrary ERC20 as its argument. This is a dangerous pattern that should be addressed.
The distributeERC20 method of FeesSplitter.sol has no access control and takes arbitrary ERC20 as its argument. This is a dangerous pattern that should be addressed.
Recommendation:
Modify the distributeERC20 method's logic in any or all of the following ways
Modify the distributeERC20 method's logic in any or all of the following ways
- Add nonReentrant and/or onlyOwner modifier to the distributeERC20 method.
- Use Openzeppelin's SafeERC20 library for token transfers.
- Introduce ERC20 whitelist to the FeesSplitter contract's storage.
Alleviation:
The issue fix was introduced in commit f9bbbb0d1cd8d2a632405cb2f4adc3fc24417b1f.
The distributeERC20 function now uses token.safeTransfer.
The issue fix was introduced in commit f9bbbb0d1cd8d2a632405cb2f4adc3fc24417b1f.
The distributeERC20 function now uses token.safeTransfer.
Conclusion
We are happy to work with the MahaDAO team to improve security and build trust for the community and investors. Stay tuned to receive the following security updates soon.
Check out our website and please join our community!
Appendix
Severity Description
High - Bugs that can trigger a contract failure or theft of assets. Further recovery is possible only by manual modification of the contract state or replacement.
Medium - Bugs that can break the intended contract logic or expose it to DoS attacks, but do not cause direct loss of funds.
Low - Bugs that do not pose significant danger to the project or its users but are recommended to be fixed nonetheless.