Protocol yield generation
Overview
This document describes how the protocol generates yield from user deposits, how that yield is handled based on strategy type, and under what conditions it is sent to the L1SenderV2
contract for cross-chain reward minting.
Yield generation overview
When users stake tokens into deposit pools, those tokens may be used in different yield strategies, depending on the pool configuration. The protocol currently supports the following strategies:
AAVE
- token is deposited into Aave to generate yield.NO_YIELD
- token is not used in any external protocol. This is typically used forstETH
.NONE
- no yield logic is applied (only for private buckets without real stake).
Strategy-Specific Deposit Behavior
When a user calls supply()
For AAVE Strategy:
The user transfers the underlying
token
to theDistributor
.The
Distributor
supplies the token to the Aave protocol viaAaveIPool.supply()
.Yield is later measured by checking the
aToken
balance of theDistributor
.
For NO_YIELD Strategy (e.g., stETH
):
stETH
):The user transfers
stETH
to theDistributor
.It is not deposited anywhere; yield is not actively generated.
Instead, the
stETH
is held and passively earns staking rewards (as per Lido).
Reward Distribution Timing and Constraints
Rewards are distributed using distributeRewards()
which performs the following:
Fetch emitted MOR - calls
RewardPool.getPeriodRewards()
using the last distribution timestamp.Check if distribution is due: public pools must respect
minRewardsDistributePeriod
(e.g., once per day).This is enforced because
stETH
yield is not readable on-chain per second or block. It's accrued slowly, and daily intervals allow consistent accounting.
Update Prices:
For each deposit pool in the reward pool, the price of the deposit token is fetched from Chainlink (via
ChainLinkDataConsumer
).This allows yield across tokens (USDC, WETH, etc.) to be normalized to a dollar value.
Calculate Yield Per Pool. See MOR distribution. Step #1
Calculate Pool Shares. See MOR distribution. Step #1
Update State. See MOR distribution. Step #1
Transferring Yield to L1SenderV2
The protocol does not retain accrued yield within the Distributor
contract. Instead, yield is extracted and forwarded to L1SenderV2
selectively — only for the specific DepositPool
that triggers the operation.
At the end of a yield cycle (e.g., daily), when any function (e.g., supply
, withdraw
, or withdrawYield
) is called on a given deposit pool, the Distributor
contract:
Calls
distributeRewards
to calculate and assign MOR rewards based on relative yield of all deposit pools in the same reward pool.Then calls
_withdrawYield
only for theDepositPool
involved in the transaction, transferring its actual yield toL1SenderV2
.
Yield is transferred using the following logic:
For
AAVE
:Calls
AaveIPool.withdraw()
to redeemaTokens
.Transfers the withdrawn tokens to
L1SenderV2
.
For
NO_YIELD
:Transfers the excess tokens directly (if any) to
l1SeL1SenderV2nder
.
Once the tokens are with L1SenderV2
, they can be:
Bridged to Arbitrum.
Used for minting MOR rewards for users via
sendMintMessage()
.
Notes
stETH
pools useNO_YIELD
because stETH natively accrues rewards via rebasing.The yield on
stETH
cannot be measured at each block — hence daily distribution is preferred.Price-based yield normalization ensures fair distribution even when token values vary.
Last updated
Was this helpful?