
M^0 Minter Gateway audit
A private security review of M^0 (stablecoin framework), conducted with Three Sigma and completed on 8th January 2024. 0xSimao disclosed 32 findings: 3 high severity, 3 medium, 9 low and 17 informational.
What M^0 is
M^0 is a neutral value-transmission framework: permissioned minters generate $M against eligible off-chain collateral, validators attest collateral values on a cadence, and a two-token governance system (the TTG) sets every parameter, aiming at digital money with the risk profile of physical cash.
Scope
The Three Sigma review covered the minter gateway and governance: collateral update signatures and their timestamps, the penalty regime for missed intervals, mint proposals and delays, and the invariants tying total principal to outstanding owed M.
High severity findings
- Lack of deadline in PowerToken.buy can lead to user's cashToken being distributed through ZeroToken holders
- Validator signature with zero timestamp can always be replayed
- MToken's total principal invariant can be broken
Medium severity findings
- Creating a new proposal in StandardGovernor may reach a state of permanent DoS
- A sufficiently large collateral may break the maximum owed M calculation
- Validator signatures with greater timestamps can be reused in a subsequent updateCollateral
Low severity findings
- Multiplication after division in StableEarnerRateModel leads to loss of precision
- A decrease in updateCollateralInterval will lead to unfair penalties
- Unhandled rounding error in DistributionVault.getClaimable leads to locked dust
- MToken's total principal invariant doesn't hold without MinterGateway, leading to potential principal loss
- Unrealized inflation calculation returns wrong value when balance reaches cap
- Custom error for overflowing the total principal is not raised
- Proposals in the same voting period can have different ids but do the same
- Function cancelMint can be frontrunned to grief a validator
- StandardGovernor's implementation of quorum is incompatible with Tally
Informational findings
- Missing override keyword for interface inherited methods
- Some contracts don't implement their entire interface
- No need to set isActive to false if that mapping entry was deleted
- Unnecessary Recomputation of Storage Pointer in MToken._startEarning
- Unnecessary check in StandardGovernor.state
- Code should not panic underflow
- StartedEarning event is emitted even if account is already earning
- Wrong comment in Standard Governor's execute function
- Unnecessary currentEpoch zero check in StandardGovernor and ThresholdGovernor
- Overflow check in PowerToken._divideUp is unnecessary
- Unnecessary conditional check in ThresholdGovernance.execute
- Inconsistent naming of function in PureEpochs
- _checkAndIncrementNonce in ERC5805 raises a ReusedNonce error for non used nonces
- castVoteWithReason always fires a VoteCast event with an empty reason
- transferFrom in ERC20Extended will always emit an Approval event if the allowance changes
- EIP712's _revertIfError should use all SignatureChecker.Error errors
- The IERC3009 interface is not fully conforming to the standard
The report