# 双重质押智能合约

## 概览

双重质押合约使参与者通过持有 sBTC 并可选择质押 STX 来赚取提升的 sBTC 奖励。它以周期运行，通过定期快照根据持有量和质押参与情况计算奖励。

{% hint style="info" %}
有关主网的实时双重质押合约，请查看合约页面 [此处](https://explorer.hiro.so/txid/SP1HFCRKEJ8BYW4D0E3FAWHFDX8A25PPAA83HWWZ9.dual-stacking-v1?chain=mainnet).

在 2025 年 12 月 15 日，双重质押合约已升级为 [`.dual-stacking-v2_0_2`](https://explorer.hiro.so/txid/SP1HFCRKEJ8BYW4D0E3FAWHFDX8A25PPAA83HWWZ9.dual-stacking-v2_0_2?chain=mainnet)
{% endhint %}

### 去中心化架构

* 无需许可的操作：任何人都可以执行关键周期操作，包括捕获快照、提议/验证比率、计算权重和分发奖励。
* 仅链上数据：所有参与者数据（sBTC 余额、STX 质押金额）直接从区块链读取——不需要链下预言机或可信数据源。
* 竞争性比率发现：多个参与者可以提出不同的黄金比率；系统根据数学标准（第 95 百分位）进行验证，而不是管理员批准。
* 透明执行：所有操作在链上执行，具有可验证的结果和公共事件日志。
* 自助式注册：用户可以自行注册、退出并独立管理其参与。

### 主要操作

{% stepper %}
{% step %}
**初始化**

合约使用一个 Stacks 区块高度参数初始化，该高度为指定比特币区块中第一个存在的 Stacks 区块高度，或者如果没有任何 STX 区块锚定到该比特币区块，则为之后的第一个。
{% endstep %}

{% step %}
**注册**

用户可以自助注册并提供自定义奖励地址。DeFi 协议可由管理员使用自定义跟踪、质押和奖励地址进行注册。所有参与者可随时选择退出或更改其地址。
{% endstep %}

{% step %}
**快照与周期**

任何人都可以触发定期快照，根据预定义的区块间隔从链上数据捕获参与者的 sBTC 余额和 STX 质押金额。
{% endstep %}

{% step %}
**比率计算**

在快照完成后，任何人都可以提出黄金比率（最优 STX/sBTC 比率）、统计参与者分布，并验证其提议是否满足第 95 百分位标准以确定最大奖励的基准。
{% endstep %}

{% step %}
**权重计算**

任何人都可以触发使用已验证的双重质押公式的参与者权重计算，该公式为满足或超过黄金比率的人提供最多 10x 的提升（可配置）。
{% endstep %}

{% step %}
**奖励**

任何人都可以在每个周期基于计算出的权重触发奖励分配。管理员可以更新配置，如 APR、收益提升倍数、快照长度和每个周期的快照数量。
{% endstep %}

{% step %}
**管理控制**

管理员维护协议参数，以特殊地址配置注册/退出 DeFi 协议，管理白名单和黑名单，并在需要时执行紧急操作。
{% endstep %}
{% endstepper %}

***

## 周期结构

* 每个周期由固定数量的快照组成（默认 14 次）。
* 每次快照在一定数量的比特币区块后发生（默认 150 个）。
* 因此总的周期长度默认是 2100 个比特币区块（14 次快照 × 150 区块）。
* 这些默认值可针对生产环境进行调整（例如，按适当的区块数设置为每天 1 次快照）。

## 双重质押公式

权重计算：

$$
w\_i = \cfrac{\[B\_i \cdot (1 + M \cdot \sqrt{r\_i})]}{n}
$$

其中：

* *w*<sub>*i*</sub>*&#x20;= 用户 i 的权重*
* *B*<sub>*i*</sub>*&#x20;= 用户 i 的 sBTC 余额（跨所有快照的总和）*
* *M = 收益提升倍数（默认 9，意即最大提升为 10x）*
* *r*<sub>*i*</sub>*&#x20;= min(d*<sub>*i*</sub>*/D, 1)，比率调整因子*
* *d*<sub>*i*</sub>*&#x20;= S*<sub>*i*</sub>*/B*<sub>*i*</sub>*, 用户的个人 STX/sBTC 比率*
* *S*<sub>*i*</sub>*&#x20;= 用户 i 质押的 STX（跨所有快照的总和）*
* *D = 黄金比率（所有参与者的 STX/sBTC 比率的第 95 百分位）*
* *n = 每个周期的快照数量（默认 14）*

奖励分配：

$$
R\_i = (\frac{w\_i}{Σw}) \cdot Total Rewards
$$

其中：

* *R*<sub>*i*</sub>*&#x20;= 用户 i 的奖励*
* *Σw = 所有参与者权重之和*
* *总奖励 = min(池余额, 基于 APR 的上限)*

关键属性：

* *d*<sub>*i*</sub>*&#x20;≥ D 的参与者可获得最大提升 (M+1) 倍（默认 10x）。*
* *d*<sub>*i*</sub>*&#x20;= 0（未质押 STX）则获得基础奖励（1x）。*
* *提升随比率的平方根缩放，用于中间值。*
* *列入白名单的 DeFi 跟踪地址会自动获得最大提升，无需质押 STX。*
* *权重除以每周期的快照数以在整个周期时长上归一化。*

***

## 周期工作流程

双重质押智能合约以周期运行，每个周期划分为快照。该流程通过一系列任何人都可执行的无需许可的操作确保准确的奖励分配。

{% stepper %}
{% step %}
**快照阶段（任何人可执行）**

* capture-snapshot-balances：任何人在每次快照后都可以为已注册用户捕获余额。
* advance-to-next-snapshot：任何人都可以过渡到下一个快照。
* finalize-snapshots：任何人在最后一次快照后都可以结束所有快照数据。
  {% endstep %}

{% step %}
**比率验证阶段（竞争性且无需许可）**

* propose-golden-ratio：任何人都可以提出一个黄金比率。
* tally-participant-ratios：提议者统计参与者相对于其提议比率的比率分布。
* validate-ratio：提议者验证其提案——仅当其代表第 95 百分位时才会成功。
* 可提交多个提案；第一个有效提案将在该周期锁定。
  {% endstep %}

{% step %}
**权重计算阶段（任何人可执行）**

* calculate-participant-weights：任何人都可以使用双重质押公式计算参与者权重。
* finalize-weight-computation：任何人都可以完成权重计算。
  {% endstep %}

{% step %}
**奖励分配阶段（任何人可执行）**

* set-is-distribution-enabled：任何人都可以通过确定可用奖励池来启用奖励分配。
* distribute-rewards：任何人都可以根据权重向已注册用户分发奖励。
* finalize-reward-distribution：在所有参与者获得奖励后，任何人都可以完成奖励分配。
  {% endstep %}

{% step %}
**周期过渡（任何人可执行）**

* advance-to-next-cycle：在所有奖励分配完成后，任何人都可以推进到下一个周期。
  {% endstep %}
  {% endstepper %}

注意：所有操作直接从区块链读取数据（sBTC 余额来自 sBTC 代币合约，STX 质押来自原生 Stacks 协议）。不需要链下数据源或可信中介。

***

## 公共函数

### 1. 合约初始化

#### initialize-contract

使用初始周期激活合约。

* 参数：stx-block-height（无符号整数）
* 断言：
  * 当前比特币区块高度必须 >= 配置的周期开始比特币区块高度。
  * 合约必须处于未激活状态。
  * Stacks 区块高度必须包含在配置的比特币区块高度的前后区间内。
* 效果：
  * 初始化首个周期的状态变量并将合约标记为已激活。
  * 记录周期数据和第一次快照。

#### update-initialize-block

在合约激活前更新初始化的比特币区块高度。

* 参数：new-bitcoin-block-height（无符号整数）
* 断言：
  * 合约必须未激活。
  * 调用者必须是管理员。
* 效果：
  * 更新首个周期的起始比特币区块高度。

#### update-cycle-data-before-initialized

在初始化前更新首个周期的每周期快照数和每快照区块数。

* 参数：updated-snapshots-per-cycle（无符号整数）、updated-blocks-per-snapshot（无符号整数）
* 断言：
  * 合约必须未激活。
  * 调用者必须是管理员。
* 效果：
  * 为首个周期设置周期结构。

***

### 2. 注册

#### enroll

为未来周期注册调用者以获取奖励。

* 参数：rewarded-address（可选主体地址）
* 断言：
  * 调用者不得已注册。
  * 调用者不得被列入黑名单。
  * 调用者必须持有至少最低要求的 sBTC 数量。
* 效果：
  * 将调用者添加到参与者映射中，并适当设置跟踪、质押和奖励地址。
  * 增加下一个周期的参与者计数。

#### enroll-defi

为 DeFi 协议注册以获取奖励并使用自定义地址（仅限管理员）。

* 参数：
  * defi-contract（主体地址）
  * tracking-address（主体地址）
  * rewarded-address（主体地址）
  * stacking-address（可选主体地址）
* 断言：
  * 调用者必须是管理员。
  * DeFi 合约不得已注册。
  * DeFi 合约不得被列入黑名单。
* 效果：
  * 将 DeFi 协议以自定义地址添加到参与者映射中。
  * 增加下一个周期的参与者计数。

#### enroll-defi-batch

批量注册多个 DeFi 协议（仅限管理员）。

* 参数：defi-contracts（最多 900 个的列表 {...}）
* 断言：
  * 调用者必须是管理员。
* 效果：
  * 在单笔交易中注册多个 DeFi 协议。

#### opt-out

允许调用者选择退出未来周期的参与。

* 断言：
  * 调用者必须已注册。
* 效果：
  * 从参与者映射中移除调用者。
  * 减少下一个周期的参与者计数。

#### opt-out-defi

为 DeFi 协议选择退出参与（仅限管理员）。

* 参数：defi-contract（主体地址）
* 断言：
  * 调用者必须是管理员。
  * DeFi 合约必须已注册。
* 效果：
  * 从参与者映射中移除 DeFi 协议。

#### opt-out-defi-batch

批量让多个 DeFi 协议选择退出（仅限管理员）。

* 参数：defi-contracts（最多 200 个主体地址的列表）
* 断言：
  * 调用者必须是管理员。
* 效果：
  * 在单笔交易中让多个 DeFi 协议选择退出。

***

### 3. 参与者地址管理

* change-reward-address
* change-reward-address-defi
* change-stacking-address-defi
* change-tracking-address-defi
* change-addresses-defi
* change-addresses-defi-batch

（每个函数具有参数、适用时的管理员断言，并按原始规范所述更新参与者/DeFi 地址。）

***

### 4. 快照与周期

#### capture-snapshot-balances

在当前快照区块高度为一系列参与者捕获快照余额。无需许可。

* 参数：principals（最多 900 个主体地址的列表）
* 断言：
  * 合约必须处于激活状态。
  * 当前快照的 Stacks 区块高度必须可用。
* 效果：
  * 从 sBTC 代币合约读取每个参与者的 sBTC 余额。
  * 从原生 Stacks 协议读取 STX 质押金额（包括启用时的流动质押）。
  * 更新快照总额和参与者持有量。
  * 跟踪质押与跟踪地址。

#### advance-to-next-snapshot

将合约推进到当前周期中的下一个快照。无需许可。

* 参数：new-stx-block-height（无符号整数）
* 断言：
  * 合约必须处于激活状态。
  * 所有参与者必须已完成快照。
  * 当前比特币区块高度必须已达到下一个快照区块。
  * 周期不得已结束。
  * Stacks 区块高度必须包含在下一个快照比特币区块高度的前后区间内。
* 效果：
  * 增加快照索引。
  * 将快照总额汇总到周期总额。
  * 重置快照计数器。
  * 记录新的快照区块高度。

#### finalize-snapshots

在最后一次快照完成后为当前周期完成所有快照。无需许可。

* 断言：
  * 合约必须处于激活状态。
  * 快照不得已被完成。
  * 必须处于周期的最后一次快照。
  * 最后一次快照中必须为所有参与者完成快照。
* 效果：
  * 将最终快照总额汇总到周期总额。
  * 将快照标记为已完成。
  * 将最后操作状态设置为“concluded”。
  * 启用比率提议阶段。

#### advance-to-next-cycle

在所有奖励分发完成后将合约推进到下一个周期。无需许可。

* 参数：stx-block-height（无符号整数）
* 断言：
  * 合约必须处于激活状态。
  * 当前比特币区块高度必须已达到下一个周期。
  * 所有参与者必须已获得奖励。
  * 奖励分发必须已完成。
  * Stacks 区块高度必须包含在下一个周期比特币区块高度的前后区间内。
* 效果：
  * 增加周期 ID。
  * 为新周期重置状态变量。
  * 从下一个周期设置中更新周期配置。
  * 初始化新周期的第一次快照。

***

### 5. 比率计算与验证

#### propose-golden-ratio

为当前周期提出黄金比率。无需许可。

* 参数：ratio（无符号整数）——以 10^8 缩放的提议比率
* 断言：
  * 快照必须已完成。
  * 本周期不得已存在已验证的比率。
  * 调用者不得已为本周期提出过比率。
* 效果：
  * 记录调用者提出的比率。
  * 初始化参与者统计跟踪。
  * 将最后操作状态设置为“proposed-ratio”。

#### change-proposed-golden-ratio

在验证前更改先前提出的黄金比率。

* 参数：ratio（无符号整数）
* 断言：
  * 调用者必须已提出过比率。
  * 该比率不得已被验证。
* 效果：
  * 更新提议比率并重置统计数据。

#### tally-participant-ratios

统计有多少参与者的比率高于、低于或等于提议的黄金比率。

* 参数：principals（最多 900 个主体地址的列表）
* 断言：
  * 调用者必须已提出比率。
  * 该比率不得已被验证。
  * 不得已已统计所有参与者。
* 效果：
  * 计算每个参与者的 STX/sBTC 比率。
  * 跟踪高于、低于和等于提议比率的 sBTC 数量。
  * 增加已统计的参与者计数。

#### validate-ratio

验证提议的比率是否代表参与者比率的第 95 百分位。

* 断言：
  * 调用者必须已提出比率。
  * 必须已统计所有参与者。
  * 该比率不得已被验证。
  * 如果无人质押 STX，则比率必须等于 1.0（基线）。
  * 高于该比率的 sBTC 必须 ≤ 总 sBTC 的 5%。
  * 等于或高于该比率的 sBTC 必须 ≥ 总 sBTC 的 5%。
* 效果：
  * 将该比率标记为已验证。
  * 记录该周期的已验证比率。
  * 将最后操作状态设置为“ratio-validated”。

#### set-max-percentage-above-ratio

更新验证的百分比阈值（仅限管理员）。

* 参数：new-max-percentage-above-ratio（无符号整数）——默认 500 = 5%
* 断言：
  * 调用者必须是管理员。
* 效果：
  * 更新验证阈值。

***

### 6. 权重计算

#### calculate-participant-weights

使用双重质押公式计算参与者权重。无需许可。

* 参数：principals（最多 900 个主体地址的列表）
* 断言：
  * 比率必须已验证。
  * 当前周期的 Stacks 区块高度必须可用。
* 效果：
  * 检索已验证的黄金比率 D。
  * 对 D 应用最小阈值以防止除以零。 $$D = max(D, 10^-8)$$.
  * 对每个参与者，使用以下公式计算权重： $$w\_i = \cfrac{\[B\_i \cdot (1 + M \cdot √r\_i)]}{n}$$
  * 将总权重累积到 total-weights-sum。
  * 记录每个跟踪地址的单独权重（而非每个已注册地址）。

注：

* 多个共享同一跟踪地址的已注册地址将共享相同权重。
* 可以在最多 900 个参与者的批次中调用。

#### finalize-weight-computation

完成权重计算阶段。无需许可。

* 断言：
  * 比率必须已验证。
  * 权重不得已被完成。
  * 必须为所有参与者计算权重。
* 效果：
  * 将权重标记为已计算。
  * 将最后操作状态设置为“weights-finalized”。
  * 启用奖励分配阶段。

***

### 7. 奖励分配

#### set-is-distribution-enabled

通过确定可用奖励池来准备合约分发奖励。无需许可。

* 断言：
  * 合约必须处于激活状态。
  * 分配不得已被启用。
  * 权重必须已计算。
* 效果：
  * 读取合约的 sBTC 余额。
  * 计算要分发的奖励：min(池余额, 基于 APR 的上限)。
  * 上限为： $$(CPR × total-weights-sum) / (M + 1)$$
  * 将奖励标记为已准备好分配。
  * 将最后操作状态设置为“set-can-distribute”。

#### distribute-rewards

根据计算出的权重向参与者分发奖励。无需许可。

* 参数：principals（最多 900 个主体地址的列表）
* 断言：
  * 分配必须已启用。
* 效果：
  * 计算每个参与者的奖励： (权重 / 总权重) × 总奖励。
  * 将 sBTC 奖励转移到奖励地址。
  * 将参与者标记为已奖励。
  * 按奖励地址汇总奖励。

注：

* 可以在最多 900 个参与者的批次中调用。
* 多个共享同一奖励地址的已注册地址将合并奖励，并且每个跟踪地址只触发一次转账。

#### finalize-reward-distribution

将当前周期的奖励分配标记为已完成。无需许可。

* 断言：
  * 合约必须处于激活状态。
  * 所有参与者必须已获得奖励。
  * 分配必须已启用。
  * 不得已被完成。
* 效果：
  * 记录完成的区块高度。
  * 将最后操作状态设置为“finalized”。
  * 启用周期推进。
  * 触发外部 DeFi 协议分发其内部奖励（它们监听此完成事件）。

***

### 8. 管理控制

* update-admin
* update-min-sbtc-hold-required-for-enrollment
* update-snapshot-length
* update-snapshots-per-cycle
* update-cycle-data
* update-bitcoin-blocks-per-year
* update-APR
* update-yield-boost-multiplier
* set-liquid-stacking
* emergency-withdraw-sbtc

（上述每项具有参数、适用时的仅限管理员断言，以及原始规范中描述的效果。值得注意的约束包括 APR 边界和倍数边界。）

***

### 9. 黑名单管理

* add-blacklisted
* add-blacklisted-batch
* remove-blacklisted
* remove-blacklisted-batch

（仅限管理员的操作以管理黑名单；将已注册地址加入黑名单会自动将其选择退出。）

***

### 10. DeFi 白名单管理

#### whitelist-defi-tracking

将 DeFi 跟踪地址添加到白名单（自动授予最大权重提升）。

* 参数：defi-rewards-contract（主体地址）
* 断言：
  * 调用者必须是管理员。
  * 地址不得已被列入白名单。
* 效果：
  * 将跟踪地址添加到白名单。
  * 列入白名单的地址在权重计算中获得最大提升（r<sub>i</sub> = 1.0）。
  * 在快照期间，列入白名单的地址其 STX 质押记录为 0（它们无需质押 STX 即可获得最大提升）。

#### remove-whitelisted-defi-tracking

从白名单中移除 DeFi 跟踪地址（仅限管理员）。

* 参数：defi-rewards-contract（主体地址）
* 断言：
  * 调用者必须是管理员。
  * 地址必须已被列入白名单。
* 效果：
  * 从白名单中移除该跟踪地址。

#### remove-whitelisted-defi-tracking-batch

批量从白名单中移除 DeFi 跟踪地址（仅限管理员）。

* 参数：defi-rewards-contract（最多 200 个主体地址的列表）
* 断言：
  * 调用者必须是管理员。
* 效果：
  * 从白名单中移除多个跟踪地址。

***

## 私有函数

* update-snapshot-for-new-cycle：重置快照计数器并设置初始快照区块高度。
* reset-state-for-cycle：应用下一个周期配置、重置标志和总额、记录周期数据、更新参与者计数。
* capture-participant-balances：在快照高度读取 sBTC 和已质押的 STX，更新持有量并汇总总额。
* calculate-participant-weight：使用双重质押公式计算每个跟踪地址的权重（整数运算细节见原始规范）。
* tally-user-ratio：将用户的比率分类为相对于提议比率的高/低/等并累积 sBTC 总额。
* distribute-reward-user：按跟踪地址转移奖励并更新已奖励状态。
* remove-participant：删除参与者并减少计数。
* enroll-defi-one / change-addresses-defi-one：批量操作的辅助函数。
* is-blacklisted：检查是否在黑名单中。

（私有函数实现所述效果和整数缩放的考虑；有关数学/缩放行为请参照上方函数细节。）

***

## 只读函数

### 周期信息

* get-current-cycle-id
* cycle-data
* get-cycle-current-state
* current-overview-data
* get-yield-cycle-data
* nr-cycles-year
* cycle-percentage-rate

### 快照信息

* snapshot-data
* get-stacks-block-height-for-cycle-snapshot
* get-bitcoin-block-height-for-cycle-snapshot

### 奖励信息

* get-reward-distribution-status
* is-distribution-ready
* reward-amount-for-cycle-and-address
* reward-amount-for-cycle-and-reward-address
* is-distribution-finalized-for-current-cycle
* get-distribution-finalized-at-height

### 比率与权重信息

* get-ratio-data
* get-weight-computation-status
* get-participant-weight

### 参与者信息

* is-enrolled-in-next-cycle
* is-enrolled-this-cycle
* get-is-blacklisted
* get-is-blacklisted-list
* get-is-whitelisted-defi
* get-latest-reward-address
* get-participant-cycle-info

### 状态与配置

* get-last-operation-state
* get-admin
* get-is-contract-active
* get-current-bitcoin-block-height
* get-minimum-enrollment-amount
* get-next-action-bitcoin-height
* get-contract-sbtc-balance
* get-apr-data

### STX 质押查询

* get-amount-stx-stacked
* get-amount-stx-stacked-at-block-height
* get-amount-stacked-at-block-height
* get-amount-stacked-now
