### LEAF Protocol — Technical Whitepaper #### Abstract LEAF is a redemption-focused protocol that allows LEAF holders to redeem value in a reserve-backed stable asset (vbUSDC, 6 decimals) and an ecosystem token (CAPS, 18 decimals), while sustaining a reserve through periodic yield injections and buybacks. The protocol enforces per-user daily limits and global budget constraints, uses Merkle-based allowances to coordinate distribution, and relies on a modular oracle adapter for price discovery. Importantly, LEAF does not custody or utilize users’ principal assets: users’ assets remain on Morpho (Ethereum), and only the generated yield is bridged and distributed by LEAF. The system is upgradeable and operator-governed to adjust parameters and respond to market or liquidity conditions. --- ### 1. System Overview - **Core goals**: Provide orderly redemptions of LEAF into vbUSDC and CAPS; protect the reserve; enforce fair daily limits; and recycle external yield into reserves and CAPS liquidity/burn. - **Key components**: - `RewardsDistributorV2`: Redemption engine (vbUSDC-only and mixed modes; optional emergency exit). - `RedemptionReserve`: Custodies vbUSDC and pays redemptions. - `ConversionEscrow`: Custodies CAPS for redemptions. - `RedemptionAllowance`: Stores daily Merkle roots of per-user vbUSDC allowances and tracks consumption. - `BuybackManagerV2`: Executes swaps (vbUSDC<->CAPS) and funds escrow/reserve per policy. - `YieldDistributorV2`: Periodically injects vbUSDC yield to the reserve, executes buybacks, and burns CAPS. - `LEAFStaking`: Staking with a 30-day cooldown and emergency withdraw toggle. - `Oracle Adapter`: Provides CAPS price for mixed redemptions and health checks. Custody and yield model: - Users’ principal assets remain on Morpho (Ethereum). LEAF never rehypothecates or deploys user principal. - Only the yield produced by those assets is harvested off-chain/on Ethereum and bridged as vbUSDC to the LEAF domain for reserve funding, redemptions, and buybacks. Token precisions and conversion: - LEAF: 18 decimals - vbUSDC: 6 decimals - CAPS: 18 decimals - Conversion factor used on-chain: `LEAF_TO_VB_SCALE = 1e12`, so `vb = leaf / 1e12` and `leaf = vb * 1e12`. --- ### 2. Actors and Roles - **Users**: LEAF holders redeeming value and optionally staking LEAF. - **Owner/Governance**: Controls parameters, budgets, and toggles across upgradeable contracts. - **Operator/Keeper**: Executes scheduled operations (e.g., buybacks via `BuybackManagerV2`). - **Bridge/Feeder**: Feeds vbUSDC to `RedemptionReserve` and price/MA data to the oracle adapter where applicable. --- ### 3. Redemption Mechanics (RewardsDistributorV2) The `RewardsDistributorV2` contract is the primary redemption engine. Values are computed in vbUSDC units (6 decimals) with `day = floor(block.timestamp / 1 days)`. Two redemption paths are available, with a third “emergency exit” overlay for mixed redemptions. #### 3.1 Per-user daily limit - Reserve balance: `(reserveVbUSDC,,) = RedemptionReserve.balances()` - User LEAF balance: `LEAF.balanceOf(user)` - Daily cap by user LEAF: `byLeafVb = (leafBalance / 1e12) * dailyCapBps / 10_000` - Reserve share cap: `byReserveVb = reserveVbUSDC * maxReserveShareBps / 10_000` - User daily limit: `userLimitVb = min(byLeafVb, byReserveVb)` - The contract tracks `userUsedToday[user]` (vbUSDC units). Remaining: `capLeft = max(0, userLimitVb - userUsedToday[user])`. Parameters (defaults on init): - `dailyCapBps = 2000` (20% of LEAF balance per day) - `maxReserveShareBps = 50` (0.5% of the reserve per user per day) - `dailyBudget` and `budgetRemaining` (global vbUSDC budget per day) - Per-user allowance via `RedemptionAllowance` Merkle proof #### 3.2 Allowance (Merkle) - `RedemptionAllowance` stores a daily Merkle root of leaves `keccak256(abi.encodePacked(user, totalAllowance))` in vbUSDC units. - On redemption, `RewardsDistributorV2` calls `allowance.consume(day, user, totalAllowance, proof, amount)` to enforce per-user allowance limits. #### 3.3 vbUSDC-only redemption - 100% payout in vbUSDC. - No fee (V2 deprecates the prior small fee). - Effective cap: `effectiveVb = min(inputVb, capLeft, budgetRemaining, allowanceRemaining)`. - Burns exactly `leafToBurn = effectiveVb * 1e12` and pays `effectiveVb` via `RedemptionReserve.payVbUsdcOnly`. - Updates `userUsedToday[user] += effectiveVb` and `budgetRemaining -= effectiveVb`. - Any shortfall is deferred (not burned). #### 3.4 Mixed redemption (65% vbUSDC + 35% CAPS) - Splits the effective redemption value into vbUSDC and CAPS by value: `vb = 65%`, `capsValue = 35%`. - Normal mode caps by: user remaining cap, daily budget, and allowance. - CAPS quantity uses oracle-converted price: `capsPay = (capsValueVb * 1e18) / (priceVb * 1e6)`. - Burns the LEAF corresponding to the effective value. - Pays vbUSDC from reserve and CAPS from escrow. #### 3.5 Emergency exit (mixed mode overlay) - If requested total value exceeds `capLeft` or `budgetRemaining`, and `emergencyExitEnabled` is true, the contract allows a full redemption bypassing daily caps and allowance, provided sufficient reserve and CAPS are available. - An emergency exit fee reduces the net LEAF redeemed: `fee = amountLEAF * emergencyExitFeeBps / 10_000`, then the net value is split 65/35 as above. Default fee is 10% (`emergencyExitFeeBps = 1000`). The fee portion is burned. - Preconditions: `vbUsdcPay <= reserveBalance` and `capsPay <= escrow.availableCaps()`. #### 3.6 Toggling redemption types (V3 storage) - `vbUsdcOnlyEnabled` (default true), `mixedEnabled` (default false), `emergencyExitEnabled` (default false) are owner-togglable. --- ### 4. Reserve and Escrow #### 4.1 RedemptionReserve - Holds vbUSDC, pays redemptions on distributor instruction. - Interfaces: - `depositFromBridge(amount)` called by a designated `bridge` to fund the reserve. - `payVbUsdcOnly(to, amount)` callable by the distributor as `operator`. - Tracks `targetVbUSDC` and `floorVbUSDC` for policy/monitoring; exposes `coverage()` and `balances()`. #### 4.2 ConversionEscrow - Holds CAPS to fulfill mixed redemptions. - `depositCaps(amount)` is called by the `BuybackManagerV2` after swaps. - `allocateTo(user, amount)` is called by the distributor to deliver CAPS to the user. - Owner can set approvals for rebalancing operations. --- ### 5. Yield Injection and Buybacks #### 5.1 YieldDistributorV2 - Input: vbUSDC yield harvested from users’ principal deployed on Morpho (Ethereum) and/or treasury sources, bridged to the LEAF domain on a weekly or chosen cadence. - Splits the amount by basis points (default: 60% reserve, 30% buyback, 10% burn): - Reserve: approves and forwards to `RedemptionReserve.depositFromBridge`. - Buyback: approves and instructs `BuybackManagerV2` to purchase CAPS for escrow. - Burn: swaps a portion to CAPS on a DEX and sends directly to a burn address with slippage protection. - Owner can change percentages and slippage bounds. #### 5.2 BuybackManagerV2 - Operator-scheduled buybacks on a DEX router with slippage tolerance. - `setEpochBudget` accumulates a vbUSDC budget the operator can spend. - `executeBuy(amountIn, deadline)`: swaps vbUSDC->CAPS and sends to `ConversionEscrow`. - `executeBuyAndBurn(amountIn, deadline)`: swaps vbUSDC->CAPS and sends to burn address. - Rebalancing: owner can swap CAPS->vbUSDC sourced from escrow and send the vbUSDC to a specified recipient (e.g., the reserve). --- ### 6. Staking (LEAFStaking) - Users can create multiple stakes (max 50) and must start a 30-day cooldown before unstaking. - Functions: `stake`, `startCooldown`, `startCooldownAll`, `unstake`, `partialUnstake`, `unstakeAll`. - Emergency withdraw can be toggled by owner to allow immediate exit of all staked LEAF. - Pausable and reentrancy-protected; upgradeable using UUPS pattern. Staker rewards and sources (policy-level): - vbUSDC yield share: Stakers are intended to receive a share of the yield generated on users’ principal assets held on Morpho (Ethereum). LEAF never uses the principal itself; only harvested yield (bridged as vbUSDC) is distributed. In the current codebase, vbUSDC yield is injected via `YieldDistributorV2` primarily to the `RedemptionReserve` and buybacks/burns; a future auxiliary distributor can route a configurable portion directly to stakers. - DEX fees: Protocol-directed swaps (buybacks/burn) on AMMs generate trading fees that accrue to LPs. While fees are not directly captured on-chain by the protocol in V2, their effect is reflected in execution prices; policy can earmark part of buyback budgets or realized advantages to staker distributions in an extended module. - Exit fees: In `RewardsDistributorV2` emergency exits, the fee is burned, reducing supply and indirectly increasing per-token claim on reserves. This benefits all holders (including stakers) via deflation rather than direct cash flow. - Boost: A boost factor (e.g., tenure/size multiplier) can be applied when distributing rewards among stakers. This is not implemented in `LEAFStaking` and can be added as an auxiliary reward accounting module. Implementation note: `LEAFStaking` tracks stakes and cooldowns only; it does not mint claim tokens or accrue yield internally. Any direct reward distribution to stakers should be implemented via an auxiliary distributor that reads staking balances and pays vbUSDC/CAPS according to policy (including boosts), while maintaining upgradeable and pausable safety properties. --- ### 7. Oracle and Price Feeds - The redemption engine requires a CAPS price in vbUSDC units to size CAPS payouts in mixed mode. - The repository includes a RedStone-based adapter (`RedStoneOracleAdapter`) exposing spot and 30d MA prices and a health check. Deployments can map this (or another adapter) to the interface used by the distributor. - Health checks (freshness and MA availability) should gate operational use at the policy layer. --- ### 8. Governance, Access Control, and Upgradeability - All core modules are `OwnableUpgradeable`; owner controls: - Distributor: caps/fees, daily budget, allowance address, oracle, redemption type toggles. - Reserve: operator and bridge, targets/floor. - Escrow: manager/distributor, approvals. - BuybackManager: operator, router, oracle, escrow, slippage, budgets, pause. - YieldDistributor: split percentages, slippage, component addresses. - Staking: pause/unpause, emergency withdraw toggle; UUPS upgrades authorized by owner. - Upgradeability via OpenZeppelin upgradeable contracts; storage layout extensions are appended at the end in newer versions (e.g., V2/V3 fields in `RewardsDistributorV2`). --- ### 9. Economics and Formulas - Units: - `vb = leaf / 1e12` - `leaf = vb * 1e12` - Per-user daily cap (vbUSDC units): - `byLeafVb = (LEAF_balance / 1e12) * dailyCapBps / 10_000` - `byReserveVb = reserveVbUSDC * maxReserveShareBps / 10_000` - `userLimitVb = min(byLeafVb, byReserveVb)` - Effective vbUSDC payout caps: - vbUSDC-only: `vbPay = min(inputVb, capLeft, budgetRemaining, allowanceRemaining)` - Mixed (normal): `effectiveVb = min(totalValueVb, capLeft, budgetRemaining, allowanceRemaining)`; then split 65/35 by value - Mixed (emergency): fee reduces net LEAF first; check on-chain liquidity; bypass allowance and caps --- ### 10. Security Considerations - Reentrancy: critical flows are guarded by `ReentrancyGuardUpgradeable`. - Access control: owner-only configuration; operator-only execution paths; distributor/operator roles on reserve/escrow. - Pausing/Emergency: staking supports pause; distributor supports disabling redemption types; emergency exit fee deters abuse. - Oracle risk: price feed freshness and correctness are critical; deployments should enforce health checks and safe fallbacks. - Merkle allowance integrity: off-chain root generation must be trustworthy; proofs are verified on-chain. - Token handling: burns use `address(0xdead)`; approvals are tightly scoped; slippage protections in swaps. --- ### 11. Typical Flows - vbUSDC-only redemption: 1) User submits `amountLEAF` + Merkle proof; contract computes caps and budget; 2) burns only the effective portion; 3) pays vbUSDC; 4) defers remainder. - Mixed redemption (normal): 1) Compute effective value under caps/budget; 2) split 65/35; 3) burn corresponding LEAF; 4) pay vbUSDC from reserve; 5) allocate CAPS from escrow. - Mixed redemption (emergency): 1) Apply emergency fee and bypass caps/allowance; 2) ensure reserves and CAPS are sufficient; 3) burn and pay 65/35. - Yield injection: 1) Treasury calls `distributeYield(amount)`; 2) reserve funded, escrow funded via buyback, and CAPS burned via DEX. - Buyback: 1) Operator sets epoch budget; 2) executes swaps to fill escrow or burn. --- ### 12. Parameters and Defaults (illustrative) - `dailyCapBps = 2000` (20%) - `maxReserveShareBps = 50` (0.5%) - `dailyBudget` set by owner; resets daily with `budgetRemaining`. - `emergencyExitFeeBps` default 10% (set via `initializeV2` or `setEmergencyExitFee`). - `vbUsdcOnlyEnabled = true`, `mixedEnabled = false`, `emergencyExitEnabled = false` (post-`initializeV3`). - Yield split default: 60% reserve, 30% buyback, 10% burn; `slippageBps` default 1%. --- ### 13. Implementation Notes - Upgradeability: storage-compatible additions are appended; UUPS in staking; other modules use OZ upgradeable patterns. - Time granularity: day index uses UTC seconds-based division (`block.timestamp / 1 days`). - Decimals: strict handling of 18 vs 6 decimals via explicit scaling. - Events: all critical actions emit structured events for off-chain indexing. --- ### 14. Roadmap and Extensions - Enhanced oracle aggregation and fallback logic. - On-chain queueing for deferred redemptions. - Governance module for parameter voting. - Automated reserve rebalancing based on coverage targets. --- ### 15. Disclaimer This document describes the current on-chain implementation as reflected in the repository’s Solidity contracts and may evolve with upgrades. Parameter values are subject to change by the owner through governed processes in production deployments. This is not financial advice.