Skip to content
Cosmopediaby Unity Nodes
Documentationinformalsystems/hydroinformalsystems/hydro › docs › inflowView on informalsystems/hydro ↗

performance fees

Context

Inflow is a vault system for managing pooled funds across multiple yield-generating strategies. The architecture consists of:

  • Control Center: Aggregates state across subvaults, tracks total deployed amount and global pool value
  • Vault (Subvault): Accepts deposits of a specific token (e.g., stATOM), issues vault shares, manages withdrawals and adapter deployments
  • Proxy: Intermediary contract for external (web2) users to interact with vaults, irrelevant here
  • Adapters: Integrations with external protocols (e.g., Mars) where vault funds are deployed for yield

Users deposit tokens and receive vault shares. The share price is calculated as:

share_price = total_pool_value / total_shares_issued

When the vault generates yield (from adapter returns or other sources), total_pool_value increases while total_shares_issued stays constant, causing share price appreciation. Users withdrawing later receive more tokens than they deposited.

Problem Statement

We need to capture a portion of the yield generated by the vault as performance fees. Requirements:

  1. Fee basis: Fees are charged on vault yield (share price appreciation), not on deposits
  2. Continuous accrual: Fees should accrue as yield is generated, not only at withdrawal
  3. Tiered fees: Some users receive rebates, effectively paying lower fees than the baseline
  4. Treasury distribution: Collected fees flow to the Hydro treasury (minus rebates)

Proposed Solution: Treasury Share Minting (Dilution Model)

Mint new vault shares to a rebate contract when yield is generated. This dilutes all holders proportionally, effectively extracting a fee on the yield.

Core Mechanism

Use high-water mark logic to track share price appreciation since the last fee accrual. This means we only charge fees on new yield generated since the last accrual, and not on the entire share price. Losses do not reduce the high-water mark, so fees are only charged on net new gains.

  1. Track high_water_share_ratio in the ControlCenter state
  2. On fee accrual (triggered via permissionless AccrueFees):
    • If current_share_ratio > high_water_share_ratio:
      • yield_per_share = current_share_ratio - high_water_share_ratio
      • total_yield = yield_per_share × total_shares
      • fee_amount = total_yield × fee_rate
      • shares_to_mint = fee_amount / current_share_ratio
      • Mint shares_to_mint to rebate contract
      • Update high_water_share_ratio = current_share_ratio

current_share_ratio is the ratio between total pool value and total shares.

We mint each subvaults shares proportionally according to how many shares of each subvault exist.

Rebates

The rebate contract tracks user rebates. Whenever shares are minted to it, some of the shares are transferred to users, and the rest go to the treasury.

For each user, it tracks:

  • rebate_rate (e.g., 20% rebate means user pays 80% of the fee)

When shares are minted to the rebate contract, store them. There is an endpoint ApplyRebates to call that computes:

  • For each subvault denom:
    • denom_shares_to_distribute = shares of this denom held by rebate contract
    • total_denom_shares = total supply of this denom, minus the shares held by this rebate contract (since they were just newly minted)
    • For each user with rebates:
      • user_denom_shares = shares of this denom held by user
      • user_ownership_fraction = user_denom_shares / total_denom_shares
      • user_rebate_shares = denom_shares_to_distribute x user_ownership_fraction x rebate_rate
      • Send user_rebate_shares (in this denom) to user
    • Remainder shares go to treasury
      • treasury_shares = denom_shares_to_distribute - sum(user_rebate_shares)
      • Send treasury_shares (in this denom) to treasury address
  • Reset stored shares in rebate contract to zero

ApplyRebates is called by AccrueFees automatically as the final step in the fee accrual process.

The advantage of a separate contract for the rebates is easier upgradeability and separation of concerns.