The staking manager (StakingManager_v1) takes issuance tokens from a staker, locks them in the market’s ReserveManager_v1, draws collateral from the market’s reserve against them at the reference price, and deposits that collateral into a strategy. The launch route creates one staking manager with every market, together with the credit facility and the elevation treasury. The staked asset is the issuance token. The strategy receives the collateral token. The staker receives strategy shares for that collateral. A withdrawal returns collateral to the reserve and releases the locked issuance tokens. Position value above the drawn amount is paid, less a performance fee, to a receiver the staker names.

Parts of a staking position

A strategy is an ERC-4626 vault that takes the market’s collateral token from the staking manager, places it with a venue, and mints shares to the staker (Strategies).

Staking

A staker calls stake with a strategy, an amount of issuance tokens and a minimum number of shares. The staking manager:
  1. pulls the issuance tokens from the staker;
  2. computes the collateral the tokens are worth at the reference price;
  3. calls openPosition on the ReserveManager_v1 for the first stake in that strategy, or lockAndDraw on the existing position for a later stake. Either call takes the issuance tokens into the ReserveManager_v1, adds the collateral to the drawn amount, and draws that collateral from the reserve to the staking manager;
  4. deposits the collateral into the strategy, which mints shares to the staker’s address;
  5. reverts if the strategy minted fewer shares than the minimum (minSharesOut_).
c=⌊q⋅Pref⌋c = \left\lfloor q \cdot P_{\text{ref}} \right\rfloor where:
  • qq is the issuance tokens staked (issuanceTokenAmount_)
  • PrefP_{\text{ref}} is the reference price, in collateral per token, 18 decimals (getReferencePrice)
  • cc is the collateral drawn and deposited, rounded down. The drawn amount increases by cc
The staking manager draws the full reference value of the tokens staked. After each call, the ReserveManager_v1 checks that the drawn amount is at or below the locked issuance tokens × the reference price, rounded down, and reverts otherwise. The first stake in a strategy places the position at that bound. A later stake draws only the value of the new tokens. When the reference price has increased since the earlier stakes, stake does not draw the added value of the issuance tokens already locked. Only rebalance draws that value (Rebalancing a position). Example. The reference price is 2.00. A staker stakes 1,000 tokens. Later the reference price increases to 2.50 and the staker stakes 200 more tokens in the same strategy. Values are rounded to two decimals; the contract works in the tokens’ smallest units and rounds cc down.

Withdrawing

A staker calls withdrawFunds with a strategy, an amount to repay, a receiver and a maximum number of shares to burn. The staking manager:
  1. reverts if the amount is above the drawn amount;
  2. computes the issuance tokens to release, in proportion to the share of the drawn amount repaid;
  3. withdraws the amount from the strategy, which burns the staker’s shares and pays the collateral to the staking manager;
  4. reverts if the strategy burned more shares than the maximum (maxSharesBurned_), or if the staking manager received less collateral than the amount;
  5. calls repay on the ReserveManager_v1. The curve takes the collateral from the staking manager back into the reserve, and the ReserveManager_v1 releases the issuance tokens to the staking manager;
  6. sends the released tokens to the receiver;
  7. harvests the position’s remaining yield to the same receiver, with the performance fee (Harvest and the performance fee). A failure in this harvest does not revert the withdrawal.
u=⌊q⋅aD⌋,a≤Du = \left\lfloor q \cdot \frac{a}{D} \right\rfloor, \qquad a \le D where:
  • aa is the amount repaid, in collateral (reserveAmount_)
  • DD is the drawn amount before the withdrawal
  • qq is the locked issuance tokens before the withdrawal
  • uu is the tokens released to the receiver, rounded down
When the position value is 1 smallest unit below aa, the staking manager withdraws the whole position value from the strategy and pulls the missing unit from the staker’s wallet. A larger gap reverts (InsufficientPosition). The position stays open in the ReserveManager_v1 when its drawn amount and locked issuance tokens reach zero. The next stake in the same strategy reuses the same position. Example. Continuing from the first stake above (1,000 tokens locked, drawn amount 2,000.00, position value 2,000.00, no yield), the staker withdraws 500.00, then the rest.

Rebalancing a position

rebalance draws the difference between the value of the caller’s locked issuance tokens at the current reference price and the drawn amount, and deposits that collateral into the strategy for the caller’s position. The function reverts if the strategy mints fewer shares than the minimum (minSharesOut_). B=⌊q⋅Pref⌋,Δ=B−DB = \left\lfloor q \cdot P_{\text{ref}} \right\rfloor, \qquad \Delta = B - D where:
  • qq is the locked issuance tokens
  • BB is the value of the locked issuance tokens at the current reference price
  • DD is the drawn amount
  • Δ\Delta is the collateral drawn and deposited. The call reverts if DD is at or above BB (NothingToRebalance)
