Documentation

Overview

Tortino is a decentralized exchange (AMM) with dynamic fees that adjust based on how each swap affects the pool balance. Trades that improve balance pay the base fee. Trades that push the pool out of balance pay higher fees that increase quadratically with the deviation.

The system is arbitrage-driven. Each pool tracks an internal exchange rate that adapts slowly to market price through arbitrage activity. This rate determines what "balanced" means for that pool. When reserves deviate from the target ratio, fees kick in to discourage further imbalance. Arbitrageurs are naturally incentivized to restore balance because rebalancing trades pay lower fees.

This creates a self-correcting mechanism: imbalanced pools become expensive to trade against in the wrong direction, but cheap to rebalance. Liquidity providers benefit from reduced impermanent loss and fee revenue that scales with market volatility.

Key Properties

  • Immutable: No proxy, no upgrades, no DAO
  • Dynamic fees: Fees adjust based on how swaps affect pool balance
  • Adaptive pricing: Internal rate adjusts to market through arbitrage
  • LP protection: ILP vault offsets impermanent loss when available

Fee Distribution

  • 75%: Goes directly to LP reserves
  • 25%: Goes to ILP vault and TINO stakers

Pool Types

  • Stable pools: For pegged assets (stablecoins, wrapped tokens). Base fee ranges from 0.02% to 0.08% based on pool health.
  • Volatile pools: For regular token pairs. Base fee ranges from 0.2% to 0.8% based on pool health.
Tortino

Liquidity Providers

When you add liquidity, you deposit both tokens and receive LP tokens representing your share of the pool. The amount you can deposit depends on the current ratio: you can't dump a single token to unbalance the pool.

Deposit & Withdrawal Fees

Fees depend on pool balance. A pool is considered balanced when the value ratio stays between 35:65 and 65:35.

  • Balanced pool: 0% deposit, 0.5% withdrawal
  • Imbalanced pool: 0.5% deposit, 1% withdrawal

These fees protect existing LPs from arbitrage extraction. The withdrawal fee goes to the ILP vault (minted as LP tokens owned by the pool).

Earnings

LPs earn 75% of swap fees directly added to reserves, making your LP tokens worth more over time. Additionally, if the pool receives incentives from TinoSwap, those get distributed hourly to LP holders over the following week.

LP Tokens

LP tokens are standard ERC20. You can transfer them, use them in other protocols, or simply hold them. When you remove liquidity, you burn LP tokens and receive both underlying tokens proportionally to your share.

Tortino

Adaptive Prices

Pools track an internal exchange rate (base rate) that determines what "balanced" means. This rate adapts to market conditions through arbitrage. When the pool is imbalanced, it gradually adjusts its internal price to match the market.

How Updates Work

The oracle checks the pool ratio hourly. When deviation from the balanced 50:50 ratio exceeds 5%, an adjustment kicks in. The adjustment is quadratic: small imbalances cause tiny changes, large imbalances cause larger changes.

Adjustment Formula

Adjustment = k * deviation², where k = baseFee. If the pool has too much token A (ratio > 50%), the rate decreases (making A cheaper). If it has too much token B (ratio < 50%), the rate increases (making B cheaper). This incentivizes arbitrageurs to rebalance the pool.

Rate Limits

Each hourly adjustment is capped at 0.2% to prevent manipulation. Large price moves require sustained arbitrage over multiple hours, making oracle manipulation expensive and impractical.

Tortino

Fee Engine

Swap fees adjust dynamically based on how the trade affects pool balance. The goal is to reward trades that improve balance, penalize trades that worsen it.

Dynamic Fee Calculation

If the swap keeps the pool within the 5% balance threshold, or improves the current balance, the base fee applies. If the swap pushes the pool further out of balance, the fee scales quadratically: fee = k * deviation², where k = baseFee * 400.

Example: With a 0.4% base fee: a swap that keeps the pool balanced costs 0.4%. A swap that pushes deviation to 10% costs ~1.6%. A swap that pushes to 20% deviation costs ~6.4%. At extreme imbalance (45%), fees can exceed 30%.

Weekly Base Fee Adjustment

The base fee itself adjusts at the end of each weekly cycle based on average pool health:

  • Pool stayed balanced: base fee decreases by 0.05%
  • Pool was imbalanced: base fee increases by 0.2%

