Skip to main content

Window Mechanism

The compound window is the core operational mechanism of the Catpound vault. This page provides a detailed look at how the window lifecycle works and what happens at each transition.

State Diagram

Phase Details

CLOSED (Silent Phase)

Duration: 0 to 2,001 blocks after window closes

  • MOTO is staked in MotoChef, earning rewards.
  • Exit fees apply, decaying from the maximum to 0% over 2,001 blocks.
  • Deposits are accepted normally. New MOTO enters the liquid buffer.
  • Only the vault owner or whitelisted compounders can open the window.

READY (Slash Fully Decayed)

Starts at: 2,001 blocks after window close

  • Exit fee has reached 0% -- withdrawals are free even though the window is still technically closed.
  • The vault is still earning rewards in MotoChef.
  • Compounders can call openWindow() at any time.
  • After the auto-open threshold (default: 4,000 blocks), anyone can call autoOpen().

OPEN (Free Exit Window)

Duration: From window open until compounder closes it

  • Everything has been unstaked from MotoChef.
  • Rewards have been harvested.
  • All MOTO is liquid (available for withdrawal).
  • Exit fees are 0%.
  • Reward tokens are swapped to MOTO via MotoSwap during this phase.
  • Deposits are still accepted.

What Happens at Each Transition

openWindow()

Called by a compounder or the vault owner. Requirements: window must be closed and at least 2,001 blocks must have passed since the last close.

  1. Unstake all MOTO from MotoChef
  2. Snapshot the pre-harvest MOTO balance (this is used later to calculate rewards)
  3. Harvest rewards from MotoChef via claimRewards()
  4. Set window flag to open
  5. Update totalAssets to reflect the current MOTO balance (including harvested rewards)

swapRewards() (between open and close)

Called by a compounder, potentially multiple times. Swaps non-MOTO reward tokens to MOTO:

  1. For each reward token, check the vault's balance
  2. Approve the MotoSwap router to spend the reward token
  3. Execute the swap with a minimum output amount (slippage protection)
  4. Update totalAssets after swaps to ensure accurate share pricing for any deposits during this phase

closeWindow()

Called by a compounder or the vault owner. Finalizes the compound cycle:

  1. Calculate reward delta: Current Balance - Pre-Harvest Balance - Deposits During Window
  2. Apply floor protocol fee (default 2%) to the reward delta
  3. Update surcharge accumulator for per-user fee tracking
  4. Send protocol fee to the treasury address
  5. Calculate reserve split: Keep 15% liquid, stake 85%
  6. Stake the allocated MOTO into MotoChef
  7. Set window flag to closed
  8. Record the current block as lastReinvestBlock
  9. Clear temporary state (pre-harvest balance, deposit delta)

The share price increases at this point because totalAssets now includes the harvested rewards (minus protocol fee), while the cpMOTO supply has not changed.

autoOpen()

The permissionless fallback mechanism. Anyone can call autoOpen() when:

  • The window is closed
  • At least 2,001 blocks have passed since the last close (slash fully decayed)
  • At least autoOpenThreshold blocks have passed (default: 4,000)

The auto-open threshold must be at least 2,001 blocks and is configurable by the vault owner. This ensures:

  • The vault eventually compounds even if compounder bots go offline
  • Users are never permanently locked out of free exits

autoOpen() executes the same logic as openWindow() -- unstake, snapshot, harvest, set flag.

Edge Cases

What if nobody opens the window?

The exit fee decays to 0% after 2,001 blocks regardless of whether the window opens. Users can always withdraw for free after waiting the full decay period. The autoOpen mechanism ensures someone can eventually trigger the compound.

What if the vault is paused?

Pausing only blocks new deposits. Withdrawals continue to work normally, and compound cycles can still be executed. This is a safety measure, not a lockout.

What if there are no rewards to harvest?

The window can still be opened and closed even with zero rewards. The share price simply does not change in that cycle. This is a no-op compound -- no harm, just unnecessary gas.

What about deposits during the open window?

Deposits during the open window are tracked via a windowDepositDelta counter. When calculating rewards at close time, this delta is subtracted from the balance change to avoid counting deposited MOTO as if it were harvested rewards.