Example. After the second stake in the staking example (1,200 tokens locked, drawn amount 2,500.00, reference price 2.50): The launch route grants no role on rebalance (Who can call what at launch).

Where the collateral comes from

The staking manager holds no pool of its own. Each draw takes collateral from the market’s reserve through the ReserveManager_v1, and each repayment returns it there. These are the same ReserveManager_v1 functions the credit facility uses. Credit and looping describes what drawReserves and restoreReserves do to the curve. The launch route grants the staking manager no permission on closePosition or mergePositions. At initialization the staking manager approves the ReserveManager_v1 for an unlimited amount of the issuance token and the curve for an unlimited amount of the collateral token.

Strategies

A strategy is an ERC-4626 vault built on StrategyBase_v1. Its asset is the market’s collateral token. Each strategy is bound at initialization to one staking manager (designatedStakingManager), and no function changes that binding.
  • deposit and withdraw run only when the caller is the designated staking manager and also passes the authorizer check for that selector.
  • withdraw burns the owner’s shares and pays the receiver the staking manager names. The strategy runs no allowance or owner check on that call.
  • transfer, transferFrom and approve revert, so shares cannot move between addresses. mint and redeem revert; collateral enters and leaves only through deposit and withdraw.
  • Share accounting uses a decimals offset of 27. Initialization reverts unless the collateral token has 6 or 18 decimals.
  • When the venue pays out less than requested on withdraw, the strategy burns shares in proportion to the amount paid, rounded up.
addStrategy approves a strategy for staking. The call reverts if the strategy:
  • is the zero address or is already approved;
  • does not report the IStrategyBase_v1 interface;
  • has an asset other than the market’s collateral token;
  • designates another staking manager;
  • belongs to another curve.
Approval does not give the staking manager permission to call the strategy’s deposit and withdraw. That permission is a separate grant on the authorizer. Without it, stake reverts at the deposit.

With no strategy

When no strategy has ever been approved, stake and rebalance revert (StrategyNotApproved). No position exists, so harvestYield, withdrawFunds and repayShortfall revert (NoPosition). The staking manager draws no collateral and holds no issuance tokens.

The strategy at launch

The launch configuration names one strategy kind (strategyKind). The strategy configuration must name the same environment as the market plan. On a production plan the route refuses testnet and aave, so a production market launches with strategy kind none: the staking manager has no approved strategy, and stake reverts until a strategy bound to the staking manager is deployed, the holder of DEFAULT_ADMIN_ROLE approves it with addStrategy, and a role holding the strategy’s deposit and withdraw is granted to the staking manager.

Emergency mode

enableEmergencyMode on a strategy withdraws what the venue will release into the strategy’s own balance and sets emergency mode. While emergency mode is set:
  • deposit reverts, so stake and rebalance revert for that strategy;
  • withdraw pays from the strategy’s own balance without calling the venue. maxWithdraw caps each withdrawal at the lesser of the owner’s share of the assets and that balance;
  • totalAssets is the strategy’s own balance plus the amount still held at the venue.
AaveStrategy_v1.migratePool runs only in emergency mode and ends it. The function withdraws from the old pool up to its withdrawable liquidity, switches to the pool the addresses provider returns now, supplies the strategy’s balance to the new pool and clears emergency mode. The call reverts if the old pool reverts, or if the aToken changes and a balance of the old aToken remains.

Harvest and the performance fee

The performance fee is a share, in basis points, of each harvest. harvestYield withdraws the position’s yield from the strategy, sends the performance fee to the market fee treasury and sends the rest to a receiver the staker names. The drawn amount and the locked issuance tokens do not change. The staking manager leaves enough shares in the position to cover the drawn amount. The function computes the shares the drawn amount needs at the strategy’s withdrawal rate, rounded up, and harvests at most the value of the shares above that number. The fee is computed on the collateral the staking manager receives from the strategy. Y=max⁡(V−D, 0),feep=⌈H⋅fp10 000⌉,paid=H−feepY = \max(V - D,\ 0), \qquad \text{fee}_p = \left\lceil H \cdot \frac{f_p}{10\,000} \right\rceil, \qquad \text{paid} = H - \text{fee}_p where:
  • VV is the position value (getPositionValue)
  • DD is the drawn amount
  • YY is the yield (getAvailableYield)
  • HH is the collateral the staking manager receives from the strategy for the harvest. HH equals YY, unless the shares above the drawn amount’s share count are worth less than YY; then HH is their value
  • fpf_p is the performance fee in basis points (getPerformanceFeeBps)
