Deep Dive: MYieldToOne Extension
The MYieldToOne extension is the simplest and most direct way to build on M0. It creates an upgradeable ERC-20 token that wraps $M on a 1:1 basis, while directing 100% of the accrued $M yield to a single, designated recipient address.
This model is perfect for builders who want the stability and liquidity of an $M-backed token within their ecosystem, but prefer to centralize the yield for strategic purposes like funding protocol development, ecosystem grants, or operational expenses.
Source Code: MYieldToOne.sol
Architecture and Mechanism
The beauty of MYieldToOne lies in its simplicity. It separates the token holding experience from the yield generation, while incorporating freezing capabilities for compliance.
Roles (Access Control)
MYieldToOne inherits from both MExtension and Freezable, using OpenZeppelin's AccessControl to manage permissions with these distinct roles:
DEFAULT_ADMIN_ROLE: The super-user. This role can grant and revoke any other role. It should be held by a secure multi-sig or governance contract.YIELD_RECIPIENT_MANAGER_ROLE: This role has one job: to manage where the yield goes. It can callsetYieldRecipient()to change the beneficiary address.FREEZE_MANAGER_ROLE: This role can block specific addresses from wrapping, unwrapping, or transferring the token, adding a layer of compliance through thefreeze()andunfreeze()functions.
How It Works
- Wrapping: A user wraps 
$Mthrough the SwapFacility and receives an equal amount of your new extension token (e.g., wrap 100$M, receive 100YourToken). TheMYieldToOnecontract now holds 100$M. - Accruing Yield: Your deployed 
MYieldToOnecontract must callenableEarning()to start earning$M. The 100$Mit holds begins to accrue yield from the underlying US Treasury bills. - Creating a Surplus: As yield accrues, the contract's 
$Mbalance becomes greater than the total supply of your extension token. For example, the contract might hold 100.05$Mwhile thetotalSupply()ofYourTokenis still 100. - Claiming Yield: This surplus is the claimable yield. Anyone can call the 
claimYield()function to realize this yield. - Distribution: When 
claimYield()is called, the contract mints newYourTokenequivalent to the surplus amount (0.05 in our example) and sends them directly to the designatedyieldRecipientaddress. ThetotalSupplynow becomes 100.05. 
For end-users holding your token, their balance remains stable and unchanged. The yield is handled completely behind the scenes.
Key Interface & Functions
While MYieldToOne is a full ERC-20 token, its unique logic revolves around a few key functions.
Storage Layout
The state is kept minimal and efficient.
struct MYieldToOneStorageStruct {
    uint256 totalSupply;
    address yieldRecipient;
    mapping(address account => uint256 balance) balanceOf;
}Core Yield Functions
- 
yield() external view returns (uint256)
This view function calculates the amount of claimable yield at any moment. It returns the difference between the contract's current$Mbalance and thetotalSupplyof the extension token:mBalance > totalSupply ? mBalance - totalSupply : 0. - 
claimYield() external returns (uint256)
This is the function that triggers the yield distribution. It calculates the yield, mints that amount of new tokens, and transfers them to theyieldRecipient. Returns 0 if there is no yield to claim. 
Management Functions
setYieldRecipient(address yieldRecipient) external
Callable only by theYIELD_RECIPIENT_MANAGER_ROLE, this function updates the address that receives the yield. It automatically claims any existing yield for the previous recipient before making the change.
Freezing Functions (Inherited from Freezable)
freeze(address account) external
Callable by theFREEZE_MANAGER_ROLE, this function prevents an address from interacting with the token. Reverts if the account is already frozen.unfreeze(address account) external
Removes an address from the frozen list. Reverts if the account is not currently frozen.isFrozen(address account) external view returns (bool)
Checks if an address is currently frozen.freezeAccounts(address[] calldata accounts) external
Batch version for freezing multiple accounts.unfreezeAccounts(address[] calldata accounts) external
Batch version for unfreezing multiple accounts.
Standard MExtension Functions
As a child of MExtension.sol, MYieldToOne automatically inherits all the essential functionalities for interacting with the M0 ecosystem:
wrap(address recipient, uint256 amount)- Called by SwapFacility onlyunwrap(address recipient, uint256 amount)- Called by SwapFacility onlyenableEarning()- Starts earning yield on held$MdisableEarning()- Stops earning yield
Hook Functions
The contract implements several internal hook functions that enforce freezing:
_beforeApprove()- Checks both account and spender aren't frozen_beforeWrap()- Checks both depositor and recipient aren't frozen_beforeUnwrap()- Checks the account isn't frozen_beforeTransfer()- Checks sender, recipient, and msg.sender aren't frozen
Constants
YIELD_RECIPIENT_MANAGER_ROLE:keccak256("YIELD_RECIPIENT_MANAGER_ROLE")FREEZE_MANAGER_ROLE:keccak256("FREEZE_MANAGER_ROLE")(inherited from Freezable)
Ready to build? Follow the implementation guide to deploy your MYieldToOne extension.

