# 奖励分配设计拆解

### 1 Convex: Booster

是核心的控制合约，相当于管理员或操作员，在奖励分配方面他可以通过VoterProxy到Curve中铸造CRV奖励，然后将奖励传入BaseRewardPool分配给挖矿用户，供用户领取奖励。

<figure><img src="/files/JUv7pZEEMgTxS5vGzPHe" alt=""><figcaption><p>涉及奖励分配的主要合约</p></figcaption></figure>

### 2 CurveVoterProxy

* **存款**: deposit 函数允许operator将特定的Curve LP token存入对应的Curve gauge中。
* **提取**: withdraw 函数允许operator从特定的Curve gauge中取出LP token。withdrawAll 提取合约中的所有LP token和余额。
* **Curve锁仓操作:**
  * createLock 创建一个新的CRV锁仓。
  * increaseAmount 增加锁仓的CRV数量。
  * increaseTime 延长CRV锁仓时间。
  * release 从Curve escrow中提取锁定的CRV。
* **投票**:
  * vote 允许代理投票。
  * voteGaugeWeight 允许为特定的Curve gauge投票。
* **奖励索取:**
  * claimCrv 从Curve gauge索取CRV奖励。
  * claimRewards 索取其他可能的奖励。
  * claimFees 从分发合约中索取费用或奖励。

### 3 Booster

通过 earmarkRewards 方法索取CRV奖励，并进行分配。

<figure><img src="/files/KnawfL0b9fDFG3Imdy3g" alt="" width="563"><figcaption><p><a href="https://etherscan.io/tx/0x4c3924d854942bc98958ef1e058aaa2836cfcb09db5de48432c08596ac0d3b10">earmarkRewards</a></p></figcaption></figure>

### 4 BaseRewardPool

1. 当任何与奖励分配相关的函数（如notifyRewardAmount或queueNewRewards）被调用时，首先会检查block.timestamp（当前区块的时间戳）是否大于或等于periodFinish。这决定了是否开始一个新的奖励分配周期或是在现有周期内更新奖励分配。
2. 计算未分配完的奖励：如果当前时间尚未达到periodFinish，则意味着当前奖励周期还未结束，还有一些奖励尚未分配完。这部分剩余奖励可以通过计算与periodFinish之间的时间差并乘以rewardRate来得到。

**periodFinish** 在合约中有两个主要的用途：

* **rewardRate**: 这表示每秒分发给所有质押者的奖励数量。它是通过将总奖励数量除以一个固定的时间段（即duration, 在此合约中被设置为7天）来计算的。
* **rewardPerToken**: 这表示每个质押的代币应得的奖励。它是基于rewardRate和上次更新的时间来计算的，并随时间逐渐累积。
* **extraRewards**: 允许添加额外奖励，比如LDO，wstETH。
* **periodFinish**时间戳： 表示当前奖励分配周期的结束时间。每次periodFinish更新时，它通常会被设置为block.timestamp（当前时间）加上duration。这里的duration定义了一个奖励周期的长度，例如7天。这样，**periodFinish就始终表示奖励周期的结束时间。如果在新奖励被传入时当前时间已经超过了periodFinish，则启动一个新的奖励周期，rewardRate会相应地被更新。**

在合约中，**periodFinish**可能会由以下情况更新：

1. 当一个新的奖励分配周期开始时，通常在奖励被加入到合约并通知开始分配时。
2. 当更多的奖励在当前奖励周期内被加入到合约时，并且决定将其与尚未发放完的奖励一起在当前周期内发放。

每次periodFinish更新时，它通常会被设置为block.timestamp（当前时间）加上duration。这里的duration定义了一个奖励周期的长度，例如7天。这样，periodFinish就始终表示奖励周期的结束时间。

***

### 5 案例分析

我们来通过实际案例进行分析：

💡 在Convex的某一个池中，只有用户A在挖矿，当用户A进入挖矿3天后，奖励被Booster传入BaseRewardPool。

