# Options Liquidity Mining (OLM)

### 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.&#x20;

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](https://dev.bondprotocol.finance/smart-contracts/option-system/options-liquidity-mining-olm/manual-strike-olm) or [Oracle Strike](https://dev.bondprotocol.finance/smart-contracts/option-system/options-liquidity-mining-olm/oracle-strike-olm).

* 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.&#x20;

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.

<figure><img src="https://content.gitbook.com/content/RLNHGppzWLIBhbHOvrRS/blobs/IC49nTjNRlbkxLLC8HES/OLM%20Inheritance.jpeg" alt=""><figcaption></figcaption></figure>

### Deployment

Setting up an OLM requires three steps.

1. Deploy an OLM contract from a [factory](https://dev.bondprotocol.finance/smart-contracts/option-system/olm-factories).
2. Fund the OLM contract with `payoutTokens` to pay rewards with (via a simple ERC20 transfer). Owners must monitor the balance of `payoutTokens` in the contract to ensure that users can claim their rewards.&#x20;
3. [Initialize](#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)

[Git Source](https://github.com/Bond-Protocol/option-contracts/blob/master/src/fixed-strike/liquidity-mining/OLM.sol)

### State Variables

#### stakedToken

Token that is staked in the OLM contract

```solidity
ERC20 public immutable stakedToken;
```

#### depositsEnabled

Whether users can deposit staking tokens into the OLM contract at the current time

```solidity
bool public depositsEnabled;
```

#### initialized

Whether the OLM contract has been initialized

*No settings can be changed or tokens deposited before the OLM contract is initialized*

```solidity
bool public initialized;
```

#### allowlist

(Optional) Address of the allowlist contract which determines which addresses are allowed to interact with the OLM contract

```solidity
IAllowlist public allowlist;
```

#### optionTeller

Option Teller contract that is used to deploy and create option tokens

```solidity
IFixedStrikeOptionTeller public immutable optionTeller;
```

#### payoutToken

Token that stakers receive call options for

```solidity
ERC20 public immutable payoutToken;
```

#### quoteToken

Token that stakers must pay to exercise the call options they receive

```solidity
ERC20 public quoteToken;
```

#### timeUntilEligible

Amount of time (in seconds) from option token deployment to when it can be exercised

```solidity
uint48 public timeUntilEligible;
```

#### eligibleDuration

Amount of time (in seconds) from when the option token is eligible to when it expires

```solidity
uint48 public eligibleDuration;
```

#### receiver

Address that will receive the quote tokens when an option is exercised.&#x20;

**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.&#x20;

```solidity
address public receiver;
```

#### epoch

Current staking epoch

```solidity
uint48 public epoch;
```

#### epochDuration

Staking epoch duration

```solidity
uint48 public epochDuration;
```

#### epochStart

Timestamp of the start of the current staking epoch

```solidity
uint48 public epochStart;
```

#### REWARD\_PERIOD

Amount of time (in seconds) that the reward rate is distributed over

```solidity
uint48 public constant REWARD_PERIOD = uint48(1 days);
```

#### lastRewardUpdate

Timestamp when the stored rewards per token was last updated

```solidity
uint48 public lastRewardUpdate;
```

#### rewardRate

Amount of option tokens rewarded per reward period

```solidity
uint256 public rewardRate;
```

#### rewardsPerTokenStored

Global reward distribution variable, used to calculate user rewards

```solidity
uint256 public rewardsPerTokenStored;
```

#### epochTransitionReward

Amount of option tokens that are rewarded for starting a new epoch

```solidity
uint256 public epochTransitionReward;
```

#### epochRewardsPerTokenStart

Rewards Per Token value at the start of each epoch

```solidity
mapping(uint48 => uint256) public epochRewardsPerTokenStart;
```

#### totalBalance

Total amount of staked tokens currently in the contract

```solidity
uint256 public totalBalance;
```

#### stakeBalance

Mapping of staker address to their staked balance

```solidity
mapping(address => uint256) public stakeBalance;
```

#### rewardsPerTokenClaimed

Mapping of staker address to the rewards per token they have claimed

```solidity
mapping(address => uint256) public rewardsPerTokenClaimed;
```

#### lastEpochClaimed

Mapping of staker address to the last epoch they claimed rewards for

```solidity
mapping(address => uint48) public lastEpochClaimed;
```

#### epochOptionTokens

Mapping of epochs to the option tokens that was rewarded for that epoch

```solidity
mapping(uint48 => FixedStrikeOptionToken) public epochOptionTokens;
```

### 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.*

```solidity
modifier updateRewards();
```

#### tryNewEpoch

Modifier that tries to start a new epoch before a function is executed and rewards the caller for doing so

```solidity
modifier tryNewEpoch();
```

#### requireInitialized

Modifier that requires the OLM contract to be initialized before a function is executed

```solidity
modifier requireInitialized();
```

### 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

```solidity
function stake(uint256 amount_, bytes calldata proof_)
    external
    nonReentrant
    requireInitialized
    updateRewards
    tryNewEpoch;
```

**Parameters**

| Name      | Type      | Description                                                |
| --------- | --------- | ---------------------------------------------------------- |
| `amount_` | `uint256` | Amount of staking tokens to deposit                        |
| `proof_`  | `bytes`   | Optional proof data for specific allowlist implementations |

#### unstake

Withdraw staking tokens from the contract

May receive reward if calling triggers new epoch

```solidity
function unstake(uint256 amount_) external nonReentrant updateRewards tryNewEpoch;
```

**Parameters**

| Name      | Type      | Description                          |
| --------- | --------- | ------------------------------------ |
| `amount_` | `uint256` | Amount of staking tokens to withdraw |

#### unstakeAll

Withdraw entire balance of staking tokens from the contract

May receive reward if calling triggers new epoch

```solidity
function unstakeAll() external nonReentrant updateRewards tryNewEpoch;
```

#### 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.

```solidity
function emergencyUnstakeAll() external nonReentrant;
```

#### claimRewards

Claim all outstanding rewards for the user across epochs

May receive reward if calling triggers new epoch

```solidity
function claimRewards() external nonReentrant updateRewards tryNewEpoch returns (uint256);
```

#### 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

```solidity
function claimNextEpochRewards() external nonReentrant updateRewards tryNewEpoch returns (uint256);
```

### View Functions

#### currentRewardsPerToken

Returns the current rewards per token value updated to the second

```solidity
function currentRewardsPerToken() public view returns (uint256);
```

#### nextStrikePrice

Returns the strike price that would be used if a new epoch started right now

```solidity
function nextStrikePrice() public view virtual returns (uint256);
```

### 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.*

```solidity
function initialize(
    ERC20 quoteToken_,
    uint48 timeUntilEligible_,
    uint48 eligibleDuration_,
    address receiver_,
    uint48 epochDuration_,
    uint256 epochTransitionReward_,
    uint256 rewardRate_,
    IAllowlist allowlist_,
    bytes calldata allowlistParams_,
    bytes calldata other_
) external onlyOwner;
```

#### Parameters

| Name                     | Type         | Description                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ------------------------ | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `quoteToken_`            | `ERC20`      | Token that stakers must pay to exercise the call options they receive                                                                                                                                                                                                                                                                                                                                                             |
| `timeUntilEligible_`     | `uint48`     | Amount of time (in seconds) from option token deployment to when it can be exercised                                                                                                                                                                                                                                                                                                                                              |
| `eligibleDuration_`      | `uint48`     | Amount of time (in seconds) from when the option token is eligible to when it expires                                                                                                                                                                                                                                                                                                                                             |
| `receiver_`              | `address`    | 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 `reclaim` function on the Option Teller contract.**                                                                                                                                                                  |
| `epochDuration_`         | `uint48`     | Staking epoch duration (in seconds)                                                                                                                                                                                                                                                                                                                                                                                               |
| `epochTransitionReward_` | `uint256`    | Amount of option tokens that are rewarded for starting a new epoch                                                                                                                                                                                                                                                                                                                                                                |
| `rewardRate_`            | `uint256`    | Amount of option tokens rewarded per reward period (1 day)                                                                                                                                                                                                                                                                                                                                                                        |
| `allowlist_`             | `IAllowlist` | 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.                                                                                                                                                                                                                                                                                |
| `allowlistParams_`       | `bytes`      | Parameters that are passed to the allowlist contract when this contract registers with it                                                                                                                                                                                                                                                                                                                                         |
| `other_`                 | `bytes`      | Additional parameters that are required by specific implementations of the OLM contract. Must be abi-encoded. See [Manual Strike OLM](https://dev.bondprotocol.finance/smart-contracts/option-system/options-liquidity-mining-olm/manual-strike-olm) or [Oracle Strike OLM](https://dev.bondprotocol.finance/smart-contracts/option-system/options-liquidity-mining-olm/oracle-strike-olm) for details on what each expects here. |

#### setDepositsEnabled

Toggle whether deposits are enabled

Only owner

```solidity
function setDepositsEnabled(bool depositsEnabled_) external onlyOwner requireInitialized;
```

**Parameters**

| Name               | Type   | Description                        |
| ------------------ | ------ | ---------------------------------- |
| `depositsEnabled_` | `bool` | Whether deposits should be enabled |

#### triggerNextEpoch

Manually start a new epoch

Only owner

```solidity
function triggerNextEpoch() external onlyOwner requireInitialized updateRewards;
```

#### withdrawPayoutTokens

Withdraw payout tokens that were deposited to the contract for rewards

Only owner

```solidity
function withdrawPayoutTokens(address to_, uint256 amount_) external onlyOwner;
```

**Parameters**

| Name      | Type      | Description                |
| --------- | --------- | -------------------------- |
| `to_`     | `address` | The address to withdraw to |
| `amount_` | `uint256` | The amount to withdraw     |

#### setRewardRate

Set the staking reward rate

Only owner

```solidity
function setRewardRate(uint256 rewardRate_) external onlyOwner requireInitialized updateRewards;
```

**Parameters**

| Name          | Type      | Description                                                |
| ------------- | --------- | ---------------------------------------------------------- |
| `rewardRate_` | `uint256` | Amount of option tokens rewarded per reward period (1 day) |

#### setEpochDuration

Set the epoch duration

Only owner

```solidity
function setEpochDuration(uint48 epochDuration_) external onlyOwner requireInitialized;
```

**Parameters**

| Name             | Type     | Description                         |
| ---------------- | -------- | ----------------------------------- |
| `epochDuration_` | `uint48` | Staking epoch duration (in seconds) |

#### setEpochTransitionReward

Set the epoch transition reward

Only owner

```solidity
function setEpochTransitionReward(uint256 amount_) external onlyOwner requireInitialized;
```

**Parameters**

| Name      | Type      | Description                                                        |
| --------- | --------- | ------------------------------------------------------------------ |
| `amount_` | `uint256` | Amount of option tokens that are rewarded for starting a new epoch |

#### setOptionReceiver

Set the option receiver

Only owner

```solidity
function setOptionReceiver(address receiver_) external onlyOwner requireInitialized;
```

**Parameters**

| Name        | Type      | Description                                                                                                                                                                                                                                                  |
| ----------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `receiver_` | `address` | 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 `reclaim` function on the Option Teller contract. |

#### setOptionDuration

Set the option duration

Only owner

```solidity
function setOptionDuration(uint48 timeUntilEligible_, uint48 eligibleDuration_) external onlyOwner requireInitialized;
```

**Parameters**

| Name                 | Type     | Description                                                                          |
| -------------------- | -------- | ------------------------------------------------------------------------------------ |
| `timeUntilEligible_` | `uint48` | Amount of time (in seconds) from option token deployment to when it can be exercised |
| `eligibleDuration_`  | `uint48` | 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

```solidity
function setQuoteToken(ERC20 quoteToken_) external virtual onlyOwner requireInitialized;
```

**Parameters**

| Name          | Type    | Description                                                           |
| ------------- | ------- | --------------------------------------------------------------------- |
| `quoteToken_` | `ERC20` | Token that stakers must pay to exercise the call options they receive |

#### setAllowlist

```solidity
function setAllowlist(IAllowlist allowlist_, bytes calldata allowlistParams_) external onlyOwner requireInitialized;
```

### Events

#### NewEpoch

```solidity
event NewEpoch(uint48 indexed epoch_, FixedStrikeOptionToken optionToken_);
```

### Errors

#### OLM\_InvalidParams

```solidity
error OLM_InvalidParams();
```

#### OLM\_InvalidAmount

```solidity
error OLM_InvalidAmount();
```

#### OLM\_InvalidEpoch

```solidity
error OLM_InvalidEpoch();
```

#### OLM\_ZeroBalance

```solidity
error OLM_ZeroBalance();
```

#### OLM\_PreviousUnclaimedEpoch

```solidity
error OLM_PreviousUnclaimedEpoch();
```

#### OLM\_AlreadyInitialized

```solidity
error OLM_AlreadyInitialized();
```

#### OLM\_NotInitialized

```solidity
error OLM_NotInitialized();
```

#### OLM\_DepositsDisabled

```solidity
error OLM_DepositsDisabled();
```

#### OLM\_NotAllowed

```solidity
error OLM_NotAllowed();
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://dev.bondprotocol.finance/smart-contracts/option-system/options-liquidity-mining-olm.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
