Skip to content

Commit

Permalink
docs: update abci spec (#52)
Browse files Browse the repository at this point in the history
* add abci spec

* docs: updating abci spec

* fix typo

* update contents and figure

* remove begin block and block mds

* updated related contents
* re-order docs

* update diagram

more detail description for covering penalty

---------

Co-authored-by: poorphd <bc.park@bharvest.io>
  • Loading branch information
zsystm and poorphd authored Sep 6, 2023
1 parent 42cd98f commit c117fe0
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 191 deletions.
2 changes: 1 addition & 1 deletion x/liquidstaking/spec/01_concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ The `liquidstaking` module fee is calculated as follows: `fee = (delegation rewa
* if optimal < u <= hardCap then, **fee rate =** `r0 + slope1 + ((u - optimal) / (hardcap - optimal) x slope2)`
* if hardCap < u, then, **fee rate =** `r0 + slope1 +slope2`

An explanation of the parameters used in the above formula can be found in [09_params.md](09_params.md).
An explanation of the parameters used in the above formula can be found in [09_params.md](08_params.md).

The `liquidstaking` module fee is calculated at the beginning of every epoch and is applied to the delegation rewards of all chunks.
The calculated fee is burned and the rest of the delegation reward goes to the reward pool.
Expand Down
8 changes: 4 additions & 4 deletions x/liquidstaking/spec/02_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The fee rate is determined by the sum of the insurance fee rate set by the insur
the commission fee rate set by the validator designated by the insurance provider.
2. `Unpairing`: A paired chunk enters an `Unpairing` status when paired insurance begins to be withdrawn, its balance becomes less than 5.75% of a chunk's size, or the validator becomes invalid (e.g., tombstoned). The 5.75% represents the minimum amount of tokens required to cover both downtime slashing and double signing slashing penalties once.
* The calculation of 5.75% involves the sum of the `SlashFractionDoubleSign` and `SlashFractionDowntime` parameters. Modifying these parameters while the `liquidstaking` module is operational can introduce unforeseen risks. To mitigate this, changes to the slashing parameters are restricted via antehandlers.
For more information, please refer to the details provided in the **[Param Change Ante Handlers](10_ante_handlers.md#param-change-ante-handlers)**.
For more information, please refer to the details provided in the **[Param Change Ante Handlers](09_ante_handlers.md#param-change-ante-handlers)**.
3. `UnpairingForUnstaking`: When a delegator (also referred to as a liquid staker) submits a MsgLiquidUnstake, the request is enqueued as UnpairingForUnstakingChunkInfo.
At the conclusion of the epoch, the actual undelegation process is initiated, causing the chunk to transition into this state. Following the completion of the unbonding period in the subsequent epoch, tokens equivalent to the chunk's size are restored to the delegator's account, and the related chunk object is subsequently deleted.
Once the unbonding period is over in next epoch, the tokens corresponding chunk size are returned to the delegator's account and the associated chunk object is removed.
Expand Down Expand Up @@ -65,7 +65,7 @@ In the following epoch, the insurance will either remain paired or undergo unpai
## UnpairingForUnstakingChunkInfo

This object is created when msgServer receives `MsgLiquidUnstake` for a paired chunk.
The actual unbonding process is started on an upcoming epoch (**[Handle Queued Liquid Unstakes](06_end_block.md#handle-queued-liquid-unstakes)**).
The actual unbonding process is started on an upcoming epoch (check **HandleQueuedLiquidUnstakes** at EndBlocker).

The unstaking request does not take place immediately; it is initiated within the upcoming epoch and the actual unstaking occurs after the unbonding period has elapsed. During the unbonding period, changes in the chunk size may occur (if the insurance is unable to cover all penalties, the chunk size may decrease). In such cases, a portion of the escrowed lsTokens must be refunded. Therefore, the associated object serves to track the quantity of escrowed lsTokens when an unstaking request is made.

Expand All @@ -77,7 +77,7 @@ type UnpairingForUnstakingChunkInfo struct {
EscrowedLsTokens sdk.Coin
}
```
It is removed when the chunk unbonding is finished (**[Cover slashing and handle mature unbondings](06_end_block.md#cover-slashing-and-handle-mature-unbondings)**).
It is removed when the chunk unbonding is finished (check **CoverSlashingAndHandleMatureUnbondings** at EndBlocker).


## WithdrawInsuranceRequest
Expand All @@ -94,7 +94,7 @@ type WithdrawInsuranceRequest struct {

It is created when re-delegation for chunk happens between insurances pointing to different validators at epoch.
This situation happens when there's a more appealing validator and insurance pair on an epoch. The chunk keeps its paired status while being redelegated to a new validator.
When the chunk is undergoing redelegation, a separate logic (**[Cover redelegation penalty](05_begin_block.md#Cover-Redelegation-Penalty)**) is followed to ensure that the insurance covers any penalties. Therefore, the object is used to track whether the chunk is being redelegated or not.
When the chunk is undergoing redelegation, a separate logic (check **CoverRedelegationPenalty** at BeginBlocker) is followed to ensure that the insurance covers any penalties. Therefore, the object is used to track whether the chunk is being redelegated or not.



Expand Down
100 changes: 100 additions & 0 deletions x/liquidstaking/spec/05_abci.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<!-- order: 5 -->

# ABCI

This document describes the prerequisites needed to understand the BeginBlocker and EndBlocker logic of the liquidstaking module.

## Insurance Ranking

Each insurance-validator pair is ranked at epoch. The ranking is calculated based on the sum of the validator's commission rate and the insurance's fee rate.

![make-up-penalty](./ranking.png)

The above figure is a diagram illustrating the insurance-validator pairs' ranking calcualtion and re-pairing of chunks process in the liquid staking module.
Five insurances have been allocated to the available chunk slot (`max chunk slot = 5`), each with the following insurance fees and the ranking (Ranking is determined in ascending order of insurance fees and validator commission rates).
In case of the same ranking, the ranking is assigned in a "first come, first served" manner (e.g., insurance 2 and 4).

| id | fee rate | validator commission rate | total | ranking |
|------|----------|---------------------------|-------|---------|
| 1 | 2% | 7% | 9% | 3 |
| 2 | 3% | 7% | 10% | 4 |
| 3 | 3% | 5% | 8% | 2 |
| 4 | 4% | 6% | 10% | 5 |
| 5 | 5% | 2% | 7% | 1 |


When a chunk is liquid staked, pairing is done sequentially starting from the insurance with the highest ranking. Therefore, in the above diagram, the 3 chunks that are staked will be paired with insurance 5, 3, 1, 2 and 4 in that order.

Before reaching the next epoch, a new insurance, Insurance 6, has been added, which refers to Validator 4. The total fee for this insurance-validator pair is 5%, making it more attractive in terms of fees compared to the existing insurance-validator pairs.
Therefore, in the next epoch, this insurance-validator pair will occupy the top position in the ranking, and since the max chunk slot is 5, the insurance with the lowest ranking, Insurance 4, will be pushed out of the slot.
In other words, the chunks paired with Insurance 4 (rank-out) are re-paired with Insurance 6 (rank-in).

## Re-pairing
The re-pairing process depends on whether the rank-in insurance points to the same validator as the rank-out insurance or not.

**Case 1**: Rank-in insurance points to the same validator as the rank-out insurance

![re-pairing-same-validator](./re-pairing-same-validator.png)

In this case, where both the rank-in and rank-out insurances indicate the same validator, the re-pairing process is relatively straightforward. Since the validator remains the same, there is no need to modify the chunk's delegation. The only change required is to update the insurance reference for the chunk, ensuring that it correctly reflects the rank-in insurance. This process ensures that the chunk's delegation continues to be properly insured by the same validator, and it can be accomplished by updating the insurance reference without additional delegation changes.

**Case 2**: Rank-in insurance points to a different validator than the rank-out insurance

![re-pairing-different-validator](./re-pairing-different-validator.png)

In this case, a more complex re-pairing process is necessary as the chunk's delegation needs to be realigned with the change in the insured validator. This entails re-delegating the chunk's stake from the validator specified by the rank-out insurance to the new validator indicated by the rank-in insurance. This adjustment ensures that the chunk's stake is appropriately insured by the rank-in insurance and maintains the security and integrity of the liquid staking module.
Since the re-delegation period is the same as the epoch duration, the re-delegation process will be completed during the next epoch. This ensures a smooth transition with the chunk's delegation effectively moved to the new validator specified by the rank-in insurance at the beginning of the next epoch.

## Slashing Penalty Covering

### Basics

When a validator is slashed, the chunk's delegation may be lost due to downtime or double signing. This is the reason insurance exists. Insurance is designed to cover such losses.

![make-up-penalty](./make-up-penalty.png)

The figure above illustrates a scenario where a chunk's delegation is lost due to a validator's double signing.
When insurance covers the loss, there are two cases depending on the size of the loss.

**Case 1:** When insurance can cover the loss completely (penalty <= insurance balance, colored in orange)

In this scenario, insurance sends the full penalty amount of coins to the chunk, and the chunk subsequently delegates those coins to the validator.
The chunk's delegation is restored to its original size, and the chunk's delegation shares are updated accordingly.

**Case 2:** When insurance cannot cover the loss completely (penalty > insurance balance, colored in red)

In this situation, the chunk's value is less than the required chunk size even if insurance covers the loss with all of its balance. In this case, insurance sends all of its balance to the reward pool, and the chunk's delegation is un-delegated. The un-delegated tokens from the chunk are sent to the reward pool at the next epoch.

Arbitragers will purchase those tokens from the reward pool using lsCanto. Rather than leaving the chunk as unusable, making it usable with lsCanto adds more value to it.

### Advanced

A chunk can indeed have both paired insurance and unpairing insurance simultaneously.
This situation arises during re-pairing when an insurance with a high fee rate, initially paired with the chunk for a limited chunk slot, is replaced with a lower fee rate insurance.

If the cause of the loss occurred before the epoch, then the responsibility for covering the loss lies with the unpairing insurance.
However, if the cause of the loss occurred after the epoch, then the paired insurance takes responsibility for covering the loss.
This division of responsibility ensures that the appropriate insurance is used depending on when the loss occurred in relation to the epoch.

In this section, we will describe a scenario in which the unpairing insurance is required to cover the loss.

![make-up-penalty](./make-up-penalty-redelegation.png)

The above diagram illustrates the re-pairing (re-delegation) process and penalty cover in chronological order.

0. Initially, The blue insurance initially covered the chunk. As the blue insurance is associated with validator A, the current delegation of the chunk is directed to validator A.
1. An orange insurance with a lower fee rate (3%) than the blue insurance (5%) was offered. However, as all chunk slots are already occupied, and the epoch transition has not occurred yet, the orange insurance remains in a pairing state without being applied.
2. Validator A double signs, but as of now, no evidence has been submitted, and therefore, no penalty has been imposed.
3. The epoch has been reached, and the orange insurance is paired with the chunk, while the original blue insurance transitions into an unpairing insurance.
4. Evidence of a double sign by Validator A is submitted and accepted. During this process, the delegation shares of the chunk that were originally with Validator B become affected, resulting in the chunk's delegation shares differing from the `sharesDst` in the `ReDelegation` object. This indicates a decrease in the delegation shares due to the penalty imposed on Validator A.
5. In the upcoming epoch, the unpairing insurance will be responsible for covering the loss incurred due to the penalty imposed on Validator A.

The cause of the slashing occurred **before the epoch (re-pairing)**, so the unpairing insurance (blue one) is responsible for covering the loss because that loss is not related to the paired insurance (orange one). This rule applies even in cases where the paired insurance and the unpairing insurance point to the same validator.

### The distinction between BeginBlock and EndBlock

Re-delegation can occur when there was re-pairing in the previous epoch, and insurances have changed, pointing to different validators. To accurately track responsibility for losses during the re-delegation period, we require the `Redelegation` object to be stored in the `staking` module.

However, the `Redelegation` object is deleted at the `BeginBlock` of the `staking` module when the re-delegation period is over. Additionally, the `staking` module's `BeginBlock` is executed before the `liquidstaking` module's `BeginBlock`.

Therefore, if we rely solely on the `EndBlock`, we cannot precisely track responsibility because the `Redelegation` object has been deleted.
15 changes: 0 additions & 15 deletions x/liquidstaking/spec/05_begin_block.md

This file was deleted.

Loading

0 comments on commit c117fe0

Please sign in to comment.