The fee is rounded up. harvestYield reverts when HH is 0 (NoYieldToHarvest). The fee goes to the market fee treasury through the same fetchFunds path as every other market fee (Fees and routing). Example. A position has 1,000 tokens locked and drawn amount 2,000.00. The position value grows to 2,120.00. The performance fee is 1,000 bps (10%). Values are rounded to two decimals; share rounding in the contract can leave HH some smallest units below YY.

Losses

When the position value falls below the drawn amount, withdrawFunds works for amounts up to the position value plus 1 smallest unit, and reverts above that (InsufficientPosition). Tokens are released in proportion to the drawn amount repaid, as in Withdrawing. repayShortfall lets the position owner repay the rest of the drawn amount from the owner’s wallet. The amount must be above 0 and at most the drawn amount minus the position value. The function reverts when the position value is at or above the drawn amount. The strategy shares are not touched. Released tokens follow the same formula as withdrawFunds and go to a receiver the owner names. The staking manager has no function that writes off drawn amount. The launch route grants no role on repayShortfall. Example. A position has 1,000 tokens locked and drawn amount 2,000.00, and the position value falls to 1,900.00. Without repayShortfall, the 50 tokens stay locked against the 100.00 drawn amount.

Strategy removal

Removing a strategy takes two calls separated by a delay. initiateStrategyRemoval records a time after which removal can run: the call time plus the removal delay of 5 days (10 minutes on chain ID 412346). removeStrategy runs only inside the execution window, from that time to 72 hours later, both ends included. cancelStrategyRemoval deletes a recorded notice. From initiation to the end of the execution window, stake and rebalance revert for that strategy (StrategyRemovalScheduled). harvestYield and withdrawFunds do not check approval or the notice, so a staker with a position can exit before and after removal. Removal sets the strategy to not approved. The function moves no collateral and burns no shares. addStrategy can approve the same strategy again. Example. The holder of DEFAULT_ADMIN_ROLE calls initiateStrategyRemoval at time TT. initiateStrategyRemoval runs while the market is frozen. cancelStrategyRemoval and removeStrategy do not.

Who can call what at launch

A permissioned function with no role granted passes its permission check only for the holder of DEFAULT_ADMIN_ROLE. rebalance and repayShortfall act on the caller’s own position. The staking setters and the strategy functions are in the authorizer’s critical set, which only named roles can hold, not PUBLIC_ROLE. Authority lists every role.

Parameters

Edge cases

  • Zero amounts. stake and withdrawFunds revert for an amount of 0. A stake whose collateral rounds down to 0 reverts at the strategy’s deposit, which rejects a zero amount.
  • Amount above the drawn amount. withdrawFunds reverts for an amount above the drawn amount (InsufficientPosition).
  • Slippage bounds. stake and rebalance revert when the strategy mints fewer shares than minSharesOut_. withdrawFunds reverts when the strategy burns more shares than maxSharesBurned_.
  • One-unit shortfall. When the position value is 1 smallest unit below the amount withdrawn, the staking manager pulls 1 smallest unit of collateral from the staker’s wallet. That transfer needs the staker’s approval; without it the withdrawal reverts.
  • Short payout. withdrawFunds reverts when the staking manager receives less collateral from the strategy than the amount (IncompleteWithdrawal).
  • Harvest inside a withdrawal. The harvest after a withdrawal runs in a separate call that the staking manager catches. A revert in the strategy, the fee treasury or the transfer to the receiver undoes the harvest and keeps the withdrawal.
  • Frozen market. stake, harvestYield, withdrawFunds, rebalance, repayShortfall, addStrategy, cancelStrategyRemoval, removeStrategy and setPerformanceFeeBps revert while the market is frozen. A strategy’s deposit and withdraw revert too. initiateStrategyRemoval, a strategy’s enableEmergencyMode, and AaveStrategy_v1.rescueFunds in emergency mode stay callable (Authority).
  • Removed strategy. Exits stay open. harvestYield and withdrawFunds check that the caller has a position in that strategy, not that the strategy is approved.
  • Endowed market. In a market with an endowment controller, every draw for stake and rebalance is subject to the endowment’s readiness and draw bound (Endowed reference segment).
  • Strategy decimals. A strategy cannot be initialized for a collateral token with other than 6 or 18 decimals.

Code

Source: house-markets/contracts at 0ebbc89a (branch integration/v12-post-qa).