From bf214b2fb3d15f0264c790105c2239fc55c1e535 Mon Sep 17 00:00:00 2001 From: Kerber0x Date: Mon, 20 May 2024 16:13:37 +0100 Subject: [PATCH] docs(incentive-manager): add readme to incentive manager --- .../liquidity_hub/incentive-manager/README.md | 84 ++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/contracts/liquidity_hub/incentive-manager/README.md b/contracts/liquidity_hub/incentive-manager/README.md index 6cada5e4c..f3b7abd2d 100644 --- a/contracts/liquidity_hub/incentive-manager/README.md +++ b/contracts/liquidity_hub/incentive-manager/README.md @@ -1,4 +1,84 @@ # Incentive Manager -The Incentive Manager is the V2 iteration of the original incentives. This is a monolithic contract that handles all -the incentives-related logic. \ No newline at end of file +The Incentive Manager is the V2 iteration of the original incentives; this is a monolithic contract that handles all +the incentives-related logic. + +## How it works + +The following is a high-level overview of how the Incentive Manager works. It touches on some technical details, assisting +developers in understanding the contract's inner workings, while also providing a general understanding of the contract's +functionality, so a regular user can understand how to interact with it. + +There are two main concepts in the Incentive Manager: an `Incentive` and a `Position`. An `Incentive` is a reward that is +distributed to users based on their `Position`. A `Position` is a user's liquidity in a pool, and it is represented by +LP tokens, which the user gets when providing liquidity into pools in the Pool Manager contract. + +When a user provides liquidity into a pool, they receive LP tokens. These LP tokens can be locked in the Incentive Manager +to get incentive rewards (if there are any). + +### Incentives + +Creating incentives is permissionless, and incentives can be perpetual. This means they can be expanded forever. Anyone +can create an incentive by calling the `ManageIncentive` message with the `IncentiveAction::Fill` action and paying the +incentive creation fee, which is sent to the Bonding Manager. + +Users can decide to provide an identifier, which they can later use to top up or close the incentive. If no identifier is +provided, the contract will generate one. + +To top up an incentive, the owner of the incentive must call `ManageIncentive` with the `IncentiveAction::Fill` action. +The user must provide the same identifier as the original incentive. The incentive can only be topped up with the same +token as the original incentive, and the amount must be a multiple of the original incentive's amount. + +To close an incentive, the owner of the incentive or the owner of the contract must call `ManageIncentive` with the +`IncentiveAction::Close` action with the identifier of the incentive to be closed. The incentive will be closed, and the +remaining tokens will be sent to the owner of the incentive. + +Incentive rewards are distributed every epoch, which is created by the Epoch Manager. Whenever an epoch is created; the +Incentive Manager gets called via the `EpochChangedHook` hook, alerting the contract of the new epoch. The contract will +then take snapshots for every LP token in the contract and save it in the `LP_WEIGHT_HISTORY` map for the current epoch. +That helps to calculate the rewards when users claim them. + +The maximum number of concurrent incentives for a given LP denom is defined when the contract is instantiated, and it is +stored in the config as `max_concurrent_incentives`. + +### Positions + +Positions can be created, expanded (topped up), or withdrawn. This is done via the `ManagePosition` +message, followed by the desired action, i.e. `PositionAction::Fill` or `PositionAction::Close`. When a user creates a +position, it must provide an unlocking duration. The unlocking duration is the time it takes in seconds to unlock the +position, which is necessary to withdraw the LP tokens from the contract. + +When a user creates a position, the LP tokens are locked in the contract. The user can't withdraw them until the unlocking +duration is complete. To expand a position, the user must call `ManagePosition` with the `PositionAction::Fill` action +using the same position identifier as the original position. In this case, since it's considered to be the same position, +any changes in the unlocking duration parameter passed along with the `PositionAction::Fill` action will be ignored. +Instead, the one in the original position will be used. + +If a user doesn't provide an identifier when creating a position, the contract will generate one. + +The minimum unlocking duration is 1 day, and the maximum is 365 days. + +Closing a position is done by calling `ManagePosition` with the `PositionAction::Close` action. The user must provide the +identifier of the position to be closed. Once this action is triggered, the `Position.open` state is set to false, and +`expiring_at` is set to the block height after which the position will be able to be withdrawn. + +Once the unlocking duration is complete, the user can withdraw the LP tokens from the contract by calling the `ManagePosition` +with the `PositionAction::Withdraw` action. Alternatively, if the user doesn't want to wait for the unlocking duration to +complete, it is possible to do an emergency withdrawal by passing `true` on the `emergency_unlock` parameter. This will +unlock and withdraw the position immediately, but the user will pay a penalty fee that will go the Bonding Manager and +distributed to the bonders. + +Once the user closes and withdraws the position, they receive their LP tokens back. + +### Claiming Incentive Rewards + +Users can claim incentive rewards from active incentives for their LP tokens, only if they have a position in the +contract. Users can only claim rewards for future epochs, i.e. after the epoch in which the position was created. + +Incentive rewards are distributed based on the user's share of the total LP tokens in the contract. So if there's a total +of 100 LP tokens in the contract, and a user has 10 LP tokens, the user will receive 10% of the rewards for that epoch, +for that given incentive. + +To claim rewards, the user must call the `Claim` message. Once that's done, the contract will save the epoch in which the +claim was made in `LAST_CLAIMED_EPOCH`, and will sync the user's LP weight history saved in `LP_WEIGHT_HISTORY`. This helps +computing the rewards for the user.