Skip to main content

Net pressure and the PID controller

Net pressure is the crvUSD debt of YieldBasis markets that the crvUSD in their Curve liquidity does not cover. When YieldBasis markets are out of balance, a proportional–integral–derivative (PID) controller sets a bonus annual percentage rate (APR). The bonus pays for crvUSD liquidity in one Curve pool, the sink pool. YieldBasis admin fees fund the bonus, and Merkl, an offchain service that distributes incentive rewards, runs it as a campaign. The controller adjusts the bonus each cycle until the imbalance clears, faster than a governance vote can. To see the live bonus, follow the YieldBasis campaign on Merkl.

What net pressure is​

Each YieldBasis market holds Curve liquidity provider (LP) tokens (for example cbBTC/crvUSD) as collateral against crvUSD debt. Net pressure is the market's debt minus the crvUSD inside those LP tokens.

The following example uses round numbers. A cbBTC market owes 100 million crvUSD, and its LP tokens contain 92 million crvUSD. A full unwind frees 92 million, so someone must buy the remaining 100 million − 92 million = 8 million on the open market. The net-pressure oracle reports that 8 million crvUSD of buy pressure.

A balanced market reads near zero. At 2× leverage, the debt is half the collateral value. A balanced Curve pool also holds half its value in crvUSD, so the debt and the crvUSD in the LP tokens are about equal. In a sharp price drop, traders sell the asset into the Curve pool for crvUSD. The LP tokens then hold less crvUSD than the debt, so net pressure rises. Sharp drops are when crvUSD liquidity depth matters most.

Why a feedback controller instead of a gauge vote​

Curve-style gauge votes steer emissions over the long term and take days to change. Net pressure can spike in minutes. A feedback controller measures the pressure and adjusts the bonus each cycle.

How the controller works​

The PID controller compares the pressure with the sink, the crvUSD liquidity in the sink pool. The gap is the pressure minus the sink. In each step, the controller does these things:

  1. It measures pressure across a set of YieldBasis markets that the YieldBasis DAO (YB DAO) selects, normalized by their size.
  2. It measures the sink: the crvUSD/pyUSD liquidity that Merkl reports.
  3. It calculates a bonus APR from the gap, with proportional, integral, and derivative terms.

An onchain contract, MerklPIDDriver, publishes the inputs and the controller math but keeps no controller state. Merkl runs the loop, stores the controller state, and distributes the rewards. The DAO sets the controller parameters within limits in the contract.

The following figure shows the feedback loop between the markets, the MerklPIDDriver, the Merkl campaign, and the sink pool:

Flowchart of the net-pressure feedback loop. An admin-fee share from the FeeSplitter funds the MerklPIDDriver, and the net-pressure oracle of the YieldBasis markets sends it pressure. The driver gives the Merkl campaign a target bonus APR, and Merkl passes sink liquidity and controller state back to the driver. The campaign incentivizes crvUSD liquidity in the sink pool on Curve. Merkl measures that liquidity, and the liquidity relieves pressure on the markets.Flowchart of the net-pressure feedback loop. An admin-fee share from the FeeSplitter funds the MerklPIDDriver, and the net-pressure oracle of the YieldBasis markets sends it pressure. The driver gives the Merkl campaign a target bonus APR, and Merkl passes sink liquidity and controller state back to the driver. The campaign incentivizes crvUSD liquidity in the sink pool on Curve. Merkl measures that liquidity, and the liquidity relieves pressure on the markets.

Pressure from the markets and the admin-fee share both feed the MerklPIDDriver, which sets a target bonus APR for the Merkl campaign. The campaign draws liquidity into the sink pool, and that liquidity relieves the pressure. Merkl measures the sink pool's crvUSD liquidity and passes it, with its saved controller state, to the driver for the next step.

Where the incentives point​

All incentives go to the crvUSD/pyUSD stableswap pool on Curve. Liquidity in that pool deepens the crvUSD side of the market, so demand for crvUSD during an imbalance can clear without a large peg move. To find the pool, call sink_pool() on the MerklPIDDriver.

How you earn from it​

Provide liquidity to the crvUSD/pyUSD pool on Curve, and follow the YieldBasis campaign on Merkl. Merkl pays the incentive to qualifying crvUSD/pyUSD LPs.

The bonus is a multiple of a market savings rate (sUSDS). It rises when pressure is high. The controller sets an offer, a multiple of that rate with a floor of 1×. The bonus is the part of the offer above 1×, so the bonus falls to zero when the offer is at its floor. The campaign pays only while pressure exists. In quiet weeks, it can pay little or nothing.

Where the incentives come from​

The net-pressure reserve is the crvUSD that the MerklPIDDriver holds to fund the campaign. The FeeSplitter sends a DAO-set share of admin fees to the net-pressure reserve and the rest to veYB holders. For the full fee flow, read Fees and veYB revenue.

To read the share, call FeeSplitter.split_fraction(). To find the receiver, call FeeSplitter.pid(). Contract addresses lists the MerklPIDDriver as that receiver.

Fees arrive as yb-LP tokens. The driver converts them to crvUSD through swaps with an oracle-based minimum output. The YB DAO can install a Merkl wrapper token on the driver with set_merkl, and a campaign then pays its rewards in that token. When an LP claims, the wrapper pulls crvUSD from the net-pressure reserve. So the reserve limits what the campaign can pay out. To check the wrapper, call reward_wrapper() on the driver.

veYB holders give up that share of the weekly fee stream. In return, they get deeper crvUSD liquidity under the markets that generate the fees.