1. **用户A加入挖矿：**\
   用户A加入Pool并开始挖矿。此时，由于BaseRewardPool中还没有奖励，所以用户A的奖励为0。但是此时用户A的资金已经进入Curve产生了收益，只是没有被铸造。
2. **3天后奖励被传入BaseRewardPool：**\
   当外部有人调用了相关合约，Convex: Booster将奖励传入BaseRewardPool。这些奖励则是用户A的资金在Curve池中挖矿3天的奖励（经过了Convex的加速）

{% hint style="info" %}
所以在某种程度上，用户A的奖励被“延迟”了。
{% endhint %}

3. **调用queueNewRewards分配这些奖励。**
4. **判断当前时间是否超过periodFinish：**\
   \
   **-** 如果block.timestamp（当前时间）超过了periodFinish，则说明前一个奖励周期已结束。但因为此前合约中没有奖励，所以这一次是启动了新的奖励周期。\
   \
   \- 未超过periodFinish的情况：如果当前时间未超过periodFinish，则考虑在当前周期内尚未分配的奖励。将这部分剩余奖励与新传入的奖励相加，并重新计算rewardRate，以便在当前周期的剩余时间内将它们一起分配完。
5. **更新periodFinish：**\
   无论在哪种情况下，periodFinish都将被更新为“当前时间 + 奖励周期的时长”（通常是7天）。这样，它将代表新的奖励周期的结束时间。

{% hint style="info" %}
rewardRate = 总奖励数量 / periodFinish
{% endhint %}

6. **奖励分配：**\
   用户A从此开始将根据rewardRate获得奖励，直至新的periodFinish。每次用户A提取奖励或进行其他与奖励相关的操作时，都会根据他挖矿的时间长度计算他的奖励。

{% hint style="info" %}
用户A的奖励被“延迟”后，再次被“缓速”，将以均匀的速度发放（rewardRate）
{% endhint %}

7. 其他用户的加入：

   如果在这一周期内有其他用户加入挖矿，他们也会根据自己的挖矿权重和时间长度分享奖励。

综上，当奖励在用户A挖矿后的3天被传入BaseRewardPool时，这些奖励将在接下来的奖励周期内（通常是7天，除非合约内有其他设置）按照rewardRate被分配给用户A和可能的其他挖矿用户。

***

在第一个例子中，我们没有详细说明有其他用户加入的情况，我们进一步引入用户B。假设用户B在用户A进入挖矿的第4天加入，奖励在3天时被第一次传入，在5天时，被第二次传入。

* **第1至第3天:**

  在这3天里，只有用户A在挖矿，所以第三天被传入的奖励理论上完全是基于用户A挖矿产生的。
* **第4天:**

  用户B和加入了挖矿。
* **第5天:**

  奖励第二次被传入。
* 奖励分配: 第3天传入的奖励:

1. 这部分奖励是用户A在前三天挖矿所产生的。根据此时的总奖励计算rewardRate1。
2. 在用户B还没有加入之前，1-3天的奖励，由用户A根据rewardRate1独享。
3. 用户B在第4天加入，意味着从第4天的奖励开始，还未到第5天新奖励传入，这段时间rewardRate未更新，用户A和用户B根据各自的资金权重共享rewardRate1。

{% hint style="info" %}
我们可以看出，在第4天，用户A的奖励由于用户B的加入被稀释了，即使目前被传入的是1-3天的收益（全部属于用户A的资金挖矿产出）。即使用户A是这3天的唯一挖矿者，当奖励在第3天传入时，这些奖励并不是一次性全部分配给A的。而是根据rewardRate来分配的。
{% endhint %}

4. A在第4天之前是没有办法将前3天的所有奖励全部提走的，即使这些收益理论上全部属于他的资金挖矿产出。他只能提走这三天按照rewardRate1所应得的那部分奖励。当B在第4天加入时，他们也会开始获得按照这个rewardRate1分配的奖励，这意味着A未来几天的奖励速率将减少，因为奖励需要A和B之间按权重分配。