Stable pools range from 0.02% to 0.08% base fee. Volatile pools range from 0.2% to 0.8%. The fee engine ensures pools naturally find their equilibrium: too low means imbalance and fee increase, too high means less volume and fee decrease.

Tortino

Impermanent Loss Protection

25% of all swap fees go to the ILP vault. The vault converts these fees into LP tokens owned by the pool itself.

How it protects LPs

When the price moves (base rate changes), ILP vault gets burned proportionally. Burning vault LP tokens increases the value of remaining LP tokens, offsetting some of the impermanent loss that LPs would otherwise suffer. Protection is only available when the vault has funds.

Vault cap

If the ILP vault exceeds the total LP held by liquidity providers, the excess burning is redirected to TINO stakers hourly instead of being used for IL protection.

Overflow to stakers

The vault can only mint LP when it has both tokens in the right ratio. When fees accumulate but can't be deposited (due to ratio constraints), they get distributed to TINO stakers instead.

Tortino

Stables Imbalance Protection

SIP is an extra safety mechanism for stable pools only. It activates instantly when the pool reaches a severely imbalanced ratio.

How it works

Each hourly update checks the pool's current value ratio. If the ratio hits 95:5 or worse in either direction, the base fee immediately jumps to 0.8% (volatile pool maximum). No averaging or delay - escalation is instant on the first severe imbalance.

Why it matters

During a depeg event, arbitrageurs drain one side of the pool. SIP makes this more expensive, protecting LPs from one-sided exposure. The higher fees also mean more revenue flows to the ILP vault during the crisis.

De-escalation

Once the ratio recovers inside 90:10 in both directions, the base fee resets to 0.08% (stable pool maximum) and the pool exits escalated state. Normal weekly fee adjustments resume from there.

Tortino

Staking

You can stake TINO tokens in any pool to earn a share of that pool's fees and boost its ranking for TinoSwap incentives.

Earnings

