Architecture
This page provides a technical overview of how the Catpound vault fits into the OPNet ecosystem.
System Overview
Components
Catpound Vault Contract
The core smart contract, written in AssemblyScript and compiled to WASM. It extends the OP20 token standard, which means the vault itself is the cpMOTO token contract. Key responsibilities:
- Accept MOTO deposits and mint cpMOTO shares
- Manage the two-bucket model (liquid buffer + staked)
- Execute compound cycles (unstake, harvest, swap, re-stake)
- Calculate and apply exit fees
- Track user tiers, NFT staking, and whale detection
- Enforce all safety invariants (reentrancy guard, SafeMath, hard caps)
MotoChef
The staking/farming protocol where MOTO earns yield. The vault interacts with MotoChef through three operations:
stake(amount)-- Deposit MOTO to earn rewardsunstake()-- Withdraw all staked MOTOclaimRewards()-- Harvest accumulated reward tokens
MotoSwap Router
The decentralized exchange used to swap harvested reward tokens back to MOTO. During the compound phase, the vault approves the router to spend reward tokens and executes swaps with slippage protection.
Frontend
A React/Vite web application that provides the user interface. It communicates with the OPNet node via JSON-RPC and with OPWallet for transaction signing. The frontend never has access to your private keys.
Relayer (NFT Binding)
A backend service that facilitates binding ordinal NFTs to OPNet. When you want to stake an NFT, the relayer handles the cross-layer binding process and mints the corresponding OPNet NFT (OP721 standard).
Two-Bucket Model
The vault splits its total MOTO holdings into two pools:
| Bucket | Purpose | Typical % |
|---|---|---|
| Staked | MOTO earning rewards in MotoChef | ~85% |
| Liquid | Available for immediate withdrawals | ~15% |
The reserve ratio (default 15%) determines the split. After each compound cycle, the vault re-balances to maintain the target ratio.
During the open window, everything is unstaked and 100% of assets are liquid. This is when large withdrawals are easiest to execute.
Contract Inheritance
OP20 (Base Token Standard)
└── CatpoundMotoVault
├── OP20 token functionality (cpMOTO)
├── Vault deposit/withdraw logic
├── Compound cycle management
├── Tier system (NFT + whale + manual)
├── Surcharge accumulator
└── Admin controls (owner, compounder ACL)
The vault extends OP20 directly, which means cpMOTO inherits all standard token features (transfer, approve, balanceOf) automatically. The vault overrides the burn function to prevent direct burns -- shares can only be destroyed through the withdraw function.
Surcharge Accumulator
Per-user protocol fee surcharges are tracked via an accumulator pattern to avoid expensive per-user calculations on every compound cycle.
How it works:
- When the vault closes a compound window, it computes the per-share reward and records a
surchargePerSharesnapshot. - Each user has a
userSurchargeDebtthat represents how much they have already been charged. - When a user deposits, withdraws, or transfers cpMOTO, the vault settles any outstanding surcharge:
Owed = (currentSurchargePerShare - userDebt) × userShares- The owed amount is burned from the user's cpMOTO (reducing their claim on total assets by the fee amount)
userDebtis updated tocurrentSurchargePerShare
This means the protocol fee is deferred and collected lazily at the point of user interaction, not in a loop over all users at compound time.
Key Storage Slots
| Slot | Description |
|---|---|
totalAssets | Tracked vault total (donation-proof) |
windowOpen | 0 = closed, 1 = open |
lastReinvestBlock | Block when the last compound window closed |
stakedInChef | Boolean flag: is MOTO currently staked in MotoChef? |
surchargePerShareAccumulator | Global surcharge accumulator (increases with each compound) |
preHarvestBalance | Snapshot taken at window open for reward delta calculation |
windowDepositDelta | MOTO deposited during the current open window (excluded from reward calc) |