摘要
Acala 流动性质押允许您将 DOT 存入 Acala 的质押模块并获得 LDOT,这是一种可转让的衍生代币,在您将其用于 DeFi 其他场景时仍能持续赚取质押奖励。本文解释了该流程如何运作、LDOT 代表什么,以及读取质押状态或构建流动性质押集成所需的 RPC 和 API 接口。文章还涵盖了开发者首先遇到的运营问题:使用哪些端点、如何查询汇率和解除绑定状态,以及何时共享公共端点足够,何时更适合使用专用节点。
Acala 流动性质押是 Acala 网络的一部分,允许您质押 DOT 而无需将资金锁定在单一的非流动性头寸中。您存入 DOT,协议通过其质押模块进行质押,然后您收到 LDOT——一种代表您质押头寸且保持可转让的衍生代币。LDOT 可以被持有、转移或用于其他 Acala DeFi 原语,同时底层 DOT 持续累积质押奖励。
如果您是开发者或基础设施买家,有趣的部分不仅仅是代币机制。而是数据接口:如何读取质押状态、如何跟踪 LDOT 汇率、如何检测解除绑定窗口,以及将后端指向哪个 RPC 端点。本文将从两方面进行探讨——质押模型和您实际会编写的 API 调用。
快速建议:共享端点还是专用节点?
在编写任何集成代码之前,请确定您正在运行的工作负载类型。Acala 流动性质押以两种截然不同的方式与链交互,它们具有不同的基础设施需求。
| 工作负载 | 典型调用模式 | 起步建议 |
|---|---|---|
| 读取余额和汇率的钱包或仪表板 | 低频、周期性读取 | 来自托管提供商的共享 RPC 端点 |
| 监视解除绑定队列和奖励累积的质押机器人 | 频繁轮询,有时使用订阅 | 专用节点或具有可预测吞吐量的提供商计划 |
| 回填历史质押事件的索引器 | 大区块范围、归档式读取 | 支持归档的基础设施,而非公共端点 |
| 代表用户提交质押外部交易的 dApp | 写入路径加确认跟踪 | 可在其间故障转移并提供监控的提供商 |
共享端点通常适用于只读仪表板和原型。当您以紧凑的间隔轮询质押状态、回填历史或提交用户依赖的外部交易时,共享路径就会成为瓶颈。此时,专用节点或具有明确吞吐量预期的托管 RPC 计划是更安全的选择。OnFinality 为 Acala 提供 RPC API 访问 和 专用节点基础设施,因此您可以从共享开始,然后迁移到专用,而无需更改应用程序代码。
Acala 流动性质押流程实际如何运作
在接触 API 之前,您应该了解该流程的四个组成部分。
- 存入。 您将 DOT 发送到质押模块。协议将该 DOT 绑定到其验证者集合。
- 铸造。 作为回报,您按当前汇率收到 LDOT。LDOT 不是固定的 1:1 索取权——它代表池化质押头寸的一部分。
- 累积。 随着底层 DOT 赚取质押奖励,每个 LDOT 背后的价值增长。LDOT 和 DOT 之间的汇率随时间向上漂移。
- 赎回。 当您想要回 DOT 时,您赎回 LDOT。根据模块的状态,赎回可能是即时的,也可能进入一个在解除绑定期内结算的解除绑定队列。
对开发者的关键启示:LDOT 不是静态余额。如果您的 UI 显示“1 LDOT = 1 DOT”,那么您显示的数字是错误的。您需要从链状态读取当前汇率,并在每次显示时重新计算用户的底层 DOT 价值。
通过 RPC 读取质押状态
Acala 是基于 Substrate 的链,因此您通过 Polkadot.js 风格的 JSON-RPC 接口以及运行时的存储和外部交易元数据与之交互。确切的存储键和外部交易名称来自运行时,因此始终从链的元数据中解析它们,而不是从博客文章(包括本文)中硬编码。下面的模式展示了调用的形式。
首先,确认您正在与正确的链通信,并且您的端点有响应:
curl -s https://acala.api.onfinality.io/public \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "system_chain",
"params": []
}'
健康的响应会返回链名称。如果您遇到超时或空响应体,这是您的第一个调试信号——检查端点,而不是您的质押逻辑。
接下来,读取运行时版本和元数据,以便您的客户端知道存在哪些存储项和外部交易:
curl -s https://acala.api.onfinality.io/public \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "state_getRuntimeVersion",
"params": []
}'
然后,Polkadot.js 客户端可以直接查询质押模块的存储。在 JavaScript 中,模式如下所示:
import { ApiPromise, WsProvider } from '@polkadot/api';
const provider = new WsProvider('wss://acala.api.onfinality.io/public-ws');
const api = await ApiPromise.create({ provider });
// Resolve the staking module and its storage from live metadata
const staking = api.query.homa || api.query.homaLite;
// Example: read total staked and the current exchange rate
const totalStaked = await staking.totalStakingBonded();
const exchangeRate = await staking.liquidTokenExchangeRate();
console.log('Total staked:', totalStaked.toString());
console.log('LDOT exchange rate:', exchangeRate.toString());
模块名称和存储项名称取决于运行时版本。如果 api.query.homa 未定义,请在运行时检查 api.query 键,并确认您连接的链上实际部署的模块。这是“我的质押调用返回空”错误的最常见来源。
查询 LDOT 汇率和解除绑定状态
对于任何流动性质押集成,两个数字最重要:汇率和解除绑定状态。
汇率。 这是将 LDOT 余额转换为其底层 DOT 价值的关键。从链状态读取它,短暂缓存,并按照与其实际变化频率相匹配的计划刷新。每个区块轮询通常是浪费的;每个 epoch 轮询一次对于实时仪表板通常太慢。选择一个节奏并记录下来。
解除绑定状态。 当用户赎回时,DOT 可能不会立即可用。您的 UI 应区分“现在可赎回”和“在解除绑定队列中,将在 N 个 era 内结算”。这意味着从运行时读取队列长度和解除绑定周期,而不是猜测。
| 您想显示的内容 | 来源 | 刷新频率 |
|---|---|---|
| 用户的 LDOT 余额 | 流动代币的账户存储 | 按需 / 每区块 |
| 底层 DOT 价值 | LDOT 余额 × 当前汇率 | 每几分钟 |
| 待处理的赎回 | 解除绑定队列存储 | 每几分钟 |
| 结算时间 | 运行时常量中的解除绑定周期 | 运行时升级时 |
| 奖励累积趋势 | 汇率历史 | 每小时或每天 |
如果您需要历史汇率来制作图表,那么您现在处于归档领域。公共端点不是回填数月状态数据的正确工具;请规划支持归档的基础设施。
Acala 链设置一览
在您的钱包配置、后端和监控中保持这些设置一致。
| 设置 | 值 |
|---|---|
| 网络 | Acala(Polkadot 平行链) |
| 代币 | ACA(原生)、DOT(质押资产)、LDOT(流动衍生品) |
| 接口 | Substrate JSON-RPC 和 WebSocket |
| 公共 HTTP 端点 | https://acala.api.onfinality.io/public |
| 公共 WebSocket 端点 | wss://acala.api.onfinality.io/public-ws |
| 传输支持 | HTTP 和 WebSocket |
您可以在 Acala 网络页面 上找到当前端点列表和网络详情。如果您通过 EVM 兼容路径进行集成,请注意 Acala 的 EVM 层与 Substrate 质押模块是分开的——流动性质押状态存在于 Substrate 侧,因此不要期望 ERC-20 风格的调用返回它。
常见故障模式及如何调试
流动性质押集成以少数可预测的方式失败。以下是简短的诊断列表。
- 存储项返回 null。 您的客户端所在的运行时中模块或项名称已更改,或者您连接到了不同的链。首先检查
system_chain和state_getRuntimeVersion。 - 汇率看起来冻结。 您正在读取缓存值,或者您的轮询间隔长于汇率的更新频率。将原始值和区块号一起记录。
- 外部交易提交但从未最终确定。 您正在跟踪包含,而不是最终确定。在标记质押操作完成之前,订阅最终确定的头部,而不仅仅是新头部。
- WebSocket 在负载下断开连接。 长期订阅需要带有退避的重连逻辑。将断开的套接字视为正常,而非异常。
- 高峰时读取变慢。 共享端点吸收来自许多调用者的流量。如果您的延迟不可预测,这是迁移到专用节点的信号,而不是更努力地重试。
一个最小的监控探针可以让您提前发现大多数这些问题:
#!/usr/bin/env bash
# Probe Acala RPC health and record the block height
RESP=$(curl -s --max-time 5 https://acala.api.onfinality.io/public \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"chain_getHeader","params":[]}')
echo "$(date -u +%FT%TZ) $RESP" >> acala-rpc-health.log
按计划运行此脚本,当高度停止推进时发出警报,您将在用户之前发现端点问题。
质押后端的构建与购买
如果您正在运行流动性质押仪表板、奖励跟踪器或根据解除绑定窗口采取行动的机器人,您需要在基础设施上做出构建与购买的决策。
运行自己的 Acala 节点为您提供完全控制且没有共享吞吐量上限,但这意味着自行配置、同步、在运行时更改时升级以及监控节点。对于产品是质押逻辑的团队来说,这通常是一种干扰。
托管 RPC 提供商消除了节点操作,但引入了依赖:您需要了解提供商的吞吐量预期、是否支持 WebSocket 订阅、是否提供归档读取以及如何故障转移。在评估选项时,请按以下顺序提出问题:
- 它是否支持 Acala 的 HTTP 和 WebSocket?
- 它能否处理您的轮询频率而不会出现不可预测的延迟?
- 如果您需要历史状态,是否有归档路径?
- 当端点降级时会发生什么——您能否在不重新部署的情况下切换?
- 在您的请求量下,定价是否可预测?
OnFinality 通过其 API 服务 提供 Acala RPC,并在您需要隔离吞吐量时提供 专用节点。您可以查看 RPC 定价 和完整的 支持的 RPC 网络 列表,了解 Acala 如何与您运行的其他链配合。如需更广泛的框架,RPC 提供商选择指南 更深入地介绍了评估标准。
关键要点
- Acala 流动性质押将质押的 DOT 转换为 LDOT,一种可转让的衍生品,持续赚取奖励。
- LDOT 与 DOT 不是 1:1——在显示价值之前,始终从链状态读取实时汇率。
- Acala 基于 Substrate,因此您通过 Polkadot.js 风格的 JSON-RPC 和运行时元数据查询质押状态,而不是 ERC-20 调用。
- 从实时元数据解析模块和存储名称;硬编码的名称会在运行时升级时失效。
- 在标记质押外部交易完成之前,跟踪最终确定的头部,而不仅仅是新头部。
- 共享端点适合仪表板和原型;专用节点适合机器人、索引器和写入密集型路径。
- 按计划监控区块高度,以便在用户注意到之前发现端点降级。
常见问题解答
LDOT 是否总是与 DOT 等值? 不。LDOT 代表池化质押头寸的一部分,因此其 DOT 价值随着奖励累积而变化。从链状态读取汇率。
我可以通过 EVM 调用读取流动性质押状态吗? 质押模块位于 Acala 的 Substrate 侧。使用 Substrate JSON-RPC 接口,而不是期望 ERC-20 风格的合约调用返回质押状态。
为什么我的质押存储查询返回 null?
通常是因为模块或存储项名称在运行时升级中更改,或者因为您连接到了不同的链。使用 system_chain 和 state_getRuntimeVersion 验证。
质押仪表板需要专用节点吗? 不一定。共享端点适用于低频读取。当您的轮询频率、订阅数量或写入路径使共享吞吐量不可预测时,请迁移到专用节点。
我应该多久刷新一次汇率? 将您的频率与价值实际变化的频率相匹配。每个区块轮询通常是浪费的;每个 epoch 轮询一次对于实时 UI 通常太慢。
我可以在公共端点上回填历史质押数据吗? 公共端点不适用于大量历史读取。如果您需要回填状态或事件,请规划支持归档的基础设施。