Stakers earn from two sources: ILP overflow (fees that couldn't be deposited due to ratio constraints) and vault cap redistribution (0.01% of ILP vault burned hourly when it exceeds user-held LP). Earnings are proportional to stake relative to all TINO staked in that specific pool.

Rankings

Each token tracks its top 5 pools by TINO stake. Pools need at least 10,000 TINO staked to appear in rankings. TinoSwap distributes converted tokens as incentives to the top ranked pools for the target token each cycle.

Unstaking

There's a 0.5% penalty for unstaking. This penalty feeds the weekly TinoSwap cycle, creating a sustainable incentive loop. Of the penalty, 95% goes to TinoSwap for conversion, 5% goes to the frontend UI that processed the transaction.

Tortino

TinoSwap

Every week, the TinoSwap contract automatically converts accumulated TINO (from unstaking penalties) into target tokens and distributes them as incentives to top-ranked pools. No user interaction required.

How It Works

  1. Unstaking penalties accumulate as pending TINO in TinoSwap
  2. Once per cycle, checkAndConvert() triggers the conversion
  3. TinoSwap finds the #1 TINO pool by staking rank and swaps the accumulated TINO through it via internalConvert()
  4. The output tokens (the non-TINO side of the pool) are distributed as incentives to the top-ranked pools for that token

Target Selection

The target token is the non-TINO token from the #1 ranked TINO pool by stake. The pool must have at least 10,000 TINO in reserves to qualify. If no valid TINO pool exists, the conversion is skipped and TINO rolls over to the next cycle.

Incentive Distribution

After conversion, the output tokens are split equally among all valid top-ranked pools for the target token (up to 5 pools). Pools must be valid, have ranking enabled, and contain the target token.

Fallback

If the swap fails (e.g. pool at 99:1 ratio), TINO is sent directly as incentives to the originating pool. If incentive delivery also fails, TINO is kept for the next cycle.

Manual Deposits

Anyone can deposit TINO into TinoSwap via depositTINO(). Deposited TINO enters the pending pool and gets converted alongside penalty-sourced TINO in the next cycle.

Tortino

Incentives

The incentive system creates a flywheel: staking penalties > TinoSwap > pool incentives > more LP interest > more volume > more fees > more staking rewards.

Flow

  1. Users unstake TINO > penalty collected by TinoSwap
  2. Penalties accumulate until weekly conversion
  3. TinoSwap converts TINO to target token via pool swap
  4. Target tokens are distributed equally to top-ranked pools for that token
  5. Incentives distribute to LPs hourly over the following week

Distribution

Incentives don't dump into pools instantly. They're added to reserves gradually: each hour, a portion gets released based on time remaining in the cycle. This prevents sudden ratio changes and spreads rewards evenly.

Adding Incentives Directly

Anyone can add incentives to any pool by calling addIncentives(). Projects can use this to bootstrap liquidity or reward their community. The tokens follow the same hourly distribution schedule.

Tortino

Pool Updates

Pools need periodic updates to adjust the exchange rate, distribute incentives, recalibrate fees, and handle cycle transitions. Updates happen automatically during swaps and liquidity operations.

Update Queue

Pools with at least 10,000 TINO staked are added to the update queue. Every pool operation processes a small batch from this queue, keeping active pools updated even without direct interaction.

What Gets Updated

  • Exchange rate (price adaptation)
  • Base fee adjustments (weekly cycle)
  • Impermanent Loss Protection (ILP)
  • Stables Imbalance Protection (SIP)
  • Incentive distribution (hourly releases)

Manual Updates

Pools below 10,000 TINO staked can be updated by calling updatePool() directly on the pool. Pools in the queue require calling processBatchFromQueue(maxPools) on the UpdateQueue contract instead.

Tortino

Integration

For developers building on Tortino. All contracts are immutable, no proxies, no upgradability.

Key Contracts

  • PoolRegistry: find pools, create pools, check validity
  • TortinoPool: swap, add/remove liquidity, claim rewards (ERC20)
  • PoolInfo: read-only pool and user position queries
  • PoolPreview: simulate operations without executing
  • StakingManager: stake/unstake TINO, view rankings
  • TinoSwap: TINO conversion and incentive distribution

Finding Pools

// Get pools for a token pair
(address stablePool, address volatilePool, 
 bool stableExists, bool volatileExists) = 
  registry.getPoolPair(tokenA, tokenB);

// Check if address is a valid pool
bool valid = registry.isValidPool(pool);

// Batch fetch pool info
IPoolRegistry.PoolInfo[] memory info = 
  registry.getMultiplePoolsInfo(poolAddresses);

Reading Pool State

// Get tokens
address tokenA = pool.tokenA();
address tokenB = pool.tokenB();

// Get reserves
(uint256 reserveA, uint256 reserveB) = pool.getReserves();

// Get full pool info (via PoolInfo contract)
IPoolInfo poolInfo = IPoolInfo(POOL_INFO_ADDRESS);
(address tokenA, address tokenB, uint256 reserveA, 
 uint256 reserveB, uint256 baseRate, uint256 baseFee, 
 uint256 totalLP, uint256 vaultLP, uint256 lastUpdateHour) = 
  poolInfo.getPoolInfo(pool);

// Get user position
(address tokenA, address tokenB, uint256 lpBalance, 
 uint256 tinoStaked, uint256 pendingA, uint256 pendingB) = 
  poolInfo.getUserPosition(pool, user);

// Get pending staker fees
uint256 pending = poolInfo.getPendingTinoStakerFees(
  pool, user, feeToken);

Swapping

ITortinoPool(pool).swap(
  tokenIn,
  tokenOut,
  amountIn,
  minAmountOut,
  recipient,
  deadline
);

Adding Liquidity

ITortinoPool(pool).addLiquidity(
  maxAmountA,
  maxAmountB,
  minLiquidity,
  recipient,
  deadline
);

Removing Liquidity

ITortinoPool(pool).removeLiquidity(
  liquidity,
  minAmountA,
  minAmountB,
  recipient,
  deadline
);

Previewing

// Get preview contract from registry
IPoolPreview preview = registry.POOL_PREVIEW();

// Preview swap
(uint256 amountOut, uint256 fee) = 
  preview.previewSwap(pool, amountIn, tokenIn);

// Preview add liquidity
(uint256 lp, uint256 usedA, uint256 usedB, uint256 depositFee) = 
  preview.previewAddLiquidity(pool, maxA, maxB);

// Preview remove liquidity
(uint256 amountA, uint256 amountB, uint256 withdrawalFee) = 
  preview.previewRemoveLiquidity(pool, liquidity);

Creating Pools

// Check creation fee
uint256 fee = registry.poolCreationFee();

// Predict deployment address
address predicted = registry.predictPoolAddress(
  tokenA, tokenB, Constants.PoolType.Volatile);

// Create pool (send ETH for creation fee)
address pool = registry.createPool{value: fee}(
  tokenA, tokenB, Constants.PoolType.Volatile);

Staking TINO

IStakingManager staking = 
  ITortinoPool(pool).STAKING_MANAGER();

// Stake TINO in a pool
staking.stakeInPool(pool, amount, referrer);

// Unstake (0.5% penalty)
staking.unstakeFromPool(pool, amount, referrer);

// View functions
uint256 staked = staking.getStakeAmount(pool, user);
uint256 totalInPool = staking.getTotalStakedInPool(pool);
(address[5] memory pools, uint256[5] memory amounts) = 
  staking.getTokenTopPools(token);

// Claim staker fees (from pool's trading fees)
ITortinoPool(pool).claimTinoStakerFees();

Token Requirements

Only standard ERC20 tokens with 6-18 decimals. No fee-on-transfer, rebasing, or other non-standard implementations.

Tortino

FAQ

Are the contracts upgradeable?
No. All contracts are immutable, no proxies. Admin control is limited to toggling pool ranking on/off.
Can a pool run out of one token?
Practically no. As imbalance increases, fees rise quadratically, making further swaps in that direction extremely expensive. The 99:1 ratio is the hard limit.
Can I add liquidity with just one token?
No. You must provide both tokens in the current ratio. This is by design, single-sided deposits would allow manipulation.
Can I stake in multiple pools?
Yes. You can stake TINO in as many pools as you want.
How do I know if a pool is imbalanced?
Check the pool's value ratio via getPoolInfo(). A balanced pool has both tokens at roughly equal value (accounting for the base rate). The UI shows this visually.
Is there a time lock on liquidity?
No. You can withdraw anytime (minus the 0.5-1% fee).
What happens to fees I earn as a staker?
They accumulate in the pool contract. Call claimTinoStakerFees() to collect anytime.
What's the minimum to create a pool?
0.01 ETH creation fee. Anyone can create a pool for any valid token pair.
When does a new cycle start?
Every Thursday at 00:00 UTC. TinoSwap conversions, fee adjustments, and incentive distribution follow this schedule.
Why is there an unstaking penalty?
It funds TinoSwap and discourages short term staking just to farm rewards. The penalty creates sustainable incentives for long term participants.
Cherry

Overview

CHERRY is a stablecoin with a floating target price, not pegged to any currency. The target starts at the basket value and moves based on an autonomous monetary policy. Users deposit ETH-based collateral to borrow CHERRY.

The protocol uses a PI controller to adjust the target price: when market price is too high, the target falls (incentivizing borrowing and more supply); when too low, the target rises (incentivizing repayment and less supply). This creates a self-correcting system without governance intervention.

Key Properties

  • Immutable: No proxy, no upgrades, no DAO, no admin keys
  • Over-collateralized: 125% minimum collateral ratio
  • ETH-native: Accepts rETH, wstETH, and wstETH/rETH LP tokens as collateral
  • Tortino-integrated: Uses Tortino pools for price discovery and incentive distribution
Cherry

Safes & Collateral

A safe is a collateralized debt position. You deposit collateral and borrow CHERRY against it. Each collateral type has its own safe per user.

Opening a Safe

Deposit collateral and borrow CHERRY in one transaction. The resulting collateral ratio must be at least 125%. Minimum debt is 1,000 CHERRY. A 0.5% minting fee is paid in ETH (sent as msg.value), converted to WETH internally and stored for protocol-owned LP creation.

Adjusting a Safe

Add or remove collateral, borrow more or repay debt. Any adjustment must keep the collateral ratio above 125%. ETH minting fee is required when increasing debt.

Closing a Safe

Repay all debt to withdraw all collateral. The safe is deleted after closing.

Collateral Types

  • rETH: Rocket Pool ETH
  • wstETH: Lido wrapped stETH
  • LP: wstETH/rETH Tortino stable pool LP tokens

LST exchange rates are read directly from their contracts (rETH, wstETH) and capped at ±1% per day to prevent manipulation. ETH/USD price comes from quad-redundant oracles (Chainlink, Pyth, Redstone, TWAP). LP tokens are valued using tracked reserves and oracle prices.

Borrow Rate

Interest accrues on debt continuously. The rate depends on protocol health:

  • 0.9%: Market premium (market price ≥ 110% of basket)
  • 1.8%: Default rate
  • 2.4%: Low reserve (reserve < 0.5% of total debt)
  • 3.6%: Recovery mode (unbacked debt exists)
Cherry

Liquidations

Safes become liquidatable when their collateral ratio drops below 125%. Anyone can trigger a liquidation - no CHERRY payment needed.

Redistribution Model

When a safe is liquidated, its collateral and debt are redistributed proportionally to all active borrowers of the same collateral type. The caller receives 2% of the liquidated collateral as compensation for triggering the liquidation. The remaining 98% is spread across other borrowers.

This means every borrower's position gradually absorbs liquidated debt and collateral. Borrowers should periodically check their safe health, as redistributions increase both their collateral and debt.

Liquidation Parameters

  • Liquidation ratio: 125%
  • Caller compensation: 2% of collateral
  • Redistribution: 98% of collateral and 100% of debt spread to all active borrowers

Batch Liquidations

Multiple safes can be liquidated in a single transaction using batchLiquidate(). Liquidations are always possible regardless of vault pause state.

Cherry

Target Price

The target price is not a peg. It floats freely, adjusted by an autonomous PI controller that reacts to the gap between market price and target price. When market price deviates from the target, the controller moves the target to influence borrowing incentives, which in turn affects CHERRY supply and market price. It starts at the basket value at launch (70% + 30%*CHF/USD) and diverges from there based on market conditions.

Reference Basket

The basket is a weighted price reference used only by the weekly anchor correction (see below), not by the PI controller itself.

  • USD: 70%
  • CHF: 30%

PI Controller

The controller measures the error between market price and target price, then adjusts the target to correct it:

  • Kp = 6.7: Response to current deviation
  • Ki = 0.007: Response to accumulated deviation
  • Upper bound: +200%/year max rise
  • Lower bound: -200%/year max fall
  • Leak: 0.999/hour decay on accumulated error

Large Kp reacts quickly to current errors. Small Ki accumulates over time, correcting persistent deviations.

Basket Anchor

To prevent excessive drift from the basket, a weekly correction mechanism applies. The rate is linear: 0% at 0% drift > 1% at 10% drift from basket price, capped at 1%. This gently pulls the target back toward the basket without overriding the PI controller.

Cherry

Reserve

The reserve is an internal buffer that accumulates protocol revenue and absorbs losses during extreme market conditions. It acts as a backstop for the system's solvency.

Revenue Sources

  • Borrow interest: Interest paid by borrowers on their debt flows into the reserve
  • Minting fees: The 0.5% fee (paid in ETH, stored as WETH for protocol-owned LP)

Incentive Distribution

The reserve distributes CHERRY weekly as incentives to stakers and Tortino pools. Distribution happens whenever the reserve has funds and debt exists in the system.

The distribution rate is linear based on buffer ratio: rate = bufferRatio / 200

  • Example: 5% buffer > 0.025% weekly distribution rate
  • Floor: 0.005% minimum rate
  • Below peg: Rate is multiplied when market price is below basket (*2 at <99%, *3 at <90%) and reserve exceeds 100k CHERRY

Incentives are allocated three ways:

  • 30% Protocol LP: Collected WETH minting fees are paired with CHERRY to create LP in the WETH/CHERRY Tortino pool. Unused WETH accumulates for the next cycle. Unused CHERRY flows to pool incentives.
  • 10% Staking: Sent to the sCHERRY vault, increasing the share price for all stakers
  • 60% Top 5 pools: Distributed equally to the top 5 CHERRY pools by staked TINO

Loss Absorption

When a safe becomes undercollateralized and liquidation doesn't fully cover the debt, the reserve absorbs the shortfall. This prevents bad debt from affecting other users. The reserve is the first line of defense before the system becomes undercollateralized and activates recovery mode.

Reserve Health

A healthy reserve should grow over time from borrow interest. The protocol tracks:

  • Reserve balance: Total accumulated funds
  • Unbacked CHERRY: Debt not covered by collateral (ideally zero)

When unbacked CHERRY exists, the reserve is used to cover it. If the reserve is depleted and unbacked debt remains, the system enters recovery mode with increased borrow rate to rebuild the buffer.

Cherry

Staking

sCHERRY is an ERC-4626 vault for staking CHERRY and earning protocol rewards. Fully immutable with no admin functions.

How It Works

Deposit CHERRY to receive sCHERRY shares. The share price increases over time as rewards accrue to the vault. No claiming needed - simply redeem your sCHERRY to get back more CHERRY than you deposited.

Rewards

CherryLend sends 10% of each weekly incentive distribution to the vault, increasing totalAssets() and thus the share price for all stakers.

Standard ERC-4626

The vault implements the standard ERC-4626 interface. Use deposit() to stake, redeem() to unstake. A 0.5% withdrawal fee applies on redemption. sCHERRY shares are transferable ERC-20 tokens.

Cherry

Oracles

Quad-redundant oracle system ensures price availability:

  • Chainlink: Primary source
  • Pyth: Secondary fallback
  • Redstone: Tertiary fallback
  • TWAP: Derives ETH/USD from the WETH/CHERRY Tortino pool TWAP and CHERRY target price

If all four fail or return stale data (>4 hours old), the protocol freezes prices and blocks new borrows and liquidations until fresh data is available. LST prices combine ETH/USD with the LST's specific exchange rate. CHF uses dual oracles (Chainlink, Pyth), falling back to the last known price if both fail.

LST Rate Cap

LST exchange rates (rETH, wstETH) are capped at max(1%, 0.01 ETH) per day to prevent oracle manipulation attacks. If the current rate exceeds the cap in either direction, the capped rate is used for collateral ratio calculations. Downward moves also pause the vault (no new borrows), while upward moves are conservatively capped but the vault stays open.

Market Price Handling

If market price is unavailable (no pool liquidity), redemption rate updates are skipped gracefully without blocking other operations. Existing positions remain unchanged.

Cherry

Integration

For developers building on Cherry. All contracts are immutable, no proxies, no upgradability.

Key Contracts

  • Cherry: ERC20 token with ERC-3009 transfers and burn
  • CherryLend: Safe management, liquidations, redistribution, rate updates, and incentive distribution
  • CherryOracle: Price feeds (ETH/USD, CHF/USD), basket price, LST rate snapshots with manipulation protection
  • CherryStaking: ERC-4626 vault for staking CHERRY (sCHERRY)

Safe Operations

ICherryLend lend = ICherryLend(CHERRY_LEND_ADDRESS);

// Open a safe  - send ETH to cover the 0.5% minting fee
lend.openSafe{value: ethFee}(collateral, collateralAmount, debtAmount);

// Adjust existing safe  - ETH required only when increasing debt
lend.adjustSafe{value: ethFee}(collateral, collateralDelta, debtDelta);

// Close safe (repay all debt, withdraw all collateral)
lend.closeSafe(collateral);

// Get safe info
(uint256 collateralAmount, uint256 actualDebt, uint256 cr, 
 bool liquidatable) = lend.getSafe(user, collateral);

// Get actual debt with accrued interest
uint256 debt = lend.getActualDebt(user, collateral);

Liquidations

// Liquidate unhealthy safe (CR < 125%)
lend.liquidate(user, collateral);

// Batch liquidate multiple safes
lend.batchLiquidate(users, collaterals);

// Check pending redistribution gains/debt
(uint256 collReward, uint256 debtReward) = 
  lend.getPendingRedistribution(user, collateral);

Keeper Functions

// Refresh safe state (apply pending redistributions)
lend.refreshSafe(user, collateral);

// Batch refresh multiple safes
lend.batchRefreshSafes(collateral, users);

// Batch check which safes are liquidatable
bool[] memory liquidatable = 
  lend.batchGetLiquidatable(collateral, users);

// Batch check which safes need redistribution refresh
bool[] memory needsRefresh = 
  lend.batchGetNeedsRefresh(collateral, users);

Price Queries

// Target price (starts at basket value: 70% USD + 30% CHF)
uint256 target = lend.targetPrice();

// Current basket price (70% USD + 30% CHF)
uint256 basket = lend.getBasketPrice();

// Market price (TWAP from WETH/CHERRY Tortino pool)
uint256 market = lend.getMarketPrice();

// Borrow rate (0.9% premium, 1.8% default, 
//              2.4% low reserve, 3.6% recovery)
uint256 rate = lend.getBorrowRate();

Staking Vault

IERC4626 vault = IERC4626(lend.stakingVault());

// Stake CHERRY > receive sCHERRY shares
cherry.approve(address(vault), amount);
uint256 shares = vault.deposit(amount, receiver);

// Unstake sCHERRY > receive CHERRY
uint256 assets = vault.redeem(shares, receiver, owner);

// Check share price (increases as rewards accrue)
uint256 assetsPerShare = vault.convertToAssets(1e18);

Protocol Stats

// Get all stats at once
(uint256 totalDebt, uint256 reserve, uint256 unbacked, 
 uint256 rate) = lend.getProtocolStats();

// Individual queries
uint256 rate = lend.accumulatedRate();
int256 redemption = lend.redemptionRate();
uint256 reserve = lend.reserve();
uint256 unbacked = lend.unbackedDebt();
uint256 totalCollateral = lend.totalCollateral(collateral);
uint256 wethFees = lend.collectedWethFees();

Protocol Maintenance

// Update accumulated rate (borrow rate)
lend.updateRate();

// Update redemption rate (PI controller)
(uint256 basketPrice, uint256 marketPrice) = 
  lend.updateRedemptionRate();

// Distribute incentives from reserve to stakers and pools
lend.distributeIncentives();

Oracle Access

// Get CherryOracle contract
ICherryOracle oracle = lend.CHERRY_ORACLE();

// Check if vault is paused (LST rate outside daily cap)
bool paused = lend.isVaultPaused(collateral);

// Direct oracle queries
(uint256 rate, uint256 timestamp,
 uint256 maxRate, uint256 minRate) =
  oracle.getRateSnapshot(collateral);
bool failed = oracle.areOraclesFailed();
bool capped = oracle.isRateCapped(collateral);
uint256 lstRate = oracle.getLSTRate(collateral);
uint256 ethUsd = oracle.getEthUsdView();
uint256 chfUsd = oracle.getChfUsdView();
uint256 basket = oracle.getBasketPriceView();
Cherry

FAQ

Are the contracts upgradeable?
No. All contracts are immutable, no proxies, no admin keys.
Can I have multiple safes?
One safe per collateral type. You can have a rETH safe, a wstETH safe, and an LP safe simultaneously.
Can I repay partial debt?
Yes, use adjustSafe() to repay any amount. Just keep the remaining debt above 1,000 CHERRY and collateral ratio above 125%.
Can I use CHERRY in other protocols?
Yes. CHERRY is a standard ERC20 with ERC-3009 support. Use it anywhere that accepts ERC20 tokens.
How often does the target price change?
The PI controller adjusts the target price based on market deviation. Larger deviations cause larger adjustments. Updates happen during protocol interactions.
Is CHERRY pegged to $1?
No. CHERRY has a floating target price that starts at the basket value (70% USD + 30% CHF) and moves based on the PI controller. It's designed to be stable, not pegged.
Is there a withdrawal delay?
No time lock. You can withdraw collateral anytime as long as your collateral ratio stays above 125%. There's only a same-block restriction (can't borrow and repay in the same block).
What happens during oracle failures?
The protocol freezes prices and blocks new borrows until fresh data is available. Existing positions remain unchanged. Liquidations use the last known price.
What happens if I get liquidated?
Your collateral and debt are redistributed proportionally to all other active borrowers of the same collateral type. The caller who triggered the liquidation receives 2% of your collateral.
What if CHERRY trades below target for a long time?
The PI controller gradually raises the target price, incentivizing repayment and reducing supply. If the reserve is large enough, incentive distribution rates also increase.
What's the minimum debt?
1,000 CHERRY per safe.
What's the minting fee?
0.5% of the CHERRY debt amount, paid in ETH. The ETH is wrapped to WETH and used for protocol-owned LP creation. Excess ETH is refunded.
Who pays the borrow rate?
Borrowers. Interest accrues continuously on debt and is collected when repaying or during liquidation. Revenue goes to the reserve.