Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

跟踪解除质押完成情况

当解除质押期完成时,协议会通过系统交易,通过 StableSystem 预编译合约(0x0000000000000000000000000000000000009999)发出一个 UnbondingCompleted 事件。这允许 dApp 实时通知用户并更新余额,而无需运行自定义索引器或轮询 REST 端点。

前提条件

  • 了解系统交易
  • 熟悉质押,特别是 undelegate 和解除质押过程。
  • 有使用标准 web3 库(例如 ethers.js v6)进行合约事件订阅和过滤的经验。

概述

  • 设置合约实例:为 StableSystem 预编译合约创建合约实例。
  • 在你的应用程序中处理事件:根据你的应用程序逻辑订阅实时事件或查询历史数据。
  • 处理连接问题:为持久的 WebSocket 订阅实现重新连接逻辑。

步骤 1:设置合约实例

使用 UnbondingCompleted 事件 ABI 为 StableSystem 预编译合约创建一个合约实例。

// config.ts
import { ethers } from "ethers";
 
export const STABLE_SYSTEM_ADDRESS =
  "0x0000000000000000000000000000000000009999";
 
export const STABLE_SYSTEM_ABI = [
  "event UnbondingCompleted(address indexed delegator, address indexed validator, uint256 amount)",
];
 
export const provider = new ethers.JsonRpcProvider("https://rpc.testnet.stable.xyz");
export const stableSystem = new ethers.Contract(
  STABLE_SYSTEM_ADDRESS,
  STABLE_SYSTEM_ABI,
  provider
);

步骤 2:在你的应用程序中处理事件

根据你的应用程序逻辑,订阅实时事件、查询历史数据或两者兼而有之。

实时订阅

订阅 UnbondingCompleted 事件以获取任何解除质押完成时的实时通知。这对于触发余额更新、发送通知或刷新仪表板统计数据非常有用。

// subscribeBasic.ts
import { stableSystem } from "./config";
 
stableSystem.on("UnbondingCompleted", (delegator, validator, amount, event) => {
  console.log("Unbonding completed:");
  console.log("  Delegator:", delegator);
  console.log("  Validator:", validator);
  console.log("  Amount:", ethers.formatEther(amount), "tokens");
  console.log("  Block:", event.log.blockNumber);
  console.log("  Tx Hash:", event.log.transactionHash);
});

按用户筛选

要仅接收特定委托人地址的事件,请使用索引事件参数创建过滤器。

// subscribeByUser.ts
import { ethers } from "ethers";
import { stableSystem } from "./config";
 
const userAddress = "0xabcd...";
const filter = stableSystem.filters.UnbondingCompleted(userAddress);
 
stableSystem.on(filter, (delegator, validator, amount, event) => {
  refreshUserBalance(userAddress);
  showNotification(
    `您的 ${ethers.formatEther(amount)} 代币的解除质押已完成!`
  );
});

按验证者筛选

// subscribeByValidator.ts
import { stableSystem } from "./config";
 
const validatorAddress = "0x1234...";
const validatorFilter = stableSystem.filters.UnbondingCompleted(
  null,
  validatorAddress
);
 
stableSystem.on(validatorFilter, (delegator, validator, amount) => {
  updateValidatorStats(validator, amount);
});

历史查询

如果你的 dApp 需要显示过去解除质押完成的历史记录,请使用带有区块范围的事件过滤器查询历史事件。

// queryHistory.ts
import { ethers } from "ethers";
import { provider, stableSystem } from "./config";
 
async function getUnbondingHistory(
  userAddress: string,
  fromBlock: number,
  toBlock: number
) {
  const filter = stableSystem.filters.UnbondingCompleted(userAddress);
  const events = await stableSystem.queryFilter(filter, fromBlock, toBlock);
 
  return events.map((event) => ({
    delegator: event.args.delegator,
    validator: event.args.validator,
    amount: ethers.formatEther(event.args.amount),
    blockNumber: event.blockNumber,
    txHash: event.transactionHash,
  }));
}
 
const currentBlock = await provider.getBlockNumber();
const history = await getUnbondingHistory(
  "0xabcd...",
  currentBlock - 1000,
  currentBlock
);

步骤 3:处理连接问题

事件订阅依赖于持久的 WebSocket 连接。为生产 dApp 实现重新连接逻辑。

// subscribeWithReconnection.ts
import { ethers } = "ethers";
import { STABLE_SYSTEM_ADDRESS, STABLE_SYSTEM_ABI } from "./config";
 
let reconnectAttempts = 0;
const MAX_RECONNECT_ATTEMPTS = 5;
 
function handleUnbonding(delegator: string, validator: string, amount: bigint) {
  console.log("解除质押完成:", { delegator, validator, amount });
}
 
function setupEventListener() {
  const wsProvider = new ethers.WebSocketProvider("wss://rpc.testnet.stable.xyz");
 
  wsProvider.on("error", (error) => {
    console.error("提供者错误:", error);
    if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
      reconnectAttempts++;
      setTimeout(() => setupEventListener(), 5000);
    }
  });
 
  const stableSystem = new ethers.Contract(
    STABLE_SYSTEM_ADDRESS,
    STABLE_SYSTEM_ABI,
    wsProvider
  );
 
  stableSystem.on("UnbondingCompleted", handleUnbonding);
}
 
setupEventListener();

下一步推荐