{% hint style="info" %}
如果在第4天传入奖励，此时用户A和B都已经加入，那么A和B将始终根据权重共享总奖励（没有独享的过程），对于A来说，在第3天传入奖励要优于第4天传入奖励。
{% endhint %}

* **奖励分配：第5天传入的奖励:**

1. 新的奖励传入，重新计算出rewardRate2。
2. 这部分奖励是基于所有用户（A和B）在第4天和第5天的挖矿活动产生的。它会根据用户A和B的资金权重在他们之间进行分配。

{% hint style="info" %}
同样的道理，第4、5天的收益理论上由用户A和B的资金挖矿产生，当后续有用户C进入时，A和B的收益会再次被稀释，用户B在上一次类似“占便宜”的现象，也会被后加入的C、D、E“占便宜”。
{% endhint %}

### 6 引申问题：Current APR、Projected APR

Current APR是由当前BaseRewardPool中的奖励计算得出的，根据rewardRate按照用户资产权重来分配，也就是当前已经传入合约中的奖励。

Projected APR是当前矿池的理论APR，也是当前Curve池内资金挖矿的实际APR，但并不是实际分配到Convex用户手中的APR，因为这些奖励未必已经被传入合约中，在这个过程中也可能逐渐被稀释。

如果当前Convex上的用户量、资金量都始终保持不变，那么Current APR将逐渐靠拢Projected APR，因为没有新用户进入来稀释奖励分配，但用户当前能够实际claim出来的奖励数量是由Current APR决定的（已经传入的奖励数量）。

如下图的例子，Current APR和Projected APR存在很大差距，其原因就是已经被传入合约中的奖励非常少，导致根据当前可领取奖励数量计算出来的Current APR非常低，而Projected APR则与Curve Pool实际的收益率非常接近。

池中的资金实际在Curve中挖矿50%的收益（Convex加速中），但未传入Convex BaseRewardPool合约。

<figure><img src="/files/TUkDNt3Qvw1DZrdyXtDI" alt="" width="375"><figcaption><p>Convex crvUSD-stUSDT Pool</p></figcaption></figure>

<figure><img src="/files/Es4YzsC8AZTFSrCjVcET" alt="" width="375"><figcaption><p>Curve crvUSD-stUSDT Pool</p></figcaption></figure>

<figure><img src="/files/4ObfSftKOnoQv48y1qdD" alt="" width="563"><figcaption><p>crvUSD-stUSDT BaseRewardPool</p></figcaption></figure>

### **7 设计分析**

1. **鼓励长期参与**：通过将奖励在一定的时间内均匀分配，系统鼓励用户长时间参与而不是只是短时间追求快速回报。这可以帮助减少所谓的"短线"玩家对奖励池的影响，使得真正长期参与的用户能够获得更为稳定的收益。
2. **“缓速”早期的冲矿者**：在这种机制设计中，早期的冲矿者奖励将会被在奖励周期（7天）内线性释放分配，同时可能被后加入的用户稀释。
3. **更公平的分配**：如果早期用户获得了绝大部分的奖励，新用户可能会觉得没有动力加入。但通过这种方式，新用户仍然可以看到他们有公平的机会获得奖励，这鼓励了新用户的参与，而不是完全由早期用户占据。
4. **鼓励交互：**&#x8FD9;个奖励分配设计是鼓励用户尽可能频繁地去调用合约来去铸造Curve上的CRV奖励，因为Convex平台本身类似一个代理挖矿的角色，Convex无法永远代替用户去领取奖励，或者替用户决定何时去领取奖励。每次奖励的传入都会重新计算rewardRate，尽早分配实时奖励，避免被更多的后来者稀释，这对当前的挖矿者有利。


---

# 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://cmdefi.gitbook.io/cmdefi/home/defi-qu-zhong-xin-hua-jin-rong/convex/jiang-li-fen-pei-she-ji-chai-jie.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.
