# Wrapped M Specification

> Low-level technical specification for Wrapped M (wM) - function signatures, events, errors, and storage layout.

## Contract overview

`WrappedMToken` (wM) is a non-rebasing ERC-20 wrapper for the rebasing `$M` token. It maintains yield-earning capabilities while providing compatibility with DeFi protocols that require standard ERC-20 tokens.

- **Decimals:** 6 (matches `$M`)
- **Index:** Derived from the underlying `$M` token's index
- **Yield realization:** Explicit claiming (not automatic rebasing)

---

## Key functions

### Wrapping and Unwrapping

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        wrap(address recipient, uint256 amount)
      </code>
    </td>
    
    <td>
      Deposit <code>
        $M
      </code>
      
       tokens, receive equivalent wM
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        unwrap(address recipient, uint256 amount)
      </code>
    </td>
    
    <td>
      Burn wM tokens, receive equivalent <code>
        $M
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        wrapWithPermit(address recipient, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
      </code>
    </td>
    
    <td>
      Wrap with gasless <code>
        $M
      </code>
      
       approval
    </td>
  </tr>
</tbody>
</table>

### ERC20 Standard

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        transfer(address to, uint256 amount)
      </code>
    </td>
    
    <td>
      Transfer wM tokens
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        transferFrom(address from, address to, uint256 amount)
      </code>
    </td>
    
    <td>
      Transfer wM on behalf of another address
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        approve(address spender, uint256 amount)
      </code>
    </td>
    
    <td>
      Approve a spender allowance
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        balanceOf(address account)
      </code>
    </td>
    
    <td>
      Returns stored balance (excludes unclaimed yield)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        totalSupply()
      </code>
    </td>
    
    <td>
      Returns total wM in circulation
    </td>
  </tr>
</tbody>
</table>

### Earning Management

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        startEarningFor(address account)
      </code>
    </td>
    
    <td>
      Activate earning mode for an approved account
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        stopEarningFor(address account)
      </code>
    </td>
    
    <td>
      Deactivate earning mode (claims outstanding yield)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        enableEarning()
      </code>
    </td>
    
    <td>
      Enable earning for the wM contract itself on <code>
        $M
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        disableEarning()
      </code>
    </td>
    
    <td>
      Disable earning for the wM contract on <code>
        $M
      </code>
    </td>
  </tr>
</tbody>
</table>

### Yield Management

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        claimFor(address account)
      </code>
    </td>
    
    <td>
      Claim accrued yield for an account
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setClaimRecipient(address recipient)
      </code>
    </td>
    
    <td>
      Set a custom address to receive claimed yield
    </td>
  </tr>
</tbody>
</table>

### Balance and Yield Queries

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Returns
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        balanceOf(address account)
      </code>
    </td>
    
    <td>
      Stored balance (excludes unclaimed yield)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        accruedYieldOf(address account)
      </code>
    </td>
    
    <td>
      Unclaimed yield for an earning account
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        balanceWithYieldOf(address account)
      </code>
    </td>
    
    <td>
      <code>
        balanceOf
      </code>
      
       + <code>
        accruedYieldOf
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        isEarning(address account)
      </code>
    </td>
    
    <td>
      Whether the account is in earning mode
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        totalNonEarningSupply()
      </code>
    </td>
    
    <td>
      Sum of all non-earning balances
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        totalEarningSupply()
      </code>
    </td>
    
    <td>
      Sum of all earning balances (excluding yield)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        projectedEarningSupply()
      </code>
    </td>
    
    <td>
      Total earning supply if all yield were claimed
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        excess()
      </code>
    </td>
    
    <td>
      <code>
        $M
      </code>
      
       held by contract minus total wM liabilities
    </td>
  </tr>
</tbody>
</table>

### Excess Management

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        claimExcess()
      </code>
    </td>
    
    <td>
      Transfer accumulated excess <code>
        $M
      </code>
      
       to <code>
        excessDestination
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        excessDestination()
      </code>
    </td>
    
    <td>
      Returns the address that receives claimed excess (typically Distribution Vault)
    </td>
  </tr>
</tbody>
</table>

### Admin Operations (via EarnerManager)

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        setEarnerDetails(address account, bool status, uint16 feeRate)
      </code>
    </td>
    
    <td>
      Set earning status and fee rate for an account
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setEarnerDetails(address[] accounts, bool[] statuses, uint16[] feeRates)
      </code>
    </td>
    
    <td>
      Bulk set earning details
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        earnerStatusFor(address account)
      </code>
    </td>
    
    <td>
      Check earner status for an account
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        getEarnerDetails(address account)
      </code>
    </td>
    
    <td>
      Get full earner details including admin and fee rate
    </td>
  </tr>
</tbody>
</table>

---

## Account storage model

```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
}
```

---

## Events

<table>
<thead>
  <tr>
    <th>
      Event
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        Transfer(address indexed from, address indexed to, uint256 value)
      </code>
    </td>
    
    <td>
      Standard ERC20 transfer
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        Approval(address indexed owner, address indexed spender, uint256 value)
      </code>
    </td>
    
    <td>
      Standard ERC20 approval
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        StartedEarning(address indexed account)
      </code>
    </td>
    
    <td>
      Account entered earning mode
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        StoppedEarning(address indexed account)
      </code>
    </td>
    
    <td>
      Account exited earning mode
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        Claimed(address indexed account, address indexed recipient, uint256 yield)
      </code>
    </td>
    
    <td>
      Yield claimed
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ExcessClaimed(uint240 amount)
      </code>
    </td>
    
    <td>
      Excess <code>
        $M
      </code>
      
       claimed to destination
    </td>
  </tr>
</tbody>
</table>

---

## Errors

<table>
<thead>
  <tr>
    <th>
      Error
    </th>
    
    <th>
      Condition
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        NotApprovedEarner()
      </code>
    </td>
    
    <td>
      Account is not approved for earning
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        EarningIsEnabled()
      </code>
    </td>
    
    <td>
      Operation not permitted while earning is enabled
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        EarningIsDisabled()
      </code>
    </td>
    
    <td>
      Operation requires earning to be enabled
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        InsufficientBalance(address account, uint256 balance, uint256 amount)
      </code>
    </td>
    
    <td>
      Transfer, unwrap, or burn exceeds balance
    </td>
  </tr>
</tbody>
</table>

---

## Index mechanism

The wM index is derived from the underlying `$M` token's index:

**When earning is enabled:**

<span className="katex-display">
<span className="katex">
<span className="katex-mathml">
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
<semantics>
<mrow>
<mi>

w

</mi>

<msub>
<mi>

M

</mi>

<mtext>

index

</mtext>
</msub>

<mo>

=

</mo>

<mfrac>
<msub>
<mi>

M

</mi>

<mtext>

currentIndex

</mtext>
</msub>

<mrow>
<mi>

e

</mi>

<mi>

n

</mi>

<mi>

a

</mi>

<mi>

b

</mi>

<mi>

l

</mi>

<mi>

e

</mi>

<mi>

M

</mi>

<mi>

I

</mi>

<mi>

n

</mi>

<mi>

d

</mi>

<mi>

e

</mi>

<mi>

x

</mi>
</mrow>
</mfrac>

<mo>

×

</mo>

<mi>

d

</mi>

<mi>

i

</mi>

<mi>

s

</mi>

<mi>

a

</mi>

<mi>

b

</mi>

<mi>

l

</mi>

<mi>

e

</mi>

<mi>

I

</mi>

<mi>

n

</mi>

<mi>

d

</mi>

<mi>

e

</mi>

<mi>

x

</mi>
</mrow>

<annotation encoding="application/x-tex">

wM_{\text{index}} = \frac{M_{\text{currentIndex}}}{enableMIndex} \times disableIndex

</annotation>
</semantics>
</math>
</span>

<span className="katex-html" ariaHidden="true">
<span className="base">
<span className="strut" style="height:0.8333em;vertical-align:-0.15em;">



</span>

<span className="mord,mathnormal" style="margin-right:0.0269em;">

w

</span>

<span className="mord">
<span className="mord,mathnormal" style="margin-right:0.109em;">

M

</span>

<span className="msupsub">
<span className="vlist-t,vlist-t2">
<span className="vlist-r">
<span className="vlist" style="height:0.3361em;">
<span style="top:-2.55em;margin-left:-0.109em;margin-right:0.05em;">
<span className="pstrut" style="height:2.7em;">



</span>

<span className="sizing,reset-size6,size3,mtight">
<span className="mord,mtight">
<span className="mord,text,mtight">
<span className="mord,mtight">

index

</span>
</span>
</span>
</span>
</span>
</span>

<span className="vlist-s">

​

</span>
</span>

<span className="vlist-r">
<span className="vlist" style="height:0.15em;">
<span>



</span>
</span>
</span>
</span>
</span>
</span>

<span className="mspace" style="margin-right:0.2778em;">



</span>

<span className="mrel">

=

</span>

<span className="mspace" style="margin-right:0.2778em;">



</span>
</span>

<span className="base">
<span className="strut" style="height:2.0463em;vertical-align:-0.686em;">



</span>

<span className="mord">
<span className="mopen,nulldelimiter">



</span>

<span className="mfrac">
<span className="vlist-t,vlist-t2">
<span className="vlist-r">
<span className="vlist" style="height:1.3603em;">
<span style="top:-2.314em;">
<span className="pstrut" style="height:3em;">



</span>

<span className="mord">
<span className="mord,mathnormal">

e

</span>

<span className="mord,mathnormal">

nab

</span>

<span className="mord,mathnormal" style="margin-right:0.0197em;">

l

</span>

<span className="mord,mathnormal">

e

</span>

<span className="mord,mathnormal" style="margin-right:0.109em;">

M

</span>

<span className="mord,mathnormal" style="margin-right:0.0785em;">

I

</span>

<span className="mord,mathnormal">

n

</span>

<span className="mord,mathnormal">

d

</span>

<span className="mord,mathnormal">

e

</span>

<span className="mord,mathnormal">

x

</span>
</span>
</span>

<span style="top:-3.23em;">
<span className="pstrut" style="height:3em;">



</span>

<span className="frac-line" style="border-bottom-width:0.04em;">



</span>
</span>

<span style="top:-3.677em;">
<span className="pstrut" style="height:3em;">



</span>

<span className="mord">
<span className="mord">
<span className="mord,mathnormal" style="margin-right:0.109em;">

M

</span>

<span className="msupsub">
<span className="vlist-t,vlist-t2">
<span className="vlist-r">
<span className="vlist" style="height:0.3361em;">
<span style="top:-2.55em;margin-left:-0.109em;margin-right:0.05em;">
<span className="pstrut" style="height:2.7em;">



</span>

<span className="sizing,reset-size6,size3,mtight">
<span className="mord,mtight">
<span className="mord,text,mtight">
<span className="mord,mtight">

currentIndex

</span>
</span>
</span>
</span>
</span>
</span>

<span className="vlist-s">

​

</span>
</span>

<span className="vlist-r">
<span className="vlist" style="height:0.15em;">
<span>



</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>
</span>

<span className="vlist-s">

​

</span>
</span>

<span className="vlist-r">
<span className="vlist" style="height:0.686em;">
<span>



</span>
</span>
</span>
</span>
</span>

<span className="mclose,nulldelimiter">



</span>
</span>

<span className="mspace" style="margin-right:0.2222em;">



</span>

<span className="mbin">

×

</span>

<span className="mspace" style="margin-right:0.2222em;">



</span>
</span>

<span className="base">
<span className="strut" style="height:0.6944em;">



</span>

<span className="mord,mathnormal">

d

</span>

<span className="mord,mathnormal">

i

</span>

<span className="mord,mathnormal">

s

</span>

<span className="mord,mathnormal">

ab

</span>

<span className="mord,mathnormal" style="margin-right:0.0197em;">

l

</span>

<span className="mord,mathnormal">

e

</span>

<span className="mord,mathnormal" style="margin-right:0.0785em;">

I

</span>

<span className="mord,mathnormal">

n

</span>

<span className="mord,mathnormal">

d

</span>

<span className="mord,mathnormal">

e

</span>

<span className="mord,mathnormal">

x

</span>
</span>
</span>
</span>
</span>

**When earning is disabled:**

<span className="katex-display">
<span className="katex">
<span className="katex-mathml">
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
<semantics>
<mrow>
<mi>

w

</mi>

<msub>
<mi>

M

</mi>

<mtext>

index

</mtext>
</msub>

<mo>

=

</mo>

<mi>

d

</mi>

<mi>

i

</mi>

<mi>

s

</mi>

<mi>

a

</mi>

<mi>

b

</mi>

<mi>

l

</mi>

<mi>

e

</mi>

<mi>

I

</mi>

<mi>

n

</mi>

<mi>

d

</mi>

<mi>

e

</mi>

<mi>

x

</mi>
</mrow>

<annotation encoding="application/x-tex">

wM_{\text{index}} = disableIndex

</annotation>
</semantics>
</math>
</span>

<span className="katex-html" ariaHidden="true">
<span className="base">
<span className="strut" style="height:0.8333em;vertical-align:-0.15em;">



</span>

<span className="mord,mathnormal" style="margin-right:0.0269em;">

w

</span>

<span className="mord">
<span className="mord,mathnormal" style="margin-right:0.109em;">

M

</span>

<span className="msupsub">
<span className="vlist-t,vlist-t2">
<span className="vlist-r">
<span className="vlist" style="height:0.3361em;">
<span style="top:-2.55em;margin-left:-0.109em;margin-right:0.05em;">
<span className="pstrut" style="height:2.7em;">



</span>

<span className="sizing,reset-size6,size3,mtight">
<span className="mord,mtight">
<span className="mord,text,mtight">
<span className="mord,mtight">

index

</span>
</span>
</span>
</span>
</span>
</span>

<span className="vlist-s">

​

</span>
</span>

<span className="vlist-r">
<span className="vlist" style="height:0.15em;">
<span>



</span>
</span>
</span>
</span>
</span>
</span>

<span className="mspace" style="margin-right:0.2778em;">



</span>

<span className="mrel">

=

</span>

<span className="mspace" style="margin-right:0.2778em;">



</span>
</span>

<span className="base">
<span className="strut" style="height:0.6944em;">



</span>

<span className="mord,mathnormal">

d

</span>

<span className="mord,mathnormal">

i

</span>

<span className="mord,mathnormal">

s

</span>

<span className="mord,mathnormal">

ab

</span>

<span className="mord,mathnormal" style="margin-right:0.0197em;">

l

</span>

<span className="mord,mathnormal">

e

</span>

<span className="mord,mathnormal" style="margin-right:0.0785em;">

I

</span>

<span className="mord,mathnormal">

n

</span>

<span className="mord,mathnormal">

d

</span>

<span className="mord,mathnormal">

e

</span>

<span className="mord,mathnormal">

x

</span>
</span>
</span>
</span>
</span>

---

## Yield claim recipient priority

When determining where to send claimed yield:

1. User-specified recipient (via `setClaimRecipient`)
2. Governance-specified override (via Registrar)
3. The account itself (default)

---

## Solvency invariant

<span className="katex-display">
<span className="katex">
<span className="katex-mathml">
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
<semantics>
<mrow>
<msub>
<mtext>

M Balance

</mtext>

<mrow>
<mo stretchy="false">

(

</mo>

<mtext>

wM contract

</mtext>

<mo stretchy="false">

)

</mo>
</mrow>
</msub>

<mo>

≥

</mo>

<mtext>

totalNonEarningSupply

</mtext>

<mo>

+

</mo>

<mtext>

projectedEarningSupply

</mtext>
</mrow>

<annotation encoding="application/x-tex">

\text{M Balance}_{(\text{wM contract})} \ge \text{totalNonEarningSupply} + \text{projectedEarningSupply}

</annotation>
</semantics>
</math>
</span>

<span className="katex-html" ariaHidden="true">
<span className="base">
<span className="strut" style="height:1.0496em;vertical-align:-0.3552em;">



</span>

<span className="mord">
<span className="mord,text">
<span className="mord">

M Balance

</span>
</span>

<span className="msupsub">
<span className="vlist-t,vlist-t2">
<span className="vlist-r">
<span className="vlist" style="height:0.3448em;">
<span style="top:-2.5198em;margin-right:0.05em;">
<span className="pstrut" style="height:2.7em;">



</span>

<span className="sizing,reset-size6,size3,mtight">
<span className="mord,mtight">
<span className="mopen,mtight">

(

</span>

<span className="mord,text,mtight">
<span className="mord,mtight">

wM contract

</span>
</span>

<span className="mclose,mtight">

)

</span>
</span>
</span>
</span>
</span>

<span className="vlist-s">

​

</span>
</span>

<span className="vlist-r">
<span className="vlist" style="height:0.3552em;">
<span>



</span>
</span>
</span>
</span>
</span>
</span>

<span className="mspace" style="margin-right:0.2778em;">



</span>

<span className="mrel">

≥

</span>

<span className="mspace" style="margin-right:0.2778em;">



</span>
</span>

<span className="base">
<span className="strut" style="height:0.8889em;vertical-align:-0.1944em;">



</span>

<span className="mord,text">
<span className="mord">

totalNonEarningSupply

</span>
</span>

<span className="mspace" style="margin-right:0.2222em;">



</span>

<span className="mbin">

+

</span>

<span className="mspace" style="margin-right:0.2222em;">



</span>
</span>

<span className="base">
<span className="strut" style="height:0.8889em;vertical-align:-0.1944em;">



</span>

<span className="mord,text">
<span className="mord">

projectedEarningSupply

</span>
</span>
</span>
</span>
</span>
</span>

The excess above this threshold accumulates from yield on `$M` backing non-earning wM holders and minor rounding effects.

---

## Related

- [Wrapped M overview](/protocol/wrapped-m) - Full conceptual documentation
- [M Token specification](/protocol/m-token-spec) - `$M` token spec
- [Distribution Vault](/protocol/distribution-vault) - Where excess is typically directed
