MToken
Code
MToken is an ERC20 token implementing a dual-balance accounting system, allowing users to choose between non-earning and earning balances.
Token Overview
MBalance Struct
The MToken uses a special balance struct to track the state of each account's balance:
struct MBalance {
bool isEarning;
uint240 rawBalance;
}This struct serves dual purposes:
- For non-earning accounts:
rawBalancerepresents the actual token balance - For earning accounts:
rawBalancerepresents the principal amount, which grows over time via indexing
Key State Variables
address public immutable minterGateway;
address public immutable ttgRegistrar;
uint240 public totalNonEarningSupply;
uint112 public principalOfTotalEarningSupply;
mapping(address account => MBalance balance) internal _balances;These variables track the essential state of the token system:
minterGateway: authorized address for minting and burningttgRegistrar: address of the TTG Registrar that governs earnings eligibilitytotalNonEarningSupply: total supply of non-earning tokensprincipalOfTotalEarningSupply: principal amount of earning tokens_balances: mapping of account balances
Functions
constructor
constructor(address ttgRegistrar_, address minterGateway_) ContinuousIndexing() ERC20Extended("M by M0", "M", 6)Initializes the token with:
- Name: "M by M0"
- Symbol: "M"
- Decimals: 6
- TTG Registrar and Minter Gateway addresses
Parameters:
| Name | Type | Description |
|---|---|---|
ttgRegistrar_ | address | The TTG Registrar contract address |
minterGateway_ | address | The Minter Gateway contract address |
mint
function mint(address account_, uint256 amount_) external onlyMinterGatewayMints new tokens to the specified account.
- Only callable by the minter gateway
- Handles both earning and non-earning accounts differently
Parameters:
| Name | Type | Description |
|---|---|---|
account_ | address | The recipient of the tokens |
amount_ | uint256 | The amount of tokens to mint |
burn
function burn(address account_, uint256 amount_) external onlyMinterGatewayBurns tokens from the specified account.
- Only callable by the minter gateway
- Handles both earning and non-earning accounts differently
Parameters:
| Name | Type | Description |
|---|---|---|
account_ | address | The account to burn tokens from |
amount_ | uint256 | The amount of tokens to burn |
startEarning
function startEarning() externalTransitions the caller's account to earning mode.
- Converts non-earning balance to principal
- Reverts if caller is not approved as an earner by TTG Registrar
- Emits a
StartedEarningevent
stopEarning (self)
function stopEarning() externalTransitions the caller's account to non-earning mode.
- Converts principal plus accrued interest to a standard balance
- Emits a
StoppedEarningevent
stopEarning (for other account)
function stopEarning(address account_) externalTransitions a specified account to non-earning mode.
- Reverts if the account is approved as an earner by TTG Registrar
- Useful for administrative operations or governance
Parameters:
| Name | Type | Description |
|---|---|---|
account_ | address | The account to stop earning for |
updateIndex
function updateIndex() public virtual returns (uint128 currentIndex_)Updates the stored index based on time elapsed and current rate.
- Fetches the latest rate from the rate model
- Emits an
IndexUpdatedevent
Return Values:
| Name | Type | Description |
|---|---|---|
currentIndex_ | uint128 | The new index value |
rateModel
function rateModel() public view returns (address rateModel_)Returns the address of the rate model contract.
Return Values:
| Name | Type | Description |
|---|---|---|
rateModel_ | address | The address of the rate model |
earnerRate
function earnerRate() public view returns (uint32 earnerRate_)Returns the current rate used for interest calculations.
Return Values:
| Name | Type | Description |
|---|---|---|
earnerRate_ | uint32 | Current rate in basis points |
totalEarningSupply
function totalEarningSupply() public view returns (uint240 totalEarningSupply_)Calculates the current total of all earning tokens including accrued interest.
Return Values:
| Name | Type | Description |
|---|---|---|
totalEarningSupply_ | uint240 | Total amount of earning tokens |
totalSupply
function totalSupply() external view returns (uint256 totalSupply_)Returns the sum of total non-earning supply and total earning supply.
Return Values:
| Name | Type | Description |
|---|---|---|
totalSupply_ | uint256 | Total supply of all tokens |
principalBalanceOf
function principalBalanceOf(address account_) external view returns (uint240 balance_)Returns the principal amount for earning accounts.
Parameters:
| Name | Type | Description |
|---|---|---|
account_ | address | The account to check |
Return Values:
| Name | Type | Description |
|---|---|---|
balance_ | uint240 | Principal balance if earning, otherwise zero |
balanceOf
function balanceOf(address account_) external view returns (uint256 balance_)Returns the token balance of an account.
- For earning accounts: Returns principal with accrued interest
- For non-earning accounts: Returns raw balance
Parameters:
| Name | Type | Description |
|---|---|---|
account_ | address | The account to check |
Return Values:
| Name | Type | Description |
|---|---|---|
balance_ | uint256 | Current token balance |
isEarning
function isEarning(address account_) external view returns (bool isEarning_)Checks if an account is in earning mode.
Parameters:
| Name | Type | Description |
|---|---|---|
account_ | address | The account to check |
Return Values:
| Name | Type | Description |
|---|---|---|
isEarning_ | bool | Whether the account is in earning mode |
currentIndex
function currentIndex() public view override returns (uint128)Calculates the current index based on the rate and time elapsed.
Return Values:
| Name | Type | Description |
|---|---|---|
currentIndex_ | uint128 | Current index value |
Key Internal Functions
_transfer
Internal override of the ERC20 transfer function handling transfers between earning and non-earning accounts.
_startEarning/_stopEarning
Internal functions to handle transitioning accounts between earning and non-earning modes.
_getPresentAmount
Calculates the present value of a principal amount using the current or specified index.
_getPrincipalAmount
Calculates the principal amount from a present value using rounding favoring the protocol.
_isApprovedEarner
Checks if an account is approved to earn by the TTG Registrar.
_rate
Retrieves the current rate from the rate model contract.
Events
event StartedEarning(address indexed account);
event StoppedEarning(address indexed account);
event IndexUpdated(uint128 indexed index, uint32 indexed rate);StartedEarning: Emitted when an account transitions to earning modeStoppedEarning: Emitted when an account transitions to non-earning modeIndexUpdated: Emitted when the index is updated with a new value
Custom Errors
error InsufficientBalance(address account, uint256 rawBalance, uint256 amount);
error IsApprovedEarner();
error NotApprovedEarner();
error NotMinterGateway();
error OverflowsPrincipalOfTotalSupply();
error ZeroMinterGateway();
error ZeroTTGRegistrar();These custom errors provide clear signals about issues during operations.

