# M0 Documentation import { Callout } from 'vocs/components'; ## WrappedMToken ### Code WrappedMToken is an ERC20 token for wrapping the $M token into a non-rebasing token with claimable yields. Solidity - Github Repository - [m0-foundation/WrappedMToken.sol](https://github.com/m0-foundation/wrapped-m-token/blob/v2/src/WrappedMToken.sol) ### Token Overview #### Account Struct The WrappedMToken uses a special account struct to track the state of each user's balance: ```solidity struct Account { // First Slot bool isEarning; uint240 balance; // Second slot uint112 earningPrincipal; bool hasClaimRecipient; bool hasEarnerDetails; } ``` This struct serves multiple purposes: * `isEarning`: Tracks whether the account is earning yield * `balance`: Represents the token balance held by the account * `earningPrincipal`: Tracks the principal amount for yield calculation * `hasClaimRecipient`: Indicates if account has a custom claim recipient * `hasEarnerDetails`: Indicates if account has additional earning parameters #### Key State Variables ```solidity uint16 public constant HUNDRED_PERCENT = 10_000; bytes32 public constant EARNERS_LIST_IGNORED_KEY = "earners_list_ignored"; bytes32 public constant EARNERS_LIST_NAME = "earners"; bytes32 public constant CLAIM_OVERRIDE_RECIPIENT_KEY_PREFIX = "wm_claim_override_recipient"; bytes32 public constant MIGRATOR_KEY_PREFIX = "wm_migrator_v2"; address public immutable earnerManager; address public immutable migrationAdmin; address public immutable mToken; address public immutable registrar; address public immutable excessDestination; uint112 public totalEarningPrincipal; uint240 public totalEarningSupply; uint240 public totalNonEarningSupply; mapping(address account => Account balance) internal _accounts; uint128 public enableMIndex; uint128 public disableIndex; int240 public roundingError; mapping(address account => address claimRecipient) internal _claimRecipients; ``` These variables track the essential state of the token system: * Constants for percentage calculations and registry keys * `earnerManager`: Address of the manager governing earning eligibility * `migrationAdmin`: Address allowed to perform migrations * `mToken`: Address of the underlying $M token * `registrar`: Address of the Registrar for configuration * `excessDestination`: Address where excess tokens are sent * Supply tracking for earning and non-earning tokens * Index tracking for earning calculations * `roundingError`: Tracking imprecise $M token transfers ### Functions #### constructor ```solidity constructor( address mToken_, address registrar_, address earnerManager_, address excessDestination_, address migrationAdmin_ ) ERC20Extended("M (Wrapped) by M0", "wM", 6) ``` Initializes the token with: * Name: "M (Wrapped) by M0" * Symbol: "wM" * Decimals: 6 * References to $M Token, Registrar, Earner Manager, and other essential contracts ##### Parameters: | Name | Type | Description | | :------------------- | :------ | :---------------------------------- | | `mToken_` | address | The $M Token contract address | | `registrar_` | address | The Registrar contract address | | `earnerManager_` | address | The Earner Manager contract address | | `excessDestination_` | address | The destination for excess tokens | | `migrationAdmin_` | address | The migration admin address | #### wrap ```solidity function wrap(address recipient_, uint256 amount_) external ``` Wraps $M tokens into wrapped $M tokens. * Transfers $M tokens from the caller to this contract * Mints wrapped $M tokens to the recipient ##### Parameters: | Name | Type | Description | | :----------- | :------ | :---------------------------------- | | `recipient_` | address | The recipient of the wrapped tokens | | `amount_` | uint256 | The amount of $M tokens to wrap | #### wrapWithPermit ```solidity function wrapWithPermit( address recipient_, uint256 amount_, uint256 deadline_, uint8 v_, bytes32 r_, bytes32 s_ ) external ``` Wraps $M tokens using EIP-2612 permit for approval. ##### Parameters: | Name | Type | Description | | :----------- | :------ | :---------------------------------- | | `recipient_` | address | The recipient of the wrapped tokens | | `amount_` | uint256 | The amount of $M tokens to wrap | | `deadline_` | uint256 | Expiration timestamp for the permit | | `v_` | uint8 | ECDSA signature component | | `r_` | bytes32 | ECDSA signature component | | `s_` | bytes32 | ECDSA signature component | #### wrapWithPermit (alternative) ```solidity function wrapWithPermit( address recipient_, uint256 amount_, uint256 deadline_, bytes memory signature_ ) external ``` Wraps $M tokens using arbitrary signature format. ##### Parameters: | Name | Type | Description | | :----------- | :------ | :---------------------------------- | | `recipient_` | address | The recipient of the wrapped tokens | | `amount_` | uint256 | The amount of $M tokens to wrap | | `deadline_` | uint256 | Expiration timestamp for the permit | | `signature_` | bytes | Arbitrary signature data | #### unwrap ```solidity function unwrap(address recipient_, uint256 amount_) external ``` Unwraps wrapped $M tokens back to $M tokens. * Burns wrapped $M tokens from the caller * Transfers $M tokens to the recipient ##### Parameters: | Name | Type | Description | | :----------- | :------ | :------------------------------------ | | `recipient_` | address | The recipient of the unwrapped tokens | | `amount_` | uint256 | The amount of tokens to unwrap | #### claimFor ```solidity function claimFor(address account_) external returns (uint240 yield_) ``` Claims accrued yield for an account. * Only affects accounts in earning mode * Routes yield to configured claim recipient * Handles fee distribution if earner details exist ##### Parameters: | Name | Type | Description | | :--------- | :------ | :----------------------------- | | `account_` | address | The account to claim yield for | ##### Return Values: | Name | Type | Description | | :------- | :------ | :-------------------------- | | `yield_` | uint240 | The amount of yield claimed | #### claimExcess ```solidity function claimExcess() external returns (uint240 claimed_) ``` Claims any excess $M tokens that aren't earmarked for balances. * Verifies excess exists before claiming * Transfers excess to the configured destination ##### Return Values: | Name | Type | Description | | :--------- | :------ | :---------------------------------- | | `claimed_` | uint240 | The amount of excess tokens claimed | #### enableEarning ```solidity function enableEarning() external ``` Enables yield earning for the contract. * Verifies contract is approved as an earner * Records the current $M index as the reference point * Calls `startEarning` on the $M token #### disableEarning ```solidity function disableEarning() external ``` Disables yield earning for the contract. * Verifies contract is not approved as an earner * Records the current index as the disable point * Calls `stopEarning` on the $M token #### startEarningFor ```solidity function startEarningFor(address account_) external ``` Transitions an account to earning mode. * Verifies earning is enabled globally * Checks if account is an approved earner * Updates account and global state variables ##### Parameters: | Name | Type | Description | | :--------- | :------ | :--------------------------- | | `account_` | address | The account to start earning | #### startEarningFor (batch) ```solidity function startEarningFor(address[] calldata accounts_) external ``` Transitions multiple accounts to earning mode. * Processes each account individually ##### Parameters: | Name | Type | Description | | :---------- | :--------- | :---------------------------- | | `accounts_` | address\[] | The accounts to start earning | #### stopEarningFor ```solidity function stopEarningFor(address account_) external ``` Transitions an account to non-earning mode. * Claims any accrued yield * Updates account and global state variables ##### Parameters: | Name | Type | Description | | :--------- | :------ | :-------------------------- | | `account_` | address | The account to stop earning | #### stopEarningFor (batch) ```solidity function stopEarningFor(address[] calldata accounts_) external ``` Transitions multiple accounts to non-earning mode. * Processes each account individually ##### Parameters: | Name | Type | Description | | :---------- | :--------- | :--------------------------- | | `accounts_` | address\[] | The accounts to stop earning | #### setClaimRecipient ```solidity function setClaimRecipient(address claimRecipient_) external ``` Sets a custom recipient for yield claims. * Updates the claim recipient mapping * Sets a flag on the account for optimization ##### Parameters: | Name | Type | Description | | :---------------- | :------ | :----------------------------- | | `claimRecipient_` | address | The recipient to receive yield | #### migrate ```solidity function migrate(address migrator_) external ``` Performs arbitrary migration logic. * Only callable by the migration admin * Delegates to migrator contract ##### Parameters: | Name | Type | Description | | :---------- | :------ | :------------------------------------------- | | `migrator_` | address | The contract that will perform the migration | ### View/Pure Functions #### accruedYieldOf ```solidity function accruedYieldOf(address account_) public view returns (uint240 yield_) ``` Returns the yield accrued by an account. ##### Parameters: | Name | Type | Description | | :--------- | :------ | :------------------- | | `account_` | address | The account to check | ##### Return Values: | Name | Type | Description | | :------- | :------ | :-------------------------------- | | `yield_` | uint240 | The accrued yield for the account | #### balanceOf ```solidity function balanceOf(address account_) public view returns (uint256 balance_) ``` Returns the token balance of an account. ##### Parameters: | Name | Type | Description | | :--------- | :------ | :------------------- | | `account_` | address | The account to check | ##### Return Values: | Name | Type | Description | | :--------- | :------ | :-------------------- | | `balance_` | uint256 | Current token balance | #### balanceWithYieldOf ```solidity function balanceWithYieldOf(address account_) external view returns (uint256 balance_) ``` Returns the token balance plus accrued yield. ##### Parameters: | Name | Type | Description | | :--------- | :------ | :------------------- | | `account_` | address | The account to check | ##### Return Values: | Name | Type | Description | | :--------- | :------ | :------------------------------ | | `balance_` | uint256 | Balance including accrued yield | #### earningPrincipalOf ```solidity function earningPrincipalOf(address account_) external view returns (uint112 earningPrincipal_) ``` Returns the principal amount for earning accounts. ##### Parameters: | Name | Type | Description | | :--------- | :------ | :------------------- | | `account_` | address | The account to check | ##### Return Values: | Name | Type | Description | | :------------------ | :------ | :------------------------------------------ | | `earningPrincipal_` | uint112 | Principal amount used for yield calculation | #### claimRecipientFor ```solidity function claimRecipientFor(address account_) public view returns (address recipient_) ``` Returns the recipient for an account's yield. ##### Parameters: | Name | Type | Description | | :--------- | :------ | :------------------- | | `account_` | address | The account to check | ##### Return Values: | Name | Type | Description | | :----------- | :------ | :----------------------------------- | | `recipient_` | address | Address to receive the claimed yield | #### currentIndex ```solidity function currentIndex() public view returns (uint128 index_) ``` Returns the current index for yield calculations. ##### Return Values: | Name | Type | Description | | :------- | :------ | :------------------ | | `index_` | uint128 | Current index value | #### isEarning ```solidity 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 earning yield | #### isEarningEnabled ```solidity function isEarningEnabled() public view returns (bool isEnabled_) ``` Checks if earning is enabled contract-wide. ##### Return Values: | Name | Type | Description | | :----------- | :--- | :-------------------------------- | | `isEnabled_` | bool | Whether global earning is enabled | #### excess ```solidity function excess() public view returns (int240 excess_) ``` Calculates excess $M tokens held by the contract. ##### Return Values: | Name | Type | Description | | :-------- | :----- | :------------------------------------------- | | `excess_` | int240 | Amount of excess $M tokens (can be negative) | #### totalAccruedYield ```solidity function totalAccruedYield() external view returns (uint240 yield_) ``` Calculates total yield accrued across all accounts. ##### Return Values: | Name | Type | Description | | :------- | :------ | :------------------ | | `yield_` | uint240 | Total accrued yield | #### totalSupply ```solidity function totalSupply() external view returns (uint256 totalSupply_) ``` Returns the total supply of wrapped tokens. ##### Return Values: | Name | Type | Description | | :------------- | :------ | :------------------------- | | `totalSupply_` | uint256 | Total supply of all tokens | #### projectedEarningSupply ```solidity function projectedEarningSupply() public view returns (uint240 supply_) ``` Calculates projected total of earning tokens including yield. ##### Return Values: | Name | Type | Description | | :-------- | :------ | :-------------------------------- | | `supply_` | uint240 | Projected total of earning tokens | ### Key Internal Functions #### \_mint/\_burn Internal functions to mint and burn tokens, handling both earning and non-earning accounts. #### \_wrap/\_unwrap Internal functions to handle the wrapping and unwrapping of $M tokens. #### \_claim Internal function to calculate and distribute accrued yield. #### \_transfer Internal override of the ERC20 transfer function handling transfers between different account types. #### \_startEarningFor/\_stopEarningFor Internal functions to handle transitioning accounts between earning and non-earning modes. #### \_getAccruedYield Calculates the yield given an account's balance, earning principal, and current index. #### \_handleEarnerDetails Calculates and transfers fees for accounts with earner details. ### Events ```solidity event Claimed(address indexed account, address indexed recipient, uint240 yield); event ClaimRecipientSet(address indexed account, address indexed claimRecipient); event EarningEnabled(uint128 index); event EarningDisabled(uint128 index); event ExcessClaimed(uint240 excess); event StartedEarning(address indexed account); event StoppedEarning(address indexed account); ``` * `Claimed`: Emitted when yield is claimed for an account * `ClaimRecipientSet`: Emitted when a claim recipient is set * `EarningEnabled`: Emitted when earning is enabled contract-wide * `EarningDisabled`: Emitted when earning is disabled contract-wide * `ExcessClaimed`: Emitted when excess tokens are claimed * `StartedEarning`: Emitted when an account starts earning * `StoppedEarning`: Emitted when an account stops earning ### Custom Errors ```solidity error EarningIsDisabled(); error EarningIsEnabled(); error IsApprovedEarner(address account); error InsufficientBalance(address account, uint240 balance, uint240 amount); error NotApprovedEarner(address account); error NoExcess(); error UnauthorizedMigration(); error ZeroEarnerManager(); error ZeroExcessDestination(); error ZeroMToken(); error ZeroMigrationAdmin(); error ZeroRegistrar(); ``` These custom errors provide clear signals about issues during operations. import { Callout } from "vocs/components"; ## MToken ### Code MToken is an ERC20 token implementing a dual-balance accounting system, allowing users to choose between non-earning and earning balances. Solidity - Github Repository - [m0-foundation/MToken.sol](https://github.com/m0-foundation/protocol/blob/main/src/MToken.sol) ### Token Overview #### MBalance Struct The MToken uses a special balance struct to track the state of each account's balance: ```solidity struct MBalance { bool isEarning; uint240 rawBalance; } ``` This struct serves dual purposes: * For non-earning accounts: `rawBalance` represents the actual token balance * For earning accounts: `rawBalance` represents the principal amount, which grows over time via indexing #### Key State Variables ```solidity 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 burning * `ttgRegistrar`: address of the TTG Registrar that governs earnings eligibility * `totalNonEarningSupply`: total supply of non-earning tokens * `principalOfTotalEarningSupply`: principal amount of earning tokens * `_balances`: mapping of account balances ### Functions #### constructor ```solidity 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 ```solidity function mint(address account_, uint256 amount_) external onlyMinterGateway ``` Mints 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 ```solidity function burn(address account_, uint256 amount_) external onlyMinterGateway ``` Burns 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 ```solidity function startEarning() external ``` Transitions 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 `StartedEarning` event #### stopEarning (self) ```solidity function stopEarning() external ``` Transitions the caller's account to non-earning mode. * Converts principal plus accrued interest to a standard balance * Emits a `StoppedEarning` event #### stopEarning (for other account) ```solidity function stopEarning(address account_) external ``` Transitions 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 ```solidity 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 `IndexUpdated` event ##### Return Values: | Name | Type | Description | | :-------------- | :------ | :------------------ | | `currentIndex_` | uint128 | The new index value | #### rateModel ```solidity 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 ```solidity 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 ```solidity 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 ```solidity 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 ```solidity 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 ```solidity 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 ```solidity 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 ```solidity 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 ```solidity 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 mode * `StoppedEarning`: Emitted when an account transitions to non-earning mode * `IndexUpdated`: Emitted when the index is updated with a new value ### Custom Errors ```solidity 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. import { HomePage } from 'vocs/components' My Awesome Docs This is a description of my documentation website. Get started GitHub ## Upgrades and Migration ### I. Key Improvements in V2 Wrapped $M (wM) fundamentally operates as a non-rebasing token where yield is realized through manual claiming, a characteristic distinct from the native $M token's automatic rebasing. The V2 implementation builds upon this established model with several important enhancements: 1. **Re-enabling Earning**: V2 allows earning to be re-enabled after being disabled 2. **Admin-Managed Earners**: Introduction of EarnerManager for delegated administration 3. **Fee Mechanism**: Ability for admins to take fees from yield 4. **Principal-Based Accounting**: Changed from lastIndex tracking to principal amount tracking 5. **Explicit Claim Recipients**: Added ability for users to explicitly set yield recipients 6. **Gas Efficiency**: Optimized storage layout and operations ### II. Migration from V1 The migration from V1 to V2 involved several key transformations: #### Account Model Change * V1: Used last interaction index for earning accounts * V2: Uses principal amount for earning accounts * Migration formula: `principal = balance ÷ lastIndex` #### Index Handling * V1: Used an array for enable/disable indices * V2: Uses enableMIndex and disableIndex slots * Migration preserved earning state and index values #### Migration Process The migration was handled through a specialized migrator contract that: 1. Identified all earning accounts in V1 2. Converted their account structure to the V2 format 3. Preserved their earning status and equivalent yield position ## Technical Design ### I. Account Model The wM contract uses a sophisticated account model to efficiently track balances and yield information: ```solidity struct Account { bool isEarning; // Whether the account is in earning mode uint240 balance; // Current token balance (excluding yield) uint112 earningPrincipal; // Principal amount for earning accounts bool hasClaimRecipient; // Whether a custom recipient is set bool hasEarnerDetails; // Whether admin fee settings exist } ``` This structure packs related data together to minimize storage costs while maintaining all necessary information for the dual-mode system. ### II. Principal-Based Accounting A key aspect of wM's design is its principal-based accounting system for earning accounts: #### Principal Conversions When an account starts earning, its balance is converted to a principal amount: ``` principal = balance ÷ currentIndex (rounded down) ``` This principal remains constant while the account is earning, while its value in tokens grows with the index. #### Present Value Calculation The current token value of a principal is: ``` presentValue = principal × currentIndex ``` This calculation is used when checking balances and claiming yield. #### Rounding Strategy The contract employs consistent rounding rules: * When converting from tokens to principal (adding to earning), principal is rounded DOWN * When calculating present value (for balance displays), the value is exact * When subtracting from earning accounts, principal is rounded UP These rules slightly favor the protocol, creating a small buffer of excess tokens that enhances stability. ### III. Supply Tracking The contract maintains precise tracking of token supply: * `totalNonEarningSupply`: Sum of all non-earning account balances * `totalEarningSupply`: Sum of all earning account balances (excluding accrued yield) * `totalEarningPrincipal`: Sum of all earning account principals * Total supply = `totalNonEarningSupply + totalEarningSupply` * `projectedEarningSupply`: The total earning supply if all accrued yield was claimed These values are used for various calculations, including excess determination. ### IV. Transfer Mechanics The transfer system handles different scenarios based on account earning status: #### Same Status Transfers * Between earning accounts: Converts the amount to principal using the current index * Between non-earning accounts: Simple balance transfers without conversion #### Cross-Status Transfers * From earning to non-earning: Converts from principal to tokens * From non-earning to earning: Converts from tokens to principal * Affects total earning and non-earning supply tracking Each transfer type ensures that exact token amounts move between accounts while maintaining proper accounting in the appropriate mode. ### V. Fee Mechanism When enabled by an admin through the EarnerManager, fees can be taken from yield: * Fees are a percentage (in basis points, max 10,000) of claimed yield * Fee amounts are transferred to the admin who approved the account * If an admin is removed from the admin list, their fee settings become invalid * Fees are processed during the claim operation This creates an incentive for admins to onboard and manage accounts in the system. \[//]: ## 'TODO: Diagram showing the flow of tokens during a claim operation with fees, including the original account, claim recipient, and admin fee recipient.' ### VI. Excess Mechanism The `WrappedMToken` (wM) contract is designed to naturally accumulate "excess" $M tokens over time. This excess represents the $M tokens held by the contract *above and beyond* what is required to fully back all circulating wM tokens and their accrued yield entitlements. This mechanism enhances system stability and creates a value capture opportunity for the protocol. **Core Principle: Yield Mismatch** The fundamental driver of excess accumulation stems from a mismatch in yield earning: 1. **wM Contract Earns $M Yield:** As confirmed by its status as a major $M holder and its requirement to be an approved M earner (`enableEarning` requires `_isThisApprovedEarner`), the **entire balance of $M tokens held within the `WrappedMToken` contract continuously earns yield** according to the $M token's native rebasing mechanism. 2. **Not All wM Holders Earn wM Yield:** However, only wM holders whose accounts are explicitly set to **Earning Mode** (via Governance or EarnerManager approval) accrue a corresponding claimable wM yield entitlement based on their principal. Holders in **Non-Earning Mode** do not accrue wM yield. **Sources of Excess Accumulation:** The excess $M balance primarily grows from: 1. **Yield on $M Backing Non-Earning wM (Primary Source):** The $M yield generated by the portion of $M tokens backing the wM held by users in Non-Earning Mode directly contributes to the excess. Since these users aren't entitled to wM yield, the $M yield earned on their underlying share remains within the contract as surplus. 2. **Rounding Effects during Principal Conversions (Secondary Source & Potential Deficit):** The contract utilizes principal-based accounting for earners, requiring conversions between token amounts and principal values whenever balances change (e.g., `wrap`, `unwrap`, `startEarningFor`, `stopEarningFor`, cross-status transfers). This process involves rounding: * Tokens to Principal (e.g., starting to earn): Principal is rounded **DOWN** (`getPrincipalAmountRoundedDown`). * Subtracting Principal (e.g., stopping earning, transfers out): The principal equivalent of the token amount removed is rounded **UP** (`getPrincipalAmountRoundedUp`) before being deducted. * Yield Calculation (`_getAccruedYield`): The potential yield payout is based on a present value calculation rounded **DOWN** (`getPresentAmountRoundedDown`). * Calculating Liabilities (`projectedEarningSupply`): The present value of earning principals is rounded **UP**. While some rounding directions favor the protocol (contributing positively to excess over time), others (like subtracting principal rounded up during transfers/unwraps) can slightly disadvantage the protocol. The combination of wM's internal rounding necessities with the behavior of the underlying $M token during external transfers (wrapping/unwrapping M) can lead to temporary discrepancies. Specifically, if the $M token's transfer mechanism results in the wM contract sending slightly more $M or receiving slightly less $M than the nominal amount due to M's own rebasing logic, the wM contract might temporarily hold slightly less $M than strictly required by its wM liabilities (a potential negative excess). The system is designed such that the primary sources of excess $M (like yield on $M backing non-earning wM and wM's own favorable internal rounding) act as a substantial buffer to cover these minor external interaction effects over time, ensuring long-term solvency. 3. **Direct $M Transfers:** Any $M tokens sent directly to the `WrappedMToken` contract address (outside the `wrap` function) also become part of the excess. 4. **Cross-Status Transfers:** While involving rounding (covered above), the mechanics of transfers between earning and non-earning accounts can also contribute minor gains due to the specific rounding applied during the principal conversions involved. **Calculating Excess:** The contract calculates the available excess using the `excess()` view function, which basically can be computed like this: ```math \text{Excess}_{(\text{wM contract})} = \text{M Balance}_{(\text{wM contract})} - \underbrace{\text{(totalNonEarningSupply} + \text{ProjectedEarningSupply)}}_{\text{Total wM Liabilities}} ``` This calculation ensures that `excess` only represents $M tokens available *after* accounting for all obligations to wM holders (both earning and non-earning). **Excess Management:** The accumulated excess $M tokens can be claimed and transferred out of the contract via the `claimExcess()` function. The `excessDestination` is set during deployment and typically points to the **Distribution Vault**, creating a revenue stream for the broader protocol ecosystem, ultimately benefiting Zero token holders. **Relationship with Shared Earning Approval:** Crucially, the ability for a wM holder to be in Earning Mode depends on the **same approval mechanisms (Governance list or EarnerManager admin approval) used by the $M token system itself**. An account must be approved in the EarnerManager (or globally via Governance) to call startEarningFor and begin accruing wM yield. This shared approval layer is fundamental to the excess mechanism, as it governs *who* receives wM yield, directly influencing how much of the $M yield generated by the wM contract contributes to the excess pool versus being earmarked for wM earners. ## Security considerations ### I. Trust Model The wM system operates with several trust assumptions: * **MigrationAdmin**: Fully trusted role that can change contract implementation * **EarnerManager MigrationAdmin**: Can change EarnerManager implementation * **Registrar**: Source of truth for system parameters * **MToken**: Assumed to function correctly * **Admins**: Trusted to manage earning status appropriately ### II. Edge Cases Several edge cases are worth understanding: #### Admin Removal If an admin is removed from the admins list: * Accounts they approved lose earning status * Their fee settings become invalid * Accounts should be stopped from earning to prevent further yield accrual #### Disabled Earning If the wrapper contract is removed from M's earner list: * `disableEarning()` should be called to prevent further yield accrual * Individual accounts can continue to earn until that point #### Balance Precision The system has specific precision limitations: * All balances limited to uint240 to match $M token * Principal amounts limited to uint112 for gas efficiency * Indices use uint128 with 12 decimal places of precision ### III. Rounding Effects The consistent rounding strategy creates specific effects: * Multiple conversions between earning and non-earning states will result in small token losses * Transfers between accounts with different earning statuses create small protocol gains * These tiny amounts accumulate as protocol reserves, enhancing stability import ZoomableImage from '@/components/ZoomableImage'; ## Overview ### What is Wrapped $M (wM)? Wrapped $M (wM) is a non-rebasing ERC-20 wrapper for the rebasing and immutable $M token. It maintains yield-earning capabilities while providing compatibility with DeFi protocols that require standard ERC-20 tokens. While the native $M token automatically increases balances as yield accrues, Wrapped $M maintains static balances where yield can be explicitly claimed. This makes Wrapped $M compatible with protocols that aren't designed to handle rebasing tokens, dramatically expanding the utility of $M in the broader DeFi ecosystem.
### Why Wrapped M? Every M0 extension eventually wants to connect to certain utilities such as DeFi protocols, on/off ramps, etc. In order to concentrate liquidity, that utility should always exist in the form of M0's stablecoin building block. However, rebasing tokens automatically change their balances as yield accrues, which creates challenges for many DeFi protocols that expect static token balances. Wrapped $M solves this by: 1. Maintaining fixed token balances that don't automatically increase 2. Separately tracking and allowing manual claiming of accrued yield 3. Preserving the full economic benefits of the M0 platform while improving protocol compatibility 4. Enabling protocol-specific administration of earning capabilities ### Key Features * **DeFi Compatibility**: Works with lending platforms, AMMs, and other protocols that require standard ERC-20 behavior * **Yield Preservation**: Maintains yield-earning capabilities of the underlying $M token * **Value & Solvency**: wM aims for a direct value link to $M for earners. The target value for an earning token is its underlying $M principal plus accrued yield: ```math 1 \text{ }\text{earning }\text{wM} + \text{wM yield } ≈ 1 \text{ }\text{M} + \text{Accrued Yield} ``` Critically, the entire system maintains a solvency invariant, ensuring it's always fully backed. The total $M held by the wM contract is always greater than or equal to the total wM supply plus all accrued yield owed to earners: ```math \text{M Balance}_{(\text{wM contract})} \ge \underbrace{\text{totalNonEarningSupply} + \text{projectedEarningSupply}}_{\text{Total wM Liabilities, aka wM supply + accrued yield}} ``` This guarantee is maintained through the system's design, where yield earned on $M held for non-earning wM holders, along with minor positive rounding effects during transfers, accumulates as "excess" reserves within the contract. * **Flexible Yield Options**: Configurable claiming and recipient mechanisms * **Delegated Administration**: Trusted admins can manage earner status without governance * **Protocol Value Capture**: System design naturally accumulates excess reserves that benefit the broader protocol ecosystem ### Comparison to $M | **Feature** | **$M** | **Wrapped M** | | ------------------ | ---------------------------------- | --------------------------------------- | | Balance Behavior | Automatically increases (rebasing) | Remains static until explicit claim | | Earning Mechanism | Implicit (balances grow) | Explicit (yield accumulates separately) | | Yield Realization | Automatic with balance updates | Manual claiming required | | DeFi Compatibility | Limited due to rebasing | Wide compatibility with standard ERC-20 | | Recipient Options | Limited | Configurable yield recipients | | Administration | Governance only | Governance + Delegated admins | ## Integration considerations ### I. For DeFi Protocols When integrating with wM, protocols should be aware of: * Standard ERC-20 behavior (no rebasing) * Distinction between balance and balance-with-yield * Impact of earning status on user experience * Potential for yield to accumulate while tokens are locked ### II. For Developers Developers working with wM should understand: * The relationship between wM and the underlying $M token * The impact of earning status on token accounting * The claiming process and its effect on balances * The consistent rounding patterns used throughout the contract ### III. Common Patterns Several patterns are recommended when working with wM: * Check both `balanceOf()` and `balanceWithYieldOf()` to understand a user's position * Consider calling `claimFor()` before critical operations to ensure balances reflect all value * Be aware of the impact of earning status transitions on token amounts * Understand the priority order for claim recipients when handling claimed yield ## Features and Operations ### I. Basic Token Operations #### Wrapping $M to wM Users can deposit $M tokens to receive an equivalent amount of wM: ```solidity wrap(recipient, amount) ``` The $M tokens are held by the wM contract and can potentially earn yield. #### Unwrapping wM to M Users can burn wM tokens to receive the equivalent amount of M: ```solidity unwrap(recipient, amount) ``` Any accrued yield remains in the user's wM balance if they're in earning mode. #### Gasless Operations The contract supports wrapping with permits for improved UX: ```solidity wrapWithPermit(recipient, amount, deadline, signature) ``` #### Standard ERC-20 Operations All standard ERC-20 functions are supported, including: * `transfer(to, amount)` * `transferFrom(from, to, amount)` * `approve(spender, amount)` * `balanceOf(account)` ### II. Earning Management #### Starting to Earn Approved accounts can activate earning status: ```solidity startEarningFor(account) ``` This converts their balance to a principal amount that will begin accruing yield. #### Stopping Earning Accounts can deactivate earning status (or anyone can do this for an account that's no longer approved): ```solidity stopEarningFor(account) ``` This claims any outstanding yield and converts the balance back to non-earning. #### Global Earning Status The wM contract itself must be an approved earner in the $M token system. Earning can be enabled or disabled for the entire system: ```solidity enableEarning() disableEarning() ``` A key improvement in wM v2 is the ability to re-enable earning after it has been disabled. ### III. Yield Management #### Claiming Yield Accrued yield can be claimed at any time: ```solidity claimFor(account) ``` This increases the account's wM balance by the yielded amount and triggers appropriate transfers based on recipient settings. #### Setting Claim Recipients Users can direct their yield to another address: ```solidity setClaimRecipient(recipient) ``` This allows for flexible yield strategies without changing the underlying balance. #### Checking Accrued Yield Several view functions allow users and integrations to check the yield that has accrued for an earning account but has **not yet been claimed**: * `accruedYieldOf(account)`: * Returns the amount of wM tokens earned as yield based on the account's `earningPrincipal` and the time elapsed (represented by the increase in the `currentIndex`) **since the last claim or since earning started**. * This represents **only the unclaimed portion** of the yield. It does *not* include yield that has already been claimed and added to the balance. * If the account is not in Earning Mode, this returns 0. * `balanceWithYieldOf(account)`: * Returns the sum of the account's current stored `balanceOf` **plus** the currently claimable `accruedYieldOf`. * This function effectively shows the total wM value attributable to the account *at that moment*, representing what the balance *would be* if the accrued yield were claimed instantly (before considering any fees or alternate claim recipients). **Effect of Claiming:** When `claimFor(account)` is successfully executed, the calculated accrued yield is processed. If the yield (net of fees) is directed to the account owner, their stored `balanceOf` increases. Consequently, immediately after a claim, `accruedYieldOf` will return 0 (or a negligible amount due to block timing), as the yield is no longer "accrued but unclaimed". `balanceWithYieldOf` will then equal `balanceOf`. New yield will start accumulating again as time passes and the `currentIndex` increases further. ### IV. Excess Management & Value Capture **Concept:** The wM contract holds underlying $M tokens. Because the wM contract itself earns yield on *all* these $M tokens, but wM yield is only accrued for *earning-mode* wM holders, a surplus (or "excess") of $M tokens naturally accumulates within the contract over time. This primarily comes from the $M yield earned on tokens backing non-earning wM balances. **Important note:** \:::note M and WrappedM are sharing the same Earners list. An earner of $M is an earner of WrappedM ::: **Claiming Excess:** This accumulated excess M, representing value captured by the protocol, can be claimed and transferred out using the `claimExcess()` function. ```solidity claimExcess() returns (uint240 claimed_) ``` **Destination:** The excessDestination address, set during deployment, receives these claimed tokens. Typically, this is the **Distribution Vault**, directing this value back to the protocol ecosystem and ultimately benefiting Zero token holders. ### V. Admin Operations via EarnerManager The EarnerManager contract empowers designated admins ('special users') with the delegated authority to approve wM earners, managing status for potentially many accounts outside the standard governance process #### Setting Earner Status Admins can enable accounts for earning and set fee rates: ``` setEarnerDetails(account, status, feeRate) ``` #### Bulk Operations Multiple accounts can be managed in a single transaction: ``` setEarnerDetails(accounts[], statuses[], feeRates[]) ``` #### Checking Earner Status Various functions provide information about earner status: ``` earnerStatusFor(account) getEarnerDetails(account) ``` ## Core Concepts ### I. Dual Mode: Earning vs. Non-Earning The wM token operates in two distinct modes for each account: #### A. Non-Earning Mode * Default state for new accounts * Balances remain static (standard ERC-20 behavior) * No yield accrues on these tokens * Simpler accounting with direct token amounts #### B. Earning Mode * Must be explicitly activated (requires approval via Governance or EarnerManager admin designation) * Balances remain static in storage * Represents a growing value based on a **principal amount** and an **index**, using an accounting model analogous to the native $M token. * Crucially, the **index used is derived from the underlying $M token** (wM does not maintain its own independent index). * Yield accumulates based on this principal and derived index, and can be claimed separately. Users can switch between Non-Earning and Earning modes if they meet the requirements for earning. ### II. Account Status Each wM account maintains several key properties tracked internally within the `WrappedMToken` contract: * **Balance**: The current wM token balance held by the account. This value remains static between operations and *excludes* any unclaimed yield. * **Earning Status**: A boolean flag indicating whether the account is currently in Earning Mode (true) or Non-Earning Mode (false). * **Earning Principal**: For accounts in Earning Mode, this stores the base principal amount used for yield calculations. This value is derived from the account's balance when it starts earning and remains constant while earning. * **Claim Recipient**: An optional address specified by the user via `setClaimRecipient()` to receive their claimed yield. If not set by the user, and no Governance override exists, yield is sent to the account owner itself. * **Earner Details**: A boolean flag indicating if settings apply when an account's earning status is managed by an EarnerManager admin. * If true, it implies the EarnerManager contract holds details (managing admin address, fee rate) for this account. * When a fee rate is set by the admin, a portion of the claimed yield (calculated as yield \* feeRate / 10000) is sent to that admin upon claiming, and the remaining net yield goes to the designated claim recipient (user-set, governance-set, or default owner). **Principal, Balance, and Yield Relationship:** When an account enters Earning Mode (`startEarningFor`), its current balance is converted into its initial `earningPrincipal`. This conversion is performed by the `IndexingMath.getPrincipalAmountRoundedDown`(balance, currentIndex) function, which calculates the principal amount corresponding to the balance at the currentIndex, taking into account the system's fixed-point scaling for the index and applying rounding rules that slightly favor the protocol. This `earningPrincipal` remains fixed while the account continues in Earning Mode. As the global `currentIndex` (derived from the $M token's index) increases over time, the value represented by this fixed principal grows. The fundamental relationship is: ```math \text{Value Represented} = \text{earningPrincipal} \times \text{currentIndex} ``` The account's stored balance only increases when yield is explicitly claimed. Therefore, the `accruedYield` represents the difference between the current value represented by the principal and the static stored balance: ```math \text{accruedYield} = \text{earningPrincipal}\times\text{currentIndex}-\text{balance} ``` So, the target state before claiming is effectively: ```math \text{balance} + \text{accruedYield}≈\text{earningPrincipal}\times\text{currentIndex} ``` Calling the `claimFor()` function calculates this `accruedYield`. It then handles potential fee deductions if `hasEarnerDetails` is true (sending the fee portion to the managing admin). The remaining net yield is transferred to the designated `claimRecipient`. If the `claimRecipient` is the account owner itself, their stored balance is increased by this net yield amount. This operation "catches up" the account's stored balance to reflect the value earned up to that point (minus any fees paid). ### III. Yield Generation and Claiming #### How Yield Accrues For accounts in earning mode, yield accrues based on: * The account's principal amount * The global wM index (derived from the $M token's index) * The time elapsed since the last index update The formula is: ```math accruedYield=(principal\times currentIndex) - balance ``` Where: * `principal` is the stored earning principal for the account * `currentIndex` is the current wM index * `balance` is the current token balance #### Claiming Process When yield is claimed: 1. The accrued yield is calculated based on the current index 2. The account's balance is provisionally increased by the full yield amount 3. If the account's earning status is managed by an active EarnerManager admin with a configured fee rate, a percentage of the yield is deducted and sent to that admin as a fee 4. The remaining yield (minus any fees) is transferred to the designated recipient (or remains with the account owner if they are the recipient) Claiming doesn't change the principal amount, only the final balance reflects the net yield received ### IV. Index Mechanism Rather than maintaining its own independent index, wM derives its index from the $M token's index: #### When Earning is Enabled The wM index is calculated as: ```math wM_{index} = (M_{current index} \text{ }/ \text{ }enableMIndex) \times disableIndex ``` Where: * `M current index` is the current index from the $M token * `enableMIndex` is the $M index when earning was enabled * `disableIndex` is the previous wM index (if earning was previously disabled) #### When Earning is Disabled The wM index becomes static: ```math wM_{index} = disableIndex ``` This approach ensures that wM's yield calculation accurately reflects the underlying $M token's yield performance. ### V. Yield Recipients The wM system provides flexible options for directing claimed yield: #### Default Behavior By default, yield is claimed to the same account that generated it. #### Custom Recipients Account holders can specify a different address to receive their yield by calling `setClaimRecipient()`. #### Governance Overrides The TTG governance can set override recipients for specific accounts through the Registrar. #### Priority Order When determining where to send claimed yield: 1. User-specified recipient (if set) 2. Governance-specified override (if set) 3. The account itself (default) This flexibility allows for a variety of yield utilization strategies. ### VI. System Invariants and Excess The wM system is designed around a critical solvency invariant to ensure it's always fully backed by the underlying $M token. **Balance Invariant**: The total $M token balance held by the `WrappedMToken` contract must always be greater than or equal to the sum of all wM tokens in circulation plus all accrued yield owed to earners. Expressed conceptually: ```math \text{M Balance}_{(\text{wM contract})} \ge \text{Total wM Supply} + \text{Total Accrued Yield} ``` Expressed using contract variables: ```math \text{M Balance}_{(\text{wM contract})} \ge \underbrace{\text{totalNonEarningSupply} + \text{projectedEarningSupply}}_{\text{Total wM Liabilities}} ``` **How the Invariant is Maintained:** Crucially, the `M Balance` held by the `WrappedMToken` contract is not static. Since the `WrappedMToken` contract itself is registered as an $M earner (as shown in the $M dashboard where the wM contract is the largest holder), **the underlying $M tokens it holds continuously accrue yield according to the $M token's rebasing mechanism.** This intrinsic yield generation on the *entire* pool of $M tokens held within the wM contract is fundamental to maintaining the solvency invariant. It ensures the $M balance grows naturally over time, actively keeping assets (M held) ahead of liabilities (wM supply + accrued yield). **Excess Reserves:** The difference between the actual `M Balance` held by the contract and the total calculated liabilities (`totalNonEarningSupply + projectedEarningSupply`) constitutes the **"excess"** reserves within the system. This excess primarily accumulates from two sources explained further below: 1. The yield generated by the underlying $M tokens that back the balances of **non-earning** wM holders (as this yield isn't owed back to them). 2. Minor positive rounding effects during various token operations (transfers, wrapping/unwrapping, starting/stopping earning). This invariant and the resulting excess ensure that the system remains fully solvent, can always honor unwrap requests, and captures additional value for the protocol ecosystem. ## Usage & Security ### Security Considerations Key security aspects of the TTG system include: * **Trusted Parties**: The model relies on the honest behavior of several actors: * Validators are trusted for offchain data verification and intervention (cancel/freeze). * Minters are trusted to manage offchain collateral responsibly. * Governance Participants (`POWER`/`ZERO` holders and delegates) are trusted to vote in the protocol's best interest. * **Governor Security & Access Control**: * Modifying the `Registrar` is strictly limited to `StandardGovernor` and `EmergencyGovernor`. * Proposal actions within governors are restricted to predefined internal functions targeting `self`, preventing arbitrary code execution by proposals. * Epoch-based locks on `POWER` token transfers/delegations during Voting Epochs are a key defense against `StandardGovernor` vote manipulation. * `ZeroGovernor` holds significant, concentrated power over the entire governance structure via the `resetTo*` and threshold/`CashToken` setting functions. * **Voting Thresholds**: * `EmergencyGovernor` and `ZeroGovernor` employ high voting thresholds requiring substantial consensus (minimum `_MIN_THRESHOLD_RATIO` of 2.71% enforced, typically set much higher like 65%), protecting against capture but demanding significant coordination for action. * `StandardGovernor` uses economic incentives (`POWER` inflation / `ZERO` rewards) rather than a fixed quorum percentage to encourage participation, relying on rational actors voting to avoid dilution/missed rewards. * **CashToken Safety**: The system relies on the assumption that allowed `CashToken`s (list controlled by `ZeroGovernor`, initially set at deployment) are standard, well-behaved ERC20 tokens without malicious hooks (e.g., transfer fees, reentrancy vectors, rebasing). Using non-standard tokens could introduce vulnerabilities. WETH and $M are the currently expected/intended CashTokens. * **Reset Mechanism (`ZeroGovernor`)**: The ability for `ZeroGovernor` to redeploy core governance contracts (`resetToPowerHolders`, `resetToZeroHolders`) is the ultimate control mechanism. It enables protocol upgrades and recovery but represents a central point of authority vested in `ZERO` holders. Execution mid-epoch effectively cancels ongoing proposals in the old governors. * **Inflation/Reward Complexity**: The intricate interplay between `StandardGovernor` tracking voter participation per epoch, `Power token` calculating and deferring inflation realization (`markParticipation`, `_sync`), and `Zero token` receiving mint calls requires precise implementation. Bugs could disrupt core incentives. * **Epoch-Based Timing**: The system relies heavily on the `PureEpochs` mechanism for proper functioning (voting windows, transfer locks, auction timing). All participants must be aware of the current epoch status and restrictions. * **Emergency Actions**: The `EmergencyGovernor` provides faster execution for urgent needs but requires a higher consensus threshold, balancing responsiveness with security. ### Roles in Governance * **Power token Holder**: Owns `POWER`. Benefits from `POWER` inflation if their voting power (direct or delegated) fully participates in `StandardGovernor` voting epochs. Can vote directly or delegate. Can purchase discounted `POWER` in auctions. Subject to dilution if inactive. * **Power token Delegatee**: An address (can be the holder themselves) to which `POWER` voting power is delegated. Casts votes in `StandardGovernor` and `EmergencyGovernor`. If they vote on all `StandardGovernor` proposals in an active epoch, they trigger `POWER` inflation for the holder and receive `ZERO` token rewards directly to their own address. * **Zero token Holder**: Owns `ZERO` . Can vote in `ZeroGovernor` or delegate. Can claim accumulated assets from the `DistributionVault` pro-rata to their `ZERO` holdings in past epochs. Benefits indirectly from `POWER` auctions (proceeds go to Vault). * **Zero token Delegatee**: An address (can be the holder themselves) to which `ZERO` voting power is delegated. Casts votes in `ZeroGovernor`. Does *not* directly receive `ZERO` rewards from `StandardGovernor` voting (those go to the `POWER` Delegatee). * **Proposer**: Any address can create proposals in any governor. Must pay a fee in `CashToken` for `StandardGovernor` proposals (refunded on success). No fees for `EmergencyGovernor` or `ZeroGovernor`. * **Executor**: Any address can call `execute()` on a Governor for a passed proposal (`Succeeded` state) during its valid execution window. * **Distributor (Vault)**: Any address can (and should periodically) call `distribute(token)` on the `DistributionVault` to ensure new funds are accounted for and become claimable by `ZERO` holders for the relevant epoch. ### Interacting with TTG * **Voting**: Use `castVote`, `castVotes`, or their `WithReason` / `BySig` variants on the appropriate Governor (`StandardGovernor`, `EmergencyGovernor`, `ZeroGovernor`). Check the proposal `state()` and be mindful of epoch restrictions (esp. `StandardGovernor` voting *only* in Voting Epochs). * **Delegation**: Use `delegate` or `delegateBySig` on `Power token` (only during Transfer Epochs) or `Zero token` (anytime). Remember `ZERO` rewards go to the `POWER` delegatee. * **Checking `POWER` Balance**: **Crucially**, always call `Power token.sync(account)` *before* relying on `Power token.balanceOf(account)` if you expect the balance might have changed due to inflation. This function realizes any pending inflation into the actual balance. Use `getPastVotes` for historical voting power checks (which inherently accounts for inflation up to that point). * **Claiming Vault Rewards**: Call `DistributionVault.claim(...)` specifying the token and a *past* epoch range (`startEpoch`, `endEpoch`). Use `getClaimable(...)` to check expected amounts first. Ensure `distribute(token)` has been called recently for the desired token to make funds available for the latest completed epochs. * **Power token Auctions**: Call `Power token.buy(...)` during Transfer Epochs. Check `amountToAuction()` and `getCost(amount)` beforehand. Ensure your account has sufficient `CashToken` allowance approved to the `Power token` contract. ### Conclusion M0's Two-Token Governance system offers a sophisticated and resilient framework for decentralized decision-making. By carefully separating powers across three governor tiers, leveraging a deterministic epoch-based clock, and implementing robust incentive mechanisms via `Power token` inflation and `Zero token` rewards/revenue sharing, TTG encourages active participation while maintaining security and adaptability. The key components work in concert: 1. `Power token` and `Zero token` provide distinct spheres of influence: operational vs. meta-governance. 2. `StandardGovernor`, `EmergencyGovernor`, and `ZeroGovernor` offer tailored processes for different decision types. 3. The `Registrar` ensures a single, secure source of truth for parameters. 4. The `DistributionVault` aligns economic incentives for `Zero token` holders. 5. The Epoch System creates predictable cycles and enhances security. The intricate architecture of TTG provides both the flexibility needed for routine adjustments and the security required for long-term protocol stability and evolution. Understanding the specific roles, rules, and interactions of the tokens and contracts is key to effective participation. ## Token Mechanics: POWER & ZERO ### Power token (`PowerToken.sol`) *With great power comes great responsibility.* The primary token for operational governance, featuring strong incentives for active participation. * **Standard & Properties**: ERC-20 compatible. Implements `IEpochBasedInflationaryVoteToken` which includes: * Epoch-based snapshots for historical balances/votes. * ERC-5805 for voting and delegation (`delegate`, `getPastVotes`). * ERC-3009 for transfer authorization (`transferWithAuthorization`). * **0 decimals**. * **Voting Usage**: The voting token for `StandardGovernor` (simple majority) and `EmergencyGovernor` (threshold-based). Vote weight is determined by the balance snapshot taken at the *end* of the epoch *before* the voting epoch (`proposalSnapshot` function returns `voteStart - 1`). * **Inflationary Mechanism (\~10% target per active voting epoch)**: * **Activation**: An epoch becomes "active" for inflation calculation when the *first* `StandardGovernor` proposal targeting that epoch is created. This proposal action calls `Power token.markNextVotingEpochAsActive()`, which pre-calculates the target total supply for the end of that voting epoch based on a \~10% increase (`participationInflation` parameter in `Power token`). * **Distribution Trigger**: At the end of a Voting Epoch, the `StandardGovernor` identifies voting power (direct or delegated via `voter_` address in `_castVote`) that participated in *every single proposal* during that epoch. For each fully participating delegatee address, it calls `Power token.markParticipation(delegatee)`. * **Distribution Execution**: Inside `Power token`, `_markParticipation` calculates the inflation amount based on the delegatee's *current* voting power (`_getVotes`). This amount is immediately added to the delegatee's tracked voting power (`_votingPowers`) and the overall token supply (`_totalSupplies`). Crucially, the actual *token balance* (`_balances`) increase for the underlying holders is *deferred* until their next interaction with the token (e.g., `transfer`, `delegate`, `sync`) which triggers the internal `_sync` function to realize the inflation. * **Incentive Rationale**: This system directly rewards *consistent participation* in standard governance. Missing even one vote means forfeiting the \~10% inflation for that epoch, resulting in dilution relative to fully active participants. Holders whose delegates participate fully benefit from this inflation. * **Dutch Auction for Unallocated Inflation**: * **Source**: The difference between the target supply (calculated at the start of the Voting Epoch) and the actual total supply after inflation distribution. This gap arises primarily from voting power that didn't fully participate. The `amountToAuction()` function calculates this difference. * **Timing**: Auctions are active *only* during Transfer Epochs. * **Price Mechanism**: Uses a Dutch auction format (`getCost()` calculates the price in `CashToken` per `POWER`). The 15-day epoch is divided into 100 periods (`_AUCTION_PERIODS`). The price starts high and decreases linearly *within* each period. The *starting* price for each period is half the starting price of the preceding period, creating an overall exponential decay curve. Pricing is relative to the previous epoch's total supply to ensure consistent price dynamics over time. * **Purchase**: Users call `buy()` providing the active `CashToken` (e.g., WETH) and specifying amounts and expiry. Requires `CashToken` allowance. * **Proceeds Destination**: The collected `CashToken` is transferred directly to the `DistributionVault`. * **Transfer & Delegation Restrictions**: Transfers (`transfer`, `transferFrom`) and delegation (`delegate`) are *only permitted during Transfer Epochs*, enforced by the `notDuringVoteEpoch` modifier. These actions also trigger `_sync()` to update the account's balance with any pending inflation. * **Bootstrapping**: The `constructor` or a `ZeroGovernor` reset (`resetToPowerHolders`, `resetToZeroHolders`) initializes the `Power token` state. It distributes an `INITIAL_SUPPLY` of 1,000,000 tokens proportionally based on the balances of a specified `bootstrapToken` (like `PowerBootstrapToken.sol`, a previous `Power token` version, or the `Zero token`) at the `bootstrapEpoch` (the epoch before deployment/reset). Initial delegatee is self. ### Zero token (`ZeroToken.sol`) *It all starts at zero.* The apex token for meta-governance and claiming protocol-generated revenue. * **Standard & Properties**:\ ERC-20 compatible. Implements `IEpochBasedVoteToken` which includes: * Epoch-based snapshots for historical balances/votes. * ERC-5805 for voting and delegation (`delegate`, `getPastVotes`, `pastBalancesOf`, `pastTotalSupplies`). * ERC-3009 for transfer authorization (`transferWithAuthorization`). * **6 decimals**. * **Supply Dynamics**:\ Generally static. The total supply increases *only* when the `StandardGovernor` explicitly mints new `ZERO` tokens as rewards for governance participation. The initial supply (e.g., 1,000,000,000) is determined at deployment via the `constructor` minting to initial accounts. * **Minting Mechanism (Rewards)**: * Minting is controlled exclusively by the active `StandardGovernor` contract, enforced by the `only`StandardGovernor\`\` modifier on the `Zero token.mint()` function. * Triggered when \`\`StandardGovernor`._castVote` processes the *final* vote for a voter (`voter_`) in an active Voting Epoch (i.e., they voted on all proposals). * The reward is minted to the `voter_` address provided in the \`\`StandardGovernor`._castVote` context, which corresponds to the address whose voting power was utilized (this is typically the *delegatee's* address if power was delegated). This incentivizes becoming an active delegate. * The reward amount is calculated proportionally to the `POWER` voting power used (`weight_`), but capped at a maximum total of 5 million `ZERO` per epoch (`maxTotalZeroRewardPerActiveEpoch` in `StandardGovernor`). Formula: `reward = (maxTotalZeroRewardPerActiveEpoch * weight_) / totalSupply(epoch - 1)`. * **Voting Usage**:\ The voting token for the `ZeroGovernor` (threshold-based). Vote weight is determined by the `ZERO` balance snapshot taken at the *end* of the epoch *before* the voting epoch (`proposalSnapshot`). * **Core Utility**: * Grants voting rights on fundamental meta-governance proposals within the `ZeroGovernor` (system resets, `CashToken` changes, threshold adjustments). * Entitles holders to claim a pro-rata share of various assets accumulated in the `DistributionVault`. Claiming is based on `ZERO` holdings in *past* epochs. * Provides an indirect economic benefit from `Power token` auctions, as the proceeds (`CashToken`) flow into the `DistributionVault`. import ZoomableImage from '@/components/ZoomableImage'; ## Two Token Governance (TTG): Overview *Coordinating the protocol's evolution.* ### Introduction Two Token Governance (TTG) is the robust, multi-layered governance system powering the M0 Protocol. Inspired by constitutional systems with checks and balances, it provides a balanced approach to protocol management through a carefully designed dual-token framework that separates day-to-day operational decisions from foundational meta-governance authority. TTG divides governance responsibilities between two primary tokens: * **Power token (`POWER`)**: The primary token for operational governance proposals and emergency actions, utilized within the `StandardGovernor` and `EmergencyGovernor`. * **Zero token (`ZERO`)**: The meta-governance token used within the `ZeroGovernor`, controlling the governance framework itself and enabling holders to claim a share of protocol revenue via the `DistributionVault`. This segregation of powers, combined with a deterministic epoch-based system and sophisticated incentive mechanisms, creates a resilient and adaptable governance structure designed for long-term protocol health, security, and decentralized control. ### Core Principles * **Separation of Powers**: Distinct tokens (`POWER`, `ZERO` ) and governor contracts (`StandardGovernor`, `EmergencyGovernor`, `ZeroGovernor`) handle different scopes of decisions, ensuring appropriate oversight for routine changes versus fundamental system modifications. * **Incentivized Participation**: `Power token`'s inflationary mechanism rewards active voting in standard governance, while `Zero token` ownership grants access to protocol revenue via the `DistributionVault`, encouraging informed engagement. * **Structured Process**: Governance actions adhere to fixed 15-day epoch cycles (`Transfer` and `Voting` epochs), defined proposal types per governor, and clear voting rules (majority vs. threshold), enhancing security and predictability. * **Centralized Configuration**: The `Registrar` contract acts as the single source of truth for all protocol parameters (rates, lists, intervals, etc.), modifiable only through successful, formally passed governance proposals. ### Core Components Overview The TTG system comprises several interconnected smart contracts: Picture representing the TTG Smart Contract Architecture diagram:
#### Governance Components * **`StandardGovernor` (\`\`StandardGovernor`.sol`)**: Manages regular governance for common operations using `Power token`. Uses simple majority voting (yes > no) and distributes rewards (`ZERO` tokens and enabling `POWER` inflation) for full participation in active voting epochs. Requires a proposal fee. * **`EmergencyGovernor` (\`\`EmergencyGovernor`.sol`)**: Handles emergency governance for critical situations using `Power token`. Uses threshold-based voting (minimum percentage of total `POWER` supply) for faster decisions. No proposal fee or direct incentives. * **`ZeroGovernor` (\`\`ZeroGovernor`.sol`)**: Manages meta-governance for system resets and fundamental protocol changes using `ZERO` . Controls the governance framework itself through threshold-based voting. No proposal fee. * **Registrar (`Registrar.sol`)**: Central parameter store containing all protocol configurations (lists like `APPROVED_MINTERS`, key-value pairs like `MINT_RATE_MODEL`). Single source of truth, writable only by `StandardGovernor` and `EmergencyGovernor`. * **DistributionVault (`DistributionVault.sol`)**: Collects protocol revenue (e.g., `Power token` auction proceeds, unrefunded proposal fees, excess yield) and distributes various assets pro-rata to `Zero token` holders based on past epoch holdings. #### Token Components * **Power token (`Power token.sol`)**: ERC-20 compatible voting token with **0 decimals**. Features epoch-based mechanics, inflation rewards (\~10% target per active voting epoch for full participants), delegation (ERC-5805), transfer authorization (ERC-3009), and Dutch auctions for unallocated inflation. Used in `StandardGovernor` and `EmergencyGovernor`. * **Zero token (`Zero token.sol`)**: ERC-20 compatible meta-governance token with **6 decimals**. Features epoch-based mechanics, delegation (ERC-5805), and transfer authorization (ERC-3009). Supply primarily increases through rewards minted by `StandardGovernor` for governance participation. Entitles holders to claim revenue from `DistributionVault`. Used in `ZeroGovernor`. #### Supporting Contracts * **Deployers**: Specialized contracts (`Power tokenDeployer.sol`, `StandardGovernorDeployer.sol`, `EmergencyGovernorDeployer.sol`) controlled by `ZeroGovernor` that deterministically deploy new instances of core governance contracts during system resets using `CREATE`. * **PureEpochs (`PureEpochs.sol`)**: Library defining the epoch-based time system (fixed 15-day periods) that structures all governance activities. #### Configs Current governance and protocol configurations can be found at [governance.m0.org/config/governance](https://governance.m0.org/config/governance) and [governance.m0.org/config/protocol](https://governance.m0.org/config/protocol) respectively. ## Governance Structure Tiers TTG employs a three-tiered approach to decision-making: ### 1. Standard Governance (via `StandardGovernor` - `POWER` holders) The primary governance layer for routine protocol management. * **Purpose**: Routine adjustments and list management essential for day-to-day protocol operation. * **Scope**: Modifying parameters stored in the `Registrar` like interest rates, time intervals, mint ratios; adding/removing addresses from lists (`APPROVED_MINTERS`, `APPROVED_VALIDATORS`, `APPROVED_EARNERS`). Also controls its own proposal fee. * **Voting**: Uses `POWER`. Simple majority (Yes votes > No votes) of participating tokens. Occurs *only* during Voting Epochs. No fixed quorum percentage. * **Proposal Types**: Restricted to calling specific functions on `StandardGovernor` itself, which then interact with the `Registrar` or internal settings: * `addToList(bytes32 list, address account)` * `removeFromList(bytes32 list, address account)` * `removeFromAndAddToList(bytes32 list, address accountToRemove, address accountToAdd)` * `setKey(bytes32 key, bytes32 value)` * `setProposalFee(uint256 newProposalFee)` * **Incentives**: Drives `Power token` inflation and `Zero token` rewards for *full participation* within an active Voting Epoch. Requires a `proposalFee` paid in the active `CashToken`. * **Lifecycle**: Propose (during Transfer Epoch N) → Vote (during Voting Epoch N+1) → Execute (during Transfer Epoch N+2). Expired if not executed in time. ### 2. Emergency Governance (via `EmergencyGovernor` - `POWER` holders) A specialized governance layer for urgent protocol changes, sometimes referred to as the Priority Governor. * **Purpose**: Addressing urgent issues or critical parameter changes that cannot wait for the standard cycle. * **Scope**: Similar parameter and list changes via the `Registrar` as `StandardGovernor`, plus the ability to set the `StandardGovernor`'s proposal fee. * **Voting**: Uses `POWER`. High threshold (e.g., 65% of *total possible* `POWER` votes at snapshot required). Voting spans the proposal epoch and the subsequent one (`voteEnd = voteStart + 1`). * **Proposal Types**: Restricted to calling specific functions on `EmergencyGovernor` itself: * `addToList(bytes32 list, address account)` * `removeFromList(bytes32 list, address account)` * `removeFromAndAddToList(bytes32 list, address accountToRemove, address accountToAdd)` * `setKey(bytes32 key, bytes32 value)` * `setStandardProposalFee(uint256 newProposalFee)` * **Incentives**: No direct token incentives (no `POWER` inflation or `ZERO` rewards triggered). No proposal fee required. Designed for exceptional circumstances. * **Lifecycle**: Propose (any epoch N) → Vote (during Epoch N and N+1) → Execute (anytime during Epoch N or N+1 as soon as threshold is met). Expired if not executed by end of Epoch N+1. ### 3. Meta-Governance (via `ZeroGovernor` - `ZERO` holders) The highest governance layer with authority over the entire governance system structure. * **Purpose**: Governing the governance system itself and fundamental protocol settings. Enables protocol upgrades and recovery. * **Scope**: Initiating governance contract resets/upgrades, changing the allowed `CashToken`s, adjusting `EmergencyGovernor` and `ZeroGovernor` voting thresholds. * **Voting**: Uses `ZERO` . Threshold-based (e.g., 65% of total `ZERO` supply at snapshot required). Voting spans the proposal epoch and the subsequent one (`voteEnd = voteStart + 1`). * **Proposal Types**: Restricted to calling specific functions on `ZeroGovernor` itself: * `resetToPowerHolders()`: Redeploys `Power token`, `StandardGovernor`, `EmergencyGovernor`, bootstrapping new `Power token` from *old* `Power token` balances. * `resetToZeroHolders()`: Redeploys same contracts, bootstrapping new `Power token` from *current* `Zero token` balances. * `setCashToken(address newCashToken, uint256 newProposalFee)`: Changes the designated `CashToken` (must be pre-approved) and sets the `StandardGovernor` fee. * `setEmergencyProposalThresholdRatio(uint16 newThresholdRatio)` * `setZeroProposalThresholdRatio(uint16 newThresholdRatio)` * **Incentives**: Control over the system's future; access to protocol revenue via `DistributionVault`. No proposal fee required. * **Lifecycle**: Propose (any epoch N) → Vote (during Epoch N and N+1) → Execute (anytime during Epoch N or N+1 as soon as threshold is met). Expired if not executed by end of Epoch N+1. import ZoomableImage from '@/components/ZoomableImage'; ## Core Contracts & Epoch System Deep Dive ### Component Deep Dive #### Registrar (`Registrar.sol`) The authoritative, onchain configuration registry for the M0 protocol. It acts as the single source of truth for parameters. * **Functionality**: Implements `IRegistrar`. Acts as a secure key-value store (`setKey(key, value)`, `get(key)`) and manages critical address lists (`addToList(list, account)`, `removeFromList(list, account)`, `listContains(list, account)`). * **Control**: Write access (`setKey`, `addToList`, `removeFromList`) is strictly limited to the currently active `StandardGovernor` and `EmergencyGovernor` contracts, enforced by the `onlyStandardOr`EmergencyGovernor\`\` modifier. Read access is public. * **Usage**: Essential for protocol operation. Core contracts (like those managing MToken minting/burning, rates) read configurations from the Registrar. `listContains` is fundamental for permission checks (e.g., verifying if an address is an approved Minter). * **Key Parameters Stored (Examples)**:
| Parameter Key String (Used to derive `bytes32`) | Description | Modified By | Read By (Examples) | | ----------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------- | -------------------------------------------------- | | `"minters"` | Whitelist of accounts allowed to mint $M | StandardGov/EmergencyGov (via lists) | MinterGateway | | `"validators"` | Whitelist of offchain collateral validators | StandardGov/EmergencyGov (via lists) | MinterGateway | | **`"earners"`** | Whitelist for enabling $M earning status | StandardGov/EmergencyGov (via lists) | MToken, **WrappedMToken (direct & via EarnerMgr)** | | **`"earners_list_ignored"`** | If set (non-zero), ignores the "earners" list | StandardGov/EmergencyGov (via `setKey`) | MToken, **WrappedMToken (direct & via EarnerMgr)** | | `"minter_rate_model"` | Address of contract calculating minter interest | StandardGov/EmergencyGov (via `setKey`) | MinterGateway | | `"earner_rate_model"` | Address of contract calculating earner interest | StandardGov/EmergencyGov (via `setKey`) | MToken | | N/A (Read via `vault()` func / constructor) | Address of the `DistributionVault` | `ZeroGovernor` (during deployment/reset) | MinterGateway, Power token, Registrar | | `"mint_ratio"` | Maximum permitted mint-to-collateral ratio | StandardGov/EmergencyGov (via `setKey`) | MinterGateway | | `"update_collateral_interval"` | Required frequency for collateral updates | StandardGov/EmergencyGov (via `setKey`) | MinterGateway | | `"minter_freeze_time"` | Duration a minter is frozen upon penalty | StandardGov/EmergencyGov (via `setKey`) | MinterGateway | | `"penalty_rate"` | Penalty rate for infractions (e.g., missed updates) | StandardGov/EmergencyGov (via `setKey`) | MinterGateway | | `"update_collateral_threshold"` | Number of validator signatures needed | StandardGov/EmergencyGov (via `setKey`) | MinterGateway | | `"mint_delay"` | Delay before a mint proposal is executable | StandardGov/EmergencyGov (via `setKey`) | MinterGateway | | `"mint_ttl"` | Time-to-live for a mint proposal after delay | StandardGov/EmergencyGov (via `setKey`) | MinterGateway | | `"base_minter_rate"` | Base rate for minter interest | StandardGov/EmergencyGov (via `setKey`) | MinterRateModel | | `"max_earner_rate"` | Max rate for earner interest | StandardGov/EmergencyGov (via `setKey`) | EarnerRateModel | | `"em_admins"` | List of admins allowed to manage earners via EarnerManager | StandardGov/EmergencyGov (via lists) | EarnerManager | #### DistributionVault (`DistributionVault.sol`) Aggregates and distributes various protocol revenues to `Zero token` holders. * **Revenue Sources**: Designed to receive arbitrary ERC20 tokens. Key expected sources include: * Excess yield generated by eligible collateral (must be transferred externally to the Vault's address). * `CashToken` proceeds from `Power token` Dutch auctions (transferred automatically by `Power token.buy`). * Unrefunded `CashToken` proposal fees from failed/expired `StandardGovernor` proposals (transferred by \`\`StandardGovernor`.sendProposalFeeToVault`). * **Distribution Accounting (Critical Process)**: 1. **Trigger**: The `distribute(token)` function *must be called* (permissionlessly, by any external account) for the Vault to recognize newly received balances of a specific `token`. 2. **Calculation**: It measures the increase in the Vault's balance of `token` since the last call (`IERC20(token).balanceOf(address(this)) - _lastTokenBalances[token]`). 3. **Recording**: This difference (the newly distributable amount) is added to the mapping `distributionOfAt[token][currentEpoch]`, earmarking it for `ZERO` holders of the current epoch. 4. **State Update**: `_lastTokenBalances[token]` is updated to the current balance. * **Claiming Mechanism**: * `Zero token` holders call `claim(token, startEpoch, endEpoch, destination)` or its gasless signature variant `claimBySig(...)`. * The function processes epochs *strictly in the past* (`endEpoch < currentEpoch`). It reverts if the range includes the current epoch or future epochs. * It iterates from `startEpoch` to `endEpoch`. For each epoch `i`: * It retrieves the claimant's historical `ZERO` balance (`claimantBalance`) and the total `ZERO` supply (`epochTotalSupply`) for epoch `i` using `IZero token(zeroToken).pastBalancesOf(account, i, i)` and `IZero token(zeroToken).pastTotalSupplies(i, i)`. * It calculates the pro-rata share for that epoch: `share = (distributionOfAt[token][i] * claimantBalance * _GRANULARITY) / epochTotalSupply`. The `_GRANULARITY` constant (1e9) is used during accumulation to minimize precision loss from integer division. * It checks the `hasClaimed[token][i][account]` mapping and skips the epoch if already claimed. * After iterating, it marks all processed epochs (`startEpoch` to `endEpoch`) as claimed in the `hasClaimed` mapping for that `token` and `account`. * The final accumulated `claimed_` amount (scaled by `_GRANULARITY`) is divided by `_GRANULARITY` to get the true token amount, `_lastTokenBalances[token]` is decremented, and the tokens are transferred to the `destination`. * **State**: Maintains `_lastTokenBalances` (internal balance tracking), `distributionOfAt` (per-token, per-epoch distributable amounts), and `hasClaimed` (per-token, per-epoch, per-user claim status) mappings. More about the overall place of the Distribution Vault in the protocol in its [dedicated section](/home/technical-documentations/distribution-vault/) #### StandardGovernor (`StandardGovernor.sol`) Manages the regular, day-to-day governance process with economic incentives. * **Allowed Proposal Actions**: Limited to calling specific functions *on itself* which then interact with the `Registrar` or its own settings: `addToList`, `removeFromList`, `removeFromAndAddToList`, `setKey`, and `setProposalFee`. This prevents proposals from executing arbitrary code. Enforced by `onlySelf` modifier and internal `_revertIfInvalidCalldata` check. * **Proposal Fees**: Requires a `proposalFee` (set via governance, stored in `proposalFee` state variable, initially set in constructor) paid in the currently active `CashToken` (`cashToken` state variable). The fee is transferred from the proposer using `transferFrom` when `propose` is called. It is refunded via `transfer` upon successful execution (`execute`), or can be optionally sent to the `DistributionVault` via `sendProposalFeeToVault` if the proposal is Defeated or Expired. The `cashToken` and `proposalFee` can be changed by the `ZeroGovernor` via `setCashToken`. * **Voting Mechanism**: Uses `POWER` tokens. Success requires a simple majority (Yes votes > No votes), checked within the `state()` function logic (specifically `proposal_.yesWeight > proposal_.noWeight` when epoch > voteEnd). Voting is strictly confined to the designated Voting Epoch (odd-numbered epoch N+1 following the proposal epoch N). * **Proposal Lifecycle**: 1. **Propose**: During a Transfer Epoch (N). Pays fee. Records proposal details. Increments `numberOfProposalsAt[N+1]`. If it's the first proposal for epoch N+1, triggers `Power token.markNextVotingEpochAsActive`. 2. **Vote**: During the subsequent Voting Epoch (N+1). `state()` is `Active`. `POWER` transfers/delegations disabled. Voters call `castVote` or `castVotes`. 3. **Tally & Outcome**: At the start of Epoch N+2 (Transfer Epoch), the outcome is determined based on votes tallied at the end of Epoch N+1. `state()` becomes `Succeeded` or `Defeated`. 4. **Execute**: If `Succeeded`, can be executed by anyone calling `execute()` during Epoch N+2. Executes the proposed action (e.g., `setKey` on `Registrar`). Refunds fee to proposer. 5. **Expire/Send Fee**: If `Defeated`, or `Succeeded` but not executed during Epoch N+2, becomes `Expired`. Fee can then be sent to `DistributionVault` via `sendProposalFeeToVault`. * **Reward Distribution**: Tracks participation per voter per epoch (`numberOfProposalsVotedOnAt`, `numberOfProposalsAt`). If `hasVotedOnAllProposals` returns true for a voter (`voter_`) after they cast their final vote in an epoch (checked inside `_castVote`), the contract calls `Power token.markParticipation(voter_)` (to enable `POWER` inflation for the delegatee) and `Zero token.mint(voter_, reward)` (to distribute `ZERO` reward to the delegatee). The `reward` calculation uses `maxTotalZeroRewardPerActiveEpoch`. #### EmergencyGovernor (`EmergencyGovernor.sol`) Provides an expedited path for critical governance actions using threshold consensus. * **Allowed Proposal Actions**: Similar restricted scope as `StandardGovernor`, targeting itself to interact with the `Registrar` or `StandardGovernor`: `addToList`, `removeFromList`, `removeFromAndAddToList`, `setKey`, `setStandardProposalFee`. Enforced by `onlySelf` and `_revertIfInvalidCalldata`. * **Proposal Fees**: None required. * **Voting Mechanism**: Uses `POWER` tokens. Requires a high threshold (`thresholdRatio`, e.g., 6500 basis points = 65%) of the *total* `POWER` supply at the snapshot block (`voteStart - 1`). The required number of votes is calculated by `proposalQuorum()`. Success determined in `state()` by checking `yesWeight >= quorum()`. Faster voting window: `voteEnd = voteStart + 1`, meaning voting spans the proposal epoch and the subsequent one. * **Proposal Lifecycle**: 1. **Propose**: Can be proposed in any epoch (N). Records proposal details including the current `thresholdRatio`. 2. **Vote**: Voting is active during Epoch N and Epoch N+1. Voters call `castVote` or `castVotes`. 3. **Execute**: Can be executed by anyone calling `execute()` as soon *as* the state becomes `Succeeded` (i.e., threshold is met), up until the end of Epoch N+1. `proposalDeadline` is end of Epoch N+1. Executes the proposed action. 4. **Outcome**: If not executed by end of Epoch N+1, becomes `Expired`. If threshold never met, remains `Defeated`. * **No Direct Incentives**: Does not trigger `Power token` inflation or `Zero token` reward minting. Its use is reserved for genuine emergencies. The threshold ratio can be changed by the `ZeroGovernor`. #### ZeroGovernor (`ZeroGovernor.sol`) The apex governor, controlling the structure of the governance system itself via threshold consensus. * **Allowed Proposal Actions**: Limited to highly impactful, predefined functions targeting itself or the governors it controls: * `resetToPowerHolders()`: Redeploys `Power token`, `StandardGovernor`, `EmergencyGovernor` via their respective Deployer contracts, bootstrapping the new `Power token` from the *old* `Power token` balances. * `resetToZeroHolders()`: Redeploys the same contracts, but bootstraps the new `Power token` from the *current* `Zero token` balances. * `setCashToken(address newCashToken, uint256 newProposalFee)`: Changes the designated `CashToken` used for `StandardGovernor` fees and `Power token` auctions (must be pre-approved in `_allowedCashTokens` mapping, set at deployment). Also sets the `StandardGovernor` fee simultaneously via an internal call. * `setEmergencyProposalThresholdRatio(uint16 newThresholdRatio)`: Adjusts the voting threshold for the `EmergencyGovernor` via an internal call. * `setZeroProposalThresholdRatio(uint16 newThresholdRatio)`: Adjusts the voting threshold for the `ZeroGovernor` itself via `_setThresholdRatio`. * **Proposal Fees**: None required. * **Voting Mechanism**: Uses `ZERO` tokens. Requires a threshold (`thresholdRatio`) percentage of the total `ZERO` supply at the snapshot block (`voteStart - 1`). `proposalQuorum()` calculates required votes. Success determined in `state()` by checking `yesWeight >= quorum()`. Faster voting window: `voteEnd = voteStart + 1`. * **Proposal Lifecycle**: Same faster lifecycle as `EmergencyGovernor`: Propose (N) -> Vote (N & N+1) -> Execute (anytime during N or N+1, once threshold met). `proposalDeadline` is end of Epoch N+1. * **Reset Functionality**: The `resetTo*` functions call the `deploy()` method on the relevant deployer contracts (`Power tokenDeployer`, `StandardGovernorDeployer`, `EmergencyGovernorDeployer`). These deployers use `CREATE` to deterministically deploy new contract instances. The `ZeroGovernor` emits a `ResetExecuted` event logging the addresses of the newly deployed contracts and the bootstrap token used. This is the designated mechanism for major governance upgrades or system recovery. ### Epoch System (`PureEpochs.sol`) #### Overview The entire governance system operates on a strict, time-based **epoch system** defined in the `PureEpochs.sol` library. This structures governance activities and enhances security by preventing certain actions during sensitive periods. * **Epoch Length**: Fixed at 15 days (`EPOCH_PERIOD = 15 days`). * **Starting Timestamp**: Epoch 1 commenced on September 15, 2022, 06:42:42 AM UTC (`STARTING_TIMESTAMP = 1_663_224_162`). The current epoch can be calculated based on `block.timestamp`. * **Clock Mode**: Conforms to ERC-6372 standard, defined by `PureEpochs.clockMode()` (which encodes the starting timestamp and period). * **Epoch Types**: Epochs alternate between two types: * **Transfer Epochs (Even-numbered Epochs)**: * **Activity**: `Power token`s *can* be transferred and delegated. `Power token` Dutch auctions *are active* (if supply available). `StandardGovernor` proposals *can* be created targeting the next Voting Epoch. * **Voting Epochs (Odd-numbered Epochs)**: * **Restrictions**: `Power token` transfers and delegations *are disabled* by the `notDuringVoteEpoch` modifier in `Power token` to ensure stable voting power for the duration. `Power token` Dutch auctions *are inactive*. * **Activity**: `StandardGovernor` proposals created in the previous Transfer Epoch *can be voted on*. `Power token` inflation and `Zero token` rewards *are calculated and distributed* by the respective contracts based on voting participation within *this* specific epoch. * **Note on Emergency/Zero Governors**: Their faster proposal lifecycle (`voteEnd = voteStart + 1`) means voting can span across the boundary between any two consecutive epochs (one Transfer, one Voting, or vice-versa), regardless of type restrictions on `Power token` transfers. The system uses simple functions in `PureEpochs.sol` like `currentEpoch()` and `timeRemainingInCurrentEpoch()` to manage time. This alternating Transfer/Voting epoch structure is crucial for the integrity of `StandardGovernor` voting, preventing vote manipulation through last-minute `Power token` movements. #### Epoch-Based Token Tracking Both `Power token` and `Zero token` inherit from `EpochBasedVoteToken`, which uses a sophisticated snapshot system to track balances, total supply, voting power, and delegations historically across epochs. Key structures include: ```solidity // Stores an amount valid from a specific epoch onwards struct AmountSnap { uint16 startingEpoch; uint240 amount; } // Stores an address valid from a specific epoch onwards struct AccountSnap { uint16 startingEpoch; address account; } // Storage patterns (simplified representation) mapping(address => AmountSnap[]) internal _balances; // Balance snaps per account mapping(address => AccountSnap[]) internal _delegatees; // Delegatee snaps per delegator mapping(address => AmountSnap[]) internal _votingPowers; // Voting power snaps per delegatee AmountSnap[] internal _totalSupplies; // Total supply snaps ``` This allows the system to efficiently query any past state using functions like `getPastVotes`, `pastBalanceOf`, and `pastTotalSupplies`, which are essential for: 1. Determining voting weight for proposals based on past snapshots. 2. Calculating fair distribution in the `DistributionVault`. 3. Enabling the inflation (`_getUnrealizedInflation`) and auction (`_getTotalSupply(epoch - 1)`) mechanisms in `Power token`. 4. Calculating `ZERO` rewards in `StandardGovernor` (`_getTotalSupply(epoch - 1)`). #### Vote Batching All three governors (`StandardGovernor`, `EmergencyGovernor`, `ZeroGovernor`) inherit from `BatchGovernor` and support vote batching to enable efficient multi-proposal voting in a single transaction: ```solidity // Cast votes for multiple proposals function castVotes( uint256[] calldata proposalIds, uint8[] calldata supportList ) external returns (uint256 weight); // Cast votes with reasons for multiple proposals function castVotesWithReason( uint256[] calldata proposalIds, uint8[] calldata supportList, string[] calldata reasonList_ ) external returns (uint256 weight); // Gasless signature variants also exist (e.g., castVotesBySig) ``` This reduces gas costs and improves the user experience for active participants. import ZoomableImage from '@/components/ZoomableImage'; ## M0 on Solana: Technical Deep Dive This document provides a detailed technical overview of the M0 Protocol's implementation on the Solana blockchain. It is intended for developers who want to integrate with or build on top of `$M` and its extensions on Solana. It assumes you are familiar with Solana's programming model (programs, accounts, CPIs) and have a conceptual understanding of M0's hub-and-spoke architecture. ### Architecture & Core Components M0's Solana deployment functions as a "spoke" in the cross-chain model, with Ethereum as the "hub". Communication and token transfers are managed by the **M Portal**, which is a customized implementation of Wormhole's **Native Token Transfer (NTT)** framework. The system is composed of three core onchain programs and several offchain services that work in concert.
The core onchain programs for M0 on Solana.
#### Onchain Programs The onchain logic is modular, distributed across three main Solana programs written in Rust using the Anchor framework.
| Program | Mainnet Program ID | Devnet Program ID | Description | | ----------------- | ---------------------------------------------- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Portal** | `mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY` | `mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY` | The gateway for bridging `$M` between EVM chains and Solana. A fork of Wormhole's NTT program with M0-specific payload support and executor integration. | | **Earn** | `MzeRokYa9o1ZikH6XHRiSS5nD8mNjZyHpLCBRTBSY4c` | `MzeRokYa9o1ZikH6XHRiSS5nD8mNjZyHpLCBRTBSY4c` | Manages yield distribution and earner permissions for the base `$M` token with frozen-by-default security model. | | **M Extensions** | `3C865D264L4NkAm78zfnDzQJJvXuU3fMjRUvRxyPi5da` | `3C865D264L4NkAm78zfnDzQJJvXuU3fMjRUvRxyPi5da` | Unified extension framework (`m_ext`) compiled with feature flags for NoYield, ScaledUi, and Crank models. | | **Swap Facility** | `MSwapi3WhNKMUGm9YrxGhypgUEt7wYQH3ZgG32XoWzH` | `MSwapi3WhNKMUGm9YrxGhypgUEt7wYQH3ZgG32XoWzH` | Permissioned router for atomic swaps between whitelisted M0 extensions (`ext_swap` program). |
#### Key Onchain Assets
| Asset | Mainnet Mint Address | Devnet Mint Address | Description | | ------------- | --------------------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | **$M Token** | `mzerokyEX9TNDoK4o2YZQBDmMzjokAeN6M2g2S3pLJo` | `mzeroZRGCah3j5xEWp2Nih3GDejSBbH1rbHoxDg8By6` | The base yield-bearing stablecoin, implemented as a Token-2022 asset with frozen-by-default security. | | **$wM Token** | `mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp` | `mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp` | The wrapped, 1:1 `$M`-backed extension using the Crank model, also a Token-2022 asset. |
### V2 Upgrades: What Changed The V2 upgrade introduced seven major enhancements to the Solana implementation: #### 1. Direct Bridging to Extensions **What Changed:** The Portal now supports a `destination_token` field in the `AdditionalPayload`, allowing users to bridge directly to extension tokens (like `$wM`) instead of only receiving base `$M`. **Why It Matters:** Eliminates the need for a separate wrap transaction after bridging, improving UX and reducing costs. **Technical Implementation:** ```rust pub struct AdditionalPayload { pub index: u64, pub destination_token: [u8; 32], // NEW: Target mint address (M or extension) pub earner_root: Option<[u8; 32]>, } ``` #### 2. Frozen-by-Default $M **What Changed:** All new `$M` token accounts are initialized with `AccountState::Frozen` using Token-2022's `DefaultAccountState` extension. **Why It Matters:** Enhances security by preventing unauthorized accounts from holding `$M`. Only approved earners (verified via Merkle proof) can have their accounts thawed. **Technical Implementation:** ```rust // $M mint is created with DefaultAccountState::Frozen let default_state = DefaultAccountState { state: AccountState::Frozen, }; ``` #### 3. Onchain Yield Distribution **What Changed:** Yield distribution is now fully onchain via the scaled-ui mechanism, replacing V1's centralized distribution. **Why It Matters:** Increases transparency and decentralization. All yield calculations and distributions are verifiable onchain. **Technical Implementation:** * Yield distributed via scaled-ui mechanism * Index updates propagated onchain * Extensions automatically sync on wrap/unwrap operations #### 4. Permissionless Index Updates **What Changed:** The `sync()` instruction for extension index updates is now permissionless—anyone can call it. Additionally, anyone can bridge an index update, and extensions automatically sync on wrap/unwrap operations. **Why It Matters:** Enables keeper bots and users to ensure yield indices are always up-to-date without relying on centralized services. **Who Can Call:** Anyone (no signer required for sync, though accounts must be valid). Index updates can also be bridged permissionlessly. #### 5. Executor Support for Generic Bridge Messages **What Changed:** Integration with Wormhole's executor pattern (`executor-account-resolver-svm`) enables arbitrary cross-chain instructions to be executed atomically with bridge transfers. **Why It Matters:** Unlocks advanced cross-chain composability, such as "bridge and stake" or "bridge and swap" in a single transaction. **Technical Implementation:** * Portal validates executor messages * Executor Account Resolver resolves required accounts * Arbitrary CPI instructions executed after mint #### 6. Unified Extension Framework **What Changed:** All extensions (NoYield, ScaledUi, Crank) are now compiled from a single `m_ext` program using Rust feature flags. **Why It Matters:** Reduces code duplication, simplifies auditing, and ensures consistent behavior across all extension types. **Feature Flags:** ```rust [features] no-yield = [] scaled-ui = [] crank = [] ``` #### 7. Multi-Network Support (Fogo Compatibility) **What Changed:** V2 architecture is designed to support both Solana and Fogo (Wormhole's native rollup) with minimal changes. **Why It Matters:** Future-proofs the protocol for multi-network deployment and leverages Wormhole's native cross-chain capabilities. **Implementation:** Feature flags enable Fogo-specific configurations without forking the codebase. ### Program Specifications #### 1. Portal Program (`programs/portal`) The Portal is the entry and exit point for `$M` into the Solana ecosystem. ##### Core Logic & Custom Payload * **Core Logic:** Based on Wormhole NTT, it validates Wormhole Verifiable Action Approvals (VAAs) and processes inbound/outbound transfers. The key inbound instruction is `release_inbound_mint_multisig`, which mints `$M` tokens and makes a CPI to the `Earn` program's `propagate_index` function. * **Custom Payload (`payloads/token_transfer.rs`):** The standard `NativeTokenTransfer` struct is extended with an `AdditionalPayload`. This is the most critical customization, allowing M0-specific data to be securely transmitted with every bridge transfer. ```rust // programs/portal/src/payloads/token_transfer.rs pub struct AdditionalPayload { pub index: u64, // Latest $M Earning Index from Ethereum pub destination_token: [u8; 32], // Target token mint (M or extension) pub earner_root: Option<[u8; 32]>, // Merkle root of approved earners } ``` * **`index`:** The latest `$M` Earning Index from Ethereum. * **`destination_token`:** The target token mint address on Solana (e.g., `$M` or `$wM`). **NEW in V2.** * **`earner_root`:** An optional Merkle root of the official `$M` earner list, as determined by M0 Governance on Ethereum. ##### Executor Integration V2 Portal integrates with Wormhole's executor pattern to enable generic cross-chain instructions: ```rust // Executor message structure pub struct ExecutorMessage { pub instruction_data: Vec, pub program_id: Pubkey, pub account_metas: Vec, } ``` The executor account resolver (`executor-account-resolver-svm`) resolves required accounts and executes instructions atomically with bridge transfers. #### 2. Earn Program (`programs/earn`) This program manages yield and permissions for the base `$M` token on Solana. ##### V2 Security Model: Frozen by Default All `$M` token accounts are initialized with `AccountState::Frozen`. Accounts are only thawed after: 1. User submits Merkle proof via `add_registrar_earner` 2. Proof is verified against `earner_merkle_root` 3. Account state is updated to `AccountState::Initialized` ##### State (`state/`) * **`Global` Account (`state/global.rs`):** A PDA seeded with `b"global"` that stores the program's configuration. * `admin`: The administrative authority. * `earn_authority`: A permissioned key that can call `claim_for` instructions. * `index`: The most recently propagated `$M` Earning Index. * `claim_cooldown`: The minimum time between yield claim cycles. * `max_yield` & `distributed`: Used to track and cap the amount of yield distributed in a cycle. * `claim_complete`: A flag indicating if the current claim cycle has finished. * `earner_merkle_root`: The Merkle root of the governance-approved earner list. * **`Earner` Account (`state/earner.rs`):** A PDA seeded with `b"earner"` and the user's token account address. It tracks an individual's earning status. * `last_claim_index`: The index at which the user last received yield. * `user`: The wallet address of the earner. * `user_token_account`: The specific token account that is earning yield. ##### Key Instructions (`instructions/`) * **`propagate_index`:** Called by the Portal via CPI. It updates the `Global` account's `index` and `earner_merkle_root`, and can initiate a new claim cycle if conditions are met (cooldown passed, new yield available). * **`add_registrar_earner`:** A **permissionless** instruction allowing a user to prove their eligibility to earn yield. The user provides a Merkle proof that their address is included in the `earner_merkle_root`. **On success, thaws the frozen token account.** * **`claim_for`:** A permissioned instruction called by the `earn_authority`. It calculates the yield owed to a specific earner since their last claim and mints new `$M` tokens to their account. **NEW in V2: fully onchain distribution.** * **`complete_claims`:** Called by the `earn_authority` to mark the end of a yield distribution cycle. * **`sync`:** **NEW in V2.** Permissionless instruction to update the earning index. Anyone can call this to keep indices current. #### 3. $M Extension Framework (`programs/m_ext`) **NEW in V2:** Unified extension framework replacing separate programs for each model. ##### Architecture All extension models are compiled from a single `m_ext` program using Rust feature flags: ```rust // Cargo.toml [features] no-yield = [] scaled-ui = [] crank = [] ``` **Deployed Instances:** * **NoYield Extensions:** Compiled with `--features no-yield` * **ScaledUi Extensions:** Compiled with `--features scaled-ui` * **Crank Extensions:** Compiled with `--features crank` (used by `$wM`) ##### State Structures **ExtGlobal Account (shared across all models):** ```rust pub struct ExtGlobal { pub admin: Pubkey, pub earn_authority: Option, // Only for Crank model pub ext_mint: Pubkey, pub m_mint: Pubkey, pub m_earn_global_account: Pubkey, pub bump: u8, pub m_vault_bump: u8, pub ext_mint_authority_bump: u8, pub yield_config: YieldConfig, pub wrap_authorities: Vec, } pub struct YieldConfig { pub variant: YieldVariant, // NoYield | ScaledUi | Crank pub last_m_index: u64, pub last_ext_index: u64, } pub enum YieldVariant { NoYield, ScaledUi, Crank, } ``` **Crank-Specific State:** ```rust // Only present when compiled with 'crank' feature pub struct EarnManager { pub manager: Pubkey, pub fee_bps: u64, pub fee_token_account: Pubkey, pub bump: u8, } pub struct Earner { pub user: Pubkey, pub user_token_account: Pubkey, pub recipient_token_account: Pubkey, pub earn_manager: Pubkey, pub last_balance: u64, pub last_index: u64, pub bump: u8, } ``` ##### Core Instructions (Shared) * **`initialize`:** Sets up the extension's global state * **`wrap(amount: u64)`:** Wraps `$M` into extension token * **`unwrap(amount: u64)`:** Unwraps extension token back to `$M` * **`add_wrap_authority` / `remove_wrap_authority`:** Manage wrap permissions * **`transfer_admin`:** Transfer admin control ##### Model-Specific Instructions **NoYield:** * `claim_fees()`: Admin claims all accrued yield **ScaledUi:** * `sync()`: Permissionless index update (updates scaled-ui rate) * `set_fee(fee_bps: u64)`: Set optional fee (typically 0 for full pass-through) **Crank:** * `add_earn_manager` / `remove_earn_manager`: Admin manages earn managers * `add_earner` / `remove_earner`: Earn manager manages earners * `claim_for(user, snapshot_balance)`: Earn authority distributes yield * `sync()`: Update extension index from base $M program * `set_recipient`: Earner sets custom yield recipient #### 4. Swap Facility (`programs/ext_swap`) **NEW in V2:** Centralized router for atomic swaps between whitelisted extensions. ##### Global State ```rust pub struct SwapGlobal { pub bump: u8, pub admin: Pubkey, pub whitelisted_unwrappers: Vec, pub whitelisted_extensions: Vec, } pub struct WhitelistedExtension { pub program_id: Pubkey, pub ext_global: Pubkey, } ``` ##### Core Instructions * **`swap(amount, remaining_accounts_split_idx)`**: Atomic cross-extension swap * **`wrap(amount)`**: Convert `$M` to extension * **`unwrap(amount)`**: Convert extension to `$M` (requires `whitelisted_unwrapper`) * **`whitelist_extension` / `remove_whitelisted_extension`**: Admin manages extensions * **`whitelist_unwrapper` / `remove_whitelisted_unwrapper`**: Admin manages unwrap permissions **Security Model:** * Only whitelisted extensions can participate in swaps * Only whitelisted unwrappers can call `unwrap` directly * All swaps maintain 1:1 peg ### Developer Integration #### Interacting via SDK The recommended way to interact with the M0 Solana programs is through the official TypeScript SDK. * **Installation:** `pnpm i @m0-foundation/solana-m-sdk` * **Core Classes:** The SDK provides classes that abstract away the onchain complexity: * `EarnAuthority`: For admin-level actions like initiating claims and syncing indexes. * `EarnManager`: For managing a set of earners within an extension (Crank model). * `Earner`: For user-level actions and querying an individual's yield status. **Example: Building a Claim Transaction (V2 Crank Model)** ```tsx import { EarnAuthority, Earner } from '@m0-foundation/solana-m-sdk'; import { Connection, PublicKey } from '@solana/web3.js'; import { createPublicClient, http } from 'viem'; // Setup clients const connection = new Connection(RPC_URL); const evmClient = createPublicClient({ transport: http(EVM_RPC_URL) }); // Load authority and earner const auth = await EarnAuthority.load(connection, evmClient, M_EXT_PROGRAM_ID); const earners = await auth.getAllEarners(); const earnerToClaim = earners[0]; // Build the claim instruction const claimIx = await auth.buildClaimInstruction(earnerToClaim); if (claimIx) { // build, sign, and send transaction with the instruction... } ``` **Example: Permissionless Sync (V2 ScaledUi Model)** ```tsx import { Program } from '@coral-xyz/anchor'; // Anyone can call sync to update yield indices const tx = await program.methods .sync() .accounts({ extGlobal: extGlobalPDA, extMint: extMintAddress, mEarnGlobal: mEarnGlobalAddress, mVault: mVaultPDA, token2022Program: TOKEN_2022_PROGRAM_ID, }) .rpc(); console.log('Synced yield:', tx); ``` #### Offchain Data via API For historical data, analytics, and building dashboards, use the M0 Solana API, which is powered by a Substreams indexer. * **Base URL (Mainnet):** `https://api-production-0046.up.railway.app` * **SDK:** `pnpm i @m0-foundation/solana-m-api-sdk` * **Key Endpoints:** * `/events/bridges`: Get latest bridge events. * `/events/index-updates`: Get historical `$M` Index updates. * `/token-account/{pubkey}/{mint}/claims`: Get yield claim history for a specific token account. #### Onchain Addresses A full list of program IDs, mints, and other key accounts for both Mainnet and Devnet can be found in the [**Addresses resource page**](/get-started/resources/addresses/#solana). ### Fogo Network Support **NEW in V2:** The architecture is designed to support Fogo, Wormhole's native rollup, alongside Solana. **What is Fogo?** * Wormhole-native rollup optimized for cross-chain applications * SVM-compatible (runs Solana programs with minimal changes) * Optimized for low-latency cross-chain messaging **M0 on Fogo:** * Same program logic as Solana deployment * Feature flags enable Fogo-specific optimizations * Seamless interoperability with Solana via Wormhole NTT **Deployment Status:** Fogo support is live. Check the [Addresses page](/get-started/resources/addresses/) for Fogo-specific program IDs. ### Source Code & Audits * **Portal & Earn Programs:** [m0-foundation/solana-m](https://github.com/m0-foundation/solana-m) * **Extension Framework & Swap Facility:** [m0-foundation/solana-m-extensions](https://github.com/m0-foundation/solana-m-extensions) * **Audits:** Security audits for all programs can be found in the [**Audits resource page**](/get-started/resources/audits/). ### Next Steps * **Build with $M:** Integrate the base `$M` token into your Solana dApp * **Create an Extension:** Deploy your own `$M`-backed stablecoin using NoYield, ScaledUi, or Crank models import ZoomableImage from '@/components/ZoomableImage'; ## Roles ### Introduction The M0 Protocol operates through a carefully designed system of actors, each with distinct roles and responsibilities crucial for the protocol's operation, security, and decentralized governance. Understanding these roles is key to understanding how `$M` is created, secured, utilized, and how the protocol evolves. The protocol's core functionality is implemented in several key smart contracts that these roles interact with: * **`MToken`**: The ERC20-compliant token contract for `$M`, which includes the unique earning capabilities. * **`MinterGateway`**: The interface for minting and burning, managing Minter collateral, and tracking debt obligations. * **`TTGRegistrar`**: The central configuration store managed by Two-Token Governance (TTG), holding approved addresses for roles and key protocol parameters. Below is a high-level overview of the primary roles within the M0 ecosystem, categorized by their main area of interaction. ### Overview of Key Protocol Roles The M0 ecosystem comprises several key actors, each playing a vital part: **1. $M Supply & Security:** * **Minters**: * **Description**: Minters are permissioned institutions responsible for creating (minting) new `$M`. They are the primary on/off-ramp to and from fiat. * **Function**: They provide eligible offchain collateral (such as U.S. backed reserves held in Special Purpose Vehicles) and register its value onchain via the MinterGateway. Based on this collateral and governance-set ratios, they can mint. They also pay interest on their minted supply, which forms the basis for the yield distributed to Earners and the protocol. * **Validators**: * **Description**: Validators are independent, trusted entities acting as a crucial security and verification layer for the protocol. * **Function**: Their primary role is to verify the offchain collateral reported by Minters, ensuring that all supply remains fully and transparently backed. They provide cryptographic attestations (signatures) for Minters' collateral updates to the MinterGateway. Validators also possess emergency powers, such as freezing a Minter or canceling a suspicious mint proposal, to safeguard protocol integrity. **2. $M Usage & Yield:** To earn yield, a user has to get the earner status. Below is an overview of the Earner status: * **Description**: Earners are addresses (users, smart contracts, or M0 Extensions) that have been approved by M0 Governance (or delegated admins for certain extensions like wM) to accrue yield on their `$M` balances. * **Function**: Once approved and activated via MToken.startEarning(), their balance (or the balance of an M0-powered extension they hold) automatically increases over time due to continuous compounding, based on the prevailing earner rate. This mechanism allows `$M` to function as a yield-bearing component for authorized participants. **3. Protocol Governance:** * **Power token (POWER) Holders**: * **Description**: POWER Holders are the primary participants in the operational governance of the M0 Protocol. * **Function**: POWER tokens are used to vote on proposals in the `StandardGovernor` (e.g., approving `Minters`, `Validators`, `Earners`; setting operational parameters like interest rates or collateral ratios) and the `EmergencyGovernor` (for urgent protocol adjustments). Active and complete participation in `StandardGovernor` voting is incentivized through POWER token inflation and ZERO token rewards. * **Zero token (ZERO) Holders**: * **Description**: ZERO Holders possess meta-governance authority, effectively acting as the highest level of governance oversight for the protocol. * **Function**: ZERO holders are entitled to claim a pro-rata share of protocol revenues (e.g., excess Minter yield, Power token auction proceeds) accumulated in the DistributionVault. Additionally, ZERO tokens are used to vote in the ZeroGovernor on fundamental changes, such as upgrading the core governance contracts themselves, altering critical system parameters (like governance thresholds), or changing the accepted CashTokens for proposal fees. Visual to point to which contracts a role / major protocol / governance part it is interacting with:
### Minters #### Role Definition Minters are entities authorized to generate `$M` by securing Eligible Collateral in offchain Special Purpose Vehicles (SPVs) and maintaining an onchain Collateral Value that represents these offchain assets. #### Key Functions Minters interact with the protocol primarily through the `MinterGateway` contract: #### 1. Activation and Status Management * `activateMinter(address minter_)`: A newly approved (by governance) minter must be activated before they can mint. This explicit step stores the active status locally within `MinterGateway` for gas efficiency, avoiding repeated external checks. * Once deactivated, a minter cannot be reactivated. This permanence also optimizes gas by eliminating the need for further status checks against the external `TTGRegistrar`. #### 2. Collateral Management * `updateCollateral(collateral, retrievalIds, metadataHash, validators, timestamps, signatures)`: Updates collateral value with validator signatures * `proposeRetrieval(collateral)`: Proposes to retrieve excess collateral * Must maintain sufficient collateral to support minted $M tokens according to the governance-set mint ratio #### 3. Minting Process * `proposeMint(amount, destination)`: Proposes to mint a specific amount of tokens * `mintM(mintId)`: Executes a previously proposed mint after the mint delay period and before mint time-to-live period #### Lifecycle and Constraints Minters go through several states: 1. **Inactive**: Approved by governance but not activated 2. **Active**: Called `activateMinter()` and can mint tokens 3. **Frozen**: Temporarily restricted from minting (but can still burn) 4. **Deactivated**: Permanently removed from the system Minters face several key constraints: * Must update collateral within the required interval (typically daily). As of today, the update collateral interval is set to 30 hours as per [this proposal](https://governance.m0.org/proposal/17943707564765307947230727208177770356513863441428702266086965014917482113266). * Must maintain collateralization above the mint ratio * Pay interest on minted tokens at the minter rate * Face penalties for missed updates or undercollateralization #### Penalties Minters can receive penalties in two cases: 1. **Missed Updates Penalty**: Applied when minters fail to update collateral within required intervals * Calculated as `penaltyRate × principalOfActiveOwedM × missedIntervals` * Charged only once per missed interval 2. **Undercollateralization Penalty**: Applied when active owed $M exceeds allowed maximum * Calculated as `penaltyRate × principalOfExcessOwedM × timeSpan / updateCollateralInterval` * Proportional to the duration of undercollateralization ### Validators #### Role Definition Validators serve as a critical security layer, verifying the accuracy of Minters' collateral updates and having emergency powers to protect the protocol. They are trusted entities responsible for bridging the gap between offchain assets and onchain accounting. #### Key Functions Validators interact with the protocol primarily through signature generation and special authority functions: #### 1. Collateral Verification * Sign offchain messages (`updateCollateral` digest) verifying collateral updates, which includes the list of retrieval proposals being resolved. * Signatures include timestamps to prevent replay attacks * Multiple validators must sign collateral updates to meet the threshold #### 2. Security Controls * `cancelMint(address minter, uint256 mintId)`: Cancel suspicious mint proposals * `freezeMinter(address minter)`: Temporarily freeze a minter's ability to mint new tokens #### 3. Signature Requirements * Signatures must be provided in ascending order by validator address * Each signature must have a timestamp newer than the last signature from that validator * The protocol enforces a threshold of validator signatures for valid collateral updates #### Security Mechanisms Validators implement several security protections: * **Timestamp Verification**: Ensures signatures aren't reused or used out of order * **Signature Uniqueness**: Each validator can only provide one valid signature per collateral update * **Emergency Powers**: Ability to cancel mints and freeze Minters to mitigate potential harm ### Earners #### Role Definition Earners are approved addresses that can enable earning on their $M token balance, allowing them to receive yield based on the protocol's earning rate. This is a key feature that separates $M from traditional stablecoins. #### Key Functions Earners interact with the protocol primarily through the `MToken` contract: #### 1. Earning Status Management * `startEarning()`: Converts a regular balance to an earning balance (requires TTG approval) * `stopEarning()`: Converts an earning balance back to a regular balance (keeps all accrued interest) * `stopEarning(address)`: Safety function allowing anyone to stop earning for an account that's been removed from the approved list #### 2. Balance Mechanism When an account is in earning status: * Their balance automatically increases over time through continuous compounding * Balances are stored internally as "principal amounts" that grow with the earning index * No transactions are needed to accrue interest #### Rate Mechanics Earners receive yield based on the Earner Rate, which is determined by a sophisticated rate model: * The rate model ensures yield to earners never exceeds interest paid by minters * Uses a mathematical formula with both instantaneous and time-integrated approaches * Applied with a safety factor (98% of the theoretical safe rate) * Continuously updated when key functions are called ### Regular $M Holders #### Role Definition Regular `$M` holders use it as a stablecoin without the earning feature. Their balances remain static and only change through explicit transactions. #### Key Functions Regular `$M` holders have standard ERC20 capabilities with additional features: #### Token Operations * Standard transfers (`transfer`, `transferFrom`), approvals (`approve`), and balance inquiries (`balanceOf`). * Support for gasless approvals through EIP-2612 permits (`permit`). * Support for transfers with authorization through EIP-3009 (`transferWithAuthorization`, `receiveWithAuthorization`). #### Transfer Mechanics Transfers between different types of accounts follow specific rules: * Between two non-earning accounts: Standard token transfer. * Between non-earning and earning accounts: Balance conversion occurs, using protocol-favoring rounding (principal rounded down on receive, principal rounded up on send). * All transfers are subject to consistency checks and appropriate balance updates in the `MToken` contract. **Note on Minter Debt Repayment**: Regular `$M` holders can choose to interact with the `MinterGateway`'s `burnM` function. This allows them to burn their *own* tokens to help repay the outstanding debt of a specific Minter (either active or deactivated), acting as an indirect way to support protocol stability or participate in the informal liquidation of a deactivated minter's position. This is distinct from standard token operations. ### Power token Holders #### Role Definition Power token holders act as the primary governance participants, responsible for day-to-day protocol governance through the `StandardGovernor` and emergency actions through the EmergencyGovernor. #### Key Functions Power token holders can influence the protocol through several mechanisms: #### 1. Standard Governance * Vote on adding/removing addresses from minter/validator/earner lists * Vote on key protocol parameters like mint ratio, collateral update interval, etc. * Propose and vote on protocol parameter changes * `StandardGovernor` proposals require a simple majority to pass (yes votes > no votes) #### 2. Emergency Governance * Vote on emergency actions through the EmergencyGovernor * Can take immediate action to protect the protocol in emergency situations * EmergencyGovernor uses a threshold ratio mechanism requiring a minimum percentage of yes votes #### 3. Token Mechanics * Power token is inflationary (10% per active voting epoch) * Token holders can directly vote or delegate their voting power * Snapshots of balances, voting powers, and delegations occur at epoch boundaries * Inflation rewards are only given to those who vote on ALL proposals in a voting epoch * Cannot transfer/delegate/mint during odd epochs (voting epochs) * Voting power is calculated from the previous epoch's balance #### 4. Dutch Auction * Can buy Power tokens during Dutch auctions during non-voting epochs * Price decreases exponentially over time, with the slope halving every period * Purchase price is relative to the previous epoch's total supply * Payments go to the Distribution Vault ### Zero token Holders #### Role Definition Zero token holders possess meta-governance rights, essentially serving as the highest level of governance in the protocol. They have the unique ability to completely redeploy the governance system and receive rewards from excess yield and other protocol fees. #### Key Functions Zero token holders have special privileges in the protocol: #### 1. Meta-Governance * Can vote to completely redeploy the standard and emergency governance systems through the ZeroGovernor * Can reset governance to either the current Power token or Zero token holders (complete governance reset) * Can update the threshold ratio for proposals in ZeroGovernor or EmergencyGovernor * Can set new cashTokens for the entire system * ZeroGovernor proposals require a minimum threshold of votes to pass #### 2. Reward Mechanism * Receive Zero token rewards for participation in `StandardGovernor` voting * Claim excess yield and fees from the Distribution Vault * Buy Power token with a discount during Dutch auctions #### 3. Token Mechanics * ERC20 token with 6 decimals * Supports EIP-3009, EIP-712 with EIP-1271 support, and EIP-5805 * Can only be minted by `StandardGovernor` as reward for voting participation * Used for voting in ZeroGovernor * Epochs are 15 days long with snapshots taken at the end of each epoch ### Role Interactions and System Balance The M0 Protocol maintains balance through carefully designed interactions between roles: #### Minter-Validator Relationship * Minters propose collateral updates and mint requests * Validators verify collateral and can intervene when necessary * This creates a checks-and-balances system for minting activity #### Minter-Earner Balance * Minters pay interest on borrowed tokens (minter rate) * Earners receive interest on their holdings (earner rate) * Rate models ensure earner yield never exceeds minter interest obligations #### Governance Hierarchy * Power token holders control standard parameter changes through `StandardGovernor` * Zero token holders have meta-governance capabilities through ZeroGovernor * EmergencyGovernor provides quick response capability for urgent issues * This creates a tiered governance structure for different types of decisions #### Distribution Vault Mechanism * The DistributionVault receives excess yield generated by Minters not distributed to Earners * It also receives cash tokens from Power token auctions and unrefunded proposal fees * Zero token holders can claim their pro-rata share of these accumulated assets * This provides an incentive mechanism for Zero token holders to participate in governance #### Cash Token System * Cash tokens are used to pay proposal fees in `StandardGovernor` * They're also used to purchase Power tokens in Dutch auctions * Expected to be WETH and $M according to the Whitepaper * Must be in an allowed set defined at ZeroGovernor deployment * Can be changed via ZeroGovernor proposals #### Economic Incentives * Minters are incentivized to maintain proper collateralization * Validators are trusted to verify offchain collateral accurately * Earners benefit from yield generated by the system * Power token holders are rewarded with inflation for active participation in all proposals * Zero token holders can claim excess yield and fees while maintaining meta-governance rights ### Trust Model The protocol operates with the following trust assumptions: * **Validators**: Fully trusted to verify offchain collateral accurately and monitor onchain activities. They must be reachable and able to issue valid signatures for minters in a timely manner. * **Minters**: Trusted to maintain their offchain collateral and meet protocol obligations. Minters are expected to update their collateral at required intervals and pay any imposed penalties. * **`$M` holders**: Not trusted, but can freely use the token as a stablecoin without special permissions. * **Power token holders**: Trusted to act in the best interest of the protocol for day-to-day governance. They are expected to vote on proposals and participate actively in governance. * **Zero token holders**: Trusted with meta-governance authority to reset the entire governance system if necessary. They have the highest level of governance power and are assumed to act as responsible stewards of the protocol. * **CashTokens**: Expected to be WETH and $M as stated in the Whitepaper, but nothing prevents deployment with other cashTokens. These must be ERC20-compliant without special behavior (such as transfer hooks, rebasing mechanisms, or transfer fees). The protocol incorporates several safeguards against potential trust violations: 1. Multi-level governance (`StandardGovernor`, EmergencyGovernor, ZeroGovernor) 2. Collateral verification through multiple validators 3. Penalty systems for minters who don't follow protocol rules 4. Economic incentives aligning with protocol health for all participants This trust model creates a balanced system where each role has appropriate permissions and incentives to maintain protocol stability and security. import ZoomableImage from '@/components/ZoomableImage'; ## Rates Models & Yield ### 1. The Interest Mechanism $M token operates within a balanced interest system in the M0 Protocol: 1. **Minter Interest Accrual**: Minters accrue obligations at the minter rate on their outstanding $M balances. 2. **Earner Interest Accrual**: Simultaneously, approved earning accounts accrue additional tokens at the earner rate. 3. **Rate Synchronization**: The EarnerRateModel ensures the earner rate is calibrated so total earnings never exceed total minter obligations (see Rate Model section below for further details). 4. **Continuous Mechanism**: Both sides update through independent but synchronized continuous indexing systems. This creates a mathematically balanced system where earner yields are safely constrained by the protocol's income from minters.
$M token implements sophisticated interest rate models that ensure financial soundness while distributing yield between minters, earners, and the protocol. ### 2. Rate Model Architecture The protocol uses two primary rate models: 1. **MinterRateModel**: Determines the interest rate minters pay on borrowed $M token * Simple model that reads rates directly from the TTG Registrar * Capped at 400% APR (40,000 basis points) for system safety * Governance-controlled through the `base_minter_rate` parameter 2. **EarnerRateModel**: Calculates the interest rate paid to $M token holders who opt in to earning * Uses a mathematical formula that ensures financial soundness * Rates are capped at 98% of the calculated safe rate * Governed through the `max_earner_rate` parameter #### Minter Rate Calculation The `MinterRateModel` has a straightforward implementation: ```math minterRate = min(\text{ TTGRegistrar({\text{BASE-MINTER-RATE}})}, \text{MAX-MINTER-RATE}) ``` ```solidity function rate() external view returns (uint256) { return min(TTGRegistrar.get("base_minter_rate"), MAX_MINTER_RATE); } ``` * The rate is governance-controlled through the TTG Registrar * Has a hard cap of 400% APR to prevent system abuse * Changes to this rate affect all minters uniformly #### Earner Rate Calculation The EarnerRateModel employs a more complex approach to ensure system solvency: ```math earnerRate = min(maxRate,getExtraSafeEarnerRate) ``` ```math getExtraSafeEarnerRate = safeEarnerRate\times {RateMultiplier} ``` ```solidity function rate() external view returns (uint256) { return min( maxRate(), getExtraSafeEarnerRate( totalActiveOwedM, totalEarningSupply, minterRate ) ); } ``` Where: * `getExtraSafeEarnerRate` applies the rate multiplier to the safe earner rate * `RATE_MULTIPLIER` is 9,800 (98% in basis points) * `ONE` is 10,000 (100% in basis points) * `maxRate()` returns the governance-set maximum earner rate ##### Safe Rate Derivation The safe earner rate is calculated using two different approaches based on the relationship between total active owed $M and total earning supply: 1. **When totalActiveOwedM ≤ totalEarningSupply**: * Uses an instantaneous cashflow approach * `safeRate = totalActiveOwedM × minterRate / totalEarningSupply` * Ensures interest paid to earners never exceeds interest collected from minters 2. **When totalActiveOwedM > totalEarningSupply**: * Uses a time-integrated approach over a 30-day confidence interval * Accounts for compound interest effects * Applies complex mathematical formula to ensure long-term solvency * Allows earner rate to temporarily exceed minter rate while maintaining system safety ##### Extra Safety Factor The EarnerRateModel applies an additional safety factor to the calculated safe rate: ```solidity function getExtraSafeEarnerRate( uint240 totalActiveOwedM_, uint240 totalEarningSupply_, uint32 minterRate_ ) public pure returns (uint32) { uint256 safeEarnerRate_ = getSafeEarnerRate(totalActiveOwedM_, totalEarningSupply_, minterRate_); uint256 extraSafeEarnerRate_ = (safeEarnerRate_ * RATE_MULTIPLIER) / ONE; return (extraSafeEarnerRate_ > type(uint32).max) ? type(uint32).max : uint32(extraSafeEarnerRate_); } ``` This ensures that earners receive 98% of the theoretically safe rate, creating an additional buffer for protocol safety. ### Confidence Interval Approach The EarnerRateModel uses a 30-day confidence interval to determine safe rates: * Calculates the amount of interest minters will generate over 30 days * Derives maximum earner rate that ensures total interest paid doesn't exceed this amount * Accounts for the compounding effects of continuous interest * Assumes the `updateIndex()` function will be called at least once every 30 days ### Balance Between Minters and Earners The system maintains a mathematical relationship between interest flows: ``` totalInterestFromMinters = totalActiveOwedM × (e^(minterRate×Δt) - 1) totalInterestToEarners = totalEarningSupply × (e^(earnerRate×Δt) - 1) ``` The rate models ensure: `totalInterestToEarners ≤ 98% of totalInterestFromMinters` ### Edge Cases Handling The EarnerRateModel handles several edge cases with special logic: * When `totalActiveOwedM = 0` or `minterRate = 0`: The earner rate is set to 0 * When `totalEarningSupply = 0`: The earner rate is set to the maximum possible value (`type(uint32).max`) * When calculations might overflow: The implementation includes safeguards against numerical issues ### Yield Distribution The system distributes yield in the following manner: 1. **Minters pay interest** based on their outstanding debt at the minter rate 2. **Earners receive up to 98%** of the available interest (subject to constraints) 3. **Excess yield** (at least 2% plus any additional buffer) goes to the TTG Vault 4. The TTG Vault funds protocol operations and can distribute to governance token holders ### Rate Update Mechanism Interest rates don't change automatically when governance parameters are updated: 1. Rate changes in the TTG Registrar take effect only when `updateIndex()` is called 2. Both $M token and MinterGateway must update their respective indices 3. Updates occur automatically during key operations such as minting, burning, and transfers 4. Rate models recalculate rates during each update based on current system state ### Mathematical Precision The implementation includes several technical considerations: * Rates are stored in basis points (1/100 of a percent) for precision * Calculations use fixed-point math with 12 decimal places (1e12 scaling) * Exponential calculations use Padé approximants for gas-efficient computation * Conservative rounding strategies favor protocol safety ### Visuals
## MinterGateway *Where money is born.* The MinterGateway contract serves as the central hub for minting and burning MTokens, managing minter collateral, and tracking debt obligations in the M0 Protocol. ### Minter Types and Lifecycle The system recognizes several states for minters: 1. **Approved**: Minters whitelisted by the TTG governance system 2. **Active**: Approved minters who have activated their minting capabilities 3. **Frozen**: Active minters temporarily prevented from minting (but can still burn) 4. **Deactivated**: Former minters who have exited the system (cannot be reactivated) ### Collateral Management Unlike traditional onchain collateral systems, M0 uses a validator-verified offchain collateral model: * **Real-World Backing**: Collateral exists in a Special Purpose Vehicle (SPV) as real-world assets * **Validator Verification**: Trusted validators periodically verify and sign off on collateral values * **Update Requirements**: Minters must update their collateral regularly (typically daily) * **Expiration Mechanism**: Collateral is considered zero if not updated within the specified interval * **Update Signatures**: Multiple validator signatures are required, with the minimum threshold set by governance #### Minting Process Creating new MTokens follows a structured three-step process designed to enhance security and enable validator oversight: 1. **Update Collateral**: Minters provide validator signatures confirming offchain collateral ```solidity function updateCollateral( uint256 collateral, uint256[] calldata retrievalIds, bytes32 metadataHash, address[] calldata validators, uint256[] calldata timestamps, bytes[] calldata signatures ) ``` 2. **Propose Mint**: Minters request to mint a specific amount to a destination, creating a proposal that validators can review ```solidity function proposeMint(uint256 amount, address destination) ``` 3. **Execute Mint**: After a mandatory delay period (`mintDelay`) and before expiry (`mintTTL`), minters execute their proposal if it hasn't been frozen or canceled by validators ```solidity function mintM(uint256 mintId) ``` This multi-step approach with time delays creates security checkpoints where validators can intervene if they detect suspicious activity, providing crucial protection for the protocol's monetary integrity. #### Debt and Interest System Minters accrue interest on their outstanding debt: * **Continuous Indexing**: The same indexing system used in MToken tracks growth of obligations * **Principal Storage**: Like earning balances, minter debt is stored as principal amounts that grow with interest * **Rate Model**: Interest rates are determined by an external rate model set through governance * **ActiveOwedM**: The current value of a minter's obligations including accrued interest #### Validator Signature Verification The signature verification system includes several security features: * **Multi-signature Requirement**: Requires multiple validator signatures for collateral updates * **Ordered Validator Addresses**: Validators addresses must be provided in ascending order to prevent duplicates * **Timestamp Validation**: Each signature includes a timestamp that must be: * Newer than the last signature from that validator for that minter * Not in the future * Not zero * **Replay Protection**: The system tracks the last used timestamp for each validator-minter pair * **Signature Format**: Uses EIP-712 typed data signatures that are validator-specific #### Penalty System The protocol enforces discipline through two types of penalties: 1. **Missed Updates Penalty**: Applied when minters fail to update collateral within required intervals * Calculated as `penaltyRate × principalOfActiveOwedM × missedIntervals` * Charged only once per missed interval 2. **Undercollateralization Penalty**: Applied when active owed $M exceeds allowed maximum * Calculated as `penaltyRate × principalOfExcessOwedM × timeSpan / updateCollateralInterval` * Proportional to the duration of undercollateralization #### Collateral Retrievals Minters can reduce their collateral through a structured process: 1. **Propose Retrieval**: Minter requests to retrieve a specific amount of collateral ```solidity function proposeRetrieval(uint256 collateral) ``` 2. **Validator Inclusion**: Validators specifically include the retrieval IDs they've approved in their next collateral update signatures. Only these explicitly included retrievals will be processed. 3. **Retrieval Resolution**: When collateral is updated, the approved retrievals are processed and their amounts are no longer deducted from the minter's effective collateral value This ensures that collateral can only be retrieved with explicit validator approval, maintaining the system's safety. Note the retrieval flow includes these technical aspects: * Retrieval proposals have unique IDs generated sequentially * Proposed retrievals are tracked in `_pendingCollateralRetrievals` mapping * The system prevents retrievals that would cause undercollateralization * Pending retrievals are explicitly deducted from the minter's effective collateral value for all system calculations, ensuring proper collateralization before the retrievals are resolved * Multiple retrievals can be resolved in a single update * Retrievals can only be resolved during a validated collateral update, requiring validator signatures that explicitly approve the retrieval IDs to be processed ### Validator Role Validators serve as trusted entities who: * Verify offchain collateral and sign update requests * Must provide timestamps with their signatures to prevent replay attacks * Can cancel suspicious mint proposals * Can freeze minters to prevent further minting for a governance-defined period * Enable the bridge between offchain assets and onchain accounting ### Burning Mechanism Any token holder can burn MTokens to reduce a minter's debt: * For active minters, burns reduce the principal of their owed M * For deactivated minters, burns reduce their fixed inactive owed M * After deactivation, burning serves as an informal liquidation mechanism ### Index Update Triggers The interest index is updated in several key situations: * When collateral is updated through `updateCollateral()` * When tokens are minted via `mintM()` * When tokens are burned via `burnM()` * When a minter is deactivated via `deactivateMinter()` * When `updateIndex()` is explicitly called Each update synchronizes both the MinterGateway's index and the MToken's index simultaneously, ensuring that minter obligation rates and earner yield rates maintain proper system balance throughout the protocol. ```solidity function updateIndex() public override(IContinuousIndexing, ContinuousIndexing) returns (uint128 index_) { // ... index_ = super.updateIndex(); // Update minter index and rate. // ... IMToken(mToken).updateIndex(); // Update earning index and rate. } ``` ### Total Owed $M Accounting The system tracks minter obligations with specialized accounting: * **Active Owed M**: Tracked as principal amounts that accrue interest * **Inactive Owed M**: Fixed amounts for deactivated minters that don't accrue interest * **Total Owed M**: The sum of active and inactive obligations * **Excess Owed M**: The difference between total owed $M and total $M supply, minted to the [TTG Vault](/home/technical-documentations/distribution-vault/) ### Timing Constraints The system enforces several timing-related constraints: * **Collateral Update Frequency**: Minters must update at least once per `updateCollateralInterval` * **Mint Delay**: Proposals must wait `mintDelay` seconds before execution * **Mint TTL**: Proposals expire after `mintTTL` seconds * **Earliest Collateral Update**: The timestamp for a new update must be greater than: * The last update timestamp * The latest proposed retrieval timestamp * `block.timestamp - updateCollateralInterval` ### Security Mechanisms The MinterGateway implements several safety features: * **Mint Delay & TTL (Time-To-Leave)**: Creates a time window for validators to review and potentially cancel mints * **Collateralization Caps**: Enforces maximum mint-to-collateral ratios (set by governance) * **Multi-signature Requirement**: Requires multiple validator signatures for collateral updates * **Strictly Ordered Validations**: Validator addresses must be provided in ascending order * **Timestamp Verification**: Prevents reuse of signatures and ensures freshness of collateral data * **Excess Yield Distribution**: Any yield generated by minters beyond what's distributed to earners goes to the TTG Vault (also called the Distribution Vault) ### Emergency Measures For extreme circumstances, the protocol includes additional safeguards: #### Mint Proposal Cancellation Validators can cancel suspicious mint proposals before they're executed, allowing them to quickly intervene if they detect potentially harmful minting activity. ```solidity function cancelMint(address minter_, uint256 mintId_) external onlyApprovedValidator { uint48 id_ = _mintProposals[minter_].id; if (id_ != mintId_ || id_ == 0) revert InvalidMintProposal(); delete _mintProposals[minter_]; emit MintCanceled(id_, minter_, msg.sender); } ``` #### Validator Freeze Validators can freeze minters to stop them from minting tokens for a governance-defined period: ```solidity function freezeMinter(address minter_) external onlyApprovedValidator returns (uint40 frozenUntil_) { unchecked { _minterStates[minter_].frozenUntilTimestamp = frozenUntil_ = uint40(block.timestamp) + minterFreezeTime(); } emit MinterFrozen(minter_, frozenUntil_); } ``` #### Minter Deactivation Governance can completely deactivate minters who have been removed from the approved list: ```solidity function deactivateMinter(address minter_) external onlyActiveMinter(minter_) returns (uint240 inactiveOwedM_) { if (isMinterApproved(minter_)) revert StillApprovedMinter(); // Implementation details for deactivation process } ``` Once deactivated, a minter cannot be reactivated, providing a permanent resolution for problematic minters. #### Open Redemption Anyone can burn $M tokens to repay a deactivated minter's debt: ```solidity function _repayForDeactivatedMinter(address minter_, uint240 maxAmount_) internal returns (uint240 amount_) { amount_ = UIntMath.min240(inactiveOwedMOf(minter_), maxAmount_); unchecked { _rawOwedM[minter_] -= amount_; totalInactiveOwedM -= amount_; } } ``` This creates an informal liquidation mechanism for deactivated minters. ### Validator Roles & Security Controls Validators are independent, trusted entities that form a critical security layer for the minting and burning processes within the `MinterGateway`. Their responsibilities and powers include: #### Core Responsibilities * **Collateral Verification**: Validators verify Minters' offchain collateral and provide cryptographic signatures for `updateCollateral` transactions. These signatures attest to the value and existence of the assets backing $M. * **Timestamping**: Signatures from Validators must include a secure timestamp to prevent replay attacks and ensure the freshness of collateral data. * **Enabling Offchain-Onchain Bridge**: Validators act as the crucial link ensuring the onchain representation of collateral accurately reflects the state of offchain assets. #### Security Controls & Emergency Powers Validators are empowered with specific functions to intervene and protect the protocol: 1. **Cancel Mint Proposal**: If Validators deem a pending mint proposal to be suspicious, invalid, or potentially harmful to the protocol, they can cancel it before execution: ```solidity function cancelMint(address minter, uint256 mintId) external onlyApprovedValidator; ``` This action deletes the mint proposal, preventing the Minter from executing it. 2. **Freeze Minter**: Validators can temporarily suspend a Minter's ability to mint new $M tokens: ```solidity function freezeMinter(address minter) external onlyApprovedValidator returns (uint40 frozenUntil_); ``` This "freezes" the Minter for a duration specified by the governance parameter `MINTER_FREEZE_TIME`. A frozen Minter can still burn $M and update collateral but cannot propose or execute new mints until the freeze period expires. These controls allow Validators to act as a rapid response mechanism against potential threats or misbehavior related to $M issuance. ### Overview The `MinterGateway` contract is the central component within the M0 Protocol responsible for orchestrating the entire lifecycle of `$M`. It governs the processes for minting and burning, manages the offchain collateral system that backs the supply, and tracks the debt obligations of Minters. This contract acts as the primary interface for Minters and Validators, ensuring that issuance is always securely collateralized and transparently managed according to protocol rules defined by M0 Governance. Its key responsibilities include: * Managing Minter activation, deactivation, and operational states. * Overseeing the collateral update process, including verification of offchain assets by Validators. * Enforcing the structured minting and burning procedures. * Calculating and applying interest, debt, and penalties for Minters. * Facilitating the collateral retrieval process for Minters. * Synchronizing its interest index with the `MToken` contract to maintain system-wide consistency. ### Minting & Burning Process The creation (minting) and destruction (burning) of $M tokens are strictly controlled by the `MinterGateway`. #### Minting $M The minting process is designed with security checkpoints involving a proposal, a delay, and execution: 1. **Update Collateral (Prerequisite)**: Before proposing a mint, a Minter must have an up-to-date and sufficient verified collateral value on record. 2. **Propose Mint**: An active Minter initiates a mint request by calling `proposeMint()`: This creates a mint proposal with a unique `mintId_`. The proposal specifies the amount of $M to be minted and the recipient address. This step allows Validators to review pending mints. ```solidity function proposeMint(uint256 amount, address destination) external returns (uint48 mintId_); ``` 3. **Delay Period**: A mandatory delay period (`MINT_DELAY`), set by governance, must pass after a mint is proposed before it can be executed. This window allows Validators to intervene (e.g., cancel the mint or freeze the Minter) if they detect any issues. 4. **Execute Mint**: After the `MINT_DELAY` has elapsed, and before the proposal expires (within `MINT_TTL` - Time To Live, also set by governance), the Minter can execute the mint by calling `mintM()`: This function mints the specified amount of $M to the destination address, provided the proposal is still valid, hasn't been canceled, the Minter isn't frozen, and the mint doesn't violate collateralization requirements. ```solidity function mintM(uint256 mintId) external; ``` The `MINT_DELAY` and `MINT_TTL` mechanisms create a secure time window for oversight, preventing immediate, unreviewed mints and ensuring proposals don't remain executable indefinitely. #### Burning $M $M tokens can be burned to reduce a Minter's outstanding debt. Any $M holder can initiate a burn against a specific Minter's debt: ```solidity function burnM(address minter, uint256 amount) external; ``` * **For Active Minters**: Burning $M reduces the principal of their interest-accruing debt (`activeOwedM`). * **For Deactivated Minters**: Burning $M reduces their fixed `inactiveOwedM`. This serves as an informal liquidation mechanism, allowing the market to help settle the obligations of a Minter who has exited the system. The `_repayForDeactivatedMinter` internal function handles this logic. ### Debt, Interest, and Penalties for Minters Minters incur debt for the $M tokens they mint and are charged interest on this debt. The `MinterGateway` manages this system. #### Debt and Interest * **Debt Accrual**: When a Minter mints $M, they incur an equivalent amount of debt. * **Continuous Indexing**: Minter debt, similar to `MToken` earning balances, is tracked using a continuous indexing system. The debt is stored as a principal amount that grows over time as interest accrues. * **Interest Rate Model**: The interest rate charged to Minters (`MINTER_RATE_MODEL`) is determined by an external smart contract, the address of which is set by M0 Governance and stored in the `TTGRegistrar`. * **`activeOwedM`**: This term represents the current total value of an active Minter's obligations, including all accrued interest. It is calculated by applying the current minter index to their principal debt. #### Total Owed $M Accounting The `MinterGateway` tracks various categories of Minter debt: * **Active Owed $M**: The sum of interest-accruing debt from all active Minters. * **Inactive Owed $M**: The sum of fixed, non-interest-accruing debt from all deactivated Minters. * **Total Owed $M**: The aggregate of `activeOwedM` and `inactiveOwedM`. * **Excess Owed $M**: The difference between `totalOwedM` (interest generated from Minters) and the total supply of $M (which grows at the earner rate). This excess, if positive, represents protocol revenue and is minted directly to the `DistributionVault` (TTGVault) during index updates. #### Penalties The protocol imposes penalties on Minters for failing to adhere to specific operational requirements, ensuring system discipline: 1. **Missed Collateral Updates Penalty**: If a Minter fails to update their collateral within the `UPDATE_COLLATERAL_INTERVAL`, a penalty is applied. * Calculation: `PENALTY_RATE * principalOfActiveOwedM * missedIntervals`. * This penalty is charged once per missed interval. 2. **Undercollateralization Penalty**: If a Minter's `activeOwedM` exceeds the maximum allowed by their verified collateral and the `MINT_RATIO`, they are penalized. * Calculation: `PENALTY_RATE * principalOfExcessOwedM * (timeSpan / UPDATE_COLLATERAL_INTERVAL)`. * This penalty is proportional to the amount and duration of the undercollateralization. Penalties are added to the Minter's debt. ### Minter Lifecycle & Management Minters are permissioned entities that interact with the `MinterGateway` to issue and manage $M. Their lifecycle within the protocol is characterized by several distinct statuses: 1. **Approved**: Minters are initially whitelisted by the M0 Two-Token Governance (TTG) system. At this stage, they are recognized by the protocol but cannot yet perform minting operations. 2. **Active**: An approved Minter must explicitly activate their status by calling `activateMinter()` on the `MinterGateway`. ```solidity function activateMinter(address minter_) external; ``` This function can only be called by the Minter themselves and transitions them to an operational state, allowing them to propose collateral updates and mint $M. The active status is stored locally within `MinterGateway` for gas efficiency. 3. **Frozen**: An active Minter can be temporarily restricted from minting $M by Validators (via `freezeMinter()`). During this state, the Minter can still burn $M to reduce their debt and update their collateral but cannot propose new mints. The freeze duration is determined by governance. 4. **Deactivated**: A Minter can be deactivated if they are removed from the governance-approved list. Deactivation is a permanent state, initiated by a call to `deactivateMinter()`. ```solidity function deactivateMinter(address minter_) external returns (uint240 inactiveOwedM_); ``` This function can be called if the Minter is no longer approved by TTG. Upon deactivation: * The Minter's outstanding debt, including accrued interest, is converted into a fixed `inactiveOwedM` amount which no longer accrues interest. * The Minter can no longer mint $M or propose collateral retrievals. * Their collateral remains to back their `inactiveOwedM`. * A deactivated Minter cannot be reactivated. This permanence optimizes gas by eliminating further status checks against the `TTGRegistrar`. ### Index Synchronization with $M token The `MinterGateway` and the `MToken` contract both utilize a continuous indexing mechanism to track the accrual of interest – for Minter debt in `MinterGateway` and for earner balances in `MToken`. It is crucial that these indices are synchronized. #### Synchronization Mechanism The `MinterGateway` ensures that whenever its own interest index for Minter obligations is updated, the `MToken`'s earning index is also updated simultaneously. This is achieved within the `MinterGateway.updateIndex()` function: ```solidity function updateIndex() public override(IContinuousIndexing, ContinuousIndexing) returns (uint128 index_) { uint240 excessOwedM_ = excessOwedM(); if (excessOwedM_ > 0) IMToken(mToken).mint(ttgVault, excessOwedM_); // Mint excess to TTG Vault // First, update the MinterGateway's own index and rate (for minter debt) index_ = super.updateIndex(); // Then, explicitly trigger an update of the MToken's index and rate (for earner yield) IMToken(mToken).updateIndex(); // Emit an event if this MinterGateway instance is also the MToken's MinterGateway // (This is relevant if MToken directly calls this contract for its own updates) if (address(this) == IMToken(mToken).minterGateway()) { emit MTokenIndexUpdated(IMToken(mToken).currentIndex(), IMToken(mToken).currentRate()); } } ``` This synchronized update ensures that the calculation of interest paid by Minters and yield distributed to Earners remains consistent and balanced across the protocol, reflecting the latest rates and system state. #### Triggers for Index Updates The `updateIndex()` function in `MinterGateway` (which in turn calls `MToken.updateIndex()`) is invoked during several key operations, ensuring indices are frequently updated: * When a Minter updates their collateral via `updateCollateral()`. * When $M tokens are minted via `mintM()`. * When $M tokens are burned via `burnM()`. * When a Minter is deactivated via `deactivateMinter()`. * When `MinterGateway.updateIndex()` is explicitly called by an external party. This frequent synchronization is vital for the accurate accounting of debts, yields, and the overall economic stability of the M0 Protocol. ### Collateral System $M is backed by offchain collateral, typically real-world assets like U.S. Treasury Bills held in Special Purpose Vehicles (SPVs). The `MinterGateway` manages the onchain representation and verification of this collateral. #### Offchain Backing & Onchain Representation Minters are responsible for maintaining sufficient eligible collateral offchain. The value of this collateral is reported onchain through the `MinterGateway`. #### Validator Verification Trusted, independent Validators play a crucial role in verifying the Minters' offchain collateral. They periodically assess the collateral and provide cryptographic signatures attesting to its value. #### Update Process Minters must regularly update their onchain collateral value to reflect the current state of their offchain reserves. This is done by calling the `updateCollateral` function: ```solidity function updateCollateral( uint256 collateral, uint256[] calldata retrievalIds, bytes32 metadataHash, address[] calldata validators, uint256[] calldata timestamps, bytes[] calldata signatures ) external returns (uint40 minTimestamp_); ``` Key aspects of the collateral update process: * **Frequency**: Minters must update their collateral within a governance-defined interval (e.g., `UPDATE_COLLATERAL_INTERVAL`, typically daily). Failure to do so results in their onchain collateral value being considered zero until a new valid update is provided. * **Validator Signatures**: A collateral update requires signatures from multiple approved Validators, meeting a minimum threshold set by governance (e.g., `UPDATE_COLLATERAL_THRESHOLD`). * Signatures must be provided with validator addresses in ascending order to prevent duplicates. * Each signature includes a timestamp which must be newer than the last signature from that specific validator for that Minter and must not be in the future. This prevents replay attacks. * Signatures use EIP-712 typed data specific to each validator. * **Collateral Expiration**: If a Minter fails to update their collateral within the `UPDATE_COLLATERAL_INTERVAL`, their effective onchain collateral value is treated as zero for all protocol calculations, potentially leading to penalties or an inability to mint. * **Collateralization Caps**: Minters must maintain a collateralization ratio above the governance-set `MINT_RATIO`. This ratio dictates the maximum amount of $M a Minter can have outstanding relative to their verified collateral. * **Earliest Update Timing**: A new collateral update's effective timestamp must be greater than: * The Minter's last update timestamp. * The timestamp of the Minter's latest proposed collateral retrieval. * `block.timestamp - UPDATE_COLLATERAL_INTERVAL` to ensure updates are reasonably current. ### Collateral Retrieval Process Minters can retrieve excess collateral from their backing SPV, provided the retrieval does not compromise their ability to back their outstanding $M debt. This process is managed onchain through the `MinterGateway` and requires Validator oversight. 1. **Propose Retrieval**: The Minter initiates a request to retrieve a specific amount of collateral by calling `proposeRetrieval()`: ```solidity function proposeRetrieval(uint256 collateral) external returns (uint48 retrievalId_); ``` This creates a pending retrieval proposal with a unique, sequential `retrievalId_`. The proposed retrieval amount is tracked in the `_pendingCollateralRetrievals` mapping and is immediately deducted from the Minter's effective collateral value for all ongoing calculations, ensuring the Minter remains adequately collateralized. The system prevents proposals that would lead to undercollateralization. 2. **Validator Inclusion & Resolution**: For a pending retrieval to be finalized, it must be explicitly included and approved by Validators in a subsequent `updateCollateral` transaction. * When Validators sign off on a Minter's collateral update, their signature digest includes the list of `retrievalIds` they are approving for resolution. * During the `updateCollateral` call, the `MinterGateway` processes these approved `retrievalIds`. The corresponding amounts are then considered formally retrieved, and their values are no longer deducted from the Minter's available collateral. This multi-step process ensures that collateral can only be effectively retrieved with explicit, signed approval from Validators as part of a standard, verified collateral update, maintaining the integrity of $M's backing. Multiple retrieval proposals can be resolved within a single `updateCollateral` transaction. ### Technical Mechanics #### Dual Balance System The dual balance system is one of the core innovations of the $M token, enabling it to function both as a standard stable token and a yield-bearing asset. ##### Two Balance Types | Non-Earning | Earning (allowed by governance) | | ---------------------------------------------------- | ------------------------------------------------------------------------------- | | Function exactly like regular ERC20 tokens | Automatically increase in value over time through continuous compounding | | Value remains constant unless explicitly transferred | Stored internally as "principal amounts" that get multiplied by a growing index | | Stored as actual token amounts in the contract | Interest accrues without requiring any transactions or claim process | #### Balance Conversions in $M token The `MToken` contract implements a dual accounting system that allows users and developers to leverage both non-earning and earning states. Understanding how the state changes work is crucial. ##### Non-earning to Earning Conversion Process When an approved user calls `startEarning()` to convert from non-earning to earning status: 1. The contract first checks if the user is approved as an earner in the M0 Governance system (via the `TTGRegistrar`). 2. The user's current token balance (let's call it `amount`) is read from storage. 3. This `amount` is converted to a smaller "principal amount" using the following calculation: ```math principalAmount = \frac{amount}{currentIndex} ``` where `currentIndex` started at 1.0 (represented as 1e12) and has been growing continuously based on the `EARNER_RATE_MODEL`. 4. The conversion rounds **down** in favor of the protocol (a tiny fraction may be left, contributing to protocol reserves). 5. The user's raw balance in storage (within the `_balances` mapping, specifically `MBalance.rawBalance`) is updated to this `principalAmount`. Their `MBalance.isEarning` flag is set to `true`. 6. Global accounting variables are updated: * `totalNonEarningSupply` is decreased by the original `amount`. * `principalOfTotalEarningSupply` is increased by the `principalAmount`. This `principalAmount` will continually grow in value as the `currentIndex` increases. The user doesn't see their token count change directly in the `rawBalance` storage, but when they check their balance through `balanceOf()`, the contract multiplies their `principalAmount` by the `currentIndex` to show their true balance including all earned interest. ##### Earning to Non-earning Conversion Process When a user calls `stopEarning()` to convert from earning to non-earning status: 1. The contract reads the user's current `principalAmount` from storage. 2. This principal is converted back to a "present amount" (actual token value) by multiplying: ```math presentAmount = principalAmount \times currentIndex ``` 3. The resulting `presentAmount` includes all interest earned up to that moment. The calculation of `presentAmount` from `principalAmount` is rounded **down** (`_getPresentAmountRoundedDown`). 4. The user's `rawBalance` in storage is updated to this `presentAmount`. Their `MBalance.isEarning` flag is set to `false`. 5. Global accounting variables are updated: * `totalNonEarningSupply` is increased by the `presentAmount`. * `principalOfTotalEarningSupply` is decreased by the `principalAmount`. After this conversion, the user's balance no longer earns interest but now includes all interest accrued up to the conversion point. Their balance will remain static until they perform another transaction or start earning again (if still approved). ##### Example to Illustrate Consider a user with 1,000 $M tokens in non-earning state, and the `currentIndex` is 1.05 (representing a 5% increase since inception): 1. When they call `startEarning()`: * `principalAmount = 1000 / 1.05 \approx 952.380952` (actual value depends on 6 decimals for $M and 12 decimals for index, then rounded down). Let's say it's `952.380952 * 10^6` as raw principal. * Their storage value for `rawBalance` becomes this principal. * `balanceOf()` returns `(principalAmount * 1.05 * 10^12) / 10^{12} \approx 1000 * 10^6`. 2. After time passes and the `currentIndex` grows to 1.08: * Their stored `rawBalance` (principal) is still `952.380952 * 10^6`. * `balanceOf()` now returns `(principalAmount * 1.08 * 10^12) / 10^{12} \approx 1028.571428 * 10^6`. 3. When they call `stopEarning()`: * `presentAmount = (principalAmount * 1.08 * 10^{12}) / 10^{12}` (rounded down). * Their storage value for `rawBalance` becomes this `presentAmount`. * `balanceOf()` now returns exactly this `presentAmount`. #### Transfer Mechanics Transfers in `MToken` handle accounts with different earning statuses: 1. **In-kind Transfers**: Between two accounts with the same earning status. * Between two earning accounts: The transfer involves principal amounts. The amount to be transferred is converted to its principal equivalent (rounded **up** if sender, effectively taking slightly more principal for the given token amount) and then adjusted in the sender's and receiver's principal balances. * Between two non-earning accounts: The transfer is a standard token amount transfer. 2. **Out-of-kind Transfers**: Between accounts with different earning statuses. * From earning to non-earning: The sender's earning balance (principal) is reduced (principal equivalent rounded **up**), and the receiver's non-earning balance (token amount) is increased by the specified token amount. * From non-earning to earning: The sender's non-earning balance (token amount) is reduced, and the receiver's earning balance is increased by the principal equivalent of the token amount (rounded **down**). #### Strategic Rounding The protocol employs consistent rounding rules that slightly favor the protocol to create a small buffer, enhancing system stability and protecting against potential exploitation. These small rounding differences accumulate as protocol reserves.
| Operation | From | To | Rounding Rule for Amount Conversion to Principal | Protocol Favored | Internal Function Involved (Illustrative) | | :------------------- | :--------- | :--------- | :--------------------------------------------------------------------------------------------- | :--------------- | :------------------------------------------ | | **Conversions** | | | | | | | Start Earning | Non-Earner | Earner | Principal from present amount rounded **DOWN** | Yes | `_getPrincipalAmountRoundedDown` | | Stop Earning | Earner | Non-Earner | Present amount from principal rounded **DOWN** (for the final balance calculation) | Yes | `_getPresentAmountRoundedDown` | | **Transfers** | | | | | | | Earner to Earner | Earner | Earner | Amount to principal for sender: rounded **UP**; for receiver: (principal transferred directly) | Sender: Yes | `_getPrincipalAmountRoundedUp` (sender) | | Earner to Non-Earner | Earner | Non-Earner | Amount to principal for sender: rounded **UP** | Yes | `_getPrincipalAmountRoundedUp` (sender) | | Non-Earner to Earner | Non-Earner | Earner | Amount to principal for receiver: rounded **DOWN** | Yes | `_getPrincipalAmountRoundedDown` (receiver) | | **Mint/Burn** | | | | | | | Mint to Earner | - | Earner | Amount to principal rounded **DOWN** | Yes | `_getPrincipalAmountRoundedDown` | | Burn from Earner | Earner | - | Amount to principal rounded **UP** | Yes | `_getPrincipalAmountRoundedUp` |
*(Note: The table simplifies complex interactions. Refer to the [`MToken.sol`](/home/technical-specifications/m-token/) contract for precise implementation details, especially `_transferOutOfKind`, `_transferAmountInKind`, `_addEarningAmount`, `_subtractEarningAmount`, `_addNonEarningAmount`, `_subtractNonEarningAmount`.)* #### Global Index & Continuous Compounding At the heart of the $M token's interest mechanism for earning balances is a global index that efficiently tracks the growth of all earning balances through continuous compound interest. ##### Index Mechanism * **Single Global Index**: A single shared growth factor (`latestIndex`) applies to all earning balances, making the system highly gas-efficient. * **Mathematical Relationship**: For an earning account, its `balanceOf()` is effectively `principalAmount * currentIndex`. * **Starting Point**: The index starts at 1.0 (represented as `1e12` internally due to 12 decimal places of precision for the index) and only increases over time. * **Index Storage**: The `MToken` contract inherits from `ContinuousIndexing`, which stores `latestIndex` (uint128) and `latestUpdateTimestamp` (uint40). ##### Mathematical Implementation The `MToken` contract implements true continuous compounding: * **Continuous Compounding Formula**: The index is updated using the formula `newIndex = oldIndex * e^(rate * timeElapsed / SECONDS_PER_YEAR)`. * **Interest Accumulation**: Interest compounds with every second that passes, with the `currentIndex()` function calculating the up-to-date index on-demand. * **Exponential Approximation**: The `e^x` function is implemented onchain using a Padé approximant R(4,4) for gas efficiency and precision: ```math e(x) \approx \frac{1 + \frac{x}{2} + \frac{3x^2}{28} + \frac{x^3}{84} + \frac{x^4}{1680}}{1 - \frac{x}{2} + \frac{3x^2}{28} - \frac{x^3}{84} + \frac{x^4}{1680}} ``` * **Rate Conversion**: Rates obtained from the `EARNER_RATE_MODEL` (in basis points) are converted to a scaled format suitable for the exponential calculations. * **Time Scaling**: Rates are scaled by the time elapsed (in seconds) divided by `SECONDS_PER_YEAR` (31,536,000). ##### Principal vs. Present Value The contract manages two key value concepts for earning balances: * **Principal Amount**: The base `rawBalance` (uint240, but effectively uint112 for principal part) stored for earning accounts. This is the amount that earns interest. * **Present Amount**: The current value of an earning balance, including all accrued interest, calculated as `principalAmount * currentIndex`. This is what `balanceOf()` returns. Conversion functions handle translations: * `_getPresentAmount(uint112 principalAmount_)` or `_getPresentAmountRoundedDown(uint112 principalAmount, uint128 index_)`: Multiplies principal by the current index. * `_getPrincipalAmountRoundedDown(uint240 presentAmount_)`: Divides present amount by the current index, rounded down. Used when adding to earning accounts. * `_getPrincipalAmountRoundedUp(uint240 presentAmount_)`: Divides present amount by the current index, rounded up. Used when subtracting from earning accounts. ##### Index Updates The global earning index (`latestIndex`) in `MToken` is updated by calling `updateIndex()`. This function is typically called: * By the `MinterGateway` during its own `updateIndex()` calls (e.g., during `mintM`, `burnM`, `updateCollateral`, `deactivateMinter`). This ensures synchronization between Minter interest payments and Earner yield accrual. * Internally within `MToken` before operations that change an account's earning status or modify `principalOfTotalEarningSupply`, such as: * `_startEarning()` * `_stopEarning()` * Minting directly to an earning account via `_mint()`. * Burning directly from an earning account via `_burn()`. * Transfers that involve an earning account (`_transferOutOfKind`, `_transferAmountInKind` for earning-to-earning). Each `MToken.updateIndex()` call: 1. Fetches the current earner rate from the `EARNER_RATE_MODEL` (address obtained from `TTGRegistrar`). 2. Calculates the time elapsed since `latestUpdateTimestamp`. 3. Computes the new index: `newIndex = latestIndex * e^(rate * timeElapsed / SECONDS_PER_YEAR)`. 4. Updates `latestIndex` and `latestUpdateTimestamp` in storage. ##### Precision and Efficiency * **Fixed-Point Arithmetic**: The index uses 12 decimal places of precision (scaled by `1e12`). $M balances have 6 decimals. * **Conservative Rounding**: All rounding strategies are designed to favor protocol safety, with small residuals contributing to protocol reserves. * **Gas Optimization**: The single global index is updated only when necessary and is shared across all earning accounts. * **Overflow Protection**: The index is capped at `type(uint128).max`. Principal amounts are also managed to prevent overflow in calculations. ### Security & Governance Interaction The security and behavior of the $M token are deeply intertwined with the M0 Protocol's governance and other core contracts. #### Supply Control * The total supply of $M is exclusively controlled by the `MinterGateway` contract. * `MToken.mint(address recipient, uint240 amount)` can only be called by the `minterGateway` address set in `MToken`. * `MToken.burn(address account, uint240 amount)` can only be called by the `minterGateway` address. This ensures that $M tokens are only created or destroyed as per the protocol's minting (collateral-backed) and burning (debt-repayment) rules managed by `MinterGateway`. #### Earning Mechanism Governance * **Earner Approval**: Whether an account can switch to an earning balance (`startEarning()`) is determined by M0 Governance. The `MToken` contract checks if an account is an approved earner by querying the `TTGRegistrar` (specifically, the `APPROVED_EARNERS` list or if `EARNERS_LIST_IGNORED` is true). ```solidity // Simplified check from _isApprovedEarner(address account_) function _isApprovedEarner(address account_) internal view returns (bool) { return ttgRegistrarReader.getBool("earners_list_ignored") || ttgRegistrarReader.listContains("earners", account_); } ``` * **Rate Model Control**: The interest rate for earners is determined by the `EARNER_RATE_MODEL`. The address of this model is a governance-controlled parameter stored in the `TTGRegistrar` and read by `MToken` during `updateIndex()`. #### Safety Controls for Earners * The `stopEarning(address account_)` function allows anyone to call it for an `account_` that is *no longer* on the `APPROVED_EARNERS` list. This is a crucial safety mechanism to prevent an account from continuing to accrue yield if its earner status is revoked by governance. ```solidity function stopEarning(address account_) external { if (_isApprovedEarner(account_)) revert IsApprovedEarner(); // Can only be called if account is NOT an approved earner _stopEarning(account_); } ``` #### Index Management and Synchronization * The `MToken.updateIndex()` function is critical for reflecting the correct yield. As mentioned, it's called by `MinterGateway` to ensure synchronization with Minter-side interest accruals and by `MToken` itself during critical state changes. This synchronization is vital for the protocol's economic balance. #### Rounding and Numerical Stability * The consistent use of protocol-favoring rounding rules in conversions and transfers contributes to the robustness of the $M token system. These small, accumulated amounts act as a buffer and eventually contribute to protocol reserves (e.g., claimable by the `DistributionVault`). * Explicit overflow checks and the use of libraries like `UIntMath` and `ContinuousIndexingMath` ensure numerical precision and prevent errors during balance and index calculations. #### Immutability The `MToken` contract itself is designed to be immutable, meaning its core logic cannot be upgraded directly. Changes to its behavior (like interest rates or earner eligibility) are managed externally through governance-controlled parameters in the `TTGRegistrar` and updatable Rate Model contracts. import ZoomableImage from "@/components/ZoomableImage"; ### Overview *M is for Money.*
`$M` is an immutable ERC20-compliant token at the heart of the M0 Ecosystem. It serves as the foundational building block for all M0 Extensions. Each unit is backed 1:1 by approved collateral. It implements an innovative dual-balance accounting system: 1. **Non-earning Balances**: Standard ERC20-style token balances that remain static over time — non-rebasing amounts do not increase without external transactions. 2. **Earning Balances**: Token balances that automatically increase in quantity over time through continuous compounding. Holders with earning balances receive additional tokens without requiring any transactions. This rebasing mechanism means users see their token count grow as interest accrues continuously, with their viewable balance updating in real-time (per block). This design separates standard token functionality from interest-bearing capabilities. The M0 Two-Token Governance (TTG) system determines which accounts are eligible to become Earners through an approval process recorded in the [`TTGRegistrar`](/home/technical-documentations/ttg-governance/overview/). `$M` interacts closely with several **key components** of the M0 Protocol: * **[`MinterGateway`](/home/technical-documentations/mintergateway/overview/)**: Controls the total supply through secure mint and burn operations. * **[`Rate Models`](/home/technical-documentations/rate-models/)**: External smart contracts that dynamically calculate the interest rates for both Minters and Earners. * **[`TTGRegistrar`](/home/technical-documentations/ttg-governance/overview/)**: The governance-controlled parameter store that, among other things, maintains the list of approved Earners and the addresses of the active Rate Models. * **[`DistributionVault`](/home/technical-documentations/distribution-vault/)**: Receives excess yield, which arises when the interest charged to Minters exceeds the yield distributed to Earners. ### Key Features and User Interactions * **Governance-Approved Yield Access**: Selected accounts can earn continuous yield after Two Token Governance (TTG) approval. * **Automatic Yield**: Earning balances grow continuously without requiring any user action. * **Transparency**: All interest calculations occur onchain with fully transparent mechanics. * **Efficiency**: A single token contract handles both stable (non-earning) and yield-generating (earning) use cases. * **Precision**: Advanced mathematical techniques are employed to ensure accurate interest calculations. * **Safety Mechanisms**: Protections are in place to ensure accounts removed from the `APPROVED_EARNERS` list by governance cannot continue earning. #### User Interactions ##### Basic Token Operations `$M` implements all standard ERC20 functions and includes additional features: * It has **6 decimal places** of precision for all operations. * Supports standard transfers (`transfer`, `transferFrom`), approvals (`approve`), and balance inquiries (`balanceOf`). * Includes support for EIP-2612 `permit` for gasless approvals. * Includes support for EIP-3009 for transfers with authorization (`transferWithAuthorization`, `receiveWithAuthorization`). ##### Earning Status Management Users can interact with the earning functionality through several key functions on the `MToken` contract: * `startEarning()`: Converts an account's regular (non-earning) balance to an earning balance. This function can only be called by an account for itself, and only if that account has been approved as an Earner by M0 Governance. * `stopEarning()`: Converts an account's earning balance back to a regular (non-earning) balance. The account retains all interest accrued up to that point. This can be called by the account owner. * `stopEarning(address account_)`: A safety function that allows anyone to stop the earning status for a specified `account_` if that account is no longer on the governance-approved `APPROVED_EARNERS` list. This ensures that accounts cannot continue to earn yield if their approval is revoked. ##### Balance Querying Several methods are available to check different aspects of balances: * `balanceOf(address account)`: Returns the current balance of the account. For earning accounts, this includes all accrued interest up to the current block. * `principalBalanceOf(address account)`: Returns the underlying principal amount for earning accounts. For non-earning accounts, this will be 0. * `isEarning(address account)`: Checks if an account is currently in earning mode. * `totalEarningSupply()`: Returns the total amount of tokens (present value including accrued interest) currently held in earning balances. * `totalNonEarningSupply()`: Returns the total amount of tokens held in non-earning balances. The `totalSupply()` is the sum of `totalEarningSupply()` and `totalNonEarningSupply()`. ## Underlying Technology ### Wormhole NTT (M Portal) M Portal (Standard) is built *using* the Wormhole Native Token Transfer (NTT) framework. * **Integration:** `HubPortal` and `SpokePortal` inherit from Wormhole's `NttManager` abstract contract. This provides the base functionality for interacting with Wormhole Transceivers, encoding/decoding messages, and handling standard NTT flows. * **Customization:** M0 extends this base functionality to: * Implement the specific Lock/Release (Hub) and Mint/Burn (Spoke) logic. * Handle the automatic unwrap/wrap mechanism for $M extensions. * Inject the M0-specific metadata (like `$M Earning Index`) into the `additionalPayload` field of standard NTT messages. * Define and handle custom message types for explicit metadata propagation. * **Abstraction:** Using the NTT framework allows M Portals to leverage Wormhole's established messaging infrastructure while focusing on M0-specific logic. ### Hyperlane (M Portal Lite) M Portal Lite uses Hyperlane as its messaging layer and features a more modular design. * **Integration:** The `Portal` contracts do **not** inherit from a bridge-specific contract. Instead, they hold an address of a contract that implements the generic `IBridge` interface. The `HyperlaneBridge.sol` contract is the concrete implementation that connects the Portals to the Hyperlane protocol. * **Decoupling:** This design decouples the token bridging logic from the cross-chain messaging logic. The Portals are only aware of the `IBridge` interface, making the system potentially adaptable to other messaging bridges in the future. * **Message Flow:** 1. A `Portal` contract calls `sendMessage()` on the configured `HyperlaneBridge`. 2. `HyperlaneBridge` formats the message and dispatches it through the Hyperlane `IMailbox` contract. 3. On the destination chain, the Hyperlane network delivers the message to the destination `HyperlaneBridge` by calling its `handle()` function. 4. The destination `HyperlaneBridge` authenticates the message (verifying it comes from the Mailbox and a known peer) and then calls `receiveMessage()` on its local `Portal` contract, delivering the payload. import ZoomableImage from "@/components/ZoomableImage"; ## M0 Cross-Chain Architecture: M Portals ### Overview #### Native Multichain $M The core objective of M0's multichain strategy is to make the native $M token accessible across various blockchains beyond Ethereum mainnet. This aims to provide users with a consistent experience, particularly regarding yield-earning capabilities, regardless of the chain they operate on, while maintaining Ethereum as the authoritative source for $M issuance and governance. **M Portals** are the set of smart contracts that facilitate this cross-chain functionality. They are responsible for bridging the $M token itself, as well as propagating essential system information like the yield index and governance parameters between Ethereum and connected Spoke chains. To cater to different ecosystem needs and technical requirements, M0 offers two distinct implementations of the Portal system. #### M Portal Implementations: Standard vs. Lite M0 provides two portal versions built on different underlying technologies. While they share the same core goal of bridging $M and its metadata, they have key differences in architecture, features, and chain support. 1. **M Portal (Standard):** The original, feature-rich implementation built on the **Wormhole Native Token Transfer (NTT)** framework. It is designed for maximum compatibility, supporting both EVM and non-EVM chains (like Solana) and allowing for spoke-to-spoke transfers. 2. **M Portal Lite:** A streamlined, gas-efficient, and more modular implementation built on the **Hyperlane** messaging protocol. It is designed specifically for **EVM-only environments**, follows a stricter hub-and-spoke model (no spoke-to-spoke transfers), and introduces enhanced security mechanisms and a developer-friendly upgradeable design. #### At a Glance: M Portal vs. M Portal Lite | Feature | M Portal (Standard) | M Portal Lite | | --------------------- | ---------------------------------- | ----------------------------------------------- | | **Bridge Technology** | Wormhole NTT | Hyperlane | | **Chain Support** | EVM & non-EVM (e.g., Solana) | EVM-only | | **Communication** | Hub-Spoke & Spoke-Spoke | Strictly Hub-Spoke | | **Contract Design** | Monolithic (inherits `NttManager`) | Modular & Extendable (uses `IBridge` interface) | | **Security Model** | Hub balance = Total locked | Hub tracks `bridgedPrincipal` per spoke chain | | **Chain IDs** | Wormhole `uint16` IDs | Standard EVM `uint256` IDs | ### The Hub-and-Spoke Model Both M Portal implementations employ a Hub-and-Spoke architecture for multichain deployment:
* **Hub Chain (Ethereum):** * The single source of truth for the native $M token (where it's initially minted and governed). * Hosts the `HubPortal` contract. * Token Mechanism: **Lock-and-Release**. When bridging *from* the Hub, $M tokens are locked. When bridging *back* to the Hub, these locked tokens are released. * Acts as the source for propagating the $M Earning Index and TTG Registrar values. * *(M Portal Lite Specific):* The `HubPortal` also tracks the principal amount of $M bridged to each spoke chain to ensure it never releases more tokens than were locked for that specific spoke. * **Spoke Chains (e.g., Optimism, Arbitrum):** * Host representations of the $M token. * Host `SpokePortal` contracts. * Token Mechanism: **Mint-and-Burn**. When bridging *to* a Spoke chain, a corresponding amount of $M representation is minted. When bridging *from* a Spoke chain, the $M representation is burned. * Receive and apply the $M Earning Index and TTG Registrar values propagated from the Hub. This model ensures that the canonical $M supply originates and is controlled solely on Ethereum, while Spoke chains manage representations backed by the locked tokens on the Hub. ## Metadata Propagation Beyond token value, M Portals are crucial for synchronizing the M0 protocol state across chains. The purpose and data are the same for both implementations, but the transport mechanism differs. * **Purpose:** To ensure yield calculations (`$M Earning Index`) and governance parameters (`TTG Registrar` values) are consistent between the Hub and all Spoke chains. * **Propagated Data:** * **$M Earning Index:** A continuously accruing value representing the aggregate yield earned within the M0 system on Ethereum. Propagating this allows the $M representation on Spoke chains to reflect the correct yield. * **TTG Registrar Values:** Key-value pairs stored in the `Registrar` contract on Ethereum, set by M0 governance (TTG). Examples include the `EARNERS_LIST` which dictates which addresses are eligible for yield. Propagation ensures Spoke chains respect Hub governance decisions. * **Propagation Mechanisms:** * **Implicit (with token transfers):** Every token transfer message from the `HubPortal` automatically includes the current `$M Earning Index` in its payload. The receiving `SpokePortal` uses this to update its local state. * **Explicit (on-demand):** Anyone can permissionlessly call functions on the `HubPortal` to send the latest metadata to a specific Spoke chain. * `sendMTokenIndex(uint16 destinationChainId)`: Sends the current $M Index to a specific Spoke chain. * `sendRegistrarKey(uint16 destinationChainId, bytes32 key)`: Sends the value associated with a specific key from the Hub `Registrar` to a Spoke `Registrar`. * `sendRegistrarListStatus(uint16 destinationChainId, bytes32 listKey, address entry)`: Sends the inclusion status of a specific address within a list (like `EARNERS_LIST`) in the Hub `Registrar` to the Spoke `Registrar`. * **Frequency:** Explicit updates are often triggered periodically by automated bots to ensure timely synchronization even without user transfer activity. ## Key Components ### Common Components * **User:** The EOA or contract initiating or receiving cross-chain transfers. * **$M Token:** The native ERC-20 compliant token contract deployed on Ethereum. * **Wrapped $M / Extensions:** ERC-20 wrappers for $M that must implement `wrap` and `unwrap` functions. * **`HubPortal` (Ethereum):** Manages locking/releasing of native $M and propagates metadata. * **`SpokePortal` (Spoke Chains):** Manages minting/burning of the Spoke chain's $M representation and receives metadata. ### M Portal (Wormhole) Specific Components * **Wormhole NTT Framework:** The underlying technology. `HubPortal` and `SpokePortal` inherit from its `NttManager` contract. * **Wormhole Transceiver:** A Wormhole contract on each chain that `NttManager` uses to send/receive low-level messages. * **Wormhole Core / Guardians / Relayers:** The fundamental Wormhole infrastructure that validates and delivers messages (VAAs). * **`MerkleTreeBuilder.sol`:** A contract used on the Hub to generate Merkle roots for propagating large datasets (like earner lists) efficiently to non-EVM chains like Solana. ### M Portal Lite (Hyperlane) Specific Components * **`IBridge.sol`:** A generic interface that decouples the Portal logic from the underlying bridge technology. * **`HyperlaneBridge.sol`:** The implementation of `IBridge` that interacts with the Hyperlane protocol (`IMailbox`) to send and receive messages. * **Hyperlane Mailbox / Relayers:** The core Hyperlane infrastructure for message dispatch, security, and delivery. * **Upgradeable Contracts:** `HubPortal` and `SpokePortal` are built using the OpenZeppelin Upgrades pattern, allowing for proxy-based upgrades. ## Developer Integration & Security Considerations * **Audits:** The M Portal contracts have undergone security audits. Refer to linked audit reports for findings and details. * **Upgradeability:** * **M Portal Lite:** Is designed as an upgradeable system using the UUPS proxy pattern (via OpenZeppelin Upgrades). This allows for seamless logic updates without requiring contract migration. * **M Portal (Standard):** The contracts are also designed to be upgradeable. * **Security Dependencies:** * **M Portal (Wormhole):** Security relies significantly on the integrity of the Wormhole Guardians and the NTT framework contracts. * **M Portal Lite (Hyperlane):** Security relies on the Hyperlane protocol, including its configured Interchain Security Modules (ISMs) and the correctness of the Hyperlane Relayer network. * **Key Security Feature (Lite):** The `bridgedPrincipal` tracking in the `HubPortal` of M Portal Lite provides an additional layer of accounting security, ensuring that the Hub cannot be drained of more tokens than were originally locked for a given spoke chain. * **Code Repositories:** * M Portal (Wormhole): [https://github.com/m0-foundation/m-portal](https://github.com/m0-foundation/m-portal) * M Portal Lite (Hyperlane): [https://github.com/m0-foundation/m-portal-lite](https://github.com/m0-foundation/m-portal-lite) * **External Documentation:** * Wormhole NTT Documentation: [https://docs.wormhole.com/wormhole/ntt/overview](https://docs.wormhole.com/wormhole/ntt/overview) * Hyperlane Documentation: [https://docs.hyperlane.xyz/](https://docs.hyperlane.xyz/) * **Audit Reports:** * M Portal (Wormhole): [https://github.com/m0-foundation/m-portal/tree/main/audits](https://github.com/m0-foundation/m-portal/tree/main/audits) * M Portal Lite (Hyperlane): [https://github.com/m0-foundation/m-portal-lite/tree/main/audits](https://github.com/m0-foundation/m-portal-lite/tree/main/audits) import ZoomableImage from "@/components/ZoomableImage"; ## Core Bridging Process The transfer of $M (or its extensions like Wrapped $M) between the Hub and Spoke chains follows a similar logical flow in both implementations, orchestrated by the Portals and their underlying messaging bridge. ### Transfer: Hub Chain -> Spoke Chain
1. **User Interaction:** The user initiates a transfer by calling a function on the `HubPortal` contract on Ethereum, specifying the destination chain and amount. Beforehand, users can call a function to get the estimated delivery fee for the cross-chain transaction. * **M Portal (Standard):** The function is `quoteDeliveryPrice`, inherited from the Wormhole NTT framework. * **M Portal Lite:** The function is `quoteTransfer`. After getting the fee and approving the `HubPortal` to spend their $M or Wrapped $M, the user makes the final transfer call. 2. **Token Handling:** * If the user transferred Wrapped $M, the `HubPortal` first unwraps it to the native $M token. * The native $M tokens are then **locked** within the `HubPortal` contract. * *(M Portal Lite Specific):* The `HubPortal` increments its internal `bridgedPrincipal` counter for the destination spoke chain. 3. **Message Creation & Sending:** * The `HubPortal` constructs a cross-chain message containing transfer details (amount, recipient, destination chain) and additional metadata (like the current $M Index). * It interacts with its configured bridge to send this message. * **M Portal (Wormhole):** Interacts with the Wormhole Transceiver via the `NttManager` logic to publish a message to the Wormhole network. * **M Portal Lite (Hyperlane):** Interacts with the `HyperlaneBridge` contract, which dispatches the message via the Hyperlane Mailbox. 4. Cross-Chain Relaying (Offchain): The message is validated by the underlying bridge's security mechanism (Wormhole Guardians or Hyperlane's Interchain Security Modules (ISMs)). Once validated, the message is delivered by relayers to the destination Spoke chain. 5. **Message Reception & Processing:** * The bridge contract on the Spoke chain receives the message and passes it to the `SpokePortal`. 6. **Token Minting & Delivery:** * The `SpokePortal` processes the message. * It **mints** the corresponding amount of the $M token representation on the Spoke chain. * If the original transfer was for Wrapped $M, the `SpokePortal` wraps the newly minted $M. * The final token is transferred to the recipient address on the Spoke chain. ### Transfer: Spoke Chain -> Hub Chain This is largely the reverse process. 1. **User Interaction:** User calls the `SpokePortal` on a Spoke chain to send tokens back to the Hub. 2. **Token Handling:** * If transferring Wrapped $M, it's unwrapped to the native $M representation. * The native $M tokens are **burned** by the `SpokePortal`. 3. **Message Creation & Sending:** The `SpokePortal` sends a cross-chain message back to the Hub Chain (Ethereum). 4. **Cross-Chain Relaying:** The message is relayed back to Ethereum. 5. **Message Reception & Processing:** The bridge on Ethereum receives the message and passes it to the `HubPortal`. 6. **Token Releasing & Delivery:** * The `HubPortal` processes the message and **releases** (unlocks) the equivalent amount of native $M tokens. * *(M Portal Lite Specific):* The `HubPortal` first verifies that the requested release amount does not exceed the `bridgedPrincipal` for that source spoke chain. It then decrements the `bridgedPrincipal` counter. * The released tokens (wrapped if necessary) are delivered to the recipient on Ethereum. ### Transfer: Spoke Chain -> Spoke Chain * **M Portal (Wormhole):** **Supported.** This process involves burning tokens on the source Spoke and minting them on the destination Spoke, with a message relayed via Wormhole. * **M Portal Lite (Hyperlane):** **Not Supported.** The system is strictly Hub-and-Spoke. To move assets between spokes, a user must first bridge back to the Hub (Ethereum) and then out to the new Spoke chain. ## M0 Extensions: Custom Stablecoins Built on the M0 Platform ### What Are M0 Extensions? M0 Extensions are the **application layer** of the M0 Protocol. They are custom ERC-20 stablecoins that developers build on the M0 platform, inheriting its security and yield properties while adding their own unique features, branding, and business logic. Think of M0 as the secure, collateralized foundation—like digital infrastructure. Extensions are the applications, products, and user experiences built on top of this foundation. ### The Extension Architecture ``` Your Custom Stablecoin (Extension) ↓ wraps/unwraps M0 (Foundation) ↓ backed by US Treasury Collateral ``` **Key Relationship:** Extensions are backed 1:1 by eligible collateral, meaning: * 1 Extension Token = 1 unit of value (always redeemable) * Extensions inherit the M0 platform's stability and regulatory clarity * Extension contracts can earn yield (if approved by governance) * Developers control how that yield flows to users, treasuries, or other destinations ### SwapFacility: The Conversion Engine **SwapFacility** is the central hub enabling seamless 1:1 conversions between M0 Extensions. It acts as the exclusive gateway for wrapping/unwrapping operations, ensuring perfect value preservation across the entire M0 ecosystem. All extensions must be governance-approved earners to participate, while permissioned extensions require additional authorized swapper roles. The contract implements advanced reentrancy protection and supports gasless transactions through permit functions. By concentrating all conversion logic in a single contract, SwapFacility creates **implicit liquidity** between all M0 Extensions without requiring separate trading pairs, making it the backbone of the M0 Extension ecosystem's interoperability. ### Why Build an Extension? #### Full Customization * **Yield Distribution**: Route yield to users, treasury, or split however you want * **Access Controls**: Implement KYC, geographic restrictions, or institutional-only access * **Fee Mechanisms**: Add transaction fees, management fees, or revenue sharing * **Branding**: Create a fully branded stablecoin (YourAppUSD) or keep it generic #### Inherited Benefits * **Regulatory Clarity**: Built on M0's compliant, audited infrastructure * **Shared Liquidity**: Tap into the M0 ecosystem's shared liquidity layer * **Cross-Chain Ready**: Deploy on any chain where M0 operates * **Battle-Tested Security**: Leverage M0's proven collateral and governance systems #### Business Value * **Control**: Unlike integrating someone else's stablecoin, you own the user relationship * **Revenue**: Capture value through yield management and optional fees * **Flexibility**: Evolve your stablecoin's features as your needs change ### Common Extension Types #### Treasury Extensions Route 100% of yield to a single treasury address while providing users with a stable, non-rebasing token experience. **Use Cases**: Protocol treasuries, ecosystem development funds, corporate reserves #### User Yield Extensions Share yield with token holders while taking a small protocol fee for sustainability. **Use Cases**: DeFi protocols, consumer apps, yield savings accounts #### Institutional Extensions Provide granular, per-account control with custom fee arrangements and whitelisting. **Use Cases**: Prime brokerages, fintech platforms, institutional treasury management ### Who Should Build Extensions? **Recommended for:** * **Application Developers**: Games, payments, DeFi protocols wanting branded stablecoins * **Ecosystem Builders**: L1/L2 chains needing native stablecoins for their ecosystems * **Fintech Companies**: Businesses requiring custom compliance or yield distribution * **Treasury Managers**: Organizations needing yield-bearing accounts with specific controls **Consider Wrapped $M instead if:** * You just need standard DeFi integration (AMM pools, lending markets) * You prefer using an existing, established token rather than deploying your own ### Real-World Examples * [**Wrapped $M**](/home/technical-specifications/wrapped-m-token/): The "reference implementation" showing standard DeFi compatibility * [**Noble USD**](https://dollar.noble.xyz/): Cross-chain stablecoin serving the Cosmos ecosystem ### Technical Overview Extensions are smart contracts that: 1. **Inherit from MExtension.sol**: A base contract providing core wrap/unwrap functionality 2. **Implement Custom Logic**: Add your unique features, access controls, and yield distribution 3. **Gain Earner Approval**: Get governance approval to earn yield 4. **Deploy Anywhere**: Launch on Ethereum, L2s, or any supported chain **Key Functions Every Extension Must Implement:** * `wrap(recipient, amount)`: Convert to your extension token * `unwrap(recipient, amount)`: Convert your extension token back * Custom yield claiming/distribution logic (your choice how this works) ### Getting Started Ready to build your own stablecoin? The [Build section](/build/overview/) provides everything you need: * **Model Selection Guide**: Choose the right template for your use case * **Step-by-Step Deployment**: Deploy and configure your extension * **Earner Approval Process**: Get governance approval for yield earning * **Integration Examples**: Real code examples and best practices ## SwapFacility Deep Dive ### Architecture Overview SwapFacility serves as the universal router for the M0 Extension ecosystem, enabling atomic conversions between any approved M0 Extensions. The contract maintains minimal state while relying on the TTG governance system for extension approval and access control. #### Core Dependencies * **M Token Base**: The foundational rebasing token that backs all extensions * **TTG Registrar**: Governance-controlled registry that maintains the approved earners list * **ReentrancyLock**: Advanced protection using transient storage for atomic operations ### Swap Operations #### Extension-to-Extension Swaps ```solidity function swap(address extensionIn, address extensionOut, uint256 amount, address recipient) external ``` **Process Flow:** 1. Validates both extensions are approved earners via `_revertIfNotApprovedExtension()` 2. Transfers extension tokens from user to SwapFacility 3. Calls `extensionIn.unwrap()` to convert to $M 4. Measures actual $M received (accounts for rounding differences in v1 extensions) 5. Approves and calls `extensionOut.wrap()` to mint target extension tokens #### Direct $M Token Operations ```solidity function swapInM(address extensionOut, uint256 amount, address recipient) external function swapOutM(address extensionIn, uint256 amount, address recipient) external ``` **Access Control Differences:** * `swapInM`: Anyone can convert $M to extensions * `swapOutM`: Requires `M_SWAPPER_ROLE` or permission for specific extension ### Permission System #### Two-Tier Extension Model 1. **Standard Extensions**: Open for general extension-to-extension swaps 2. **Permissioned Extensions**: Require special authorization for $M conversions ```solidity function setPermissionedExtension(address extension, bool permissioned) external function setPermissionedMSwapper(address extension, address swapper, bool allowed) external ``` #### Role-Based Access * `DEFAULT_ADMIN_ROLE`: Contract administration and upgrades * `M_SWAPPER_ROLE`: Global permission for `swapOutM` operations on standard extensions ### Security Features #### Advanced Reentrancy Protection The contract inherits from `ReentrancyLock` which implements transient storage-based locking: ```solidity modifier isNotLocked() { if (Locker.get() != address(0)) revert ContractLocked(); address caller_ = isTrustedRouter(msg.sender) ? IMsgSender(msg.sender).msgSender() : msg.sender; Locker.set(caller_); _; Locker.set(address(0)); } ``` #### Trusted Router System For complex integrations (like UniswapV3SwapAdapter), trusted routers can specify the original caller: * Direct calls: `msg.sender` is stored as the locker * Trusted router calls: `IMsgSender(msg.sender).msgSender()` retrieves the original user Extensions can call `swapFacility.msgSender()` to get the true transaction initiator. #### Governance Integration All extension approvals are checked against the TTG Registrar: ```solidity function _isApprovedEarner(address extension) private view returns (bool) { return IRegistrarLike(registrar).get(EARNERS_LIST_IGNORED_KEY) != bytes32(0) || IRegistrarLike(registrar).listContains(EARNERS_LIST_NAME, extension); } ``` ### Gas Optimization #### Permit Integration All swap functions include permit variants supporting both EIP-2612 and EIP-712 signatures: ```solidity function swapWithPermit(..., uint256 deadline, uint8 v, bytes32 r, bytes32 s) external function swapWithPermit(..., uint256 deadline, bytes calldata signature) external ``` #### Balance Tracking Precision For compatibility with Wrapped $M v1, the contract measures actual balance changes: ```solidity uint256 mBalanceBefore = _mBalanceOf(address(this)); IMExtension(extensionIn).unwrap(address(this), amount); amount = _mBalanceOf(address(this)) - mBalanceBefore; ``` ### Technical Implementation #### Immutable Architecture ```solidity address public immutable mToken; address public immutable registrar; ``` Core dependencies are immutable for security, while operational parameters remain upgradeable. #### State Management The contract maintains minimal state: * `permissionedExtensions`: Extensions requiring special authorization * `permissionedMSwappers`: Authorized swappers for specific permissioned extensions #### Event System ```solidity event Swapped(address indexed extensionIn, address indexed extensionOut, uint256 amount, address indexed recipient); event SwappedInM(address indexed extensionOut, uint256 amount, address indexed recipient); event SwappedOutM(address indexed extensionIn, uint256 amount, address indexed recipient); ``` ### Economic Guarantees SwapFacility maintains perfect 1:1 value relationships by design: * No slippage or trading fees * Atomic execution prevents arbitrage * All conversions preserve dollar parity * Extensions remain fully backed by eligible collateral The contract creates implicit liquidity between all M0 Extensions without requiring separate AMM pools, enabling seamless cross-extension value transfer. import ZoomableImage from '@/components/ZoomableImage'; ## Distribution Vault Also called `TTGVault` or `Vault`. ### Overview The Distribution Vault is a core component of M0's economic infrastructure designed to collect, account for, and distribute various forms of protocol revenue and yield to Zero token holders. It serves as the primary mechanism for value capture within the protocol's Two Token Governance (TTG) system, turning protocol operations into direct economic benefits for governance participants. ### Purpose and Role in the Ecosystem The Distribution Vault functions as: 1. **Revenue Collector**: Accumulates various forms of protocol revenue from multiple sources 2. **Yield Distributor**: Enables proportional distribution of accumulated tokens to Zero token holders 3. **Value Capture Mechanism**: Creates a direct incentive for governance participation 4. **Economic Bridge**: Links protocol activity with governance token value ### Architecture Overview The Distribution Vault is referenced throughout the system as `TTGVault` or simply `vault`. Its address is established during deployment and made accessible to other core contracts via the `Registrar` or specific deployer contracts.
### Revenue Sources The Distribution Vault accumulates tokens from four primary sources: #### 1. Excess Yield (from `MinterGateway`) This represents a continuous source of revenue coming from the interest rate spread between minters and earners. **Mechanism:** * The `MinterGateway.updateIndex()` function calculates `excessOwedM()` - the difference between total owed $M (based on minter interest rate) and actual total $M supply (growing at the earner interest rate) * When positive, this excess amount is minted directly to the Distribution Vault **Origin of Excess:** * **Interest Rate Spread**: The inherent difference between the higher interest rate charged to minters vs. the lower rate paid to earners (capped at 98% of the "safe rate") * **Rounding Differences**: Accumulated from principal-to-present value conversions within the continuous indexing math * **Penalties**: Charges imposed on minters for missed collateral updates or undercollateralization **Code Implementation:** ```solidity // In MinterGateway.sol function updateIndex() public override(IContinuousIndexing, ContinuousIndexing) returns (uint128 index_) { uint240 excessOwedM_ = excessOwedM(); if (excessOwedM_ > 0) IMToken(mToken).mint(ttgVault, excessOwedM_); // Mint $M to TTG Vault index_ = super.updateIndex(); // Update minter index and rate IMToken(mToken).updateIndex(); // Update earning index and rate } ``` #### 2. Power token Auction Proceeds (from Power token) The Power token contract auctions off newly inflated tokens in non-voting epochs, with proceeds directed to the vault. **Mechanism:** * Power token employs a Dutch auction mechanism where price decreases over time * When users purchase Power token via the `buy()` function, the calculated cost in `cashToken` is sent to the Distribution Vault **Code Implementation:** ```solidity // In Power token.sol function buy( uint256 minAmount_, uint256 maxAmount_, address destination_, uint16 expiryEpoch_ ) external returns (uint240 amount_, uint256 cost_) { // ... calculations for amount_ and cost_ ... emit Buy(msg.sender, amount_, cost_ = getCost(amount_)); _mint(destination_, amount_); if (!ERC20Helper.transferFrom(cashToken(), msg.sender, vault, cost_)) revert TransferFromFailed(); } ``` #### 3. Forfeited Standard Governor Proposal Fees (from `StandardGovernor`) Fees submitted with proposals in the `StandardGovernor` flow to the Distribution Vault if the proposal fails. **Mechanism:** * When creating a proposal via \`\`StandardGovernor`.propose()`, proposers pay a fee in the system's `cashToken` * If the proposal succeeds, the fee is returned to the proposer * If the proposal is defeated or expires, the fee is sent to the Distribution Vault via `sendProposalFeeToVault()` **Code Implementation:** ```solidity // In `StandardGovernor`.sol function sendProposalFeeToVault(uint256 proposalId_) external { ProposalState state_ = state(proposalId_); if (state_ != ProposalState.Expired && state_ != ProposalState.Defeated) revert FeeNotDestinedForVault(state_); uint256 proposalFee_ = _proposalFees[proposalId_].fee; if (proposalFee_ == 0) revert NoFeeToSend(); address cashToken_ = _proposalFees[proposalId_].cashToken; delete _proposalFees[proposalId_]; emit ProposalFeeSentToVault(proposalId_, cashToken_, proposalFee_); _transfer(cashToken_, vault, proposalFee_); } ``` #### 4. Direct/Arbitrary Transfers The Distribution Vault can receive tokens via direct transfers from any account or contract. These tokens need to be explicitly "registered" for distribution. **Mechanism:** * Tokens can be transferred directly to the vault contract address at any time using a standard ERC20 `transfer` or `transferFrom`. * To make these externally transferred tokens available for claiming, the external `distribute(token)` function must be called for the specific `token_` address. * The `distribute(token)` function calculates the increase in the vault's balance of `token_` since the last time distribute was called for that token (using the internal `_lastTokenBalances` tracking). It then registers this newly available amount (`amount_`) within the `currentEpoch_` (the epoch when `distribute()` is called). * Crucially, Zero token holders who held tokens *during* this `currentEpoch_` become eligible to claim a share of this distributed `amount_`. The claimable share for each eligible holder is calculated pro-rata based on their fractional Zero token ownership as snapshotted at the *end* of that specific `currentEpoch_`. **Code Implementation:** ```solidity // In DistributionVault.sol function distribute(address token_) external returns (uint256 amount_) { uint256 currentEpoch_ = clock(); amount_ = getDistributable(token_); emit Distribution(token_, currentEpoch_, amount_); unchecked { distributionOfAt[token_][currentEpoch_] += amount_; // Add to the distribution for the current epoch _lastTokenBalances[token_] += amount_; // Track this contract's latest balance } } function getDistributable(address token_) public view returns (uint256) { return IERC20(token_).balanceOf(address(this)) - _lastTokenBalances[token_]; } ``` ### Distribution Mechanism The Distribution Vault implements a sophisticated epoch-based, pro-rata distribution system that ensures fair allocation of accumulated tokens to Zero token holders. #### Core Mechanics 1. **Epoch-Based Accounting**: Each token distribution is recorded in the current epoch (a time period, typically 15 days) 2. **Historical Balances**: Claims are calculated based on Zero token holders' balances during past epochs 3. **Pro-Rata Distribution**: Tokens are distributed proportionally to Zero token holdings 4. **Claimable Design**: Zero token holders must claim their share of distributed tokens #### Distribution Process 1. **Accumulation**: Tokens flow into the vault through various mechanisms 2. **Registration**: The `distribute(token)` function is called, recording the new token amount for the current epoch 3. **Claiming**: Zero token holders call `claim()` or `claimBySig()` to receive their share for specific epochs 4. **Calculation**: The claimable amount is computed based on the holder's proportional ownership during each claimed epoch #### Key Functions ```solidity // Allows claiming tokens for a specific address function claim( address token_, uint256 startEpoch_, uint256 endEpoch_, address destination_ ) external returns (uint256 claimed_) // Allows claiming with a signature (helpful for gas-less transactions) function claimBySig( address account_, address token_, uint256 startEpoch_, uint256 endEpoch_, address destination_, uint256 deadline_, bytes memory signature_ ) external returns (uint256 claimed_) // Calculates the claimable amount for a given address, token, and epoch range function getClaimable( address token_, address account_, uint256 startEpoch_, uint256 endEpoch_ ) public view returns (uint256 claimable_) ``` ### Technical Implementation Details #### Contract Structure The Distribution Vault inherits from StatefulERC712, which provides EIP-712 signature verification functionality: ```solidity contract DistributionVault is IDistributionVault, StatefulERC712 { // ... implementation ... } ``` #### Key State Variables ```solidity // The scale to apply when accumulating an account's claimable token to minimize precision loss uint256 internal constant _GRANULARITY = 1e9; // EIP-712 typehash for claim function bytes32 public constant CLAIM_TYPEHASH = 0x4b4633c3c305de33d5d9cf70f2712f26961648cd68d020c2556a9e43be58051d; // Address of the Zero Token contract address public immutable zeroToken; // Mapping of last recorded balance per token mapping(address token => uint256 balance) internal _lastTokenBalances; // Mapping of distributions per token, epoch, and amount mapping(address token => mapping(uint256 epoch => uint256 amount)) public distributionOfAt; // Mapping of claimed status per token, epoch, and account mapping(address token => mapping(uint256 epoch => mapping(address account => bool claimed))) public hasClaimed; ``` #### Signature-Based Claims The Distribution Vault supports signature-based claims, allowing users to authorize others to claim on their behalf: ```solidity function claimBySig( address account_, address token_, uint256 startEpoch_, uint256 endEpoch_, address destination_, uint256 deadline_, uint8 v_, bytes32 r_, bytes32 s_ ) external returns (uint256) { // ... signature verification logic ... // ... deadline verification ... return _claim(account_, token_, startEpoch_, endEpoch_, destination_); } ``` ### Economic Implications The Distribution Vault creates several important economic effects: 1. **Zero token Value Accrual**: By directing protocol revenue to Zero token holders, it increases the token's economic value 2. **Governance Incentive Alignment**: Creates a direct financial incentive for governance participation 3. **Sustainable Protocol Economics**: Ensures that excess yield and protocol fees flow back to governance participants 4. **Diversified Revenue Streams**: Collects different token types from multiple sources, creating a robust revenue model ### Integration with the Wrapped $M Token (Extended) The Distribution Vault also interacts with the Wrapped $M (wM) system: 1. **Excess Yield Destination**: The wM contract can send excess yield to the Distribution Vault via its `claimExcess()` function 2. **Economic Loop Completion**: This creates a complete economic loop where even wrapped token operations can generate value for governance participants ### Conclusion The Distribution Vault stands as a critical infrastructure component in the M0 protocol, serving as the central hub for value capture and redistribution. Through its sophisticated pro-rata distribution mechanism, it ensures that protocol operations consistently generate value for governance participants, creating strong economic incentives for system participation and alignment. By collecting revenue from multiple sources and making it claimable by Zero token holders, the vault creates a direct financial link between protocol usage and governance value, strengthening the economic sustainability of the entire ecosystem. One can check straight on the [dashboard](http://dashboard.m0.org) the number of $M accumulated by the vault and not claimed so far. import ZoomableImage from "@/components/ZoomableImage"; ## Protocol Overview Welcome to the core of the M0 documentation. This section is a comprehensive, first-principles exploration of the M0 Protocol. Here, you will find the foundational documents, detailed technical architecture, and smart contract specifications that define how the M0 ecosystem functions onchain and offchain. This is the definitive reference for developers, auditors, and partners who require a deep and thorough understanding of the system.
High-level architecture showing how M0 Governance configures the protocol's core components.
### Explore the M0 Protocol This section is organized into three main pillars, moving from the conceptual to the highly technical. export function CardGrid() { const cards = [ { title: 'Whitepaper', description: 'The core M0 protocol is a coordination layer enabling permissioned actors to generate M0-powered stablecoins with a fungible building block.', href: '/home/fundamentals/whitepaper/', iconClass: 'homepageCardImage-notebook', // Using an existing icon class }, { title: 'Adopted Guidance', description: 'The Adopted Guidance outlines the core rules of engagement that exist outside of the enforceable domain of the protocol smart contracts for the various actors in the M0 ecosystem.', href: '/home/fundamentals/adopted-guidance/description/', iconClass: 'homepageCardImage-notebook', // Using an existing icon class }, { title: 'Technical Documentation', description: 'Dive into the "how". Explore detailed explanations of each core smart contract and system, from token mechanics and governance to cross-chain architecture.', href: '/home/technical-documentations/m-token/overview/', iconClass: 'homepageCardImage-flow', // Using an existing icon class }, { title: 'Technical Specifications', description: 'For deep integration. Access low-level smart contract references, function definitions, events, and errors for the core M0 assets.', href: '/home/technical-specifications/m-token/', iconClass: 'homepageCardImage-playlist', // Using an existing icon class }, ] return (
{cards.map((card, index) => (

{card.title}

{card.description}
))}
) } ## Whitepaper The core M0 protocol is a coordination layer enabling permissioned actors to generate $M, a fungible stablecoin building block. ### Table of Contents *** ##### [Abstract](/home/fundamentals/whitepaper/abstract/) ##### [I. Introduction](/home/fundamentals/whitepaper/introduction/) ##### [II. Protocol](/home/fundamentals/whitepaper/protocol/) ##### [III. Governance](/home/fundamentals/whitepaper/governance/) ##### [IV. The M0 Economy](/home/fundamentals/whitepaper/economy/) ##### [V. Offchain Ecosystem](/home/fundamentals/whitepaper/offchain-ecosystem/) *** ##### [Glossary](/get-started/resources/glossary/) ##### [Whitepaper Disclosures](/get-started/resources/disclosures/) *** ##### [Download PDF Version](https://github.com/m0-foundation/documentation/tree/main/whitepaper) import ZoomableImage from '@/components/ZoomableImage'; ## II. Protocol The M0 protocol is a set of immutable smart contracts implemented for the Ethereum Virtual Machine. The M0 protocol receives all external inputs from a governance mechanism called the M0 Two Token Governor, [TTG](/get-started/resources/glossary/#ttg), (see [Governance](/home/fundamentals/whitepaper/governance/)). The M0 protocol is a coordination tool for actors permissioned by governance, namely [Minters](/get-started/resources/glossary/#minter), [validators](/get-started/resources/glossary/#validator), and [Earners](/get-started/resources/glossary/#earner). ### II.I Operation The M0 Protocol is permissioned through the Two Token Governor ([TTG](/get-started/resources/glossary/#ttg)) mechanism. The primary actors in the protocol are called [Minters](/get-started/resources/glossary/#minter) and [validators](/get-started/resources/glossary/#validator) (see [Governance Controlled Protocol Actors](/home/fundamentals/whitepaper/protocol/#iiii-governance-controlled-protocol-actors)). Once permissioned by the [TTG](/get-started/resources/glossary/#ttg), [Minters](/get-started/resources/glossary/#minter) and [validators](/get-started/resources/glossary/#validator) are able to access certain methods in the smart contracts which facilitate the creation, maintenance, and destruction of $M. $M is a standard ERC20 token. The core operating condition of the M0 protocol is to ensure that all $M in existence is backed by an equal or greater amount of [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) value that is held in an [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution) (see [offchain Actors and Components](/home/fundamentals/whitepaper/offchain-ecosystem/#offchain-actors-and-components)). \:::note In this context, the protocol acts as the enforcer of a set of rules which controls the generation of M, the validation of collateral custody and value, and the assessment of fees when appropriate. ::: #### II.I.I Generation of M In order to generate $M, [Minters](/get-started/resources/glossary/#minter) must have a sufficient offchain balance of [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) which is represented onchain by a frequently updated and validated number, known as the onchain Collateral Value. [Minters](/get-started/resources/glossary/#minter) call the Update Collateral method to put this number onchain. They must pass the amount, the list of signing [validators](/get-started/resources/glossary/#validator), a list of timestamps associated with the Validator signatures, and valid signature data (from [validators](/get-started/resources/glossary/#validator)). Whenever timestamps and signature data is passed to a method, the contracts will take the minimum timestamp and the minimum threshold of signatures as defined by the [TTG](/get-started/resources/glossary/#ttg) (see [Governance Controlled TTG Parameters](/home/fundamentals/whitepaper/governance/#governance-controlled-ttg-parameters-1)). Optionally, they can pass a hash of arbitrary metadata and any open Retrieval IDs (see [Retrieving Free Collateral](/home/fundamentals/whitepaper/protocol/#retrieving-free-collateral)) into the method as an argument. The Metadata Hash can be used to retrieve the actual offchain metadata, which can serve to add context to the update, while Retrieval IDs allow [Minters](/get-started/resources/glossary/#minter) to remove outstanding balance subtractions (see [Retrieving Free Collateral](/home/fundamentals/whitepaper/protocol/#retrieving-free-collateral)). Signature validation may either use standard ecrecover, which allows for the Minter to obtain the signature offchain, or [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) onchain contract signatures. The collateral balance is an attestation to the value of the [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) held in an [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution) (see [offchain Actors and Components](/home/fundamentals/whitepaper/offchain-ecosystem/#offchain-actors-and-components) for further details). In order to post the value of their [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) onchain, the [Minters](/get-started/resources/glossary/#minter) will need to provide the signature data (from [validators](/get-started/resources/glossary/#validator)) in the transaction. The presence of the Validator’s signature is to reinforce that the value of the [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) is correct and reflects the most up-to-date snapshot of the offchain balances. [Minters](/get-started/resources/glossary/#minter) must update their [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) number onchain and with a valid Validator signature at least once every [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) (see [Governance Controlled Protocol Parameters](/home/fundamentals/whitepaper/protocol/#governance-controlled-protocol-parameters)). If a Minter fails to call Update Collateral within [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) of the previous time they called it, their onchain Collateral Value is assumed to be 0. If the Minter cannot provide valid signature data (from [validators](/get-started/resources/glossary/#validator)), they cannot successfully call the method. Each time this method is called it will accrue the [Minter Rate](/get-started/resources/glossary/#minter-rate) (see [Protocol Fees](/home/fundamentals/whitepaper/protocol/#protocol-fees)) on the Minter’s current balance of Owed $M. If any rules are being violated at the time of the method being called, it will also charge [Penalty Rate](/get-started/resources/glossary/#penalty-rate) on the Minter’s balance which is in violation (see [Protocol Fees](/home/fundamentals/whitepaper/protocol/#protocol-fees)). \:::success **Example** [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) for $M has been deemed to be 0-90 day T-bills. Minter 1 has $10,000,000 of T-bills sitting in an [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution). Minter 1 calls Update Collateral and passes 10,000,000, and a valid Validator signature as arguments. The onchain Collateral Value of the Minter is now 10,000,000. The next day, $1,000,000 of the T-bills mature and convert to bank deposits, which are not considered [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral). The Minter calls Update Collateral and passes 9,000,000, and a valid Validator signature as arguments. The onchain collateral balance of the Minter is updated to 9,000,000. ::: Once a Minter has updated their onchain collateral they are able to generate $M. They do so by calling the Propose Mint method and passing in the amount of $M they’d like to generate and the address which they would like to generate the $M to. Once this method is called, it will first call Get Present Amount on the Minter's current balance of Owed $M. It will then check to ensure that the onchain Collateral Value multiplied by the [Mint Ratio](/get-started/resources/glossary/#mint-ratio) (see [Governance Controlled Protocol Parameters](/home/fundamentals/whitepaper/protocol/#governance-controlled-protocol-parameters)) is greater than the amount of total Owed $M from the Minter, including the amount they are currently attempting to generate and/or Retrieve (see [Retrieving Free Collateral](/home/fundamentals/whitepaper/protocol/#retrieving-free-collateral)). If these checks are passed the method will output a Mint ID which corresponds to the Propose Mint. A Minter can only have one outstanding Mint ID at any given time. If after the [Mint Delay](/get-started/resources/glossary/#mint-delay) (see [Governance Controlled Protocol Parameters](/home/fundamentals/whitepaper/protocol/#governance-controlled-protocol-parameters)) the Mint ID has not been canceled by the Validator (see [Cancel and Freeze](/home/fundamentals/whitepaper/protocol/#cancel-and-freeze)), the Minter may call the Mint method and pass the Mint ID as an argument to execute the Propose Mint. The [Mint Delay](/get-started/resources/glossary/#mint-delay) was introduced to avoid atomic Update Collateral calls and Mint calls, and to provide the network of [validators](/get-started/resources/glossary/#validator) with sufficient opportunity to intervene in the minting process if something is seemingly wrong (see [Cancel and Freeze](/home/fundamentals/whitepaper/protocol/#cancel-and-freeze)). The Minter must call Mint before the [Propose Mint Time To Live](/get-started/resources/glossary/#propose-mint-time-to-live) has expired (see [Governance Controlled Protocol Parameters](/home/fundamentals/whitepaper/protocol/#governance-controlled-protocol-parameters)). [Minters](/get-started/resources/glossary/#minter) can destroy Owed $M at any time by calling the Burn method and passing in their Minter Address and the amount of $M they’d like to burn as arguments. Any address can repay $M owed by a Minter by calling the Burn method and passing in the amount and Minter address as arguments.
#### II.I.II Protocol Fees There are two fees assessed on [Minters](/get-started/resources/glossary/#minter) in the M0 protocol. The first is called [Minter Rate](/get-started/resources/glossary/#minter-rate), a governance controlled parameter, which is levied continuously on the Minter’s balance of Owed $M. This fee compounds on a continuous basis. The beneficiaries of [Minter Rate](/get-started/resources/glossary/#minter-rate) are the Earn Mechanism (see [The Earn Mechanism](/home/fundamentals/whitepaper/protocol/#the-earn-mechanism)) and the [`ZERO`](/get-started/resources/glossary/#zero) holders (see [Governance](/home/fundamentals/whitepaper/governance/)). The second is [Penalty Rate](/get-started/resources/glossary/#penalty-rate), another governance controlled parameter, which is levied on balances that are in violation of protocol rules and has the same beneficiaries as the [Minter Rate](/get-started/resources/glossary/#minter-rate). \:::note One of the primary invariants of the protocol is that the balance of a Minter’s Owed $M should not exceed the onchain Collateral Value (sans open Retrieval IDs) multiplied by the [Mint Ratio](/get-started/resources/glossary/#mint-ratio). ::: [Penalty Rate](/get-started/resources/glossary/#penalty-rate) is imposed upon any balance in excess of this amount. If a Minter has not called Update Collateral within [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval), they will incur [Penalty Rate](/get-started/resources/glossary/#penalty-rate) on their entire balance of Owed $M for each [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) that they miss – i.e. when Update Collateral is not called in the [TTG](/get-started/resources/glossary/#ttg)-specified time the system interprets its value to be [`ZERO`](/get-started/resources/glossary/#zero). Unlike [Minter Rate](/get-started/resources/glossary/#minter-rate), [Penalty Rate](/get-started/resources/glossary/#penalty-rate) is not continuously levied on the Minter’s balance of Owed M, but is charged discretely as a one-time percentage fee on their delinquent balance at the moment the balance is checked, and then added to the Minter’s Owed $M. Collecting [Minter Rate](/get-started/resources/glossary/#minter-rate) is contained in the Get Present Amount method, which is exclusively embedded in all other Minter methods, including Burn, and cannot be called independently. The [Minter Rate](/get-started/resources/glossary/#minter-rate) is mechanically affected by updating a global index value which is applied to all Owed $M in the Minter’s balance, as is [Penalty Rate](/get-started/resources/glossary/#penalty-rate). [Penalty Rate](/get-started/resources/glossary/#penalty-rate) is contained in the Impose Penalty method, which is exclusively embedded in the Update Collateral, Burn and Deactivate Minter methods. When Impose Penalty is called in conjunction with Update Collateral, it checks for both missed [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) periods and the Minter’s balance of Owed $M relative to their onchain Collateral Value discounted by the [Mint Ratio](/get-started/resources/glossary/#mint-ratio). When it is called in conjunction with Burn, it only checks for missed [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) periods. This is done to ensure that the Minter is not penalized on the same errant balance more than once. Impose Penalty will also account for whether it has already been called in the current [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) period and will not charge a Minter twice for the same missed period. \:::success **Example** A Minter calls Update Collateral; the Get Present Amount method is called along with the Impose Penalty method. The Minter’s balance of Owed $M prior to the method call is 8,000,000 $M. First, Get Present Amount is used to fetch the latest index and apply the [Minter Rate](/get-started/resources/glossary/#minter-rate) to the Minter’s balance of Owed M, accounting for continuous compounding. Assume that this increases the Minter’s Owed $M to 8,000,010 M. If the Minter’s onchain Collateral Value is 8,000,000 and the [Mint Ratio](/get-started/resources/glossary/#mint-ratio) is 90%, then the maximum amount of Owed $M Minter 1 should have is 7,200,000 M– but the actual onchain number is 8,000,010 $M. Therefore Minter 1 will incur [Penalty Rate](/get-started/resources/glossary/#penalty-rate) on (8,000,010 $M - 7,200,000 M) = 800,010 $M. If [Penalty Rate](/get-started/resources/glossary/#penalty-rate) is 0.01%, then the Minter’s Owed $M is incremented to 8,000,010 $M + 800,010 M\* 1.0001 = 8,800,100.001 $M. ::: The following is a diagram which demonstrates a hypothetical sequence where a Minter incurs [Penalty Rate](/get-started/resources/glossary/#penalty-rate) charges. The example below describes this hypothetical sequence.
\:::success Example (some balances are rounded) Assume that the Mint to Collateral Ratio is 90%, [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) is 24 hours, [Minter Rate](/get-started/resources/glossary/#minter-rate) is 5% APY (and therefore \~0.00058% per hour), and Penalty [Minter Rate](/get-started/resources/glossary/#minter-rate) is 0.02%. * On Day 1, a Minter calls Update Collateral and passes in 100 as the value. Its Owed $M is 0. Later that day (Day 1.1) the Minter generates 90 $M. * On Day 2 the Minter fails to call Update Collateral. * On Day 3 the Minter calls Burn and passes in 50.043 $M. Assume that less than 48 hours have passed since the Mint call on Day 1. First, Get Present Amount is called and applies the latest index to the Minter’s balance of 90 $M. This increases the Minter’s Owed $M to (90 \_ (1 + (0.0000058 \_ 48))) = 90.025 $M. Next, Impose Penalty is called and is applied to the Minter’s updated balance. Since the Minter missed one [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) period (on Day 2), they are penalized one time. The Minter’s Owed $M is increased to (90.025 \_ (1 + (0.0002 \_ 1)) = 90.043 $M. The amount passed into the Burn method (50.043) is now subtracted from this new balance and reduces the Minter’s Owed $M to (90.043 - 50.043) = 40 $M. Recall that burn only checks for missed [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) periods and does not check the Minter’s current onchain Collateral Value and therefore does not penalize any currently errant balance. The Minter then calls Burn again on Day 3 and passes in 30.0014 $M. Assume 6 hours have passed since the previous Burn call. First, Get Present Amount is called and applies the latest index to the Minter’s balance of 40 $M. This increases the Minter’s Owed $M to (40 \_ (1 + (0.0000058 \_ 6))) = 40.0014 $M. Impose Penalty is then run but does not charge the Minter an additional [Penalty Rate](/get-started/resources/glossary/#penalty-rate) because it has already paid for all missed [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) periods. The amount passed into the Burn method (30.0014) is now subtracted from this new balance and reduces the Minter’s Owed $M to (40.0014 - 30.0014) = 10 $M. Finally, also on Day 3, the Minter calls Update Collateral and passes in 0 (most likely because their [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) has matured and is sitting in ineligible bank deposits). Assume another 6 hours have passed. Once again, Get Present Amount is run to apply the latest index to the Minter’s balance of $M. This increases the Minter’s Owed $M by (10 \_ (1 + (0.0000058 \_ 6))) = 10.00035 $M. Next Impose Penalty is called. There are no charges for missed periods because these were already paid when the Minter called Burn. A check for an errant balance is now run and produces 10.00035 $M since the Minter’s entire balance is in excess of their maximum permitted Owed $M due to the onchain Collateral Value being 0. The Minter’s Owed $M is increased to (10.00035 \* 1.0002) = 10.00235 $M. \::: #### II.I.III Cancel and Freeze An overview of the two methods which can be used to stop an errant generation of $M or to stop an errant Minter in the case of an emergency. The first method, Cancel, can be called by any Validator on any Mint ID associated with the generation of $M. The calling actor must pass the Mint ID as an argument to the method. Calling this method will cancel the specified Mint ID and cancel the proposal. The Cancel method can be called at any time until Mint is called. [Minters](/get-started/resources/glossary/#minter) do not have access to the Cancel method because submitting a new Propose Mint will automatically cancel and replace any that are currently outstanding. The second method, Freeze, can be called by any Validator on any Minter by passing the Minter address as the argument of the method. Calling Freeze will disable Propose Mint and Mint for [Minter Freeze Time](/get-started/resources/glossary/#minter-freeze-time) (see [Governance Controlled Protocol Parameters](/home/fundamentals/whitepaper/protocol/#governance-controlled-protocol-parameters)). It can be called multiple times on the same Minter to reset the [Minter Freeze Time](/get-started/resources/glossary/#minter-freeze-time) window. If Freeze is called during an already existing [Minter Freeze Time](/get-started/resources/glossary/#minter-freeze-time), the [Minter Freeze Time](/get-started/resources/glossary/#minter-freeze-time) window will restart from the beginning. \:::success **Example** A Validator calls Freeze on a Minter and the [Minter Freeze Time](/get-started/resources/glossary/#minter-freeze-time) window is 6 hours. After 5 hours, the Validator calls Freeze again on the same Minter. The Minter is now frozen for an additional 6 hours. This means that the Minter will be frozen for 11 hours in total, unless a Validator calls Freeze again before the end of the second 6 hour period. ::: These methods can be thought of as being a part of a series of escalations the system (first through [validators](/get-started/resources/glossary/#validator) and then through the [TTG](/get-started/resources/glossary/#ttg)) can levy against an errant Minter. The final escalation being removal of the Minter. Removal of a Minter would similarly be done via a [TTG](/get-started/resources/glossary/#ttg) proposal.
#### II.I.IV Retrieving Free Collateral This is an extensive description of the process of retrieving collateral. Any Minter with an excess of offchain value (both [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) and other forms of value that may reside in the [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution)) relative to their Owed $M, can remove this value from the [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution). They can do so by calling the Propose Retrieval method and passing the amount they wish to retrieve from custody. Like most methods this will first call Get Present Amount. After that it will check that the onchain Collateral Value, after subtracting the amount the Minter is trying to retrieve and any other open Retrieval IDs, is sufficient to support the Minter’s remaining balance of Owed $M. Unlike Propose Mint, which is limited to one Mint ID at a time, there is not a limit to the number of outstanding Retrieval IDs. If this check passes, it will sideline this balance to be deducted from future calculations where it is relevant. Finally it outputs a Retrieval ID. The subtraction from the onchain Collateral Value, when relevant, will remain until the Retrieval ID is closed. In order to close the Retrieval ID and eliminate the subtraction on the Minter’s onchain Collateral Value, the Minter must pass the Retrieval ID into an Update Collateral. In signing off on this transaction, the Validator is attesting that the Retrieval ID has been fully processed offchain, or will not be processed at all, and that the new onchain Collateral Value is correct.
#### II.I.V The Earn Mechanism This is an extensive description of the Earn mechanism within the M0 protocol. The Earn Mechanism is a mechanism in the protocol which allows Approved [Earners](/get-started/resources/glossary/#earner) (see [Governance Controlled Protocol Actors](/home/fundamentals/whitepaper/protocol/#governance-controlled-protocol-actors)) to earn the [Earner Rate](/get-started/resources/glossary/#earner-rate) (see [Governance Controlled Protocol Parameters](/home/fundamentals/whitepaper/protocol/#governance-controlled-protocol-parameters)). The [Earner Rate](/get-started/resources/glossary/#earner-rate), while input as an explicit value from the [TTG](/get-started/resources/glossary/#ttg), is bound in the smart contracts to be the lower of its input value or the maximum it can be without expending more $M than is accruing from [Minter Rate](/get-started/resources/glossary/#minter-rate). To elaborate, the utilization of the Earn Mechanism can be considered to be the total amount of Owed $M that is currently paying the [Minter Rate](/get-started/resources/glossary/#minter-rate) (hereon referred to as active M) divided by the total amount of $M in the Earn Mechanism. If a Minter is depermissioned by the [TTG](/get-started/resources/glossary/#ttg), their $M will be deducted from the active $M and thus lower utilization. The [Earner Rate](/get-started/resources/glossary/#earner-rate) is then the minimum of the value input by the [TTG](/get-started/resources/glossary/#ttg), or the [Minter Rate](/get-started/resources/glossary/#minter-rate) multiplied by utilization, which represents the lowest rate that would be safe to offer before more $M is being paid to [Earners](/get-started/resources/glossary/#earner) than is being collected from [Minters](/get-started/resources/glossary/#minter). Once approved by the [TTG](/get-started/resources/glossary/#ttg), an Approved Earner can call the Start Earning method. This will check if the address is on the Approved [Earners](/get-started/resources/glossary/#earner) list and if so the address will begin to earn the [Earner Rate](/get-started/resources/glossary/#earner-rate) on a continuously compounding basis. If an address is removed from the Earner’s list, Stop Earning can be called with the address in question passed as an argument to the method, which will cease the accrual of the [Earner Rate](/get-started/resources/glossary/#earner-rate) on the address’ balance. #### II.I.VI Removing a Permissioned Actor Overview of the process for removing permissioned actors in the M0 Protocol. Permissioned actors can be removed from the system by passing a proposal in the [TTG](/get-started/resources/glossary/#ttg) mechanism removing them from a specific list (e.g. the Minter list). Once an actor is removed they are no longer able to call the methods in the contracts, preventing them from engaging in further activity with the protocol. Once a Minter is removed from the Minter list, they cease to pay the [Minter Rate](/get-started/resources/glossary/#minter-rate) on their Owed $M. The value of current Owed $M, and potentially penalties for missed intervals, is stored for repayment by the Minter or anyone interested in their offchain collateral retrieval. This is to ensure that $M does not get paid to the Earn Mechanism and to the [`ZERO`](/get-started/resources/glossary/#zero) holders if a Minter is no longer actively in the system. The Burn method always remains available to anyone even if a Minter is no longer permissioned. This ensures that offchain actors can facilitate the wind-down of the Minter’s operations and destroy the Owed $M in order to retrieve the value from the [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution). Once a Minter is removed from the Minter list, any actor in the system can call the Deactivate Minter method to cease the accrual of [Minter Rate](/get-started/resources/glossary/#minter-rate) and the imposition of further [Penalty Rate](/get-started/resources/glossary/#penalty-rate) charges. #### II.I.VII Example Interactions and Flows The following is an example of how Permissioned Actors are intended to interact with the protocol, and how $M is intended to flow through the protocol. * **Step 1**: [Minters](/get-started/resources/glossary/#minter), [validators](/get-started/resources/glossary/#validator), and [Earners](/get-started/resources/glossary/#earner) propose their addresses to the M0 [TTG](/get-started/resources/glossary/#ttg). * **Step 2**: The [TTG](/get-started/resources/glossary/#ttg) accepts or rejects the proposals. * **Step 3**: [Minters](/get-started/resources/glossary/#minter) that were approved by the [TTG](/get-started/resources/glossary/#ttg) are now on the Minter List. These [Minters](/get-started/resources/glossary/#minter) call for their first onchain Collateral Value update. * **Step 4**: This Minter has contracted with at least one Validator offchain. The Validator(s) have full access to the records and statements of the [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution). The Validator(s) will check to ensure that the proposed onchain Collateral Value is less than the dollar value of the [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) in the [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution). Once they have confirmed this to be true, they will provide the Minter with their signature and a timestamp from when they performed the balance check. * **Step 5**: Once the Minter has obtained a valid signature and timestamp from the Validator(s) they will call Update Collateral to push the balance onchain. * **Step 6**: Now that the Minter has a positive onchain Collateral Value, they are able to generate $M. They will call the Propose Mint method and specify the amount they wish to generate. As long as this amount is within the bounds of the current onchain Collateral Value (excluding any open Retrieval IDs) multiplied by the [Mint Ratio](/get-started/resources/glossary/#mint-ratio), the method will output a Mint ID. This Mint ID will be inactionable for some [Mint Delay](/get-started/resources/glossary/#mint-delay), and then actionable for [Propose Mint Time To Live](/get-started/resources/glossary/#propose-mint-time-to-live). * **Step 7**: The Mint ID must be outstanding for [Mint Delay](/get-started/resources/glossary/#mint-delay). This is to ensure the superset of [validators](/get-started/resources/glossary/#validator) have the opportunity to scrutinize the Propose Mint and call the Cancel and/or Freeze methods if something is amiss. Once [Mint Delay](/get-started/resources/glossary/#mint-delay) has passed, the Minter can call Mint and generate the $M. * **Step 8**: Now that the $M is generated, the Minter begins to pay [Minter Rate](/get-started/resources/glossary/#minter-rate) on their Owed $M. They will be subject to [Penalty Rate](/get-started/resources/glossary/#penalty-rate) charges on this balance if they do not keep their onchain Collateral Value up to date or allow their onchain Collateral Value to decrease below the permitted level. If the latter circumstance occurs, it is likely because the assets comprising the offchain collateral have matured and are sitting in bank deposits. * **Step 9**: Assume that this Minter now wishes to repay some of the $M they have generated and to retrieve a portion of the collateral from the [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution). The Minter will first call Burn and specify the amount of $M they’d like to repay. This will reduce their Owed $M by this amount. Assuming that now there is a positive spread between the permitted amount of $M that the Minter can generate and their Owed M, they can call the Retrieve method. The Retrieve method will first check if their onchain Collateral Value, after the retrieval, is in compliance with the protocol’s rules. If it is, the method will output a Retrieval ID and reduce the Minter’s onchain Collateral Value by the amount specified. * **Step 10**: The Minter can now go to the operator of the [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution) and show them the Retrieval ID and request that they allow them to redeem the corresponding value. * **Step 11**: Once the transaction has completed and cleared the Minter will call Update Collateral and input the new Collateral Value and the Retrieval ID in order to remove the subtraction to onchain Collateral Value associated with the Retrieval ID. The Minter once again requires the Validator signature data and timestamp for the transaction to succeed. ### II.II Governance Controlled Protocol Actors List of Governance controlled protocol actors. ##### [Minters](/get-started/resources/glossary/#minter) A list of addresses (the Minter list, where the addresses are known as Minter address) maintained by the [TTG](/get-started/resources/glossary/#ttg) mechanism which are able to access the minting functionality. The minting functionality allows for addresses on the Minter list to update onchain Collateral Value associated with their Minter address, Propose Mint, Mint, Burn, and to Retrieve offchain collateral. ##### [Validators](/get-started/resources/glossary/#validator) A list of addresses (the Validator list, where the addresses are known as Validator address) maintained by the [TTG](/get-started/resources/glossary/#ttg) mechanism which act as a security layer for protocol. [validators](/get-started/resources/glossary/#validator) are required to provide signatures for the Update Collateral method. They also have the ability to call the Cancel method on any Mint ID, and the Freeze method on any Minter address. ##### [Earners](/get-started/resources/glossary/#earner) A list of addresses (the Earner list, where the addresses are known as Earner address) maintained by the [TTG](/get-started/resources/glossary/#ttg) mechanism. These addresses are able to control whether they earn the [Earner Rate](/get-started/resources/glossary/#earner-rate). ### II.III Governance Controlled Protocol Parameters \:::note These values will be set after launch through the [TTG](/get-started/resources/glossary/#ttg) mechanism. It is not possible to deploy the protocol with preset parameters. ::: ##### [Minter Rate](/get-started/resources/glossary/#minter-rate) The annualized percentage charged continuously to [Minters](/get-started/resources/glossary/#minter) on their Owed $M. It is alterable with a Standard Proposal. Logic: This annualized percentage should (generally) be less than the average rate on the [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) being earned by [Minters](/get-started/resources/glossary/#minter). This spread, adjusted for the [Mint Ratio](/get-started/resources/glossary/#mint-ratio), is the profit margin of the Minter. ##### [Penalty Rate](/get-started/resources/glossary/#penalty-rate) The percentage charged on Owed $M that is in excess of the amount a Minter is permitted to have generated. It is assessed any time Impose Penalty is called, which is embedded in both Update Collateral and Burn. It is alterable with a Standard Proposal. This is a fixed percentage and not an annualized rate. Logic: This percentage should be sufficiently high to deter Minter offenses, but not so high as to overly punish [Minters](/get-started/resources/glossary/#minter) that are victims of circumstance. \:::success **Example** Minter 1 has 1,000,000 Owed $M but has not updated their onchain Collateral Value within [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval), and hence the onchain Collateral Value is 0. Whenever they call Update Collateral or Burn, and Impose Penalty is consequently called, they will pay [Penalty Rate](/get-started/resources/glossary/#penalty-rate) on 1,000,000 - (0 \_ [Mint Ratio](/get-started/resources/glossary/#mint-ratio)). So they will pay [Penalty Rate](/get-started/resources/glossary/#penalty-rate) on their full debt. 1,000,000 \_ .01 = 10,000 $M in [Penalty Rate](/get-started/resources/glossary/#penalty-rate) charges. This assumes that only one [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) period was missed. ::: ##### [Earner Rate](/get-started/resources/glossary/#earner-rate) The annualized percentage paid to $M in the Earn Mechanism. If the cumulative $M paid out via the Earn Mechanism is going to be greater than the amount of $M being generated by the [Minter Rate](/get-started/resources/glossary/#minter-rate), the [Earner Rate](/get-started/resources/glossary/#earner-rate) is automatically discounted to whichever percentage will reduce this mismatch to 0. [`ZERO`](/get-started/resources/glossary/#zero) holders receive all remaining $M that is not paid out to the Earn Mechanism for their participation in protocol governance. It is alterable with a Standard Proposal. Logic: This annualized percentage should be consistent with the yield demanded by institutional holders of $M. It is mechanically prevented from exceeding the cumulative level of $M generated by the [Minter Rate](/get-started/resources/glossary/#minter-rate). It should not be set so low that it results in insufficient demand for $M and thus an inefficient market for [Minters](/get-started/resources/glossary/#minter). ##### [Mint Ratio](/get-started/resources/glossary/#mint-ratio) This percentage is the fraction of a Minter’s onchain Collateral Value that they can generate in $M. It effectively controls the leverage of a Minter and the over-collateralization of $M. It is alterable with a Standard Proposal. Logic: This percentage controls the leverage of [Minters](/get-started/resources/glossary/#minter) and the over-collateralization of $M. It should be set high enough to encourage attractive Minter economics, but not so high that it compromises the stability of $M. ##### [Mint Delay](/get-started/resources/glossary/#mint-delay) This amount of time is the period between when a Minter has called Propose Mint and when they can first call Mint. It serves as a protective measure to ensure all actors have sufficient time to audit each Mint. It is alterable with a Standard Proposal. Logic: This amount of time should be long enough to ensure proper auditability and to afford [validators](/get-started/resources/glossary/#validator) a chance to call Cancel or Freeze if necessary. It should not be so long that it introduces unnecessary friction into the Minting process and reduces the efficiency of [Minters](/get-started/resources/glossary/#minter) and the stability of $M. ##### [Propose Mint Time To Live](/get-started/resources/glossary/#propose-mint-time-to-live) This is the amount of time after the [Mint Delay](/get-started/resources/glossary/#mint-delay) that a Proposed Mint has to be called before it expires. It serves as a protective measure to ensure that [Minters](/get-started/resources/glossary/#minter) cannot call Propose Mint and then execute the Mint at a much later date. It is alterable with a Standard Proposal. Logic: This amount of time should be long enough to give [Minters](/get-started/resources/glossary/#minter) a chance to react to the [Mint Delay](/get-started/resources/glossary/#mint-delay) lapsing and execute their Mint, without being so long that it compromises the integrity of the previous Validator checks. ##### [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) This amount of time is the period between which Update Collateral must be called by a Minter. If they do not call Update Collateral within this amount of time after their previous call, their onchain Collateral Value is assumed to be 0 and they will incur [Penalty Rate](/get-started/resources/glossary/#penalty-rate) on the next update. It is alterable with a Standard Proposal. Logic: This amount of time should be long enough to ensure that [validators](/get-started/resources/glossary/#validator) can reliably check the status of the offchain structures and balances, but not so long that it compromises the integrity of those checks. ##### Update Collateral Threshold This number of signatures is the minimum number of Validator signatures required to execute Update Collateral. If a Minter cannot provide this number of signatures, they cannot successfully call Update Collateral. It is alterable with a Standard Proposal. Logic: This number of signatures should ensure that the Update Collateral process is as secure as possible given the number of [validators](/get-started/resources/glossary/#validator) in the network. It should not be set so high that [Minters](/get-started/resources/glossary/#minter) cannot reliably call Update Collateral. ##### [Minter Freeze Time](/get-started/resources/glossary/#minter-freeze-time) This amount of time is the duration for which a Minter will not be able to call Propose Mint or Mint after having the Freeze method called by a Validator on their address. It is alterable with a Standard Proposal. Logic: This amount of time should be sufficient for the Minter to remedy an issue, but not so long that it materially disrupts its normal course of business. import ZoomableImage from "@/components/ZoomableImage"; ## V. Offchain Ecosystem The M0 protocol relies on the presence of several offchain actors and components, and a feedback process referred to as “guidance” to function properly. ### V.I Guidance ##### The Guidance feedback loop. It is anticipated that as the M0 ecosystem grows, an increasing number of stakeholders will have an interest in its continued development and improvement. These stakeholders are referred to as Think Tanks. Much as the Basel Committee and its cooperating international regulators have provided (theoretically non-committal) guidance and rules for the banking sector, it is anticipated that similar groups and perhaps new M0-specific institutions will provide guidance for the M0 ecosystem and protocol. The protocol is designed in such a way that it can formally adopt guidance through a governance vote and enforce this guidance throughout the system via the [validators](/get-started/resources/glossary/#validator). It is intended to function as follows: ##### Step 1 Think Tanks provide guidance. ##### Step 2 The [TTG](/get-started/resources/glossary/#ttg) adopts or rejects this guidance by voting on a hash of the public document containing it. ##### Step 3 Permissioned Actors adjust their behavior accordingly. ##### Step 4 [Validators](/get-started/resources/glossary/#validator) withhold signatures, Cancel Propose IDs, or Freeze [Minters](/get-started/resources/glossary/#minter) who have not adjusted their behavior to be in line with the guidance. If there is still non-compliance, the [TTG](/get-started/resources/glossary/#ttg) can remove errant actors from the system. This combination of steps creates the “guidance feedback loop.”
:::success **Example** Think Tanks interested in the progress of the M0 ecosystem and protocol determine that only certain jurisdictions are appropriate to host [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution)s. These Think Tanks put out guidance amending the definition of an [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution) to include a list of appropriate jurisdictions, and stipulate that all [Minters](/get-started/resources/glossary/#minter) should be in compliance with this list within 180 days of the proposal’s execution. The document is hashed so that all actors can validate they have the same and correct version of the guidance, and this hash is submitted to the [TTG](/get-started/resources/glossary/#ttg) under a guidance list. The [`POWER`](/get-started/resources/glossary/#power) holders will then vote on the proposal. If it passes, the guidance should be considered approved and enforceable. Once the 180 day window is complete (which is also defined in the guidance), [validators](/get-started/resources/glossary/#validator) should begin to withhold signatures on Update Collateral calls from [Minters](/get-started/resources/glossary/#minter) that attempt to include [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) held in an unapproved jurisdiction in their onchain collateral value. [validators](/get-started/resources/glossary/#validator) can also call Cancel or Freeze on a Minter that is errant in other ways not capturable in the Update Collateral method. [validators](/get-started/resources/glossary/#validator) not enforcing the approved guidance should expect to be removed by the [TTG](/get-started/resources/glossary/#ttg). ::: ### V.II Offchain Actors and Components Key rules for eligible collateral, custody, custodians, and Minter wind-down procedures. The following components and their associated guidance represent those contemplated for the launch of the protocol. This list is not exhaustive and will likely change over time. While much of the guidance is currently quantitative, there is nothing prohibiting qualitative guidance that is left to the interpretation of the various actors. The guidance will also include legal templates and agreements that will contain terms required to ensure smooth operation of the offchain components. ##### [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) A description of portfolio composition which can be placed in [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution)s and be used to generate an onchain Collateral Value, which is subsequently used in the generation of $M. Guidance at launch: 30-90 day US Government T-bills. ##### [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution) A description of entity structures, jurisdictions, contractual agreements, and other details that will suffice for the custody of [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral). Guidance at launch: Orphaned SPV in approved jurisdiction(s). ##### Administrative Buffer An amount of value that a Minter may be compelled to set aside to the [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution) Operator that is not included in the Minter’s [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral). This value is intended to be used by the [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution) Operator to facilitate the orderly wind-down of the facility should the Minter become inactive or incapacitated. Guidance at launch: $100,000. ##### [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution) Operators The professional corporate servicing agents (e.g. Trustees) that manage the [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution). Guidance at launch: Any governance-approved Operator that is technically and operationally equipped (and licensed, as applicable) to act as manager for an orphaned SPV structure in the approved jurisdiction(s) as well as capable to read and interpret the relevant onchain information. ##### Banks The banks that hold deposits on behalf of the [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution). Guidance at launch: Any bank in the approved jurisdiction(s). ##### Custodians The custodians that hold [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) (excluding bank deposits) on behalf of the [Eligible Custody Solution](/get-started/resources/glossary/#eligible-custody-solution). Guidance at launch: Any bank in the approved jurisdiction(s) that are operationally equipped to custody the [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral). ##### Minter Wind Down Procedures The procedures a Minter is expected to follow should they be removed from the Minter list. Guidance at launch: [Minters](/get-started/resources/glossary/#minter) will be given a 90 day grace period after being removed from the Minter list to fully wind down their operations (a “cooperative wind down”). This means they will have [`ZERO`](/get-started/resources/glossary/#zero) remaining Owed $M. Should they fail to do so in this timeframe, the remainder of their offchain value will be forfeit including the Administrative Buffer. The Administrative Buffer, in addition to remaining offchain value in excess of Owed $M, is intended to be used to finance the various offchain actors that will be involved in the uncooperative wind down. ## I. Introduction The core M0 protocol (which excludes [Periphery Contracts](/get-started/resources/glossary/#periphery-contract) and is hereon referred to simply as the M0 protocol) is a coordination layer for permissioned actors to generate $M. :::note $M is a crypto asset whose value is designed to be a robust representation of an exogenous collateral basket – a relationship enforced by the financial structure and market incentives of its generators. ::: The purpose of $M is to become a superior building block for value representation, by combining the convenience of digital money with the risk profile of physical cash. While holders may find this construct appropriate as a vehicle for stablecoin use cases, builders, developers and financial services providers might be interested in it as raw material for the build out of novel products and services – including as collateral for stablecoins. When cash was primarily a physical construct, it had several properties that its holders found desirable but have since been lost in the process of digitization. Physical cash is first and foremost self-custodial; it’s a bearer instrument which guarantees that it cannot be frozen or seized without due process in the holder’s jurisdiction. For example, holders in one nation do not need to be concerned that a far away government can turn off the cash in their pocket. This feature allows cash to be credibly neutral, which means that it cannot discriminate against any specific holder. Second, physical cash does not carry additional counterparty risk, it is as good as holding reserves at the issuer’s central bank. Finally, physical cash is generally fungible with itself, which is to say that except in extraordinary circumstances where holders are wary to accept a certain serial number, no bill is more or less valuable than another. The downsides of physical cash are that it cannot be transferred electronically, it must be stored in a physically safe location which becomes exponentially more difficult to secure as the quantity held rises, is becoming less broadly accepted as a means of payment, and lacks general digital properties that can allow seamless composability and programmability. Most users have historically believed those properties to be inherited by bank deposits, as if they were merely a digital representation of cash — the fallacy of this false equivalence is becoming evident due to the stress increasingly experienced by the banking system, and is exacerbated by the global nature of stablecoins. What we call digital cash today is typically a commercial bank deposit that can be transferred electronically. It has several beneficial features such as the ability to earn interest, the ability to be transferred over the internet and across large distances, and it offers the peace of mind of digital and custodial security. It is also the most widely accepted form of payment through credit cards, debit cards, ACH, and SWIFT. Unfortunately bank deposits lose many of the desirable features of physical cash. Bank deposits are implicitly custodial and can be seized or frozen without due process in the holder’s jurisdiction – they are not credibly neutral. Due to the inherent characteristics of fractional reserve banking, bank deposits hold significant counterparty risk and are only as valuable as the specific bank’s balance sheet permits. For this reason they are also not fungible. A deposit in one bank cannot be treated as equal to a deposit in another, and thus introduces exorbitant clearing times between payments, as well as compounding complexity throughout the system. $M is credibly neutral by design, it is by default self-custodial and fungible. Each $M is the same as every other $M and there is no ability for the protocol to discriminate against any specific holder(s). $M is stored and tracked on blockchains, and thus can be stored more securely at scale than physical cash. $M’s current instantiation is intended to be generated using short term US T-bills, representing the lowest level of counterparty risk excepting physical cash and bank reserves within the US dollar system. The T-bills used to generate $M must be held exclusively throughout a network of orphaned, bankruptcy-remote entities, which are customized to interact with the M0 protocol while meeting the formalities of the existing legal system. $M can be sent anywhere in the world instantaneously using the blockchain rails on which it exists. Interest flowing to the T-bill collateral can be partly collected by the protocol and democratized across permissioned issuers and distributors. We refer to $M as raw material for value representation, and not necessarily a stablecoin in its own right, because the system relies on permissioned issuers (known as [Minters](/get-started/resources/glossary/#minter) in the protocol) for generation and distribution. These [Minters](/get-started/resources/glossary/#minter) should be compliant with all applicable regulations and may decide to distribute their own product, for example by wrapping the $M token in a stablecoin contract in a way that best meets their requirements. In this capacity, $M becomes a monetary building block on top of which novel products can be built. In summary, the M0 protocol is the platform powering builders of safe, programmable, interoperable stablecoins. It introduces a superior coordination mechanism that democratizes access to the generation and management of programmable, digital cash instruments. It is an infrastructure layer not for the simplistic tokenization of real world bank deposits, but a much more sophisticated way to provide access to the liquidity on high-quality collateral. M0 intends to redesign the monetary vertical stack, rather than build an additional layer on top of what has ultimately become byzantine infrastructure. import ZoomableImage from '@/components/ZoomableImage'; ## III. Governance The M0 protocol uses an onchain governance mechanism called a Two Token Governor ([TTG](/get-started/resources/glossary/#ttg)) to manage its various inputs. With [TTG](/get-started/resources/glossary/#ttg), holders of the voting tokens are penalized for failing to vote. There are two utility tokens used in the M0 [TTG](/get-started/resources/glossary/#ttg): [`POWER`](/get-started/resources/glossary/#power) and [`ZERO`](/get-started/resources/glossary/#zero). [`POWER`](/get-started/resources/glossary/#power) is used to vote on active proposals and can be considered the primary management token of the mechanism. [`POWER`](/get-started/resources/glossary/#power) holders will earn [`ZERO`](/get-started/resources/glossary/#zero) in exchange for their direct participation in governance. If a [`POWER`](/get-started/resources/glossary/#power) holder delegates their balance to an address that is not also the holder of the tokens, it is this address which receives the [`ZERO`](/get-started/resources/glossary/#zero) rewards. [`ZERO`](/get-started/resources/glossary/#zero) holders are comparatively (to [`POWER`](/get-started/resources/glossary/#power) holders) passive in the voting process and only vote on important changes. [`ZERO`](/get-started/resources/glossary/#zero) holders at any time may Reset (see: [`ZERO`](/get-started/resources/glossary/#zero) Threshold Proposals) the [`POWER`](/get-started/resources/glossary/#power) token supply to themselves. The goal of the [TTG](/get-started/resources/glossary/#ttg) mechanism is to ensure credible neutrality of governance. In any system there are two extremes that must be avoided: capture and fraud. In one case, the system is captured by actors whose primary interest is not in efficient protocol operation and it ceases to function in a way where all users are treated the same. In the other, the protocol ceases to function for anyone except the fraudulent actor. It is this dichotomy that is at the heart of the two token design. [`POWER`](/get-started/resources/glossary/#power) holders are treated as a managerial class that is able to earn compensation through continued benevolent participation. This continued benevolence is judged by the [`ZERO`](/get-started/resources/glossary/#zero) holders who can always strip the [`POWER`](/get-started/resources/glossary/#power) holders of their management rights, and thus their ability to earn future ownership in the protocol. If the composition and decisions of [`POWER`](/get-started/resources/glossary/#power) holders trend towards either extreme, it is in the interest of [`ZERO`](/get-started/resources/glossary/#zero) holders to call Reset in order to restore balance. ### III.I Inputs List of protocol inputs by the M0 Two Token Governor ([TTG](/get-started/resources/glossary/#ttg)). The M0 [TTG](/get-started/resources/glossary/#ttg) (hereafter [TTG](/get-started/resources/glossary/#ttg)) is responsible for the following inputs to the M0 protocol and to itself (see (Governance Controlled TTG Parameters)\[/home/fundamentals/whitepaper/governance/#governance-controlled-ttg-parameters-1], Governance Controlled Protocol Actors, and Section [Governance Controlled Protocol Parameters](/home/fundamentals/whitepaper/protocol/#governance-controlled-protocol-parameters) for further context on the actors and parameters listed below): ##### Governance Controlled TTG Parameters * Proposal Fee * [`POWER`](/get-started/resources/glossary/#power) Threshold * [`ZERO`](/get-started/resources/glossary/#zero) Threshold * CASH Toggle ##### Governance Controlled Protocol Actors * A list of approved [Minters](/get-started/resources/glossary/#minter) * A list of approved [validators](/get-started/resources/glossary/#validator) * A list of Approved [Earners](/get-started/resources/glossary/#earner) ##### Governance Controlled Protocol Parameters * [Minter Rate](/get-started/resources/glossary/#minter-rate) * [Penalty Rate](/get-started/resources/glossary/#penalty-rate) * [Earner Rate](/get-started/resources/glossary/#earner-rate) * [Mint Ratio](/get-started/resources/glossary/#mint-ratio) * [Mint Delay](/get-started/resources/glossary/#mint-delay) * [Propose Mint Time To Live](/get-started/resources/glossary/#propose-mint-time-to-live) * [Update Collateral Interval](/get-started/resources/glossary/#update-collateral-interval) * Number of Signatures * [Minter Freeze Time](/get-started/resources/glossary/#minter-freeze-time) ### III.II Operation Protocol operational attributes. The [TTG](/get-started/resources/glossary/#ttg) is used to vote on proposals seeking to amend the Actors and variables. New lists and variables may be added arbitrarily over time, however the core protocol is immutable and these additions will not directly impact its operations. The implementation which controls the M0 protocol is deployed exclusively on the Ethereum Mainnet. #### III.II.I Epochs Protocol epochs for governance and proposal execution. The mechanism practically operates in 30-day epochs, meaning in the standard operating procedure proposals are only passed on a 30-day cycle. In practice, this broader epoch is split into two epochs of 15 days. These numbers were chosen to align with an average calendar month. The first epoch (the Transfer Epoch) is a non-voting period where transfers and delegation are enabled. The second 15-day epoch (the Voting Epoch) is where voting takes place on Standard Proposals and transfers and delegation are disabled. These restrictions on onchain activity only apply to [`POWER`](/get-started/resources/glossary/#power) tokens, there are no restrictions placed on the [`ZERO`](/get-started/resources/glossary/#zero) token. The conceptual 30-day epoch is split into these two smaller epochs to ensure correct accounting for voting and inflation. This means that proposals are collected in one 15-day epoch (whether it be the Voting Epoch or the Transfer Epoch), are voted on in the following 15-day Voting Epoch, and should be executed in the following 15-day Transfer Epoch. Proposals that passed but were not executed eventually expire. Therefore a proposal may spend as short as 15 days plus two blocks, or as long as 45 days, from submission to execution. During the 15-day Transfer Epoch, holders may transfer their balances, reassign delegations, and purchase [`POWER`](/get-started/resources/glossary/#power) that is being auctioned.
#### III.II.II Proposals Protocol change proposals for [TTG](/get-started/resources/glossary/#ttg) governance. The [TTG](/get-started/resources/glossary/#ttg) has three types of proposals: (1) Standard Proposals, (2) [`POWER`](/get-started/resources/glossary/#power) Threshold Proposals, and (3) [`ZERO`](/get-started/resources/glossary/#zero) Threshold Proposals. The use of threshold in the terminology represents a yes threshold, meaning that the threshold percentage of yes votes must be reached in order for the proposal to pass. A proposal that requires a threshold never explicitly fails (although it will eventually expire), but cannot be executed without reaching the requisite number of yes votes. For example, if a proposal requires a 10% yes threshold, it will pass as soon as 10% of the relevant token supply has voted yes. If this proposal never reaches 10% of the relevant token supply voting yes, it will expire without passing. These proposal types are described next in further detail. ##### III.II.II.I Standard Proposals Standard Proposals in [TTG](/get-started/resources/glossary/#ttg) Governance. Standard Proposals are voteable only by [`POWER`](/get-started/resources/glossary/#power) holders and require a simple majority of participating tokens to pass. Standard proposals do not require a threshold percentage of yes votes to pass. If there are only 100 [`POWER`](/get-started/resources/glossary/#power) tokens voting in a Standard Proposal and 51 vote yes while 49 vote no, it will pass. If 50 vote yes and 50 vote no, it will fail as it requires the yes balance to exceed the no. Standard Proposals are the only proposal type which are “mandatory” for [`POWER`](/get-started/resources/glossary/#power) holder participation. Lack of participation will result in [`POWER`](/get-started/resources/glossary/#power) holders being diluted in terms of their overall voting [`POWER`](/get-started/resources/glossary/#power) in the system and will cause them to forfeit any [`ZERO`](/get-started/resources/glossary/#zero) rewards for which they were otherwise eligible. A successful Standard Proposal will have its Proposal Fee available to be returned to the proposer. \:::success **Example** During a Voting Epoch a proposal to change [Minter Rate](/get-started/resources/glossary/#minter-rate) is made. Only 10% of the [`POWER`](/get-started/resources/glossary/#power) tokens choose to participate. When voting on the proposal, 60% of the participating [`POWER`](/get-started/resources/glossary/#power) tokens vote yes. This proposal is passed because the yes votes are greater than the no votes. The total number of [`POWER`](/get-started/resources/glossary/#power) holders participating is only relevant in votes which require a [`POWER`](/get-started/resources/glossary/#power) Threshold. ::: ##### III.II.II.II POWER Threshold Proposals A [`POWER`](/get-started/resources/glossary/#power) Threshold Proposal requires a set vote threshold for immediate execution, used for urgent or important changes in M0 Governance. A [`POWER`](/get-started/resources/glossary/#power) Threshold Proposal can be used to submit anything which would otherwise be a Standard Proposal, except it requires a [`POWER`](/get-started/resources/glossary/#power) Threshold and is immediately votable and subsequently immediately executable rather than only being votable and executable in the future epochs. For this reason, [`POWER`](/get-started/resources/glossary/#power) holders are likely to use this proposal type in the case of an urgent or emergency situation. If a [`POWER`](/get-started/resources/glossary/#power) Threshold has not been reached before the proposal expires, the proposal cannot be executed. [`POWER`](/get-started/resources/glossary/#power) Threshold Proposals expire at the end of the next epoch. \:::success **Example** During the Transfer Period a [`POWER`](/get-started/resources/glossary/#power) Threshold Proposal is made to change [Minter Rate](/get-started/resources/glossary/#minter-rate), which requires a [`POWER`](/get-started/resources/glossary/#power) Threshold due to it being an [`POWER`](/get-started/resources/glossary/#power) Threshold Proposal. The [`POWER`](/get-started/resources/glossary/#power) Threshold is set to 75%. The proposal becomes immediately votable and a full 100% of the [`POWER`](/get-started/resources/glossary/#power) supply chooses to participate – 80% vote affirmatively. This proposal has passed and is instantly executable upon the [`POWER`](/get-started/resources/glossary/#power) Threshold being met. This is because it achieved yes votes from greater than 75% of the [`POWER`](/get-started/resources/glossary/#power) supply (100% \* 80% = 80% yes). Note that the proposal very well could have gone on to accumulate more yes votes, but was likely executed immediately or soon after meeting the [`POWER`](/get-started/resources/glossary/#power) Threshold. ::: ##### III.II.II.III ZERO Threshold Proposals [`ZERO`](/get-started/resources/glossary/#zero) Threshold Proposals allow major governance changes. A [`ZERO`](/get-started/resources/glossary/#zero) Threshold Proposal is used for Reset, to toggle CASH between WETH and $M, and to set the [`POWER`](/get-started/resources/glossary/#power) and [`ZERO`](/get-started/resources/glossary/#zero) Thresholds themselves. The Reset method is a special feature reserved for the [`ZERO`](/get-started/resources/glossary/#zero) token holders which allows a yes threshold of [`ZERO`](/get-started/resources/glossary/#zero) holders to change the current governor of the system to a new version with a new [`POWER`](/get-started/resources/glossary/#power) token that is claimable pro rata to [`ZERO`](/get-started/resources/glossary/#zero) holders or to existing [`POWER`](/get-started/resources/glossary/#power) holders. They do this by creating a proposal to call the Reset method. Mechanically this is affected by replacing the current governor ([`POWER`](/get-started/resources/glossary/#power) token address) of the system with a new instance, where the starting balance of the [`POWER`](/get-started/resources/glossary/#power) tokens are proportional to each [`ZERO`](/get-started/resources/glossary/#zero) holder's balance in the epoch before the Reset. It is immediately executable upon achieving a yes threshold. It is intended for [`ZERO`](/get-started/resources/glossary/#zero) holders to use this feature should they find something irreparably wrong with the composition and/or voting patterns of the current [`POWER`](/get-started/resources/glossary/#power) holders and wish to take on voting responsibility themselves. It is anticipated that [`ZERO`](/get-started/resources/glossary/#zero) holders will only Reset the governor to the existing [`POWER`](/get-started/resources/glossary/#power) holders if the token is nearing an overflow, which will not happen for 150+ years. There is technically no limit to how many times Reset can be called, but it is not anticipated to be frequently used if it is ever used in the first place. If a Reset is executed in the middle of a Voting Epoch, all active and/or unexecuted proposals are effectively canceled because they are using the obsolete governor. \:::success **Example** The [`ZERO`](/get-started/resources/glossary/#zero) Threshold is set to 60%. [`POWER`](/get-started/resources/glossary/#power) holders seem likely to pass a proposal to add a perceived malicious actor to the Minter List. A user submits a proposal to Reset. This proposal is immediately votable – it achieves 70% of the total [`ZERO`](/get-started/resources/glossary/#zero) supply voting yes. This proposal is passed and is immediately executable. All currently votable proposals, including the proposal to add the perceived malicious Minter, are effectively canceled. \::: ##### III.II.II.IV Proposal Matrix The Proposal Matrix provides a visual breakdown of the three [TTG](/get-started/resources/glossary/#ttg) proposal types. The diagram below details the three types of proposals in the [TTG](/get-started/resources/glossary/#ttg) and highlights which actions are associated with each type.
#### III.II.III Checkpoints and Voting A checkpoint of balances is taken at the start of epochs and the balances contained in these checkpoints are used for voting throughout the epoch. During a Transfer Epoch, only the balance a user possessed at the checkpoint will be counted towards voting on [`POWER`](/get-started/resources/glossary/#power) Threshold Proposals, which will not include standard inflationary proposals by definition. In order to vote the [`POWER`](/get-started/resources/glossary/#power) owner’s delegate address (hereon referred to as the [`POWER`](/get-started/resources/glossary/#power) holder) calls the Cast Votes method on the array of proposals they wish to vote on and specifies yes/no for each proposal. There is no abstain option in the [TTG](/get-started/resources/glossary/#ttg). #### III.II.IV Proposing Making protocol change proposals for [TTG](/get-started/resources/glossary/#ttg). Anyone with an Ethereum address and WETH or $M may submit a proposal. The [TTG](/get-started/resources/glossary/#ttg) is to be deployed with WETH as its internal currency (known as CASH in the mechanism), and therefore any Standard Proposal submission must pay a Proposal Fee in WETH, or at a later date $M depending on the current CASH toggle setting, in addition to gas fees (see [Governance Controlled TTG Parameters](/home/fundamentals/whitepaper/governance/#governance-controlled-ttg-parameters-1)). A proposal that passes makes the Proposal Fee available to be returned to the proposer upon execution. There are two primary structures of proposals that can be managed through the [TTG](/get-started/resources/glossary/#ttg): (1) configuring a registrar used by the protocol, i.e. adding and removing addresses from arbitrary lists/sets and setting arbitrary variables; (2) setting governance parameters. The M0 protocol looks to the registrar to use certain variables and sets of addresses in its processes. In order to propose a change to a list, a user submits a Standard Proposal or a [`POWER`](/get-started/resources/glossary/#power) Threshold Proposal calling the Add To List or Remove From List methods along with the address they wish to add or remove. There is also a method called Remove From And Add To List which facilitates swapping an address on a list. In order to add a new list to the [TTG](/get-started/resources/glossary/#ttg) a proposer will create a proposal which uses Add To List and will specify a new list, which is created simultaneously to the proposal being executed. Since the M0 core protocol is immutable, any list added after deployment can only be used to manage periphery smart contracts and cannot impact core operations. \:::success **Example** Alice wishes to add her company’s address to the list of approved [Minters](/get-started/resources/glossary/#minter) in the M0 protocol. Alice calls Add To List, specifying the [Minters](/get-started/resources/glossary/#minter) list along with the address she would like to gain permission to mint $M in the protocol. ::: In order to propose a change to a configuration contract proposers call the Set Key method. In order to propose a configuration change at the registrar, proposers create a proposal for the governor to call the registrar's Set Key method. The update either results in the first setting or overwriting of a value for a given key (i.e. variable name). \:::success **Example** Bob wishes to change [Minter Rate](/get-started/resources/glossary/#minter-rate) from 3% to 4%. Bob calls Set Key and specifies the configuration contract he’d like to change along with the new value he would like it to contain. ::: Once a proposal passes, and assuming the requisite amount of time has passed, anyone can call the Execute method to execute the action on chain. They must pass the proposal arguments into the Execute method. #### III.II.V Inflation Mechanics Description of protocol inflation mechanics for [TTG](/get-started/resources/glossary/#ttg). In each epoch the supply of [`POWER`](/get-started/resources/glossary/#power) is inflated by 10% and the supply of [`ZERO`](/get-started/resources/glossary/#zero) is inflated by up to 5,000,000 tokens. This inflation is claimed pro rata by participating [`POWER`](/get-started/resources/glossary/#power) holders, specifically by their delegate address. Any [`POWER`](/get-started/resources/glossary/#power) that remains undistributed (or that could not be claimed because the holder did not fully participate in that epoch) is auctioned off to the highest bidder in a pay-as-bid Dutch auction (hereon “Dutch auction”). When there are tokens to auction, the auction starts at the beginning of the Transfer Epoch and ends at the finish of the Transfer Epoch. Therefore if a user purchases [`POWER`](/get-started/resources/glossary/#power) during an auction they will always be able to use those tokens to vote in the subsequent Voting Epoch. Each participating [`POWER`](/get-started/resources/glossary/#power) holder during the Voting Epoch will also receive their pro rata (based on their percentage of total voting power) share of the 5,000,000 [`ZERO`](/get-started/resources/glossary/#zero) tokens. Once a Standard Proposal has been submitted it can be voted on in the following Voting Epoch, unless it is a [`POWER`](/get-started/resources/glossary/#power) Threshold Proposal or a [`ZERO`](/get-started/resources/glossary/#zero) Threshold Proposal, which can be voted on at any time. When a proposal becomes available for voting, it is mandatory for [`POWER`](/get-started/resources/glossary/#power) holders to vote on it or else the owner of the [`POWER`](/get-started/resources/glossary/#power) tokens will lose relative voting weight in the system. If a [`POWER`](/get-started/resources/glossary/#power) owner’s delegate fails to vote on any proposal in an epoch, they will forfeit any [`POWER`](/get-started/resources/glossary/#power) or [`ZERO`](/get-started/resources/glossary/#zero) inflation they would have otherwise been able to claim. [`POWER`](/get-started/resources/glossary/#power) holders must vote on all Standard Proposals in the Voting Epoch; [`POWER`](/get-started/resources/glossary/#power) Threshold Proposals and [`ZERO`](/get-started/resources/glossary/#zero) Threshold Proposals do not factor into [`POWER`](/get-started/resources/glossary/#power) inflation dynamics. There is no inflation if an epoch only has [`POWER`](/get-started/resources/glossary/#power) Threshold Proposals and / or [`ZERO`](/get-started/resources/glossary/#zero) Threshold Proposals, or no proposals at all. \:::success **Example** Alice is a [`POWER`](/get-started/resources/glossary/#power) holder with 1,000 [`POWER`](/get-started/resources/glossary/#power) tokens, the total [`POWER`](/get-started/resources/glossary/#power) supply is 10,000; hence Alice controls 10% of the [`POWER`](/get-started/resources/glossary/#power) voting weight. In epoch 1 she participates fully by voting on all Standard Proposals. Simultaneous to participating, Alice claims an additional 100 [`POWER`](/get-started/resources/glossary/#power) tokens and 500,000 [`ZERO`](/get-started/resources/glossary/#zero) tokens, i.e. 10% of a [`POWER`](/get-started/resources/glossary/#power) inflation of 1,000 tokens and 10% of a [`ZERO`](/get-started/resources/glossary/#zero) inflation of 5,000,000 tokens. In epoch 2 Alice fails to vote on a Standard Proposal and is therefore not able to claim any [`POWER`](/get-started/resources/glossary/#power) or [`ZERO`](/get-started/resources/glossary/#zero) tokens. The 110 [`POWER`](/get-started/resources/glossary/#power) tokens (i.e. 10% of the new additional [`POWER`](/get-started/resources/glossary/#power) supply of 1,100 tokens) that should have gone to Alice are auctioned in the Dutch auction. Bob buys these 110 tokens for 1 WETH (the internal currency of the [TTG](/get-started/resources/glossary/#ttg)) and can now participate in the following voting epoch. The [`ZERO`](/get-started/resources/glossary/#zero) tokens that should have gone to Alice are simply never minted. ::: #### III.II.VI Dutch Auction Dutch Auction for [`POWER`](/get-started/resources/glossary/#power) tokens. Once the Transfer Epoch has begun the Dutch auction will begin simultaneously if any [`POWER`](/get-started/resources/glossary/#power) holder failed to participate. The price per basis point (0.01%) of [`POWER`](/get-started/resources/glossary/#power) token, calculated as a percentage of the total [`POWER`](/get-started/resources/glossary/#power) supply, in the Dutch auction will start at 2^99 wei (the smallest unit of WETH) and decrement the exponent approximately every 3.6 hours. During the period between exponent decreases the price linearly declines. This means that after the first 3.6 hours of the auction the price will be 2^98 wei and linearly decrease to 2^97 wei over the following 3.6 hours. In the implementation, bitwise shifting is used to achieve this effect. That is to say that at the midpoint between two exponents, the value is halfway between them. In order to purchase [`POWER`](/get-started/resources/glossary/#power) in the Dutch auction, purchasers must call the Buy method. The diagrams below illustrate the intended price curve of the Dutch auction in ETH over the 15 day period. The first demonstrates the entire price curve, while the second shows a smaller slice of the curve to demonstrate its semi-linearity.
#### III.II.VII Delegation Delegation of voting [`POWER`](/get-started/resources/glossary/#power) for [TTG](/get-started/resources/glossary/#ttg). Both [`POWER`](/get-started/resources/glossary/#power) and [`ZERO`](/get-started/resources/glossary/#zero) owners may delegate their voting [`POWER`](/get-started/resources/glossary/#power) to an arbitrary Ethereum address during the Transfer Epoch. Delegated [`POWER`](/get-started/resources/glossary/#power) will retain its inflation in the owner address, while [`ZERO`](/get-started/resources/glossary/#zero) rewards will be claimable by the delegate address. Owning [`ZERO`](/get-started/resources/glossary/#zero) does not earn the owner or the owner’s delegate inflation or rewards aside from $M generated by the protocol fees, and thus delegation does not have any impact on the owner outside of transferring voting power. [`ZERO`](/get-started/resources/glossary/#zero) does earn fees from Proposal Fees on failed Standard Proposals, the payments from [`POWER`](/get-started/resources/glossary/#power) token auctions and a portion of [Minter Rate](/get-started/resources/glossary/#minter-rate) and [Penalty Rate](/get-started/resources/glossary/#penalty-rate) charges to [Minters](/get-started/resources/glossary/#minter). Delegation snapshots are taken at the beginning of the epoch and close at the end of the epoch, and the values in the snapshots are subject to change until the epoch closes. Both [`POWER`](/get-started/resources/glossary/#power) and [`ZERO`](/get-started/resources/glossary/#zero) follow the ERC20 standard and holders must call the Delegate method and provide the address they wish to delegate to. For holders that do not actively Delegate, the default delegation is set to the address which owns the tokens. Users do not need to alter their delegation in each epoch unless they wish to change delegates. #### III.II.VIII ZERO Claiming of Residual Value In exchange for [`ZERO`](/get-started/resources/glossary/#zero) holders' participation in protocol governance, they will receive the remainder of the protocol fees. The anticipated accumulation of tokens to the [`ZERO`](/get-started/resources/glossary/#zero) holders are Proposal Fee payments from rejected proposal submission, the payments from [`POWER`](/get-started/resources/glossary/#power) token auctions, and a portion of [Minter Rate](/get-started/resources/glossary/#minter-rate) and [Penalty Rate](/get-started/resources/glossary/#penalty-rate) charges to [Minters](/get-started/resources/glossary/#minter) (see [Protocol Fees](/home/fundamentals/whitepaper/protocol/#protocol-fees)). Proposal Fee and auction payments are collected in WETH or $M, depending on the status of the CASH toggle, and [Minter Rate](/get-started/resources/glossary/#minter-rate) is collected in $M. At any time a [`ZERO`](/get-started/resources/glossary/#zero) holder may call the Claim method in order to claim this accumulated value. The amount of claimable tokens are pro rata to each account's [`ZERO`](/get-started/resources/glossary/#zero) balance on the close of each epoch they are trying to claim for. They pass the array of epochs (or a starting epoch and ending epoch) they are seeking to claim for as arguments to the method. ### III.III Governance Controlled TTG Parameters List of Governance controlled [TTG](/get-started/resources/glossary/#ttg) parameters. ##### CASH The internal currency of the [TTG](/get-started/resources/glossary/#ttg). It is used to pay Proposal Fee and to purchase [`POWER`](/get-started/resources/glossary/#power) in the Dutch auction. It can be toggled between WETH and $M. Logic: This token must be permissionless and well distributed in order to prevent takeover of the [TTG](/get-started/resources/glossary/#ttg). It should also have sufficient value to its holders in order to deter spam and to increase the efficiency of the Dutch auction. ##### Proposal Fee The amount paid in CASH to submit any proposal. It is alterable with a Standard Proposal. Logic: This amount should be sufficiently high to deter spam, but not so high as to deter legitimate proposals. ##### POWER Threshold The number of yes votes as a percentage of the total [`POWER`](/get-started/resources/glossary/#power) supply required to pass proposals which require a [`POWER`](/get-started/resources/glossary/#power) Threshold. Logic: This percentage should be low enough to ensure that in an emergency situation, enough [`POWER`](/get-started/resources/glossary/#power) holders can be collected to pass a proposal. It should be high enough that a malicious proposal cannot be passed instantly. \:::success **Example** [`POWER`](/get-started/resources/glossary/#power) Threshold = 80%. Therefore if there are 1,000,000 total [`POWER`](/get-started/resources/glossary/#power) in existence, 800,000 [`POWER`](/get-started/resources/glossary/#power) will need to vote affirmatively for a proposal to pass that requires a [`POWER`](/get-started/resources/glossary/#power) Threshold. ::: ##### ZERO Threshold The number of yes votes as a percentage of the total [`ZERO`](/get-started/resources/glossary/#zero) supply required to pass proposals which require a [`ZERO`](/get-started/resources/glossary/#zero) Threshold. Logic: This percentage should be low enough that it is possible to call Reset if necessary. It should be high enough to ensure that Reset is not called without a very high level of consensus. \:::success **Example** [`ZERO`](/get-started/resources/glossary/#zero) Threshold = 60%. Therefore if there are 1,000,000,000 total [`ZERO`](/get-started/resources/glossary/#zero) in existence, 600,000,000 [`ZERO`](/get-started/resources/glossary/#zero) will need to vote affirmatively for a proposal to pass that requires a [`POWER`](/get-started/resources/glossary/#power) Threshold. ::: ### III.IV Immutable [TTG](/get-started/resources/glossary/#ttg) Parameters List of immutable [TTG](/get-started/resources/glossary/#ttg) parameters. ##### Epoch Duration The combined length of the Voting Epoch and the Transfer Epoch. Set to 30 days. Logic: This amount of time should be short enough to permit for timely management of the protocol, but long enough for all [`POWER`](/get-started/resources/glossary/#power) holders to both socialize and physically vote on Standard Proposals. ##### Voting Epoch Duration The length of the Voting Epoch. Set to 15 days. Logic: This amount of time should be long enough to permit [`POWER`](/get-started/resources/glossary/#power) holders to physically exercise their vote. ##### Transfer Epoch Duration The length of the Transfer Epoch. Set to 15 days. Logic: This amount of time should be long enough to contain the Dutch auction and for any [`POWER`](/get-started/resources/glossary/#power) holders that may wish to perform transfers or re-delegations to do so. ##### Auction Duration The length of the Dutch auction for unclaimed [`POWER`](/get-started/resources/glossary/#power) inflation. Set to 15 days and overlaps perfectly with the Transfer Epoch. Logic: This amount of time should be long enough to cross all conceivable prices while still promoting efficient price discovery. Note that this length matches the Transfer Epoch, so that tokens acquired in the Transfer Epoch will be included in the checkpoint for the following Voting Epoch. ##### Dutch Auction Exponent The exponent with a base of 2 that determines the starting auction price. Set to 99. Logic: This number should produce a sufficiently high starting price per [`POWER`](/get-started/resources/glossary/#power) token such that the market price of [`POWER`](/get-started/resources/glossary/#power) in Cash is never above this price. It should not be so high as to cause the auction to exceed the Transfer Epoch before reaching 0 given the Dutch Auction Period Time setting. ##### Dutch Auction Periods The number of equal periods that must fit into the Transfer Epoch. Set to 100. Logic: This number of periods defines how often the Dutch auction will decrease the Dutch Auction Exponent. At the current setting the Dutch auction will decrement the Dutch Auction Exponent approximately every 3.6 hours. ### III.V Immutable POWER Parameters List of immutable [`POWER`](/get-started/resources/glossary/#power) parameters. ##### POWER Initial Supply The initial supply of [`POWER`](/get-started/resources/glossary/#power) tokens before any inflation. Set to 1,000,000. Decimals are 0. Logic: The initial supply of [`POWER`](/get-started/resources/glossary/#power) should be sufficient to distribute to the initial holders in the network, but not so high as to cause a premature overflow error. The lack of decimals (and thus lack of subdivision of tokens) was also chosen for this reason. See the diagram under [`POWER`](/get-started/resources/glossary/#power) Inflator for further analysis. Another factor to consider in this initial supply is the “dust level,” meaning the level at which in a Reset a [`ZERO`](/get-started/resources/glossary/#zero) holder would not receive any [`POWER`](/get-started/resources/glossary/#power) tokens. For example, since new [`POWER`](/get-started/resources/glossary/#power) (post-Reset) is based on existing [`ZERO`](/get-started/resources/glossary/#zero) balances, anyone who owns less than 1 / [`POWER`](/get-started/resources/glossary/#power) Initial Supply of a [`ZERO`](/get-started/resources/glossary/#zero) token will get 0 [`POWER`](/get-started/resources/glossary/#power) after a Reset. ##### POWER Inflator The percentage inflation of the [`POWER`](/get-started/resources/glossary/#power) supply per active epoch. This occurs only in epochs with a votable proposal, hence why they are referred to as active. If a [`POWER`](/get-started/resources/glossary/#power) holder fails to fully participate in an epoch with at least one votable, their balance of [`POWER`](/get-started/resources/glossary/#power) tokens will not decrease but their percentage of overall voting [`POWER`](/get-started/resources/glossary/#power) will decrease by 1 / (1 + [`POWER`](/get-started/resources/glossary/#power) Inflator). Set to 10%. Logic: This percentage must sufficiently encourage [`POWER`](/get-started/resources/glossary/#power) holder participation without occasional lapses in participation destabilizing the system. At 10% inflation, a [`POWER`](/get-started/resources/glossary/#power) holder can expect to lose \~45% of their voting [`POWER`](/get-started/resources/glossary/#power) if not participating for 6 epochs (note that epochs in our implementation correspond roughly to calendar months), \~70% of their voting [`POWER`](/get-started/resources/glossary/#power) if not participating for 12 epochs, and \~90% of their voting [`POWER`](/get-started/resources/glossary/#power) if not participating for 24 epochs. To a lesser extent this number should also take into account a realistic number of epochs with votable proposals to ensure that the operation of the protocol is not impacted by an overflow error. This would require either a Reset or a Hard Fork. The following diagrams demonstrate the intended impact of the [`POWER`](/get-started/resources/glossary/#power) Inflator on an inactive participant, and a comparison of [`POWER`](/get-started/resources/glossary/#power) Inflator and decimal setting as they impact overflow times assuming a 30-day total epoch time.
Voting [`POWER`](/get-started/resources/glossary/#power) as a percentage of starting voting [`POWER`](/get-started/resources/glossary/#power) (y-axis) over missed epochs with a votable proposal (x-axis), using a 10% [`POWER`](/get-started/resources/glossary/#power) Inflator
Years to overflow assuming 12 epochs per year with votable proposals. Comparison of [`POWER`](/get-started/resources/glossary/#power) Inflator (left column) and decimal choice for [`POWER`](/get-started/resources/glossary/#power) token (top row). Assumes a starting [`POWER`](/get-started/resources/glossary/#power) supply of 1,000,000. ### III.VI Immutable ZERO Parameters List of immutable [`ZERO`](/get-started/resources/glossary/#zero) parameters. ##### ZERO Initial Supply The initial supply of the [`ZERO`](/get-started/resources/glossary/#zero) token before any rewards. Set to 1,000,000,000. Decimals are 6. Logic: The initial supply of [`ZERO`](/get-started/resources/glossary/#zero) should be large enough to promote a high level of decentralization (as it pertains to the Reset method), and small enough to not break common integrations. ##### ZERO Reward The maximum amount of [`ZERO`](/get-started/resources/glossary/#zero) given to [`POWER`](/get-started/resources/glossary/#power) holders in a Voting Epoch. Each [`POWER`](/get-started/resources/glossary/#power) holder is given their pro rata share of the reward if they fully participate and the tokens are claimed simultaneously to voting. Tokens which go unclaimed are never minted. No tokens are distributed in an epoch with no active proposals. Set to 5,000,000. Logic: The reward amount should provide enough incentive to Standard Proposal voters to consistently vote while not destabilizing the protocol through unpredictable distribution. An additional consideration is the maximum level of decentralization that can be achieved given average gas fees – i.e. the reward must at least cover the average gas fee of participants and thus the average gas fee puts a practical boundary on the percentage of [`POWER`](/get-started/resources/glossary/#power) one must own to justify participation. \:::success Example Alice has 10% of the [`POWER`](/get-started/resources/glossary/#power) supply delegated to her. She fully participates in a Voting Epoch and is rewarded with 10% of the reward, in this case 500,000 [`ZERO`](/get-started/resources/glossary/#zero) tokens. ::: See the diagrams below for further illustration of the potential impact of the reward on the [`ZERO`](/get-started/resources/glossary/#zero) supply over time.
import ZoomableImage from '@/components/ZoomableImage'; ## IV. The M0 Economy ##### High-level description of the M0 economy. The M0 protocol is a coordination mechanism. It is not intended to replace existing financial actors, but rather to provide novel and more efficient means by which they can interact. We believe that a universal blockchain-based protocol, where rules and transparency are enforced by code, is superior to the feudal and opaque landscape of value transmission present today. The M0 Protocol is intended to coordinate [Minters](/get-started/resources/glossary/#minter), [validators](/get-started/resources/glossary/#validator), and [Earners](/get-started/resources/glossary/#earner). It is anticipated that offchain this may correspond to financial services providers (such as stablecoin issuers), auditors, and institutional holders of $M. ### IV.I Minters ##### What are [Minters](/get-started/resources/glossary/#minter) in the context of M0? [Minters](/get-started/resources/glossary/#minter) are primarily incentivized to join the protocol because they want to earn the spread between the yield (net of expenses) on their [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) and the protocol’s [Minter Rate](/get-started/resources/glossary/#minter-rate). In addition, the [Mint Ratio](/get-started/resources/glossary/#mint-ratio) will determine the attractiveness of Minting relative to the yield spread. The effective ROC (return on capital) of a Minter is net yield generated on the [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral), divided by the net cash investment, which is the capital invested into [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral), minus their Owed $M (assuming they were able to sell this $M at $1) plus the Administrative Buffer. It is anticipated that [Minters](/get-started/resources/glossary/#minter) in the M0 protocol will correspond to financial services providers (such as stablecoin issuers) offchain. The ultimate function of the Minter is the generation and management of the supply of $M. Considering the initial [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) is intended to be short term T-bills, it is assumed that the [Minter Rate](/get-started/resources/glossary/#minter-rate) will need to be less than the US Federal Funds rate. See the diagram below for a visual example of the basic Minter economics.
It is also anticipated that [Minters](/get-started/resources/glossary/#minter) will engage in arbitrage. If $M is trading above $1 on secondary markets, it is logical for [Minters](/get-started/resources/glossary/#minter) to deposit [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) in order to generate more $M This will boost their net yield. Conversely, if $M is trading below $1 on secondary markets, it is logical for [Minters](/get-started/resources/glossary/#minter) to repurchase $M and to use it to Retrieve [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral). This will also boost their net yield. It is for this reason that $M is expected to trade with some volatility around (US) $1 – the mechanism relies on sometimes inefficient and unpredictable market forces to achieve an average price of $1 over the long term.
There will be no built in mechanism at the protocol level to ensure the price stability of $M; rather, that will be achieved via the economic incentives described and visualized above. ### IV.II Validators ##### What are [validators](/get-started/resources/glossary/#validator) in the context of M0? Economically, all [validators](/get-started/resources/glossary/#validator) must be incentivized offchain or use periphery smart contracts. There is no Validator compensation in the core protocol. This decision was made because the Validator landscape is complex and the chance of accurately encapsulating these complex economic arrangements onchain was nil. For the basic function of providing signatures for Update Collateral, it is expected that [validators](/get-started/resources/glossary/#validator) and [Minters](/get-started/resources/glossary/#minter) will enter into binding, offchain legal agreements specifying applicable terms and appropriate compensation. It is anticipated that [validators](/get-started/resources/glossary/#validator) in the M0 protocol will eventually correspond to auditors offchain. The ultimate function of the Validator is to provide as close to real time attestation of the [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) being used to generate $M as possible. While the protocol considers all Validator addresses to be fungible, there are in fact many specializations that could occur offchain in the Validator ecosystem. For instance, there may be [validators](/get-started/resources/glossary/#validator) that specialize in signing off on onchain Collateral Value updates, while others act as “sentinels” and exclusively exist to call Cancel and Freeze on errant [Minters](/get-started/resources/glossary/#minter). The level of specialization could even go beyond the initial methods of the protocol as [Periphery Contract](/get-started/resources/glossary/#periphery-contract)s are added by the ecosystem. ### IV.III Earners ##### What are [Earners](/get-started/resources/glossary/#earner) in the context of M0? [Earners](/get-started/resources/glossary/#earner) are simply addresses approved by the [TTG](/get-started/resources/glossary/#ttg) to earn the [Earner Rate](/get-started/resources/glossary/#earner-rate). It is expected that, throughout the cycle, the [Earner Rate](/get-started/resources/glossary/#earner-rate) will remain comparable to the US Federal Funds rate as well in order to entice [Earners](/get-started/resources/glossary/#earner) to continue to hold $M. The [Earner Rate](/get-started/resources/glossary/#earner-rate) can be used as an additional tool to encourage $M price stability around $1. If the price of $M is above $1, the [TTG](/get-started/resources/glossary/#ttg) can lower the [Earner Rate](/get-started/resources/glossary/#earner-rate) in order to discourage holding of $M and to encourage selling of $M for alternative sources of yield. If the price of $M is below $1, the [TTG](/get-started/resources/glossary/#ttg) can raise the [Earner Rate](/get-started/resources/glossary/#earner-rate) in order to encourage the holding and purchase of $M. It should be noted that the [Earner Rate](/get-started/resources/glossary/#earner-rate) can be higher than the [Minter Rate](/get-started/resources/glossary/#minter-rate) as long as the amount of $M being paid out via the [Earner Rate](/get-started/resources/glossary/#earner-rate) is less than the amount of total $M generated from [Minter Rate](/get-started/resources/glossary/#minter-rate). It is anticipated that [Earners](/get-started/resources/glossary/#earner) in the M0 protocol will correspond to institutional holders of $M offchain, and to issuers and distributors that maintain $M inventory. The ultimate function of [Earners](/get-started/resources/glossary/#earner) is as a source of demand for $M, making it more likely that [Minters](/get-started/resources/glossary/#minter) can efficiently generate $M. This is effectively to say that [Earners](/get-started/resources/glossary/#earner) align nicely with the ultimate distributors of $M to the broader market. \:::success **Example** The [TTG](/get-started/resources/glossary/#ttg) permissions a large cryptocurrency exchange to the [Earners](/get-started/resources/glossary/#earner) list. This exchange has millions of users and is regulated/licensed appropriately in the jurisdiction(s) it serves. Once permissioned, the exchange can use customer’s $M to earn the [Earner Rate](/get-started/resources/glossary/#earner-rate). They can now pass a portion or all of the [Earner Rate](/get-started/resources/glossary/#earner-rate) on to their customers. :::
## Abstract The core M0 protocol is a coordination layer for permissioned institutional actors to generate $M. $M is a fungible token that can be generated by locking [Eligible Collateral](/get-started/resources/glossary/#eligible-collateral) in a secure offchain facility. The protocol enforces a common set of rules and safety procedures for the management of $M. ## Adopted Guidance v1.50 M0's Adopted Guidance outlines the core rules of engagement outside of the enforceable domain of the protocol smart contracts for the various actors in the M0 ecosystem. * **Document Version**: 1.50 * **Last updated**: August 5, 2025 * **Document hash**: f171a7c05bdd1e39a14d4799deda12f632195a64014b49688f10c5e3a7a7c28f (can be verified against the [PDF version](https://github.com/m0-foundation/adopted-guidance/blob/main/m0_adopted_guidance_v1.50.pdf) of this document) * **Governance approval**: see [here](https://governance.m0.org/proposal/98142676326281053231530662417190301636164164389599519553602654350153003684715). ## 5. Validators ### 5.1. Contact Information of Currently Permissioned Validators :::note Validator One GmbH Friedrichstr. 114A, 10117 Berlin, Germany [contact@validator-one.com](mailto\:contact@validator-one.com) [www.validator-one.com](http://www.validator-one.com) Public Key: 0xEF1D05E206Af8103619DF7Cb576068e11Fd07270 ::: :::note Chronicle Labs 190 Elgin Ave, George Town Cayman KY1-9005, Cayman Islands [hello@chroniclelabs.org](mailto\:hello@chroniclelabs.org) [www.chroniclelabs.org](http://www.chroniclelabs.org) Public Key: 0xEe4d4938296E3BD4cD166b9b35EE1B8FeD2F93C1 ::: ### 5.2. Eligibility Criteria for Permissioned Validators Validators shall fulfill the following minimum requirements: * Be a duly incorporated entity, not in a [High-Risk Jurisdiction](/home/fundamentals/adopted-guidance/ecosystem/#high-risk-jurisdictions). * Have minimum affiliation (via its shareholders) with or (practically) control by any Minter and/or SPV Operator (or the affiliates of those) that is in direct contractual relationship with for the provision of its services. To the extent that the Validator has overlapping stakeholders with other Actors within the ecosystem, it is the duty of the Validator to provide evidence of appropriate corporate governance. * Obtain and maintain all necessary authorizations and consents for the performance of its obligations under the Mandatory Contracts it needs to enter into with other ecosystem participants according to the Adopted Guidance. * Have technical visibility of the Collateral Storage, and specifically the ability to connect to the SPVs custody accounts, e.g. via API, direct observation of a distributed ledger, or other technical means, as well as to exchange Signatures with the Minter. * Have all applicable licenses and permissions in their jurisdiction. ### 5.3. Obligations of Validators Validators provide Signatures to Minters for the update of their Collateral Balance and for the removal of RetrievalIDs. This requires the Validators to have full visibility on: * The Minter’s Collateral Storage, including its Deposit Accounts. * All order flows of such accounts. * The appropriate blockchain addresses of a Minter’s Collateral Storage. In addition to verifying account data and compliance with the eligibility criteria for collateral, the Validators shall perform checks, given that it is in the interest of the Minter to provide maximum transparency on the collateral. Validators shall, for example, confirm that the Mandatory Contracts are in place between the Minter and the SPV Operator, as well as confirm that the country of incorporation of the SPV is in an Approved Jurisdiction at the time of each confirmation, etc. In the case that the Validator gains certain knowledge that certain Mandatory Contracts have been made invalid or have been terminated without a valid replacement, the Validator shall no longer provide Signatures until those contracts have been remedied in compliance with the Adopted Guidance. Should the Validator perceive obviously suspicious or obviously non-compliant mint proposals as well as mint proposals that are the result of obvious human error (by any Minter) it shall cancel such mint proposals within the Mint Delay time frame. The Validator shall in particular cancel mint proposals of Minters if the Validator was informed by the SPV Operator of such Minter that the Administrative Buffer is not meeting the criteria set out in the Adopted Guidance for as long as such breach exists. In emergency situations where a Validator has a justifiable reason to believe that a Minter is non-compliant with the Adopted Guidance in a material way, but does not refrain from submitting mint proposals, or a damage to the collateralization of $M is to be reasonably expected, the Validator shall use the freezeMinter() function until the situation is remedied. The use of the freezeMinter() and the cancelMint() functions shall not constitute any basis for claims for damage compensation by the affected Minter and/or its BD Minter against the Validator who has called such function. Validators shall only terminate a Minter-Validator Agreement with a notice period of no shorter than 90 days, including in the case of a Wind Down. They shall help the Minter to transition to a replacement Validator. If no replacement Validator can be found within this time window, the terminating Validator shall extend its service for the Minter for up to an additional 90 days upon request of the Minter. The right to terminate for cause shall remain unaffected. ### 5.4. Guidelines for Submission of Permissioning Requests An application for the permissioning as a Validator requires the whitelisting of the applicant’s public key on the list of permissioned Validators. Before submitting its application, the Validator shall make a KYC report public via appropriate channels, as well as appropriate proof that the requirements set forth in [Eligibility Criteria for Permissioned Validators are met](/home/fundamentals/adopted-guidance/validators/#eligibility-criteria-for-permissioned-validators): * Certified copies of the commercial register and/or trade register and/or register of companies or alike, proving that the company was duly incorporated in the jurisdiction it is providing its services from. * Proof of who the ultimate beneficial owners (UBO) of the company are. * Certified copies of all required official licenses required to operate the business and to provide the services outlined in the Adopted Guidance and in the contractual agreements where the Validator is a party to. * A legally binding declaration that no insolvency, bankruptcy or similar/comparable proceedings are currently pending or to be anticipated in the foreseeable future in relation to the company. * Proof that the company is minimally affiliated (via its shareholders) with or (practically) controlled by any SPV Operator and/or Minter the Validator is in direct contractual relationship with for the provision of its service. When there is some level of affiliation, relevant evidence of appropriate corporate governance shall be presented. * A legally binding declaration, as long as objectively and legally possible, to set up its business activities in regards to the services and contractual relationships as outlined in the Adopted Guidance. * A legally binding commitment, as long as objectively and legally possible, to amend its contractual relationships reflecting potential mandatory changes of the Adopted Guidance. Where confidentiality concerns emerge the M0 Foundation can step under Non-Disclosure Agreements to analyze the required documentation and provide a qualified public opinion to the ecosystem. import ZoomableImage from '@/components/ZoomableImage'; ## 4. SPV Operators An SPV Operator is the Actor managing the portfolio of collateral in the SPV on behalf of the SPV but for the benefit of a Minter’s business operation. The SPV Operator also acts as selling agent in the context of a wind down (as described in [Obligations Outside of the Normal Course of Business](/home/fundamentals/adopted-guidance/spv-operators/#obligations-outside-of-the-normal-course-of-business)) and can even wind down a Minter in cases where the Minter is unable or unwilling to comply with the Protocol rules. Adopted Guidance indicates the entities that should be considered as appropriate to act as SPV Operators in the M0 ecosystem. ### 4.1. Contact Information of Currently Approved SPV Operators :::note CrossLend GmbH Leipziger Str. 124, 10117 Berlin, Germany [operations@crosslend.com](mailto\:operations@crosslend.com) [www.crosslend.com](http://www.crosslend.com) ::: ### 4.2. Eligibility Criteria for Approved SPV Operators SPV Operators shall fulfill the following minimum requirements: * Be a duly incorporated entity in an [Approved Jurisdiction](/home/fundamentals/adopted-guidance/eligible-collateral/#approved-jurisdictions). * Minimum affiliation (via its shareholders) with or (practically) control by any Validator and/or Minter, or the affiliates of any Validator or Minter. To the extent that the SPV Operator has overlapping stakeholders with other Actors within the ecosystem, it is the duty of the SPV Operator to provide evidence of appropriate corporate governance and liability separation in dealing with collateral. * It has obtained and maintained all necessary licenses, authorisations and consents for the performance of its obligations under the mandatory agreements it needs to enter into with other ecosystem participants according to the Adopted Guidance. * It maintains a contractual relationship with the SPV that under no circumstance endangers the status of that SPV to be considered as such in its Approved Jurisdiction, as outlined in [Approved Jurisdictions](/home/fundamentals/adopted-guidance/eligible-collateral/#approved-jurisdictions). * It has meaningful equity to sustain its business. * It has developed and can provide upon request a business plan for the following 3 years of operations. ### 4.3. Obligations of SPV Operators SPV Operators are expected to enter into a Minter-SPV Operator Agreement with every Minter they provide services to. Today, these agreements are considered part of the Mandatory Contracts as defined in the Adopted Guidance. In case of any change to the Mandatory Contracts, the Minter and SPV Operator, as any other Actor, are expected to amend the Minter-SPV Operator Agreement accordingly without delay. The mandate of the SPV Operator to manage the collateral is intended to have the main objective be to protect the stability of $M under all possible circumstances. For this reason, the Adopted Guidance suggests prudence in adopting technological innovation at this level of the stack. To that end, the duties of the SPV Operator can be divided into two groups: * Obligations in the Normal Course of Business * [Obligations Outside of the Normal Course of Business](/home/fundamentals/adopted-guidance/spv-operators/#obligations-outside-of-the-normal-course-of-business) The Normal Course of Business generally refers to the scenario where the Minter operates in accordance with the Protocol rules and is fully capable of doing so. As a consequence, outside the Normal Course of Business refers to all scenarios where the Minter is, for example, non-compliant with the rules of the Protocol, enters into insolvency, or is incapacitated or unwilling to fulfill its obligations for other reasons. #### 4.3.1. Obligations in the Normal Course of Business In the Normal Course of Business the SPV Operator shall manage the Collateral Storage in accordance with the Adopted Guidance and all applicable laws and regulations. To that extent, the SPV Operator shall use most or all available financial resources (including Deposit Equivalents) to purchase Eligible Collateral. Some flexibility on reinvestment should be provided to the SPV Operator in order to timely fulfill existing or foreseen Retrieval Requests. It shall do so whenever available financial resources are existing in the Collateral Storage unless such available financial resources are part of a Retrieval Request or the amount is economically negligible. The following chart shows an example of the replenishment of Eligible Collateral in the Normal Course of Business:
1. Any liquidity event affecting any collateral instrument (e.g. upon maturity of the instrument or as regular interest payment or other cashflow) is paid within the Collateral Storage, or more specifically to the custody accounts of the SPV. 2. Without delay, the SPV Operator initiates the purchase of new Eligible Collateral. This means that the amount of collateral, all other factors unchanged, will grow over time. The only way for the Minter to extract collateral is via the Retrieval Process. The SPV Operator shall also cooperate with the Minter to execute Retrieval Processes. When a Minter requests a retrieval of collateral with the SPV Operator, the SPV Operator shall verify that a respective RetrieveID is existing in the Protocol. Once verified, the SPV Operator shall timely sell a corresponding amount of collateral and/or use liquidity from maturity collateral maturing at the same day and transfer the amount requested to be retrieved to the Minter. #### 4.3.2. Obligations Outside of the Normal Course of Business The interruption of a Minter’s Normal Course of Business, due to a diverse set of circumstances that the Adopted Guidance intends to address, should immediately or within a realistic timeframe lead to a Wind Down of such a Minter.
Minter De-Permissioning refers to any event resulting in a successful Governance vote to remove a Minter from the list of Permissioned Minters. Permissioned Minters are any entities in the M0 ecosystem that have been permissioned by Governance to mint $M The Minter De-Permissioning is the main smart-contract enforced way for a Minter to leave the Normal Course of Business and enter a Wind Down process. A Wind Down is the process of progressively terminating a Minter’s operations by the SPV Operator, who sells or otherwise realizes the Eligible Collateral, using all available financial resources to purchase $M in the market, and burning such $M in repayment of the Minter's Owed $M Depending on the scenario, such a Wind Down will be done either in an amicable way – i.e. the Amicable Wind Down, or under the full control of the SPV Operator – i.e. the Non-Amicable Wind Down. The intention of this staged process is to give the ability to a Minter in good faith with the ability to remedy its actions and provide an orderly execution of its exit process, while maximizing funds recovery in the interest of the protocol. In other exceptional cases in which a Minter is incapable of redeeming, a Minter’s set of counterparties could go directly to the SPV Operator for the successful execution of a primary redemption, provided that all core principles of the Adopted Guidance remain intact. During an Amicable Wind Down the Minter shall continue to engage the service of a signature threshold of Validators. The Validator(s) shall continue to check the appropriate balances of the Minter’s SPV and will publish this information to a public forum at least once per Update Collateral Interval. ##### 4.3.2.1. Amicable Wind Down Process The document refers to an Amicable Wind Down Period as a 90-calendar day period starting on the day after a Minter De-Permissioning. In providing a window for the execution of an Amicable Wind Down, the Adopted Guidance intends to avoid, as much as possible, any unfairness towards a Minter, as well as protect its ability to resolve any outstanding liability against the protocol. During an Amicable Wind Down, the SPV Operator shall act as the supervisor of the orderly wind down and shall assist the Minter on a best-effort basis in redeeming its Owed $M To redeem, the Minter shall purchase and burn $M by calling the burn() function and specifying the Minter’s address in that call, which effectively reduces the Minter’s Owed $M balance by the burned amount. Following each Burn Event in its respective address, the Minter shall notify the SPV Operator, and the SPV Operator shall verify the occurrence of such Burn Event onchain. Upon successful verification, the SPV Operator shall initiate the sale of Eligible Collateral and transfer an amount to the Minter that equals the amount burned in a Burn Event divided by the Mint Ratio, which was valid at the time the Minter De-Permissioning occurred. During an Amicable Wind Down, the SPV Operator shall not be obliged to meet any portfolio composition requirements laid out in the Adopted Guidance. If the Minter wishes to provide recommendations to the SPV Operator concerning the sale of Eligible Collateral with respect to (including but not limited to) minimum execution price, execution time and type of instrument, such recommendations shall not be binding. However, the SPV Operator shall commit to following them solely on a best-effort basis. If a full repayment of the Minter’s Owed $M is reached within the Amicable Wind Down period, any residual financial value shall be paid to the Minter. If a full repayment is not reached within the Amicable Wind Down period, no further amounts shall be paid to the Minter and the SPV Operator shall initiate a Non-Amicable Wind Down, as described below. For sake of clarity: during the Amicable Wind Down Process, the option to transition into a Non-Amicable Wind Down Process with immediate effect is not excluded. While it is the main goal of the SPV Operator to protect the stability of M, this can only be achieved if the SPV Operator does not face a situation where itself might be in violation of applicable laws within the jurisdiction it is operating from. Therefore, in the case of severe changes in circumstances, especially but not limited to its contractual relationship with the Minter, leading to the situation that the SPV Operator needs to cease its contractual relationship with the Minter to maintain compliance, the SPV Operator might transition from a Amicable to a Non-Amicable Wind Down Process with immediate effect in regards to the Minter. ##### 4.3.2.2. Non-Amicable Wind Down Process Once the Amicable Wind Down Period has lapsed, and provided that the Owed $M exceeds 0 and the Collateral Storage still contains collateral, the SPV Operator shall unilaterally and contractually wind down the Minter’s structure through the so-called Non-Amicable Wind Down. In case the Minter has not been de-permissioned before, i.e. if the Non-Amicable Wind Down has been triggered by exceptional conditions described below, the SPV-Operator is required to submit a governance proposal to de-permission the respective Minter. The SPV Operator shall act as a selling agent of the collateral and shall distribute all proceeds in accordance with the rules of the Adopted Guidance. More specifically, as part of the Non-Amicable Wind Down, the SPV Operator shall no longer disburse any proceeds from the sale of collateral to the Minter. As part of a Non-Amicable Wind Down, in the case a Minter is incapable or non-cooperative of redeeming, a Minter’s set of counterparties could go directly to the SPV Operator for the successful execution of a primary redemption, provided that all core principles of the Adopted Guidance remain intact and that the appropriate contractual obligations between Minter and counterparties regulate those situations. The SPV Operator shall exercise best effort in reaching the maximum reduction of Owed $M related to the Minter part of the Non-Amicable Wind Down process by, e.g.: * Waiting for collateral maturity while interrupting the automatic replenishment (run down the portfolio) if the market conditions require to do so, and subsequently burn such $M on the Minter’s behalf. * Selling all remaining collateral on a best effort basis and using all available proceeds to purchase $M on the open market, and subsequently burn such $M on the Minter’s behalf. * Enter into contractual agreements to dispose of assets and liabilities to another Minter in the network still in the Normal Course of Business. Should the SPV Operator, due to market conditions surrounding the purchases, have remaining $M balance in its control, although the Owed $M of the Minter is 0, the SPV Operator shall burn such $M and increase the system-wide implicit overcollateralization. Should purchased $M not be sufficient to fully bring the Owed $M of the Minter to 0, such Owed $M will continue to exist, effectively decreasing the Protocol-wide overcollateralization. Governance should act proactively to ensure that such a scenario will never materialize, by appropriately monitoring individual collateralization levels and/or de-permissioning Minters that constitute excessive risk for the Protocol. In addition to Minter De-Permissioning, the Adopted Guidance considers additional circumstances that should lead immediately to a Non-Amicable Wind Down. Those circumstances are described below. ##### 4.3.2.3. Minter Insolvency The SPV Operator shall enter into a Non-Amicable Wind Down immediately as soon as they receive a valid notification that a Minter has filed for (or has been filed for) insolvency. The Minter shall need to indemnify the SPV Operator for any claims brought forward by an insolvency administrator against the SPV Operator in context of a insolvency-related Non-Amicable Wind Down. ##### 4.3.2.4. Unauthorized Termination of Minter – SPV Operator Agreement It is crucial that all Eligible Collateral is always available to back the Owed $M To that end, it is mandatory that Minters contract with SPV Operators who are permissioned by Governance and listed in the Adopted Guidance to operate the Collateral Storage. To avoid any circumvention of Governance-led rules, e.g. by exchanging the SPV Operator with an unauthorized party, it is expected that Minters shall only replace an SPV Operator with another permissioned SPV Operator. In the case a Minter, while remaining a Permissioned Minter or within the Amicable Wind Down Period, terminates the Minter-SPV Operator Agreement without replacing it with another viable agreement meeting the criteria as outlined in the Adopted Guidance, the SPV Operator shall perform an immediate Non-Amicable Wind Down. A termination during a Non-Amicable Wind Down shall generally be excluded. #### 4.3.3. Operational Obligations of SPV Operators To ensure smooth operations the SPV Operator needs to comply with the following additional obligations. ##### 4.3.3.1. Co-signature of the SPV for significant payments To protect against unauthorized transactions that could lead to significant loss of funds, the SPV Operator shall set up the respective Collateral Storage such that the signature of the SPV (via its corporate service provider) shall be required (in addition to its own) in order to externally transfer financial resources that are considered significant payments. The definition of what constitutes significant payments, as well as the respective sign off limits, shall be assessed and if necessary, adjusted on a quarterly basis such that payments exceeding the typical interest payments (in case existing) require the signature of the SPV via its corporate service provider. ##### 4.3.3.2. Cooperation with Validators The SPV Operator shall cooperate in any required way, as defined in the Adopted Guidance, with Validators in the network. This includes supporting the Minter to provide read access to the Validator of the Collateral Storage. ##### 4.3.3.3. Maintenance of Administrative Buffer **Administrative Buffer** is defined as a reserve of 25,000 worth of Deposit Equivalents that the SPV Operator can use to cover possible offchain administrative costs, such as assisting with the Wind Down of the Minter or resolving legal disputes, according to the rules set out in the Adopted Guidance. Such a buffer should exist within the Collateral Storage in a way considered satisfactory by the SPV Operator, but should not in any case be simultaneously pledged to the system as Eligible Collateral for minting. For the avoidance of doubt, the SPV Operator shall be allowed to use the Administrative Buffer to ensure operations in cases where the Minter is unwilling or unable to cooperate. Where the Administrative Buffer is not meeting the minimum amount specified in the Adopted Guidance, the Minter shall not submit any mint proposals. Should the Minter still submit a mint proposal despite an insufficient Administrative Buffer, the SPV Operator shall socialize this concern (i.e. through the network of Validators, Governors, or other stakeholders). As in any social consensus construct, stakeholders are expected to act accordingly, in their own interest. Only following the completion of a Wind Down, any unused part of the Administrative Buffer is to be paid back to the Minter. ##### 4.3.3.4. No Wire Back Instructions The SPV Operator shall not wire back any financial resources to the Minter except for: * Orderly Retrieval Process. * Residual financial value, if applicable following a Wind Down process described above. ### 4.4. Guidelines for Submission of Approval Requests An application for the approval as SPV Operator shall be submitted via a change proposal of the Adopted Guidance following the process described in [Change Process for the Adopted Guidance](/home/fundamentals/adopted-guidance/description/#change-process-for-the-adopted-guidance). The change proposal shall aim to add the SPV Operator to [Contact Information of Currently Approved SPV Operators](/home/fundamentals/adopted-guidance/spv-operators/#contact-information-of-currently-approved-spv-operators). Before submitting its application, the SPV Operator shall publish a KYC report via appropriate channels, as well as appropriate proof that the requirements set forth in [Obligations of SPV Operators](/home/fundamentals/adopted-guidance/spv-operators/#obligations-of-spv-operators) are met: * Certified copies of the commercial register and/or trade register and/or register of companies or alike, proving that the company was duly incorporated in the jurisdiction it is providing its services from. * Proof of who the ultimate beneficial owners (UBO) of the company are, including proof for negative politically exposed persons (PEP) / sanctions check. * Certified copies of all required official licenses required to operate the business and to provide the services outlined in the Adopted Guidance and in the contractual agreements where the SPV Operator is a party to. * A legally binding declaration that no insolvency, bankruptcy or similar/comparable proceedings are currently pending or to be anticipated in the foreseeable future in relation to the company. * Proof that the company is minimally affiliated (via its shareholders) with or (practically) controlled by any Validator and/or Minter named as permissioned actor in the Adopted Guidance. When there is some level of affiliation, relevant evidence of appropriate corporate governance shall be presented. * A legally binding declaration, as long as objectively and legally possible, to set up its business activities in regards to the services and contractual relationships as outlined in the Adopted Guidance. * A legally binding commitment, as long as objectively and legally possible, to amend its contractual relationships reflecting potential mandatory changes of the Adopted Guidance. Where confidentiality concerns emerge, the M0 Foundation can step under Non-Disclosure Agreements to analyze the required documentation and provide a qualified public opinion to the ecosystem. ## Adopted Guidance PDF Version v1.50 in PDF format. Find below the version 1.50 of M0's Adopted Guidance, a document that outlines the core rules of engagement outside of the enforceable domain of the protocol smart contracts for the various actors in the M0 ecosystem. > [https://github.com/m0-foundation/adopted-guidance/blob/main/m0\_adopted\_guidance\_v1.50.pdf](https://github.com/m0-foundation/adopted-guidance/blob/main/m0_adopted_guidance_v1.50.pdf) ## 3. Eligible Collateral ### 3.1. Criteria for Eligible Collateral We expect Validators to solely and exclusively recognize assets as Eligible Collateral when such assets conform to the criteria below. #### 3.1.1. Criteria for the Eligibility of Assets i. Funds (denominated in the Reference Currency) credited to an account at a United States Federal Reserve Bank. ii. Funds (denominated in the Reference Currency) held as demand deposits or insured shares at an insured depository institution - subject to specific institution in scope. a. Such financial institutions shall be deemed to be automatically in scope if the totality of deposits are held in deposit placement networks. (Note: Minter must perform a credit suitability assessment prior to placing funds at such an institution.) b. List of institutions additionally deemed in scope: (1) The Bank of New York Mellon Corporation; (2) DekaBank Deutsche Girozentrale; (3) Lead Bank. iii. United States Treasury securities with a remaining time to maturity of 180 days or less. iv. Funds (denominated in the Reference Currency) received under repurchase agreements where the Minter is the seller and with an overnight maturity. v. Reverse repurchase agreements where the Minter is the cash lender and with an overnight maturity, that are backed by United States Treasury securities and other government securities such as securities issued or guaranteed by government agencies, including, among others, Fannie Mae, Freddie Mac, and the Federal Home Loan Bank. In the event that collateral is not in the form of United States Treasury securities, such reverse repurchase agreement must be overcollateralized at a rate deemed to be appropriate by the Minter. vi. Securities issued by a regulated investment company, regulated fund or supervised entity, that is subject to prudential supervision in its home jurisdiction, provided that such vehicle invests exclusively in assets described in items (i), (ii), (iv) and (v). Specific to the requirements in (iii), securities shall be permitted to have a remaining maturity of 397 days or less so long as the weighted average portfolio maturity is 60 days or less and the weighted average portfolio life to maturity is 120 days or less. vii. Any version of items (i), (ii), (iii), (vi) in tokenized form, provided that such versions comply with all applicable laws and regulations - subject to specific definition of the financial product in scope. a. List of approved products: (1) Superstate Short Duration US Government Securities Fund (commonly referred to as USTB); (2) BlackRock USD Institutional Digital Liquidity Fund (commonly referred to as BUIDL). #### 3.1.2. Ancillary Criteria for the Eligibility of Assets * So-called In-Transit Cash, defined as Deposit Equivalents in an amount equal to placed-and-executed-but-not-yet-settled buy orders for assets defined in 3.1.1. In case such orders are ultimately canceled, settled, or never settled, such balances shall no longer be recognized. * So-called In-Transit Securities, defined as executed-but-not-yet-settled sell orders for assets defined in 3.1.1 (at the time of purchase) in case, for the avoidance of doubt, neither the securities nor balances in Deposit Equivalents are listed in the Collateral Storage (and more specifically Custody Account and Deposit Account of the SPV). ### 3.2. Valuation Policy for Eligible Collateral Eligible Collateral shall be recognized at their daily market value (according to the last closing price) published on [www.treasurydirect.gov](http://www.treasurydirect.gov). Alternatively, for approved wrappers, the recognition of the most recent NAV (net asset value) calculated by a third-party agent and published by the asset manager / fund administrator is admissible. It is understood that Validators and Minters might not observe the same market price in case they access the market data at different times. Minters shall consider this when requesting signatures for updateCollateral() calls from Validators. With Signature we refer to the cryptographically hashed meta information of a transaction with the private key of the Validator which allows the Minter to perform a certain Protocol transaction after the Validator has verified that the conditions for such a transaction are met. * So-called In-Transit Cash, defined as Deposit Equivalents in an amount equal to placed-and-executed-but-not-yet-settled buy orders for assets defined in (i). In case such orders are ultimately canceled, settled, or never settled, such balances shall no longer be recognized. * So-called In-Transit Securities, defined as executed-but-not-yet-settled sell orders for assets defined in (i) (at the time of purchase) in case, for the avoidance of doubt, neither the securities nor balances in Deposit Equivalents are listed in the Collateral Storage (and more specifically Custody Account and Deposit Account of the SPV). ### 3.2. Valuation Policy for Eligible Collateral Eligible Collateral shall be recognized at their daily market value (according to the last closing price) published on [www.treasurydirect.gov](http://www.treasurydirect.gov). Alternatively, for approved wrappers, the recognition of the most recent NAV (net asset value) calculated by a third-party agent and published by the asset manager / fund administrator is admissible. It is understood that Validators and Minters might not observe the same market price in case they access the market data at different times. Minters shall consider this when requesting signatures for updateCollateral() calls from Validators. With Signature we refer to the cryptographically hashed meta information of a transaction with the private key of the Validator which allows the Minter to perform a certain Protocol transaction after the Validator has verified that the conditions for such a transaction are met. In proposing valuation options for Eligible Collateral, the Adopted Guidance document has considered two alternative options: mark-to-market, and at-cost, opting ultimately for a mark-to-market approach. The two options somehow reflect similar accounting methodology for so-called held for trading or available for sale assets, and have a set of pros and cons that have been analyzed when proposing one over another: **Fair value representation**: the current executable market price of an asset remains the most accurate representation of its value at any given time. By opting for a mark-to-market approach Minters would see the immediate benefit of the appreciation of a fixed income asset as it approaches maturity, without having to realize it. Given the eligible instruments, we believe that a mark-to-market approach would allow Minters to operate based on the most accurate level of overcollateralization. **Non-arbitrage**: reflecting collateral value fluctuations onchain can prevent misalignments and unexpected behaviors due to arbitrage opportunities among parties. This is particularly important in scenarios of extreme price movements driven by significant interest rate changes. We are aware that recognizing the mark-to-market fluctuations of fixed income instruments onchain, even without the obligation for a Minter to redeem those assets at will, could expose the structure to interest rate risk and, in extreme scenarios, bank-run phenomena. While we believe that those effects should be accounted for and mitigated by appropriate levels of overcollateralization, similar to what happens for a bank's core capital, we think that the nature of Eligible Collateral today, as well as the dominant macroeconomic conditions, make those risks manageable. **Capital efficiency**: the continuous increases in Minters' Owed $M due to the accrual of Minter Rate introduces natural pressure on the Collateralization Ratio. Valuing collateral at market price can alleviate this pressure, due to the time value of the instruments currently considered eligible. It is important to remember that the recommended Valuation Policy is strictly interdependent with the nature of the Eligible Collateral. Following an evolution of the eligibility criteria, e.g. expanding towards longer maturities of different asset classes, will require, among other things, a revision of the Valuation Policy. This will be valid also in case of significant shifts in the current economic landscape. Collateral that is to be considered Eligible Collateral under the conditions set forth in Ancillary Criteria for the Eligibility of Assets shall be valued without a haircut. ### 3.3. Collateral Storage Collateral shall only be recognized as Eligible Collateral by the Validator if this collateral is appropriately held in the Collateral Storage. Given the current technological conditions, and the nature of the Eligible Collateral proposed by the Adopted Guidance, with appropriate Collateral Storage we refer specifically to the fact that the entity that legally owns the collateral (SPV) fulfills a set of requirements as described below. The fulfillment of these requirements should be verified through cooperation between Minters (via appropriate transparency), Validators, and Governance oversight in a way deemed satisfactory by Governance. The appropriate execution of the Mandatory Contracts described above should satisfy those conditions. Based on this set of fundamental requirements, the SPV: * is an orphaned entity; * is minimally affiliated (via its shareholders) with or (practically) controlled by any Validator or Minter or the affiliates of any Validator or Minter; * does not conduct any other business except the storage of collateral for Minters and issuance of Notes to Minters; * is a restricted-purpose vehicle that prevents entering into any other liabilities but the ones directly related to the storage of collateral and the issuance of Notes against such collateral; * is designed to be insolvency remote; * is incorporated in an Approved Jurisdiction, as described below; * possesses all required licenses and permissions (if necessary) to store collateral and to issue Notes against such collateral; * is audited on an annual basis by a licensed auditor deemed appropriate to perform the task. Additionally, any Notes issued to the Minter shall comply with the following in order to be considered Eligible Collateral: * Full asset segregation of collateral not only at the Minter level, but also at the level of each wallet address controlled by the Minter — in case the Minter controls more than one permissioned address. * Limited recourse so that the claims of any Minter are strictly limited to the collateral belonging to its Notes. ### 3.4. Approved Jurisdictions Given the current technological conditions, and the nature of the Eligible Collateral proposed by the Adopted Guidance, any form of collateral shall only be recognized as Eligible Collateral by the Validator if the Collateral Storage is located in one of the jurisdictions listed below: * Luxembourg * The Cayman Islands * United States of America As for other elements of the Adopted Guidance, the list of Approved Jurisdictions (as described above) can be amended any time through a Governance vote. In case the list is amended, Actors are expected to ensure compliance with and enforceability of the rules set out in the Adopted Guidance in such a new jurisdiction. Candidates for Approved Jurisdictions shall comply with the following minimum requirements: #### 3.4.1. Bankruptcy Remoteness The jurisdiction provides legal and structural mechanisms that reduce the risk of insolvency for the legal entity, reinforcing the effectiveness of provisions that prevent creditors and investors from initiating insolvency proceedings against the legal entity or seizing its assets or the assets of its compartments, estates or sub-funds. #### 3.4.2. Non-Petition and Non-Seizure Provisions Jurisdictions must uphold provisions that prevent creditors and investors from initiating insolvency proceedings against a legal entity or seizing its assets or the assets of its compartments or estates or sub-funds, thus ensuring the legal entity's bankruptcy remoteness. #### 3.4.3. Priority of Payments and Subordination The legal system recognises and enforces contractual or statutory arrangements that clearly define the priority of payments and the subordination of claims among investors and creditors. #### 3.4.4. Regulatory Compliance The jurisdiction has a regulatory framework that supports the business activities of the legal entity, including clear guidelines for the trading of financial instruments and Eligible Collateral associated with them. #### 3.4.5. Legal and Regulatory Framework The jurisdiction has a legal and regulatory framework that permits the issuance of financial instruments and the investment in Eligible Collateral. #### 3.4.6. Political Stability The jurisdiction exhibits a high degree of political stability, characterized by a consistent and predictable legal and regulatory environment, minimal political unrest, and an upholding of the rule of law. #### 3.4.7. Dispute Resolution An effective legal framework for dispute resolution is in place, including access to courts or arbitration panels. #### 3.4.8. Asset Segregation Collateral for each Minter is either to be stored in a separate legal entity per Minter or the jurisdiction must provide legal frameworks that enable the establishment of separate compartments or estates or sub-funds within a single legal entity, ensuring that each compartment or estate or sub-fund is its own distinct pool of assets and liabilities. There must be clear legal recognition that assets within one compartment or estate or sub-fund are exclusively reserved for the investors and creditors of that compartment or estate or sub-fund and are protected from the claims of creditors of other compartments or estates or sub-funds and claims of creditors of the legal entity to ensure the functioning of the intended wind down processes, as described below. #### 3.4.9. Limited Recourse The legal system must enforce that the claims of investors and creditors are strictly limited to the assets of the compartment or estate or sub-fund to which they have exposure. In cases where the assets of a compartment or estate or sub-fund are insufficient to satisfy the claims, the legal framework permits the extinguishment of any remaining claims, prohibiting further recovery efforts. #### 3.4.10. Investor Protection There are robust mechanisms in place to protect investors, including clear disclosure requirements and the enforcement of fiduciary duties by the managers of the legal entity. #### 3.4.11. Operational Infrastructure The jurisdiction boasts a developed financial infrastructure capable of supporting complex financial transactions, including experienced service providers and legal counsel with expertise in financial matters. #### 3.4.12. Custody Relationship The jurisdiction recognises and enforces the legal nature of the custody relationship between the legal entity and its custodian, ensuring that assets held in custody are protected and segregated from the custodian's general estate in the event of its bankruptcy. #### 3.4.13. Audit The jurisdiction requires the mandatory (by law) audit of the annual financial statements of the legal entity. Where such audits are not required by law in the jurisdiction, the audit obligation must be embedded contractually in the entity’s governing documents or operator agreements. import ZoomableImage from '@/components/ZoomableImage'; ## 2. Ecosystem Description The M0 Protocol is designed to support permissioned Actors in the minting of a crypto asset called $M The minting of $M requires collaboration across a set of Actors complying with a set of rules, some of which can be enforced onchain. First and foremost, a sufficient balance of Eligible Collateral (as described in the Adopted Guidance) must be constantly identifiable and constrained for the backing of Owed $M This requires a demonstration of the existence and validity of the collateral, repeated on an ongoing basis, and executed via the updateCollateral() function call. Only if sufficient collateral balance has been updated and only if such balance is still valid within the timeframe implied by the collateral update interval can a Minter (see below) mint $M or retrieve collateral. With Eligible Collateral we refer to the types of collateral that are defined to be suitable to back M, based on the criteria listed in [Criteria for Eligible Collateral](/home/fundamentals/adopted-guidance/eligible-collateral/#31-criteria-for-eligible-collateral). With Collateral Balance we refer to the onchain value of the Eligible Collateral available to mint $M The sufficiency of the Collateral Balance is determined by the following Core Operating Condition: ```math (Collateral \ Balance - Total \ Pending \ Retrievals) \times Mint \ Ratio \geq Owed \ $M + Proposed \ M ```
Subject to the following definitions: * **Total Pending Retrievals** indicate the total amount of collateral a Minter is trying to retrieve from SPV by submitting a Retrieval Request to the protocol via the proposeRetrieval() function. * **Retrieval Request** is the process by which a Minter submits a request to the Protocol to retrieve a specified amount of $M The Protocol verifies that the Core Operating Condition would not be breached by the retrieval of this amount of M, based on the latest Collateral Balance. * **Mint Ratio** refers to the fraction of a Minter’s Collateral Balance that can be used to generate M, which effectively controls the leverage of a Minter and the over-collateralization of $M * **Owed M** describes the amount of $M generated by the Minter, plus the Minter's Accumulated Minter Rate and Penalty, still outstanding — i.e. not burned. * **Proposed M** is the amount of new $M that a Minter is requesting to mint. The Core Operating Condition intends to guarantee that no $M can be minted and/or no collateral can be retrieved unless there is sufficient Collateral Balance. We define Burn (or Burned M) as a successful call to the `burn()` function, which specifies a Minter’s address. Such operation effectively reduces that Minter’s Owed $M balance by the amount of burned $M ### 2.1. Actors Actors are relevant participants (roles and entities) within the M0 ecosystem. Only a subset of the Actors (so-called Permissioned Actors) are explicitly approved through Governance, while the rest is explicitly, albeit more loosely, identified as part of the Adopted Guidance. The following diagram displays a schematic view of the Actors within the M0 ecosystem and how they connect to external parties (i.e. parties whose practices are not covered by the Adopted Guidance) and contracts that need to be in place between Actors. The list of Actors is defined below.
**Minter**: The Minter is an entity considered orphaned from the risk of exogenous insolvency, operated by a separate entity responsible for business operations that is in place to further distance the Minter from bankruptcy issues (referred to here as the BD Minter). The Minter owns the private key associated with a public address that is permissioned by Governance to interact with a minting smart contract in order to mint $M against a sufficient Collateral Balance, represented by Notes which are issued by the SPV (see below for details) and held on the Minter’s balance sheet. The Minter is not allowed to conduct any other business or take on any other liabilities except the $M balance it owes to the Protocol and the contractually defined liabilities vis-à-vis the BD Minter. **BD Minter**: The BD Minter is the business development entity that performs the operational obligations of the Minter and contractually absorbs any and all potential liabilities arising from agreements with service providers of the Minter. While the suggested exclusive relationship between the Minter and the BD Minter should not be overly prescriptive, we emphasize that this provision aims to maintain liability segregation, keeping all non-minting responsibilities away from the Minter. **SPV Operator**: The SPV Operator manages the portfolio of collateral in the SPV on behalf of the SPV but for the benefit of a Minter’s business operations. The SPV Operator also acts as selling agent in the context of a wind down (as described in [Obligations Outside of the Normal Course of Business](/home/fundamentals/adopted-guidance/spv-operators/#obligations-outside-of-the-normal-course-of-business)) and can even wind down a Minter in cases where the Minter is unable or unwilling to comply with the Protocol rules. **SPV**: The SPV is the orphaned and insolvency-remote legal owner of the Eligible Collateral, available financial resources, or of any other asset which is managed by the SPV Operator. **Validator**: The Validator independently verifies that the amount of collateral to be published onchain appropriately exists and is compliant with appropriate eligibility criteria. We expect the role of Validator to evolve jointly with the evolution of the nature of the underlying available collateral (e.g. appropriate tokenization). ### 2.2. Mandatory Contracts **Mandatory Contracts** are contracts that are required to be in place between the Actors to ensure maximum protection for the collateral as well as maximum degree of enforceability of the Protocol rules. The execution of these contracts should improve robustness against collusion among malicious Actors. As with many aspects outlined in the Adopted Guidance, the following set of contracts is intended for scenarios where no robust onchain equivalent exists. With advancements in tokenization efforts for instruments deemed Eligible Collateral, we anticipate that some of these contracts may become redundant in future updates of the Adopted Guidance. Given that Governance participants and holders of $M are likely not contractual parties to any of the Actors, the Mandatory Contracts are designed to ensure alignment among all Actors involved in the legal and operational framework, ensuring compliance with Protocol rules. **Minter Operating Memorandum**: The Minter is an entity with a contractually-limited purpose to hold Notes and mint $M Therefore, it is not allowed to e.g. hire personnel and build operational resources or directly enter into distribution agreements, as well as sale/ purchase agreement, with buyers of $M Notes are defined as pass-through and look-through limited recourse notes issued by the SPV in one or more tranches in accordance with the Terms and Conditions of the Note itself. The Minter Operating Memorandum should regulate that: * The BD Minter provides sufficient operational resources to the Minter for its operations, given that the Minter should not have operational staff. * The BD Minter and Minter should have appropriate liability segregation in order to limit eventual spillovers between general liabilities and those solely related to the Protocol with regards to the requirement to back the Owed $M by sufficient Collateral Balance. Minter-SPV Operator Agreement: The relationship between the Minter and the SPV Operator is of core importance since the intentional split between an entity that mints $M and another entity that manages the collateral creates a field of tension between collaboration, control and potential enforcement. The Minter-SPV Operator Agreement should regulate this relationship. It differentiates between two scenarios: * a) Normal Course of Business * b) Outside Normal Course of Business While the Normal Course of Business regulates the obligations of the SPV Operator to maintain the Eligible Collateral balance, the Outside Normal Course of Business ensures that the SPV Operator is allowed to perform actions against the Minter to enforce the Protocol rules in case the Minter is not compliant. This agreement is crucial for the protection of the collateral. **Minter-Validator Agreement (where required)**: The Validator requires broad ongoing visibility of the collateral storage. With **Collateral Storage** we identify the collection of venues such as Securities and Deposit Accounts, as well as digital asset accounts, held by the SPV. The services provided by a Validator to the Minter (and, indirectly, the ecosystem) need to be well-defined to ensure the smooth operation of the Protocol. Therefore, this agreement, where required, should regulate all transparency, access and confidentiality aspects between the parties, as well as the service of validation in compliance with the Protocol rules. **Terms and Conditions (and Subscription Agreement) of the Note**: The Terms and Conditions of the Note (as well as Subscription Agreement) represent the economic link between the collateral and the Minter entity. Their enforceability and protective clauses have an obvious direct impact on the quality and availability of the collateral for the purpose of the Protocol. Additionally, these documents need to reflect the scenarios where the SPV Operator winds down a Minter balance without the Minter’s collaboration. This requires certain rights of a party (the SPV Operator) which is not the noteholder (Minter) that need to be mandatorily reflected in the Terms and Conditions of the Note itself. **SPV Operating Memorandum**: Every Actor should practically be replaceable; in particular any operation of the SPV should be highly standardized. This is what an appropriate SPV Operating Memorandum should ensure. As a crucial point this document also regulates the transfer restrictions of funds transferred out of the Collateral Storage. In case any of the Mandatory Contracts defined here are modified as part of the change process, all parties shall work to amend the respective contracts as soon as practically feasible. Parties are not expected to perform changes on their Mandatory Contracts (or similar) that are not made in the spirit of the Adopted Guidance. Parties are expected to remedy such misaligned clauses by replacing them as soon as practical and without undue delay. ### 2.3. Duty of Transparency To the extent reasonable, and observing proper confidentiality practices, all Actors within the M0 ecosystem are encouraged to abide by a duty of transparency and candor toward Governance. The Actors will enter into Mandatory Contracts with each other and are expected to timely and appropriately make the latest versions of such agreements available to Governance and other interested parties, ideally in the public domain, but certainly upon request. ### 2.4. Core Operational Flows While the Protocol is immutable and the direct impact of Governance on the Protocol’s behavior is limited to the [Governance Controlled Parameters](/home/fundamentals/whitepaper/protocol/#governance-controlled-protocol-parameters) (the set of variables that can be modified by Governance votes and that have an impact on the Protocol's functioning) and the permissioning of certain Actors, calls of Protocol functions should go hand in hand with offchain processes that the Actors must comply with. The following processes are, at the current state of technology and collateral eligibility, to be considered binding for all Actors. #### 2.4.1. Update Collateral Process The updateCollateral() function (Update Collateral) needs to be called once per Update Collateral Interval. **Update Collateral Interval**: In accordance with Protocol specifications, the period between which Update Collateral must be called by a Minter. If Minters do not call Update Collateral within this amount of time after their previous call, their onchain Collateral Value is assumed to be 0 and they will incur a penalty rate on the next update. This protocol parameter is alterable with a Standard Proposal. The **Penalty Rate** is defined as the percentage charged on Owed $M that is in excess of the amount a Minter is permitted to have generated. It is assessed any time Impose Penalty is called, which is embedded in both Update Collateral and Burn. It is alterable with a Standard Proposal. This is a fixed percentage and not an annualized rate. Failure to do so will result in the Collateral Balance being set to 0 and the application of a respective Penalty. Some key financial definitions are outlined below: * **Deposit Equivalents** are amounts, denominated in the Reference Currency, held in either Deposit Accounts or in the form of so-called stablecoins (including M) in wallets. * **Deposit Account** is the demand deposit account held by the SPV with demand deposit providers. * **Custody Account** is the securities account or digital asset account held by the SPV with custody providers. * **The Reference Currency** throughout this document is USD (United States Dollar). An example collateral update flow, assuming a look-through validation of the collateral, is shown in the picture below:
1. The Minter purchases Notes from the SPV with Deposit Equivalents. 2. The SPV Operator on behalf of the SPV will perform the collateralization process. 3. Minter sends a Validation Request (see below) which contains the amount it would like to update onchain to the Validator. 4. Validator verifies the existence of the Collateral (e.g. via its read access to the depository account or, in case of eligible tokenized collateral, via observation of distributed ledger entries), verifies the compliance with the eligibility criteria and, potentially, verifies the implementation of Mandatory Contracts. 5. If all checks have been successful, the Validator sends a Signature to the Minter. 6. With this Signature the Minter can call the updateCollateral() function. **Validation Request**: A call from the Minter to the Validator where the Minter requests a Signature for either updating its Collateral Balance or for removing a RetrieveID from the Protocol. Steps 3-6 have to be completed at least once per Update Collateral Interval. Step 2 has to be completed whenever new funds are transferred to the Collateral Storage or whenever collateral matures thus liquidates. #### 2.4.2. Minting M The mint process of $M can be triggered by the Minter at any time as long as the Collateral Balance is sufficient and the Core Operating Condition satisfied.
1. The Minter can call the proposeMint() function at any time, indicating the amount it wants to mint. The Protocol will support the verification of the Core Operating Condition following a successful mint. The transaction will fail if the condition is not satisfied. As a reminder, during the Mint Delay time any Validator can cancel the mint. 2. Once the Mint Delay has elapsed, the Minter can execute the mint and the Protocol will again check the Core Operating Condition. If the mint is successful, the minted $M will be transferred to the wallet indicated in the mint request. #### 2.4.3. Retrieval of Collateral As defined in the [Whitepaper](/home/fundamentals/whitepaper/), and as a reminder for the reader, collateral can generally only be retrieved (at least during the [Normal Course of Business](/home/fundamentals/adopted-guidance/spv-operators/#obligations-in-the-normal-course-of-business) — see below) if the Core Operating Condition remains satisfied following a successful retrieval. Given that the retrieval flow is the main way in which funds can leave the Collateral Storage, the process should absolutely come with strict rules. We are expecting Governance to holistically assess that those rules remain satisfied by any alternative implementation proposed by a prospective Minter. An example of such a flow is described in the chart below:
1. The Minter requests a retrieval by calling the proposeRetrieval() function with the amount it wishes to retrieve. 2. If the Core Operating Condition remains satisfied after the retrieval the call succeeds and a RetrievalID is generated and stored in the Protocol. For as long as the RetrievalID is not closed the Protocol will subtract the requested amount from the Collateral Balance. 3. The Minter can now request the retrieval with the SPV Operator. 4. The SPV Operator will now validate the existence of the Retrieval Request in the Protocol. 5. If the existence of a corresponding Retrieval Request has been confirmed, the SPV Operator can initiate the liquidation of the equivalent collateral and transfer the funds back to the Minter. 6. Once the transfer has been executed the Minter can request a Signature from the Validator for the removal of the RetrievalID. 7. The Validator confirms via appropriately provided access to the Collateral Storage that the transfer was executed. 8. If the check was successful, the Validator provides a Signature for the removal of the RetrievalID. 9. The Minter can now call the updateCollateral() function and pass on the RetrievalID it wishes to remove together with the Signature. The RetrievalID will be removed, and the respective amount will no longer be subtracted from the Minter’s Collateral Balance. ### 2.5. High-Risk Jurisdictions For the benefit of this document, the countries in the following lists are considered to be high-risk jurisdictions. * **FATF “Black and Gray” lists.** As available, for instance, on [https://www.fatf-gafi.org/en/countries/black-and-grey-lists.html](https://www.fatf-gafi.org/en/countries/black-and-grey-lists.html) . * **European Commission’s list of High-risk Third Countries.** As available, for instance, on [https://finance.ec.europa.eu/financial-crime/anti-money-laundering-and-countering-financing-terrorism-international-level\_en#strategic-deficiencies](https://finance.ec.europa.eu/financial-crime/anti-money-laundering-and-countering-financing-terrorism-international-level_en#strategic-deficiencies). * **Any jurisdiction comprehensively subject to Office of Foreign Assets Control (OFAC) sanctions.** * **Any jurisdiction comprehensively subject to European Union (EU) sanctions.** import ZoomableImage from '@/components/ZoomableImage'; ## 1. Description of the Adopted Guidance Description of the Adopted Guidance's purpose and its change control process. ### 1.1. Purpose of the Adopted Guidance The Adopted Guidance is a document produced and proposed by the M0 Foundation, and approved through the M0 Two Token Governor (or, more simply, Governance) that outlines the core rules of engagement that exist outside of the enforceable domain of the protocol smart contracts for the various actors in the M0 ecosystem. In this document, Protocol refers to the deployment of the M0 Protocol on the Ethereum blockchain under the protocol address which defines the rules upon which $M can be minted. The **Protocol Address** is as follows: **0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b** While Protocol governors cannot be forced to take action for any breach of these rules, it is implicitly expected that holders of the appropriate Governance tokens will act in accordance with this document, or else change it. The Adopted Guidance describes certain actors, characteristics (e.g. Approved Jurisdictions for Collateral Storage), as well as business practices, binding contracts and business behavior. It also indicates, among other things, the type and composition of collateral that is eligible to back Owed $M Ultimately, the Adopted Guidance exists as the guiding manifesto for core business practices within the M0 ecosystem. The expectation is that as the ecosystem continues to grow and evolve, so will the Adopted Guidance through appropriate Governance oversight and approval. As such, this should be regarded as a living document that will continuously mature alongside the development of the M0 project at large. ### 1.2. Change Process for the Adopted Guidance The nature of the Adopted Guidance is such that it must allow for only one valid version per voting epoch to be agreed upon. In most cases, it is expected that a voting epoch will contain non-conflicting, **Discrete Change Proposals** which, if approved by governance vote, can be immediately put into effect. In such cases, it is expected that, upon executing the proposal, the new version of the Adopted Guidance (as specified by its document hash) is ratified and should be adopted by ecosystem Actors. While the physical act of ratifying an approved change proposal can be done by anyone, it is expected that the proponents, or the M0 Foundation as protector of the ecosystem, will perform such duties. At scale, it can be expected that a voting epoch might contain conflicting Change Proposals. This poses a specific challenge in the case where multiple changes to the Adopted Guidance are being voted on simultaneously within a single epoch, especially since Governance requires the ability to accept or reject each change separately. As such, when conflicting change proposals emerge, the process of amending and updating the Adopted Guidance should be split into two votes: * 1. In the first voting epoch, one or multiple proposals are voted on. They can be accepted or rejected independently on an individual basis (i.e. the Discrete Change Proposal). * 2. During the second voting epoch, all individually approved proposals are consolidated into a new version of the Adopted Guidance via voting (i.e. the Executive Change Proposal). While the physical act of consolidation and an Executive Change Proposal can be done by anyone, we are expecting some of the proponents, or the M0 Foundation as protector of the ecosystem, to perform such duties. We expect proponents to clearly state whether a proposal should be considered as a Discrete Change Proposal or an Executive Change Proposal. New proposals shall only be deemed valid upon confirmation of the relevant Executive Change Proposal. An example flow is detailed below:
A proposal shall clearly reference each section and/or sentence that is subject to change and clearly state what it shall be replaced with. Any ambiguity that could lead to different interpretations for the consolidated version will be avoided. In order to facilitate individual votes, a proposal should be formulated in a way that is as atomized as possible. The visual below shows an example of an appropriately proposed amendment to the Adopted Guidance: :::note Date: June 22, 1633 Author: Galileo Galilei Adopted Guidance - Discrete Change Proposal Context (option, will not become a part of the Adopted Guidance): This change is required to explain observations made on planets. Old: “0.0.1 The earth stands still.” New: "0.0.1 The earth moves around the sun.stands still." ::: In the event of conflicting versions or proposals, the most recently executed proposal that was executed onchain should be considered valid. ## 6. BD Minters and Minters ### 6.1. Contact Information of Currently Permissioned Minters :::note Minter One Generator (SPV) Ltd. 171 Main Street, PO Box 92, Road Town, British Virgin Islands VG1110 [minter.one.generator@mxon.co](mailto\:minter.one.generator@mxon.co) [www.mxon.co](http://www.mxon.co) ::: :::note Bridge Building, Inc. 2120 University Ave Suite 213 Berkeley, CA 94704 [www.bridge.xyz](http://www.bridge.xyz) ::: ### 6.2. Eligibility Criteria for Permissioned Minters BD Minters and Minters shall be set up and operated in compliance with the requirements and criteria described in the Adopted Guidance. In case the setup and operations of the BD Minter and/or Minter requires decisions on matters that are not covered in the Adopted Guidance, the stability, safety and availability of $M shall be the sole guiding principle for such decisions. Per one Minter entity, the current version of the Adopted Guidance allows only one Minter Address to be permissioned. Minters shall be set up in such a way which maximizes insolvency remoteness. They shall not be allowed to conduct any other business but interact with the Protocol for the management of $M. This excludes, for example, in particular any commercial and employment agreements. In principle, the Minter entity shall be fully owned or at least controlled by a BD Minter. Alternatively, a Minter shall be orphaned and operated by the BD Minter. Permissioned Minters are expected to fulfill the following criteria: * Be a duly incorporated entity, not in a [High-Risk Jurisdiction](/home/fundamentals/adopted-guidance/ecosystem/#high-risk-jurisdictions). * Have the technical ability to interact with the Protocol. * Be able to provide signed Minter-SPV Operator agreement with a permissioned SPV Operator. * Have all licenses and permissions required in their jurisdiction. * Have reasonably strong insolvency remoteness. * Be orphaned, solely owned, or controlled by the BD Minter. * Be affiliated to a BD Minter that is not incorporated in a [High-Risk Jurisdiction](/home/fundamentals/adopted-guidance/ecosystem/#high-risk-jurisdictions). * Have established practices that are consistent with internationally accepted standards (such as the Financial Action Task Force (FATF) Recommendations) in regards to policies and procedures reasonably designed to prevent the Minter from facilitating money laundering and terrorist financing including an established KYC program and identifying and reporting suspicious activity, as appropriate. * Have established policies and procedures designed to prevent the Minter through the BD Minter from processing transactions that violate OFAC or EU sanctions, including by implementing transaction screening procedures to identify OFAC listed Specially Designated Nationals (SDNs) and persons normally resident in jurisdictions subject to comprehensive sanctions. Minters should not enter into any other agreements except the following: * Agreements necessary to purchase Notes issued by the SPV. * Agreements with its BD Minter for the provision of services required to operate the business of the Minter. * Funding agreements with its BD Minter for the sole purpose of financing collateral purchases. * Minter-Validator Agreement(s) and Minter-SPV Operator Agreement(s). * Agreements reasonably necessary for compliance with regulatory obligations including anti-money laundering and sanctions checks (can be fulfilled by the BD Minter on behalf and for the Minter). Every agreement that the Minter enters into shall be co-signed by the BD Minter and shall contain a clause whereby the BD Minter absorbs any and all financial liabilities arising from such agreements. ### 6.3. Obligations of Minters The provisioning of sufficient collateral for its Owed $M is deemed to be in the responsibility of the Minter, irrespective whether such Owed $M was caused by the minting of M, applied Minter Rate or Penalties. It is the Minter’s obligation to at all times provide enough capital to the SPV so that the SPV Operator can purchase sufficient Eligible Collateral. Minter’s need to demonstrate that they provided a sufficient amount of Eligible Collateral via calling the updateCollateral() function at least once per every Update Collateral Interval. If they fail to do so a Penalty will be added to the Owed $M for the time they are not in compliance with Protocol rules. Minters need to at all times have a valid Minter-SPV Operator Agreement which meets the criteria set in place with an SPV Operator that is and remains for the time of service listed in [Contact Information of Currently Approved SPV Operators](/home/fundamentals/adopted-guidance/spv-operators/#contact-information-of-currently-approved-spv-operators). Before submitting the first and any consecutive mint proposals, the Minter has to make an Administrative Buffer available to the SPV Operator. The payment of the Administrative Buffer can be made in Deposit Equivalents. If the SPV Operator is making use of the Administrative Buffer or parts thereof in accordance with the criteria set out in the Adopted Guidance, the Minter shall replenish the Administrative Buffer so that it meets or exceeds the defined amount for the Administrative Buffer before submitting any further mint proposal. In the interest of the stability of $M and the ecosystem, a BD Minter should provide assurance (solely) to their direct institutional counterparties that it will buy back $M at par value (minus any applicable fees), within the scale and time frame appropriate given its business operating conditions. ### 6.4. BD Minter and Minter Compliance Requirements Each Minter and its affiliates, such as the BD Minter, must have written policies, procedures, and internal controls designed to ensure compliance with the applicable laws within the jurisdiction in which they operate. Additionally, Minters need to have anti-money laundering procedures that are reasonably designed to prevent the Minter from facilitating money laundering and terrorist financing including know-your-customer policies, maintaining highly useful records for law enforcement and regulators and identifying and reporting suspicious activity, as appropriate. These controls must be designed to comply with the obligations of the Minter’s jurisdiction of incorporation or with the international standards recommended by the Financial Action Task Force, as specified below. These obligations can be fulfilled by the BD Minter on behalf and for the Minter. Minters need to maintain anti-money laundering and counter terrorist financing (AML/CFT) programs that are reasonably designed to manage and mitigate the Minter’s risks related to money laundering and terrorist financing. The nature and extent of the AML/CFT program depends upon a number of factors, including the nature, scale and complexity of the Minter’s operations, the diversity of its operations, including geographical diversity, its customer base, product and activity profile, and the degree of risk associated with each area of its operations, among other factors. These obligations can be fulfilled by the BD Minter on behalf and for the Minter. As part of its AML/CFT program, Minters need to obtain and verify the customer identification information as required by the laws of the jurisdiction within which it operates. Minters must also implement policies and procedures to collect additional information to verify the customer’s identity at the beginning of the customer relationship to demonstrate that the Minter can form a reasonable belief of the identity of its customer. Minters must also implement policies and procedures to conduct due diligence about its customer sufficient for the Minter to establish a customer’s risk profile and conduct ongoing monitoring. Such additional, non-core identity information, could include, for example an IP address with an associated time stamp; geo-location data; device identifiers; digital asset wallet addresses; and transaction hashes. Minters may simplify the extent of these due diligence measures where the risk associated with the customer relationship or activities is lower. These obligations can be fulfilled by the BD Minter on behalf and for the Minter. Minters need to implement policies and procedures that assist with identifying customers’ unusual or suspicious movements of funds or transactions indicative of potential involvement in illicit activity. These policies and procedures should ensure that the Minter can timely identify, investigate, and report customers’ unusual or suspicious activity in compliance with the requirements and timeframes imposed by the jurisdictions within which they operate. These obligations can be fulfilled by the BD Minter on behalf and for the Minter. Minters need to designate a person with the responsibility to ensure compliance with the AML/CFT program and oversee day-to-day operations concerning such compliance. This person must be empowered with sufficient authority and autonomy to implement the Minter’s AML/CFT program including access to sufficient resources as needed to mitigate the Minter’s risks of money laundering and terrorist financing. These obligations can be fulfilled by the BD Minter on behalf and for the Minter. Minters need to develop procedures to test the effectiveness of the AML/CFT program commensurate with the Minter’s level of AML risk exposure. The party designated to test the AML/CFT program must be independent, qualified, unbiased and free from any conflicting business interests that may influence the outcome of the compliance program test. The Minter’s policies should include provisions for tracking and remediating weaknesses identified as part of these independent reviews. These obligations can be fulfilled by the BD Minter on behalf and for the Minter. BD Minters need to implement a training program to ensure that all employees at the BD Minter, or independent contractors or third party service providers involved in the BD Minter’s and/or Minter’s operations, understand their obligations under the AML/CFT program. Such training should include senior management and the board of directors or other similar governing bodies of the BD Minter and Minter. The training program should be designed to provide appropriately detailed information to employees based on their level of responsibility regarding the AML/CFT program. BD Minters and Minters need to, at all times, comply with all economic or financial sanctions or trade embargoes imposed, administered or enforced by the United States (including those administered by OFAC and the U.S. Department of State), the EU, and any other government authority with jurisdiction over the BD Minter and Minter. The Minter needs to maintain effective measures to ensure compliance with, and awareness of, its sanctions-related obligations. This includes implementing measures to conduct appropriate due diligence on customers’ underlying transactions and the parties involved by screening such parties against OFAC’s SDN list and EU sanctions and monitoring virtual asset wallet addresses against such lists. Additionally, these measures will monitor the jurisdictions within which its customers are domiciled to prevent the Minter from facilitating transactions on behalf of persons residing in any country, region or territory, or government thereof, that is the subject or target of comprehensive sanctions. These obligations can be fulfilled by the BD Minter on behalf and for the Minter. ### 6.5. Guidelines for Submission of Permissioning Requests An application for the permissioning as a Minter requires the whitelisting of the applicant’s public key on the list of permissioned Minters. As the most central actor in the ecosystem, Minters shall have a thorough understanding of the Adopted Guidance and all the ways it impacts their business. It is expected that the approval of Minters by Governance shall involve an in-depth collaboration with governors so they reach a good level of understanding of the applicant’s abilities. Before submitting its application, the Minter shall make a KYC report public via appropriate channels, as well as appropriate proof that the requirements set forth in [Eligibility Criteria for Permissioned Minters](/home/fundamentals/adopted-guidance/bd-minters/#eligibility-criteria-for-permissioned-minters) are met: * Certified copies of the commercial register and/or trade register and/or register of companies or alike, proving that the company was duly incorporated in the jurisdiction it is providing its services from. * Proof of who the ultimate beneficial owners (UBO) of the company are, including proof for negative politically exposed persons (PEP) / sanctions check. * Certified copies of all required official licenses required to operate the business and to provide the services outlined in the Adopted Guidance and in the contractual agreements where the Minter is a party to. * A legally binding declaration that no insolvency, bankruptcy or similar/comparable proceedings are currently pending or to be anticipated in the foreseeable future in relation to the company. * Proof that the company is minimally affiliated (via its shareholders) with or (practically) controlled by any SPV Operator and/or Validator named as approved or permissioned actor in the Adopted Guidance. When there is some level of affiliation, relevant evidence of appropriate corporate governance shall be presented. * A legally binding declaration, as long as objectively and legally possible, to set up its business activities in regards to the services and contractual relationships as outlined in the Adopted Guidance. * A legally binding commitment, as long as objectively and legally possible, to amend its contractual relationships reflecting potential mandatory changes of the Adopted Guidance. Where confidentiality concerns emerge, the M0 Foundation can step under Non-Disclosure Agreements to analyze the required documentation and provide a qualified public opinion to the ecosystem. ## M0 Documentation Sections ### I. For Stablecoin Builders #### Build Your Stablecoin on the Most Programmable Platform M0 is the premier stablecoin platform designed for builders, supporting a network of issuers for multiple, interoperable stablecoins. Start with the core `$M` stablecoin, add your brand, and customize features precisely for your use case. ##### Build Your Way with $M Extensions * **Customization:** Start with `$M` as your base. Add your branding and tailor features like yield distribution rules, risk and compliance settings, and upgrade management. * **Guaranteed Clearing:** The M0 platform ensures seamless 1:1 clearing across all official `$M` extensions, maintaining foundational interoperability. ##### Access Shared Liquidity * **Network Effect:** Tap into the shared liquidity pool of the entire M0 network, benefiting both users and distributors. * **Native Interoperability:** Stablecoins built as `$M` extensions are inherently interoperable via composable wrapping and unwrapping. Any Minter on the network can mint/redeem them. * **Simplified Integration:** Infrastructure providers (wallets, on/off-ramps, DeFi) integrate `$M` once for automatic compatibility with all current and future extensions. This unifies liquidity and connects diverse use cases, overcoming the limitations of siloed models. ##### Optionality to Become an M0 Issuer * **Multi-Issuer Model:** M0 uniquely allows capable entities to connect directly to the protocol and mint `$M` and its extensions. * **Path to Full Control:** Initially, work with an existing M0 issuer to source primary liquidity for your `$M` extension. The platform provides a future pathway to become an issuer yourself, gaining complete control over your stablecoin solution. ##### Key Infrastructure Features * **$M Extensions:** * Build your branded, feature-rich stablecoin in minutes. * Incorporate desired functionality using `$M` as the core building block. * Control how collateral yield is utilized for your specific use case. * Unlock unified liquidity across applications through native interoperability. * **Stablecoin Orchestration APIs:** * Easily access primary liquidity for `$M` or your custom extension from the network of M0 issuers. * Optimize treasury management by connecting directly with M0's primary market. * Embed stablecoin creation and redemption directly into your application flows. **Ready to build? Get in touch:** [https://www.m0.org/stablecoin-builders#contact-section](https://www.m0.org/stablecoin-builders#contact-section) ### II. For Stablecoin Integrators #### Connect to a Growing Network of Digital Dollar Use Cases Integrating stablecoins often involves dealing with fragmented liquidity across different tokens. M0 solves this with its unique extensions model, enabling seamless connectivity to a diverse and expanding ecosystem. ##### Integrate Once, Serve Many Use Cases * **Unified Integration:** By integrating with M0, your platform (wallet, on/off-ramp, DeFi protocol) automatically supports all current and future M0-powered stablecoins. * **Overcome Fragmentation:** All M0 extensions are natively interoperable 1:1. Maximize the return on your integration effort and provide users with a seamless experience across different digital dollar applications. ##### Easily Monetize Your Crypto Product or Service * **onchain Yield:** Integrate with M0 to access the best risk-free yield proxy available onchain. * **Permissionless Rewards:** Get rewarded simply by holding M0-powered stablecoins on your platform. Implement new revenue streams, partner payouts, or user incentives directly onchain, without needing complex offchain agreements. ##### Built-in Support for Any Crypto Architecture * **Flexible Integration:** Seamlessly integrate reward distribution mechanics into any application type using M0-powered stablecoins. * **Broad Compatibility:** Whether you run a DeFi protocol, a non-custodial wallet, or a custody service with segregated accounts, M0 infrastructure supports automated onchain tracking and facilitates your desired reward distribution logic. ##### Key Infrastructure Features * **Stablecoin Orchestration APIs:** * Easily access primary liquidity for M0-powered stablecoins from the M0 issuer network. * Optimize treasury management via direct connection to M0's primary market. * Embed stablecoin creation and redemption directly into your application flows. * **Highly-Liquid Convertibility:** * M0 works actively with liquidity providers and on/off-ramp partners to ensure deep, liquid secondary markets against other popular stablecoins like USDC and USDT, catering to user preferences. * Focus on building a great user experience while benefiting from seamless connectivity to all M0 extensions. **Ready to integrate? Get in touch:** [https://www.m0.org/stablecoin-integrators#contact-section](https://www.m0.org/stablecoin-integrators#contact-section) ## Stablecoin Features M0 empowers you to tailor a digital dollar precisely to your application's needs, leveraging the security and yield of the M0 Protocol while giving you full control over your stablecoin's behavior and features. An extension is your own smart contract that allows you to define unique rules, branding, and value flows, all built upon M0's pre-determined components and robust infrastructure. ### Key Design Decisions Before writing code, consider these crucial aspects. With M0 you will be able to customize your extension to fit any needs below. Your choices will define your extension's functionality and value proposition: #### 1. Purpose & Branding * What will your stablecoin be used for (e.g., payments, in-app currency, rewards, DeFi collateral)? * Will it be publicly branded (e.g., YourAppUSD) or an internal/infrastructure component? #### 2. Access Control * Will your extension be permissionless (publicly accessible) or restricted to a specific whitelist of users/contracts? #### 3. Yield Distribution * If your extension contract is approved as an M0 Earner, it will accrue yield. How will this yield be distributed? * **As rewards to token holders?** (e.g., via rebasing balances or a claimable mechanism) * **As revenue to a treasury/foundation/business**? * **Split between multiple parties?** (e.g., holders and a treasury) M0's design gives you complete flexibility to implement your desired yield flow. #### 4. Compliance Features * There are compliance requirements in all extensions. M0 supports [Predicate](https://predicate.io/) integration as the preferred partner on all EVM chains. You can build these directly into your extension. #### 5. Multi-Chain Deployment * What chains does your stablecoin need to live in? Extensions can be deployed across multiple networks. While M0 already supports off-ramping USDC on various chains, this option ensures that the extension token itself can natively exist and be held on other chains as needed. #### 6. Advanced Yield Management (Optional) * For more sophisticated use cases, partners can implement advanced yield controls, such as whitelisting eligible yield recipients, defining multiple yield tiers, or redirecting yield from LP contracts to alternate addresses. **Deeper Dive**: [M0 Extensions](/home/technical-documentations/extensions/) ## Glossary Glossary of main concepts across the M0 infrastructure. ##### Earner A holder or distributor of M0-powered stablecoins whose address is approved by governance to earn the Earner Rate. ##### Earner Rate The annualized percentage paid in the Earn Mechanism. ##### Eligible Collateral A description of portfolio composition which can be placed in Eligible Custody Solutions and be used to generate an onchain Collateral Value, which is subsequently used to mint M0-powered stablecoins. ##### Eligible Custody Solution A description of entity structures, jurisdictions, contractual agreements, and other details that will suffice for the custody of Eligible Collateral. ##### Mint Delay A period of time between when a Minter has called Propose Mint and when they can first call Mint. It serves as a protective measure to ensure all actors have sufficient time to audit each Propose Mint. ##### Mint Ratio The fraction size of a Minter's onchain Collateral Value that they can mint. ##### Minter An institution that connects to the protocol to generate and manage stablecoin supply. ##### Minter Freeze Time A period of time during which a Minter will be disabled to call Propose Mint and Mint methods. Can be called by any Validator on any Minter by passing the Minter address as the argument of the Freeze method. It can be called multiple times on the same Minter to reset the Minter Freeze Time window. If Freeze is called during an already existing Minter Freeze Time, the Minter Freeze Time window will restart from the beginning. ##### Minter Rate The annualized percentage charged continuously to Minters on their outstanding debt. It is alterable with a Standard Proposal. ##### Penalty Rate The percentage charged for missing Update Collateral interval(s) or being undercollateralized on outstanding debt that is in excess of the amount a Minter is permitted to have generated. It is assessed any time Accrue Penalty is called, which is embedded in both Update Collateral and Burn. It is alterable with a Standard Proposal. This is a fixed percentage and not an annualized rate. ##### Periphery Contract A smart contract that adds supplement functionality, but exists outside of the core M0 protocol. ##### `POWER` One of the two utility tokens used in the M0 TTG. It is used to vote on active proposals and can be considered the primary management token of the mechanism. `POWER` holders will earn `ZERO` in exchange for their direct participation in governance. ##### Propose Mint Time To Live The amount of time after the Mint Delay during which a Minter can complete the mint operation before Propose Mint expires. It serves as a protective measure to ensure that Minters cannot call Propose Mint and then execute the Mint at a much later date. ##### TTG TTG stands for Two Token Governor and is a mechanism by which holders of the voting tokens are penalized for failing to vote. There are two utility tokens used in the M0 TTG: `POWER` and `ZERO`. ##### Update Collateral Interval This amount of time is the period between which Update Collateral must be called by a Minter. If they do not call Update Collateral within this amount of time after their previous call, their onchain Collateral Value is set to 0 and they will incur Penalty Rate on the next update. It is alterable with a Standard Proposal. ##### Validator An independent entity that provides timely information about the offchain collateral being used to back M0-powered stablecoins. ##### ZERO One of the two utility tokens used in the M0 TTG, is earned by `POWER` holders in exchange for their direct participation in governance. The `ZERO` holders are the recipient of all remaining value that is not paid out to the Earn Mechanism for their participation in protocol governance. The anticipated accumulation of tokens to the `ZERO` holders are Proposal Fee payments from proposal submission, the payments from `POWER` token auctions, and a portion of Minter Rate and Penalty Rate charges to Minters. ## Disclosures The information contained in this document is being provided solely for informational/discussion purposes and the reader should not construe anything contained herein to be a solicitation or an offer of sale of securities. Nor should you construe the contents of this document as legal, tax or financial advice. Any potential participant in the M0 ecosystem is urged to consult their own advisors for any legal, tax or financial questions. To the extent this document contains any forecasts, projections, goals, plans, and other forward-looking statements regarding the M0 project, position, results, and/or other data, you acknowledge that such forward-looking statements are based on our assumptions, estimates, outlook, and other judgments made in light of information available at the time of preparation of such statements and involve both known and unknown risks and uncertainties. Accordingly, any forecasts, plans, goals, and other statements contained herein may not be realized as described, and actual financial results, success/failure or progress of development, and other projections may differ materially from those presented herein. Neither the $M token, nor any governance tokens associated with the M0 project, will be offered to US persons (without a valid exemption). Any token described in this document has not been registered or qualified under any state or national securities law or regulation. Participation in the purchase, use, or investment in any digital assets, tokens, or cryptocurrencies involves inherent risks, including but not limited to market volatility, regulatory changes, and technological risks. Prospective investors should conduct their own research and seek the advice of a qualified financial advisor or legal counsel before making any decisions. The team and contributors associated with this project make no representations, warranties or guarantees regarding the accuracy, completeness, or reliability of the information contained in this whitepaper or any linked materials. They disclaim any liability for any direct, indirect, or consequential losses or damages arising from reliance on this information or any errors or omissions in its content. By accessing, reading, or using this whitepaper, you acknowledge and agree to the terms outlined in this disclaimer. You are solely responsible for evaluating the risks and merits associated with any actions you take related to the contents of this document. ### M0 Protocol and TTG Smart Contracts The M0 Protocol and TTG smart contracts went through a series of extensive audits by industry-leading security companies. | Auditor | Date | Report | | --------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Quantstamp | Jan 2024 - March 2024 | [Quantstamp\_report.pdf](https://github.com/m0-foundation/documentation/blob/main/protocol-audit-reports/Quantstamp%20Audit%20Report.pdf) | | Three Sigma | Jan 2024 - March 2024 | [ThreeSigma\_report.pdf](https://github.com/m0-foundation/documentation/blob/main/protocol-audit-reports/ThreeSigma%20Audit%20Report.pdf) | | Certora | Jan 2024 - March 2024 | [Certora\_report.pdf](https://github.com/m0-foundation/documentation/blob/main/protocol-audit-reports/Certora%20Audit%20report.pdf) | | Chainsecurity | Jan 2024 - March 2024 | [Chainsecurity\_report.pdf](https://github.com/m0-foundation/documentation/blob/main/protocol-audit-reports/ChainSecurity%20Audit%20Report.pdf) | | OpenZeppelin | Jan 2024 - March 2024 | [OpenZeppelin report.pdf](https://github.com/m0-foundation/documentation/blob/main/protocol-audit-reports/OpenZeppelin%20Audit%20Report.pdf) | | Prototech Labs | Jan 2024 - Feb 2024 | [PrototechLabs\_report.pdf](https://github.com/m0-foundation/documentation/blob/main/protocol-audit-reports/Prototech%20Labs%20Audit%20Report.pdf) | | Kirill Fedoseev | Dec 2023 - April 2024 | [Kirill Fedoseev report.md](https://github.com/m0-foundation/documentation/blob/main/protocol-audit-reports/Kirill%20Fedoseev%20Independent%20Auditor%20Report.md) | | Sherlock | March 2024 - April 2024 | [Sherlock\_report.pdf](https://github.com/m0-foundation/documentation/blob/main/protocol-audit-reports/Sherlock%20Audit%20Report.pdf) | ### Wrapped $M (w$M) Wrapped $M (w$M) went through a series of audits in summer 2024. | Auditor | Date | Report | | --------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Chainsecurity | July 2024 - Aug 2024 | [ChainSecurity Wrapped $M Audit Report.pdf](https://github.com/m0-foundation/documentation/blob/main/wrapped-M-audit-reports/ChainSecurity%20Wrapped%20M%20Audit%20Report.pdf) | | Three Sigma | July 2024 - Aug 2024 | [Three Sigma Wrapped $M Audit Report.pdf](https://github.com/m0-foundation/documentation/blob/main/wrapped-M-audit-reports/ThreeSigma%20Wrapped%20M%20Audit%20Report.pdf) | | Kirill Fedoseev | July 2024 - Aug 2024 | [Kirill Fedoseev Wrapped $M Audit Report.md](https://github.com/m0-foundation/documentation/blob/main/wrapped-M-audit-reports/Kirill%20Fedoseev%20Audit%20Report.md) | ### EVM M-Extensions EVM M-Extensions, smart contract extensions for the M0 protocol, went through comprehensive audits in 2025. | Auditor | Date | Report | | ------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Certora | July 2025 | [Certora\_MExtension\_report.pdf](https://github.com/m0-foundation/evm-m-extensions/blob/main/audits/Certora%20MExtension%20Security%20Assessment%20Final%20Report.pdf) | | ChainSecurity | July 2025 | [ChainSecurity\_MExtensions\_report.pdf](https://github.com/m0-foundation/evm-m-extensions/blob/main/audits/ChainSecurity_M0_M_Extensions_audit_draft.pdf) | | Guardian | August 2025 | [Guardian\_MExtensions\_report.pdf](https://github.com/m0-foundation/evm-m-extensions/blob/main/audits/Guardian%20Audits%20M0%20Extensions%20Report%20Aug%205.pdf) | ### Solana M-Extensions Solana M-Extensions, the Solana implementation of M0 protocol extensions, underwent thorough security audits in 2025. | Auditor | Date | Report | | -------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | Halborn | June 2025 | [Halborn\_SolanaExtensions\_report.pdf](https://github.com/m0-foundation/solana-m-extensions/blob/main/audits/halborn_m_extensions_audit_report.pdf) | | Adevar | July 2025 | [Adevar\_SolanaExtensions\_report.pdf](https://github.com/m0-foundation/solana-m-extensions/blob/main/audits/adevar_m_extensions_audit_report.pdf) | | Ottersec | July 2025 | [Ottersec\_SolanaExtensions\_report.pdf](https://github.com/m0-foundation/solana-m-extensions/blob/main/audits/ottersec_m_extensions_audit_report.pdf) | ### M Portal Lite M Portal Lite, the lightweight cross-chain bridge solution, was audited by leading security firms in 2025. | Auditor | Date | Report | | --------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Three Sigma | April 2025 | [ThreeSigma\_PortalLite\_report.pdf](https://github.com/m0-foundation/m-portal-lite/blob/main/audits/Three%20Sigma%20-%20M0PortalLite.pdf) | | ChainLight | May 2025 | [ChainLight\_PortalLite\_report.pdf](https://github.com/m0-foundation/m-portal-lite/blob/main/audits/ChainLight%20-%20M%20Portal%20Lite%20Security%20Audit%20v1.0.pdf) | | ChainSecurity | September 12, 2025 | [ChainSecurity\_M0\_M\_Portal\_Lite\_audit.pdf](https://github.com/m0-foundation/m-portal-lite/blob/main/audits/ChainSecurity_M0_M_Portal_Lite_audit.pdf) | | Guardian Audits | August 15, 2025 | [GuardianAudits\_M0\_PortalLite\_audit.pdf](https://github.com/m0-foundation/m-portal-lite/blob/main/audits/GuardianAudits_M0_PortalLite_audit.pdf) | | Halborn | October 27, 2025 | [Halborn - M Portal Lite 10-27-25.pdf](https://github.com/m0-foundation/m-portal-lite/blob/main/audits/Halborn%20-%20M%20Portal%20Lite%2010-27-25.pdf) | ### Solana M Solana M, the core M0 protocol implementation on Solana, received comprehensive security reviews in 2025. | Auditor | Date | Report | | -------- | ---------- | ----------------------------------------------------------------------------------------------------------------------- | | Halborn | March 2025 | [Halborn\_SolanaM\_report.pdf](https://github.com/m0-foundation/solana-m/blob/main/audits/halborn_solana_m_audit.pdf) | | OtterSec | April 2025 | [OtterSec\_SolanaM\_report.pdf](https://github.com/m0-foundation/solana-m/blob/main/audits/ottersec_solana_m_audit.pdf) | | Sec3 | May 2025 | [Sec3\_SolanaM\_report.pdf](https://github.com/m0-foundation/solana-m/blob/main/audits/sec3_solana_m_audit_report.pdf) | ### mUSD mUSD, an M0 extension derived from `MYieldToOne`, an upgradeable ERC20 token contract designed to wrap into a non-rebasing token, where all accrued yield is claimable by a single designated recipient, underwent comprehensive security audits in August 2025. | Auditor | Date | Report | | ------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | ChainSecurity | August 26, 2025 | [ChainSecurity\_M0\_MUSD\_audit.pdf](https://github.com/m0-foundation/mUSD/blob/main/audits/ChainSecurity_M0_MUSD_audit.pdf) | | Consensys Diligence | August 2025 | [ConsensysDiligence\_M0\_MUSD\_audit.pdf](https://github.com/m0-foundation/mUSD/blob/main/audits/ConsensysDiligence_M0_MUSD_audit.pdf) | | Guardian Audits | August 15, 2025 | [GuardianAudits\_M0\_MUSD\_report.pdf](https://github.com/m0-foundation/mUSD/blob/main/audits/GuardianAudits_M0_MUSD_report.pdf) | | Kirill Fedoseev | August 6, 2025 | [MZero-review-report-v1-private.md](https://github.com/m0-foundation/mUSD/blob/main/audits/MZero-review-report-v1-private.md) | ## Deployments M0 Protocol and TTG were deployed to Ethereum Mainnet on May 7th 2024. Wrapped $M (w$M) was deployed to Ethereum Mainnet on Aug 14th 2024. ### Ethereum | Contract | Address | ABI | Repository | | -------------------- | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | $M Token | [ 0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b ](https://etherscan.io/address/0x866a2bf4e572cbcf37d5071a7a58503bfb36be1b) | [ABI](https://etherscan.io/address/0x866a2bf4e572cbcf37d5071a7a58503bfb36be1b#code#L1) | [MToken](https://github.com/m0-foundation/protocol/blob/main/src/MToken.sol) | | Wrapped $M Token | [ 0x437cc33344a0B27A429f795ff6B469C72698B291 ](https://etherscan.io/address/0x437cc33344a0B27A429f795ff6B469C72698B291) | [ABI](https://etherscan.io/address/0x437cc33344a0B27A429f795ff6B469C72698B291#code#L1) | [WrappedMToken](https://github.com/m0-foundation/wrapped-m-token/blob/v2/src/WrappedMToken.sol) | | Minter Gateway | [ 0xf7f9638cb444D65e5A40bF5ff98ebE4ff319F04E ](https://etherscan.io/address/0xf7f9638cb444D65e5A40bF5ff98ebE4ff319F04E) | [ABI](https://etherscan.io/address/0xf7f9638cb444D65e5A40bF5ff98ebE4ff319F04E#code#L1) | [MinterGateway](https://github.com/m0-foundation/protocol/blob/main/src/MinterGateway.sol) | | Minter Rate Model | [ 0xcA144B0Ebf6B8d1dDB5dDB730a8d530fe7f70d62 ](https://etherscan.io/address/0xcA144B0Ebf6B8d1dDB5dDB730a8d530fe7f70d62) | [ABI](https://etherscan.io/address/0xcA144B0Ebf6B8d1dDB5dDB730a8d530fe7f70d62#code#L1) | [MinterRateModel](https://github.com/m0-foundation/protocol/blob/main/src/rateModels/MinterRateModel.sol) | | Earner Rate Model | [ 0x26d01A2c91f6529aD72d2C27a03d963CAb90dFfd ](https://etherscan.io/address/0x26d01A2c91f6529aD72d2C27a03d963CAb90dFfd) | [ABI](https://etherscan.io/address/0x26d01A2c91f6529aD72d2C27a03d963CAb90dFfd#code#L1) | [EarnerRateModel](https://github.com/m0-foundation/protocol/blob/main/src/rateModels/EarnerRateModel.sol) | | TTG Registrar | [ 0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c ](https://etherscan.io/address/0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c) | [ABI](https://etherscan.io/address/0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c#code#L1) | [Registrar](https://github.com/m0-foundation/ttg/blob/main/src/Registrar.sol) | | Power Token | [ 0x5983B89FA184f14917013B9C3062afD9434C5b03 ](https://etherscan.io/address/0x5983B89FA184f14917013B9C3062afD9434C5b03) | [ABI](https://etherscan.io/address/0x5983B89FA184f14917013B9C3062afD9434C5b03#code#L1) | [Power token](https://github.com/m0-foundation/ttg/blob/main/src/PowerToken.sol) | | Zero Token | [ 0x988567FE094570cCE1FFdA29D1f2d842B70492be ](https://etherscan.io/address/0x988567FE094570cCE1FFdA29D1f2d842B70492be) | [ABI](https://etherscan.io/address/0x988567FE094570cCE1FFdA29D1f2d842B70492be#code#L1) | [Zero token](https://github.com/m0-foundation/ttg/blob/main/src/ZeroToken.sol) | | Standard Governor | [ 0xB024aC5a7c6bC92fbACc8C3387E628a07e1Da016 ](https://etherscan.io/address/0xB024aC5a7c6bC92fbACc8C3387E628a07e1Da016) | [ABI](https://etherscan.io/address/0xB024aC5a7c6bC92fbACc8C3387E628a07e1Da016#code#L1) | [StandardGovernor](https://github.com/m0-foundation/ttg/blob/main/src/StandardGovernor.sol) | | Emergency Governor | [ 0x886d405949F709bC3f4451491bDd07ff51Cdf90A ](https://etherscan.io/address/0x886d405949F709bC3f4451491bDd07ff51Cdf90A) | [ABI](https://etherscan.io/address/0x886d405949F709bC3f4451491bDd07ff51Cdf90A#code#L1) | [EmergencyGovernor](https://github.com/m0-foundation/ttg/blob/main/src/EmergencyGovernor.sol) | | Zero Governor | [ 0xa0DAFaEEA4A1d44534e1b9227e19CAE6358b80FE ](https://etherscan.io/address/0xa0DAFaEEA4A1d44534e1b9227e19CAE6358b80FE) | [ABI](https://etherscan.io/address/0xa0DAFaEEA4A1d44534e1b9227e19CAE6358b80FE#code#L1) | [ZeroGovernor](https://github.com/m0-foundation/ttg/blob/main/src/ZeroGovernor.sol) | | Distribution Vault | [ 0xd7298f620B0F752Cf41BD818a16C756d9dCAA34f ](https://etherscan.io/address/0xd7298f620B0F752Cf41BD818a16C756d9dCAA34f) | [ABI](https://etherscan.io/address/0xd7298f620B0F752Cf41BD818a16C756d9dCAA34f#code#L1) | [DistributionVault](https://github.com/m0-foundation/ttg/blob/main/src/DistributionVault.sol) | | Hub Portal | [ 0xD925C84b55E4e44a53749fF5F2a5A13F63D128fd ](https://etherscan.io/address/0xD925C84b55E4e44a53749fF5F2a5A13F63D128fd) | [ABI](https://etherscan.io/address/0xD925C84b55E4e44a53749fF5F2a5A13F63D128fd#code#L1) | [HubPortal](https://github.com/m0-foundation/m-portal/blob/main/src/HubPortal.sol) | | Wormhole Transceiver | [ 0x0763196A091575adF99e2306E5e90E0Be5154841 ](https://etherscan.io/address/0x0763196A091575adF99e2306E5e90E0Be5154841) | [ABI](https://etherscan.io/address/0x0763196A091575adF99e2306E5e90E0Be5154841#code#L1) | | | Swap Facility | [ 0xB6807116b3B1B321a390594e31ECD6e0076f6278 ](https://etherscan.io/address/0xB6807116b3B1B321a390594e31ECD6e0076f6278) | [ABI](https://etherscan.io/address/0xB6807116b3B1B321a390594e31ECD6e0076f6278#code#L1) | [SwapFacility](https://github.com/m0-foundation/evm-m-extensions/blob/main/src/swap/SwapFacility.sol) | ### Arbitrum | Contract | Address | ABI | Repository | | -------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | $M Token | [ 0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b ](https://arbiscan.io/address/0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b) | [ABI](https://arbiscan.io/address/0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b#code#L1) | [MToken](https://github.com/m0-foundation/protocol/blob/main/src/MToken.sol) | | Wrapped $M Token | [ 0x437cc33344a0B27A429f795ff6B469C72698B291 ](https://arbiscan.io/address/0x437cc33344a0B27A429f795ff6B469C72698B291) | [ABI](https://arbiscan.io/address/0x437cc33344a0B27A429f795ff6B469C72698B291#code#L1) | [WrappedMToken](https://github.com/m0-foundation/wrapped-m-token/blob/v2/src/WrappedMToken.sol) | | Registrar | [ 0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c ](https://arbiscan.io/address/0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c) | [ABI](https://arbiscan.io/address/0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c#code#L1) | [Registrar](https://github.com/m0-foundation/ttg/blob/main/src/Registrar.sol) | | Spoke Portal | [ 0xD925C84b55E4e44a53749fF5F2a5A13F63D128fd ](https://arbiscan.io/address/0xD925C84b55E4e44a53749fF5F2a5A13F63D128fd) | [ABI](https://arbiscan.io/address/0xD925C84b55E4e44a53749fF5F2a5A13F63D128fd#code#L1) | [SpokePortal](https://github.com/m0-foundation/m-portal/blob/main/src/SpokePortal.sol) | | Wormhole Transceiver | [ 0x0763196A091575adF99e2306E5e90E0Be5154841 ](https://arbiscan.io/address/0x0763196A091575adF99e2306E5e90E0Be5154841) | [ABI](https://arbiscan.io/address/0x0763196A091575adF99e2306E5e90E0Be5154841#code#L1) | | | Spoke Vault | [ 0x3349e443068F76666789C4f76F00D9c4F38A4DdE ](https://arbiscan.io/address/0x3349e443068F76666789C4f76F00D9c4F38A4DdE) | [ABI](https://arbiscan.io/address/0x3349e443068F76666789C4f76F00D9c4F38A4DdE#code#L1) | [SpokeVault](https://github.com/m0-foundation/m-portal/blob/main/src/SpokeVault.sol) | ### Optimism | Contract | Address | ABI | Repository | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | $M Token | [ 0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b ](https://optimistic.etherscan.io/address/0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b) | [ABI](https://optimistic.etherscan.io/address/0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b#code#L1) | [MToken](https://github.com/m0-foundation/protocol/blob/main/src/MToken.sol) | | Wrapped $M Token | [ 0x437cc33344a0B27A429f795ff6B469C72698B291 ](https://optimistic.etherscan.io/address/0x437cc33344a0B27A429f795ff6B469C72698B291) | [ABI](https://optimistic.etherscan.io/address/0x437cc33344a0B27A429f795ff6B469C72698B291#code#L1) | [WrappedMToken](https://github.com/m0-foundation/wrapped-m-token/blob/v2/src/WrappedMToken.sol) | | Registrar | [ 0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c ](https://optimistic.etherscan.io/address/0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c) | [ABI](https://optimistic.etherscan.io/address/0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c#code#L1) | [Registrar](https://github.com/m0-foundation/ttg/blob/main/src/Registrar.sol) | | Spoke Portal | [ 0xD925C84b55E4e44a53749fF5F2a5A13F63D128fd ](https://optimistic.etherscan.io/address/0xD925C84b55E4e44a53749fF5F2a5A13F63D128fd) | [ABI](https://optimistic.etherscan.io/address/0xD925C84b55E4e44a53749fF5F2a5A13F63D128fd#code#L1) | [SpokePortal](https://github.com/m0-foundation/m-portal/blob/main/src/SpokePortal.sol) | | Wormhole Transceiver | [ 0x0763196A091575adF99e2306E5e90E0Be5154841 ](https://optimistic.etherscan.io/address/0x0763196A091575adF99e2306E5e90E0Be5154841) | [ABI](https://optimistic.etherscan.io/address/0x0763196A091575adF99e2306E5e90E0Be5154841#code#L1) | | | Spoke Vault | [ 0x3349e443068F76666789C4f76F00D9c4F38A4DdE ](https://optimistic.etherscan.io/address/0x3349e443068F76666789C4f76F00D9c4F38A4DdE) | [ABI](https://optimistic.etherscan.io/address/0x3349e443068F76666789C4f76F00D9c4F38A4DdE#code#L1) | [SpokeVault](https://github.com/m0-foundation/m-portal/blob/main/src/SpokeVault.sol) | ### Plume | Contract | Address | ABI | Repository | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | $M Token | [ 0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b ](https://explorer.plume.org/address/0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b) | [ABI](https://optimistic.etherscan.io/address/0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b#code#L1) | [MToken](https://github.com/m0-foundation/protocol/blob/main/src/MToken.sol) | | Wrapped $M Token | [ 0x437cc33344a0B27A429f795ff6B469C72698B291 ](https://explorer.plume.org/address/0x437cc33344a0B27A429f795ff6B469C72698B291) | [ABI](https://optimistic.etherscan.io/address/0x437cc33344a0B27A429f795ff6B469C72698B291#code#L1) | [WrappedMToken](https://github.com/m0-foundation/wrapped-m-token/blob/v2/src/WrappedMToken.sol) | | Registrar | [ 0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c ](https://explorer.plume.org/address/0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c) | [ABI](https://explorer.plume.org/0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c#code#L1) | [Registrar](https://github.com/m0-foundation/ttg/blob/main/src/Registrar.sol) | | Spoke Portal | [ 0x36f586A30502AE3afb555b8aA4dCc05d233c2ecE ](https://explorer.plume.org/address/0x36f586A30502AE3afb555b8aA4dCc05d233c2ecE) | [ABI](https://explorer.plume.org/0x36f586A30502AE3afb555b8aA4dCc05d233c2ecE#code#L1) | [SpokePortal](https://github.com/m0-foundation/m-portal-lite/blob/main/src/SpokePortal.sol) | | Spoke Vault | [ 0x3349e443068F76666789C4f76F00D9c4F38A4DdE ](https://explorer.plume.org/address/0x3349e443068F76666789C4f76F00D9c4F38A4DdE) | [ABI](https://explorer.plume.org/0x3349e443068F76666789C4f76F00D9c4F38A4DdE#code#L1) | [SpokeVault](https://github.com/m0-foundation/m-portal-lite/blob/main/src/SpokeVault.sol) | | Bridge | [ 0x51DcE104E5ba88fabC19A2C519f955bb834b0DC3 ](https://explorer.plume.org/address/0x51DcE104E5ba88fabC19A2C519f955bb834b0DC3) | [ABI](https://explorer.plume.org/0x51DcE104E5ba88fabC19A2C519f955bb834b0DC3#code#L1) | | ### HyperEVM | Contract | Address | ABI | Repository | | ---------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | | $M Token | [ 0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b ](https://purrsec.com/address/0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b) | [ABI](https://purrsec.com/address/0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b#code#L1) | [MToken](https://github.com/m0-foundation/protocol/blob/main/src/MToken.sol) | | Wrapped $M Token | [ 0x437cc33344a0B27A429f795ff6B469C72698B291 ](https://purrsec.com/address/0x437cc33344a0B27A429f795ff6B469C72698B291) | [ABI](https://purrsec.com/address/0x437cc33344a0B27A429f795ff6B469C72698B291#code#L1) | [WrappedMToken](https://github.com/m0-foundation/wrapped-m-token/blob/v2/src/WrappedMToken.sol) | | Registrar | [ 0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c ](https://purrsec.com/address/0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c) | [ABI](https://purrsec.com/address/0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c#code#L1) | [Registrar](https://github.com/m0-foundation/ttg/blob/main/src/Registrar.sol) | | Portal | [ 0x36f586A30502AE3afb555b8aA4dCc05d233c2ecE ](https://purrsec.com/address/0x36f586A30502AE3afb555b8aA4dCc05d233c2ecE) | [ABI](https://purrsec.com/address/0x36f586A30502AE3afb555b8aA4dCc05d233c2ecE#code#L1) | [Portal](https://github.com/m0-foundation/m-portal-lite/blob/main/src/Portal.sol) | | Vault | [ 0x3349e443068F76666789C4f76F00D9c4F38A4DdE ](https://purrsec.com/address/0x3349e443068F76666789C4f76F00D9c4F38A4DdE) | [ABI](https://purrsec.com/address/0x3349e443068F76666789C4f76F00D9c4F38A4DdE#code#L1) | [Vault](https://github.com/m0-foundation/m-portal-lite/blob/main/src/Vault.sol) | | Bridge | [ 0x51DcE104E5ba88fabC19A2C519f955bb834b0DC3 ](https://purrsec.com/address/0x51DcE104E5ba88fabC19A2C519f955bb834b0DC3) | [ABI](https://purrsec.com/address/0x51DcE104E5ba88fabC19A2C519f955bb834b0DC3#code#L1) | | ### Plasma | Contract | Address | ABI | Repository | | --------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | | M Token | [ 0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b ](https://plasmascan.to/address/0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b) | [ABI](https://plasmascan.to/address/0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b#code) | [MToken](https://github.com/m0-foundation/protocol/blob/main/src/MToken.sol) | | Wrapped M Token | [ 0x437cc33344a0B27A429f795ff6B469C72698B291 ](https://plasmascan.to/address/0x437cc33344a0B27A429f795ff6B469C72698B291) | [ABI](https://plasmascan.to/address/0x437cc33344a0B27A429f795ff6B469C72698B291#code) | [WrappedMToken](https://github.com/m0-foundation/wrapped-m-token/blob/v2/src/WrappedMToken.sol) | | Registrar | [ 0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c ](https://plasmascan.to/address/0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c) | [ABI](https://plasmascan.to/address/0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c#code) | [Registrar](https://github.com/m0-foundation/ttg/blob/main/src/Registrar.sol) | | Spoke Portal | [ 0x36f586A30502AE3afb555b8aA4dCc05d233c2ecE ](https://plasmascan.to/address/0x36f586A30502AE3afb555b8aA4dCc05d233c2ecE) | [ABI](https://plasmascan.to/address/0x36f586A30502AE3afb555b8aA4dCc05d233c2ecE#code) | [SpokePortal](https://github.com/m0-foundation/m-portal-lite/blob/main/src/SpokePortal.sol) | | Spoke Vault | [ 0x3349e443068F76666789C4f76F00D9c4F38A4DdE ](https://plasmascan.to/address/0x3349e443068F76666789C4f76F00D9c4F38A4DdE) | [ABI](https://plasmascan.to/address/0x3349e443068F76666789C4f76F00D9c4F38A4DdE#code) | [SpokeVault](https://github.com/m0-foundation/m-portal-lite/blob/main/src/SpokeVault.sol) | | Bridge | [ 0x51DcE104E5ba88fabC19A2C519f955bb834b0DC3 ](https://plasmascan.to/address/0x51DcE104E5ba88fabC19A2C519f955bb834b0DC3) | [ABI](https://plasmascan.to/address/0x51DcE104E5ba88fabC19A2C519f955bb834b0DC3#code) | | | Swap Facility | [ 0xB6807116b3B1B321a390594e31ECD6e0076f6278 ](https://plasmascan.to/address/0xB6807116b3B1B321a390594e31ECD6e0076f6278) | [ABI](https://plasmascan.to/address/0xB6807116b3B1B321a390594e31ECD6e0076f6278#code) | [SwapFacility](https://github.com/m0-foundation/evm-m-extensions/blob/main/src/swap/SwapFacility.sol) | ### Solana #### Mainnet | Program/Token | Address | Explorer | Repository | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | | M Token | [ mzerokyEX9TNDoK4o2YZQBDmMzjokAeN6M2g2S3pLJo ](https://explorer.solana.com/address/mzerokyEX9TNDoK4o2YZQBDmMzjokAeN6M2g2S3pLJo) | [View](https://explorer.solana.com/address/mzerokyEX9TNDoK4o2YZQBDmMzjokAeN6M2g2S3pLJo) | [solana-m](https://github.com/m0-foundation/solana-m) | | Wrapped M Token | [ mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp ](https://explorer.solana.com/address/mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp) | [View](https://explorer.solana.com/address/mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp) | [solana-m-extensions](https://github.com/m0-foundation/solana-m-extensions) | | Portal | [ mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY ](https://explorer.solana.com/address/mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY) | [View](https://explorer.solana.com/address/mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY) | | | Transceiver | [ J1bVGcwG3nPsAJsi3GFNqC9NZmKatSuoutPbaKMiT7Bm ](https://explorer.solana.com/address/J1bVGcwG3nPsAJsi3GFNqC9NZmKatSuoutPbaKMiT7Bm) | [View](https://explorer.solana.com/address/J1bVGcwG3nPsAJsi3GFNqC9NZmKatSuoutPbaKMiT7Bm) | | | Quoter | [ Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ ](https://explorer.solana.com/address/Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ) | [View](https://explorer.solana.com/address/Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ) | | #### Devnet | Program/Token | Address | Explorer | Repository | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | | M Token | [ mzeroZRGCah3j5xEWp2Nih3GDejSBbH1rbHoxDg8By6 ](https://explorer.solana.com/address/mzeroZRGCah3j5xEWp2Nih3GDejSBbH1rbHoxDg8By6?cluster=devnet) | [View](https://explorer.solana.com/address/mzeroZRGCah3j5xEWp2Nih3GDejSBbH1rbHoxDg8By6?cluster=devnet) | [solana-m](https://github.com/m0-foundation/solana-m) | | Wrapped M Token | [ mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp ](https://explorer.solana.com/address/mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp?cluster=devnet) | [View](https://explorer.solana.com/address/mzeroXDoBpRVhnEXBra27qzAMdxgpWVY3DzQW7xMVJp?cluster=devnet) | [solana-m-extensions](https://github.com/m0-foundation/solana-m-extensions) | | Portal | [ mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY ](https://explorer.solana.com/address/mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY?cluster=devnet) | [View](https://explorer.solana.com/address/mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY?cluster=devnet) | | | Transceiver | [ J1bVGcwG3nPsAJsi3GFNqC9NZmKatSuoutPbaKMiT7Bm ](https://explorer.solana.com/address/J1bVGcwG3nPsAJsi3GFNqC9NZmKatSuoutPbaKMiT7Bm?cluster=devnet) | [View](https://explorer.solana.com/address/J1bVGcwG3nPsAJsi3GFNqC9NZmKatSuoutPbaKMiT7Bm?cluster=devnet) | | | Quoter | [ Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ ](https://explorer.solana.com/address/Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ?cluster=devnet) | [View](https://explorer.solana.com/address/Nqd6XqA8LbsCuG8MLWWuP865NV6jR1MbXeKxD4HLKDJ?cluster=devnet) | | ## Protocol Mechanics & Reward Programmability The M0 protocol is the platform powering builders of safe, programmable, interoperable stablecoins. It introduces a superior coordination mechanism that democratizes access to the generation and management of programmable, digital cash instruments. There are a few key areas to understand how value flows through the protocol: ### Eligible Collateral With the goal of maintaining a standard issuance layer, as well as ensuring stablecoins built on M0 are interoperable, M0 prescribes a list of portfolio components that are deemed eligible as reserve, or collateral, for stablecoins minted on the M0 network. These assets must be held in legally isolated SPVs or similarly bankruptcy-remote structures with independent Validators confirming daily their fair market value on-chain. The spirit of those eligibility criteria remains that of ensuring that only the safest and regulatory aligned assets will continue to constitute the value reserve, limiting regulatory arbitrage in a scenario of international issuance. While reserves remain fully orphaned and issuer-specific as part of the protocol-enabled issuance, M0 has the ability to force issuance to rely on the most stringent standards in the interest of the end customers. The current US regulatory landscape, thanks to the regulatory advancement brought forward by the GENIUS act, is running in that direction. ### Mint Ratio The mint ratio defines the percentage of a minter's collateral value that can be used to generate M0-powered stablecoins. It sets the required level of over-collateralization for each issuer and ensures that the system remains fully backed while accounting for operational and risk management needs. ### Minter Rate M0 is an accrual-based, rather than cash-based, system. The minter rate is a universal, continuously compounding rate applied to each minter's outstanding issued supply on the network. This rate is typically calibrated below the yield possibly obtained from Eligible Collateral to allow for coverage of operational costs and ensure there is a viable business for issuers. ### Earner Rate The protocol also sets an *Earner Rate* paid (only) to approved Earners on their holdings. Smart contracts ensure that value paid out via the Earner Rate does not exceed what accrued via the Minter Rate. When set equal to the Minter Rate—and 100% of holdings sit in approved earning extensions—100% of Minters' payments flow through as yield to Earners, continuously and programmatically. ### Automatic Fee Distribution All fees accumulate within the protocol and are redistributed automatically via smart contracts. Minters do not need to make manual payments. Instead, protocol logics take care of internal accounting (indexing) and ensure that all risk and reward parameters flow consistently across all the different environments where M0-powered stablecoins exist. The superiority of an on-chain native, rather than off-chain manual, reward streaming system grows exponentially with the nesting of reward distribution logics, and the omni-chain expansion of all those use cases. Effectively, universal indexing allows the seamless management of exponentially complex reward streaming configuration. ### Extension Yield Allocation Each extension defines how yield is allocated—whether directly to users, to a treasury, or through customized logic. The protocol continuously streams rewards on-chain, allowing balances to grow incrementally instead of through periodic payouts. This transparency and programmability enable flexible product designs, such as real-time savings or incentive systems tailored to each partner's needs. import ZoomableImage from "@/components/ZoomableImage"; ## M0 is the universal stablecoin platform. #### With M0, developers can build their own application-specific digital dollars and embed those into any use case. export function CardGrid() { const cards = [ { title: 'Build your Stablecoin', description: 'M0 provides battle-tested, audited contract models that serve as powerful starting points, allowing you to focus on innovation rather than reinventing the wheel.', href: '/build/overview/', iconClass: 'homepageCardImage-BuildYourStablecoin', }, { title: 'Protocol Overview', description: 'Detailed technical architecture, and smart contract specifications that define how the M0 ecosystem functions onchain and offchain.', href: '/home/overview/', iconClass: 'homepageCardImage-ProtocolOverview', }, ] return (
{cards.map((card, index) => (

{card.title}

{card.description}
))}
) } ### The M0 Model Stablecoins as a concept emerged a decade ago with the simple goal of representing a dollar on the blockchain. The initial wave of products in the sector helped settle trillions of dollars in crypto capital markets transactions over the last number of years. But money is critical infrastructure, not a product. The initial generation of stablecoins was too simplistic in its design, and a new financial system simply can't be rewritten on top of it. M0 was founded to reconstruct the monetary stack from first principles, enabling a new wave of digital dollar applications to be built.
Application developers value control and the ability to customize their technology stack for their context. One can think of fintech as the customization of dollars into a particular form-factor that favors the use case. Stablecoins allow for onchain programmability of digital dollar behavior. But one-size-fits-all stablecoins issued by centralized actors do not really allow for programmability. The M0 platform was built to help developers create and program their own bespoke digital dollars. Money, as the key infrastructure that it is, should not belong to a single, monolithic company. M0 was built as an open and federated network. Multiple [Minters](/get-started/resources/glossary#minter) can connect to the M0 protocol and pledge [eligible collateral](/home/fundamentals/adopted-guidance/eligible-collateral/) in order to mint stablecoins. [Validators](/get-started/resources/glossary#validator) independently verify the presence of eligible collateral and guarantee transparency across the network. The M0 protocol ensures purity of the reserves for M0 stablecoins, as well as provides onchain clearing and interoperability across all the platform's custom stablecoins. ## The M0 Ecosystem Before diving into building, take your time to grasp how M0 works at a high level. ### What is M0? The M0 platform consists of the M0 protocol, a liquidity delivery layer, and a network of appropriately regulated issuers that enable the creation and operation of so-called stablecoin *extensions*. M0 provides the foundational layer for building programmable, compliant, and interoperable digital currencies. ### The M0 Protocol The M0 protocol provides the base infrastructure for issuance, redemption, and programmability while allowing builders to define their own parameters for access, compliance, and yield/rewards all on-chain. Each extension operates independently but benefits from shared liquidity, governance, and cross-chain infrastructure within the broader M0 ecosystem. At its core, the M0 protocol offers an on-chain native, immutable foundation for building stable, customizable digital assets that can integrate seamlessly across networks and use cases. ### Issuance M0 has a permissioned network of appropriately regulated entities that mint M0 extensions under strict collateral, compliance, and operational standards. These issuers hold reserves and follow detailed M0 onboarding requirements to ensure safety, consistency, and legal compliance. ### Extensions Extensions are programmable stablecoins built on top of the M0 protocol. Each extension can define its own branding and policies for access control, compliance, and rewards distribution. Builders can tailor extensions to specific use cases, from institutional products with strict KYC requirements to consumer-facing assets with on-chain reward streaming. Extensions can have multiple issuers, and can be designed for seamless interoperability, allowing users and partners to interact across products within a unified framework. ### Liquidity Network M0 provides a shared liquidity delivery system that ensures smooth movement between M0-powered stablecoins and major existing stablecoins (USDC, USDT, etc.). It ensures that anyone using an M0 extension can easily convert into and out of it from other stablecoins across multiple chains. ## Cross Chain Interoperability ### M0 on EVM M0 is designed for a multichain world, enabling M0 extensions to be accessible across various blockchain ecosystems while maintaining Ethereum as the authoritative source for governance. #### M-Portals These are smart contracts facilitating the secure transfer of M0 Extensions (and critical M0 metadata like the yield index and governance parameters) between Ethereum and Spoke chains. To achieve this, M0 integrates with leading interoperability protocols. Currently, M0 supports M-Portals built on: * **Wormhole:** Leveraging its Native Token Transfer (NTT) framework. * **Hyperlane:** Utilizing its [general message passing](https://docs.hyperlane.xyz/docs/protocol/core/mailbox) for permissionless bridging. If your desired blockchain is not yet supported through these providers, please reach out to discuss custom integration possibilities. **Deeper Dive**: [M-Portals (Cross-Chain Architecture)](/home/technical-documentations/m-portal/overview/) ### M0 on Solana The M0 Protocol extends its reach beyond EVM chains by offering a native deployment on the Solana blockchain. This provides the Solana ecosystem with direct access to a secure, yield-bearing stablecoin building block, unlocking new possibilities for high-performance DeFi, payments, and other applications. This isn't just a wrapped asset; it's a native representation, inheriting its core properties of security and yield while leveraging Solana's speed and low transaction costs. #### How It Works: A High-Level View M0's presence on Solana is facilitated by the **M Portal**, which is built on **Wormhole's Native Token Transfer (NTT)** framework. This follows the same hub-and-spoke model used for EVM chains: 1. **Lock on Ethereum**: To move Extensions to Solana, the native token is locked in the `HubPortal` contract on Ethereum. 2. **Message with Wormhole**: A secure message is sent via the Wormhole network to Solana. 3. **Mint on Solana**: The Portal program on Solana receives the message and mints an equivalent amount of native Solana extension (an SPL token). This process ensures that every extension on Solana is fully backed by a corresponding token locked on Ethereum, maintaining the integrity of the total supply. #### Key Features for Solana Users & Developers * **Native Yield**: Extensions on Solana is designed to be yield-bearing. The earning index from Ethereum is propagated via Wormhole, allowing Solana holders to benefit from the same underlying collateral yield. * **High Performance**: Leverage Solana's sub-second finality and low fees for transactions. * **Deep Integration**: Extensions have the ability to be a native SPL token or follow token 2022 for more advanced functionality. This means that extensions can be seamlessly integrated into Solana's vibrant DeFi ecosystem, including DEXs, lending protocols, and derivatives platforms. #### Program Addresses You can find the relevant Solana program and token addresses in our central address registry: * [Solana Mainnet & Devnet Addresses](/get-started/resources/addresses#solana) ## Accessing Liquidity A key benefit of the M0 platform is the shared liquidity among all extensions. This provides the most flexible and lowest friction access to liquidity for your extension. ### Source Liquidity There are two key ways to source liquidity: #### 1. Primary Liquidity (Direct with Minters) For large-scale minting/redeeming of your extension directly against supported stablecoins or USD. This involves a KYB process with an approved M0 Minter. Suitable for centralized businesses and zero-slippage constraints. #### 2. Onchain Liquidity (DEXs) Through deep liquidity pools on major chains like Ethereum, Solana, and various L2s. These pools are typically against USDC and aim for efficient pricing. Ideal for decentralized applications and 24x7 access. | Dex Name | Pool Link | | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | | Uniswap | [ethereum/0x970A7749EcAA4394C8B2Bf5F2471F41FD6b79288](https://app.uniswap.org/explore/pools/ethereum/0x970A7749EcAA4394C8B2Bf5F2471F41FD6b79288) | | Uniswap | [arbitrum/4464133](https://app.uniswap.org/positions/v3/arbitrum/4464133) | | Raydium | [pool\_id=CsMzKUUJNoAoU7N4zh3hAS6qcByU81TcQMPJqCdmmcEF](https://raydium.io/clmm/create-position/?pool_id=CsMzKUUJNoAoU7N4zh3hAS6qcByU81TcQMPJqCdmmcEF) | ## Build Your Stablecoin **M0 Extensions** are the core of our platform's promise. They are custom, feature-rich stablecoins you can create. Instead of a one-size-fits-all approach, M0 provides the raw material for you to craft a digital dollar perfectly suited to your application, brand, and economic model. This section is your guide to that process. We provide battle-tested, audited contract models that serve as powerful starting points, allowing you to focus on innovation rather than reinventing the wheel. ### Start building export function Step({ num, heading, content, isLast = false }) { return(
{ num }
{ !isLast &&
}

{ heading }

{ content }

) } export function StepList({ type, link, content, icon }) { return(
{ type }
) } export function Warning({ heading, content, link }) { return(
{ heading }
{ content }
) } export function Button({ text, link }) { return( { text } ) } export function CardGrid() { const cards = [ { title: 'Treasury', description: 'Simple & Direct. All accrued yield is sent to a single, designated wallet.', href: '/build/models/treasury/overview/', iconClass: 'icon-Treasury', }, { title: 'User Yield', description: 'Flexible & Shared. Yield is passed through to token holders, with an optional protocol fee taken out.', href: '/build/models/user-yield/overview/', iconClass: 'icon-UserYield', }, { title: 'Institutional', description: 'Yield is distributed to individually whitelisted accounts, each with its own custom fee rate.', href: '/build/models/institutional/overview/', iconClass: 'icon-Institutional', }, ] return (
{cards.map((card, index) => (

{card.title}

{card.description}
))}
) }

Our team will reach out to guide your integration and help you gain early visibility and earner approval.