Options Liquidity Mining (OLM)
Contract that implements an epoch-based liquidity mining reward system using oTokens
Introduction
Options Liquidity Mining allows the protocol to re-capture some of the value from liquidity mining rewards when LPs realize profit. Additionally, it can cap the amount of sell pressure on a protocols token in a down market by limiting the profitability of exercising option tokens to above the strike price.
The OLM contract implements a version of this using fixed strike call options. Protocols can deploy an OLM contract with their specific configuration of staked token and option parameters. The contract implements epoch-based staking rewards to issue new option tokens at fixed time intervals and at a new strike price based on the configuration when an epoch transitions. The stakedToken
and option payoutToken
are fixed when the OLM contract is deployed. The owner of the contract can update the other staking and option token parameters over time to adjust their rewards program. The owner can also optionally designate an Allowlist contract to limit which users can can stake in the contract. The allowlist should conform to the IAllowlist
interface.
Protocols can choose between two implementations of the OLM contract: Manual Strike or Oracle Strike.
Manual Strike: Owners must manually update the strike price to change it over time.
Oracle Strike: Strike price is automatically updated based on an oracle and discount. A minimum strike price can be set on the Oracle Strike version to prevent it from going too low.
Users can deposit the configured stakedToken
into the contract to earn rewards. Rewards are continuously accrued based on the configured reward rate and the total balance of staked tokens in the contract. Any user action updates the reward calculations. Additionally, user actions can trigger a new epoch start, which will earn them additional option tokens in the form of the epoch transition reward for paying the extra gas. Users can claim their outstanding rewards from all epochs or from the next unclaimed epoch. If the option token for a specific epoch has expired, the user will not receive any rewards for that period since they are now worthless.
Deployment
Setting up an OLM requires three steps.
Deploy an OLM contract from a factory.
Fund the OLM contract with
payoutTokens
to pay rewards with (via a simple ERC20 transfer). Owners must monitor the balance ofpayoutTokens
in the contract to ensure that users can claim their rewards.Initialize the OLM contract, including inputting the remaining options and staking parameters.
Step three of this process is accomplished by calling initialize
on this contract.
OLM Contract (abstract)
State Variables
stakedToken
Token that is staked in the OLM contract
depositsEnabled
Whether users can deposit staking tokens into the OLM contract at the current time
initialized
Whether the OLM contract has been initialized
No settings can be changed or tokens deposited before the OLM contract is initialized
allowlist
(Optional) Address of the allowlist contract which determines which addresses are allowed to interact with the OLM contract
optionTeller
Option Teller contract that is used to deploy and create option tokens
payoutToken
Token that stakers receive call options for
quoteToken
Token that stakers must pay to exercise the call options they receive
timeUntilEligible
Amount of time (in seconds) from option token deployment to when it can be exercised
eligibleDuration
Amount of time (in seconds) from when the option token is eligible to when it expires
receiver
Address that will receive the quote tokens when an option is exercised.
IMPORTANT: This address is the only one that can reclaim the payoutToken collateral for expired option tokens. Make sure this address can call reclaim
on the FixedStrikeOptionTeller contract for any option token address.
epoch
Current staking epoch
epochDuration
Staking epoch duration
epochStart
Timestamp of the start of the current staking epoch
REWARD_PERIOD
Amount of time (in seconds) that the reward rate is distributed over
lastRewardUpdate
Timestamp when the stored rewards per token was last updated
rewardRate
Amount of option tokens rewarded per reward period
rewardsPerTokenStored
Global reward distribution variable, used to calculate user rewards
epochTransitionReward
Amount of option tokens that are rewarded for starting a new epoch
epochRewardsPerTokenStart
Rewards Per Token value at the start of each epoch
totalBalance
Total amount of staked tokens currently in the contract
stakeBalance
Mapping of staker address to their staked balance
rewardsPerTokenClaimed
Mapping of staker address to the rewards per token they have claimed
lastEpochClaimed
Mapping of staker address to the last epoch they claimed rewards for
epochOptionTokens
Mapping of epochs to the option tokens that was rewarded for that epoch
Modifiers
updateRewards
Modifier that updates the stored rewards per token before a function is executed
This modifier should be placed on any function where rewards are claimed or staked tokens are deposited/withdrawn.
Additionally, it should be placed on any functions that modify the reward parameters of the OLM contract.
tryNewEpoch
Modifier that tries to start a new epoch before a function is executed and rewards the caller for doing so
requireInitialized
Modifier that requires the OLM contract to be initialized before a function is executed
User Functions
stake
Deposit staking tokens into the contract to earn rewards
Only callable if deposits are enabled
Only callable if the user is allowed to stake per the allowlist
May receive reward if calling triggers new epoch
Parameters
Name | Type | Description |
---|---|---|
|
| Amount of staking tokens to deposit |
|
| Optional proof data for specific allowlist implementations |
unstake
Withdraw staking tokens from the contract
May receive reward if calling triggers new epoch
Parameters
Name | Type | Description |
---|---|---|
|
| Amount of staking tokens to withdraw |
unstakeAll
Withdraw entire balance of staking tokens from the contract
May receive reward if calling triggers new epoch
emergencyUnstakeAll
Withdraw entire balance of staking tokens without updating or claiming outstanding rewards.
Rewards will be lost if stake is withdrawn using this function. Only for emergency use.
claimRewards
Claim all outstanding rewards for the user across epochs
May receive reward if calling triggers new epoch
claimNextEpochRewards
Claim all outstanding rewards for the user for the next unclaimed epoch (and any remaining rewards from the previously claimed epoch)
May receive reward if calling triggers new epoch
View Functions
currentRewardsPerToken
Returns the current rewards per token value updated to the second
nextStrikePrice
Returns the strike price that would be used if a new epoch started right now
Owner Functions
initialize
Initializes the OLM contract
Only owner
This function can only be called once.
When the function completes, the contract is live. Users can start staking and claiming rewards.
Parameters
Name | Type | Description |
---|---|---|
|
| Token that stakers must pay to exercise the call options they receive |
|
| Amount of time (in seconds) from option token deployment to when it can be exercised |
|
| Amount of time (in seconds) from when the option token is eligible to when it expires |
|
| Address that will receive the quote tokens when an option is exercised IMPORTANT: receiver is the only address that can retrieve payout token collateral from expired options. It must be able to call the |
|
| Staking epoch duration (in seconds) |
|
| Amount of option tokens that are rewarded for starting a new epoch |
|
| Amount of option tokens rewarded per reward period (1 day) |
|
| Address of the allowlist contract that can be used to restrict who can stake in the OLM contract. If the zero address, then no allow list is used. |
|
| Parameters that are passed to the allowlist contract when this contract registers with it |
|
| Additional parameters that are required by specific implementations of the OLM contract. Must be abi-encoded. See Manual Strike OLM or Oracle Strike OLM for details on what each expects here. |
setDepositsEnabled
Toggle whether deposits are enabled
Only owner
Parameters
Name | Type | Description |
---|---|---|
|
| Whether deposits should be enabled |
triggerNextEpoch
Manually start a new epoch
Only owner
withdrawPayoutTokens
Withdraw payout tokens that were deposited to the contract for rewards
Only owner
Parameters
Name | Type | Description |
---|---|---|
|
| The address to withdraw to |
|
| The amount to withdraw |
setRewardRate
Set the staking reward rate
Only owner
Parameters
Name | Type | Description |
---|---|---|
|
| Amount of option tokens rewarded per reward period (1 day) |
setEpochDuration
Set the epoch duration
Only owner
Parameters
Name | Type | Description |
---|---|---|
|
| Staking epoch duration (in seconds) |
setEpochTransitionReward
Set the epoch transition reward
Only owner
Parameters
Name | Type | Description |
---|---|---|
|
| Amount of option tokens that are rewarded for starting a new epoch |
setOptionReceiver
Set the option receiver
Only owner
Parameters
Name | Type | Description |
---|---|---|
|
| Address that will receive the quote tokens when an option is exercised IMPORTANT: receiver is the only address that can retrieve payout token collateral from expired options. It must be able to call the |
setOptionDuration
Set the option duration
Only owner
Parameters
Name | Type | Description |
---|---|---|
|
| Amount of time (in seconds) from option token deployment to when it can be exercised |
|
| Amount of time (in seconds) from when the option token is eligible to when it expire |
setQuoteToken
Set the quote token that is used for the option tokens
Only owner
Parameters
Name | Type | Description |
---|---|---|
|
| Token that stakers must pay to exercise the call options they receive |