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

使用系统模块

Stable 通过固定地址的预编译合约公开协议级逻辑。您可以从 Solidity 或 ethers.js 调用这些预编译,而不是在应用合约中重新实现 Stable SDK 行为。

已公开内容

模块预编译地址用途
Bank0x0000000000000000000000000000000000001003STABLE 代币转账和余额操作
Distribution0x0000000000000000000000000000000000000801领取质押奖励、奖励查询、佣金管理
Staking0x0000000000000000000000000000000000000800委托、解除委托、重新委托、验证者查询
Gov0x0000000000000000000000000000000000000805提案、计票结果和链上投票记录
Slashing0x0000000000000000000000000000000000000806验证者签名信息和正常运行时间
StableSystem0x0000000000000000000000000000000000009999有保障的区块空间通道查询和系统交易的 EVM 事件发射

读取方法可从任何 EVM 合约或链下客户端调用。某些改变状态的方法强制执行调用者授权,notifySystemTxLogs() 仅接受协议生成的系统交易。这些地址在主网和测试网上是相同的。

何时调用预编译合约与常规合约

  • 使用预编译合约:当操作映射到 Stable SDK 模块时:质押、奖励分配、STABLE 代币操作。调用预编译合约既便宜又是触发协议级行为的唯一方法。
  • 使用常规合约:当操作是应用逻辑时:托管、定价、访问控制。如果您需要自定义授权或验证,请在您自己的合约中包装预编译调用。

预编译合约不能替代应用合约。它们是底层协议的稳定接口。

从 Solidity 调用

为您需要的方法声明一个接口,然后像调用已部署合约一样调用预编译。

将验证者的 EVM 地址传递给质押方法。预编译合约不接受 Bech32 验证者操作员字符串。

// SAFE: the precompile address is fixed on Stable.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
 
struct Coin {
    string denom;
    uint256 amount;
}
 
interface IStaking {
    function delegate(
        address delegatorAddress,
        address validatorAddress,
        uint256 amount
    ) external returns (bool success);
 
    function delegation(
        address delegatorAddress,
        address validatorAddress
    ) external view returns (uint256 shares, Coin memory balance);
}
 
contract StakingHelper {
    address constant STAKING_PRECOMPILE =
        0x0000000000000000000000000000000000000800;
 
    /// @notice Delegate STABLE tokens to a validator from this contract.
    function delegateToValidator(
        address validatorAddress,
        uint256 amount
    ) external returns (bool) {
        return IStaking(STAKING_PRECOMPILE).delegate(
            address(this),
            validatorAddress,
            amount
        );
    }
 
    /// @notice Read the current delegation of this contract to a validator.
    function myDelegation(address validatorAddress)
        external
        view
        returns (uint256 shares, Coin memory balance)
    {
        return IStaking(STAKING_PRECOMPILE).delegation(
            address(this),
            validatorAddress
        );
    }
}

使用 Foundry 或 Hardhat 编译和部署。预编译地址被写入合约中的常量槽,因此部署后无需连接。

从 ethers.js 调用

对于链下客户端,将相同的接口声明为最小 ABI,并实例化指向预编译地址的合约。

// queryDelegation.ts
import { ethers } from "ethers";
import "dotenv/config";
 
const provider = new ethers.JsonRpcProvider("https://rpc.testnet.stable.xyz");
 
const STAKING_PRECOMPILE = "0x0000000000000000000000000000000000000800";
 
const staking = new ethers.Contract(
  STAKING_PRECOMPILE,
  [
    "function delegation(address delegator, address validator) view returns (uint256 shares, (string denom, uint256 amount) balance)",
  ],
  provider
);
 
const delegator = "0x1111111111111111111111111111111111111111";
const validator = "0x2222222222222222222222222222222222222222";
 
const [shares, balance] = await staking.delegation(delegator, validator);
console.log("Delegation shares: ", shares.toString());
console.log("Delegation denomination:", balance.denom);
console.log("Delegation amount:", balance.amount.toString());
npx tsx queryDelegation.ts
Delegation shares:  <share amount>
Delegation denomination: <staking denomination>
Delegation amount: <base-unit amount>

订阅系统交易事件

一些 Stable SDK 操作(例如解除绑定完成)不会自然地发出 EVM 事件。Stable 通过系统交易弥补了这一空白:由验证者生成的交易,调用 StableSystem 预编译以在下一个区块中发出标准 EVM 事件。

要观察 UnbondingCompleted,请像任何 ERC-20 Transfer 侦听器一样,在预编译地址订阅。

// watchUnbonding.ts
import { ethers } from "ethers";
 
const provider = new ethers.JsonRpcProvider("https://rpc.testnet.stable.xyz");
 
const STABLE_SYSTEM = "0x0000000000000000000000000000000000009999";
 
const stableSystem = new ethers.Contract(
  STABLE_SYSTEM,
  [
    "event UnbondingCompleted(address indexed delegator, address indexed validator, uint64 indexed originBlockHeight, uint256 amount)",
  ],
  provider
);
 
stableSystem.on("UnbondingCompleted", (delegator, validator, originBlockHeight, amount, event) => {
  console.log("Unbonding completed for:", delegator);
  console.log("Origin block:", originBlockHeight.toString());
  console.log("Amount:", ethers.formatEther(amount), "STABLE");
  console.log("Tx:", event.log.transactionHash);
});
 
console.log("Listening for UnbondingCompleted events...");
npx tsx watchUnbonding.ts
Listening for UnbondingCompleted events...
Unbonding completed for: 0xabcd...
Origin block: 36975999
Amount: 100.0 STABLE
Tx: 0x12ab...

有关完整的系统交易机制以及按用户筛选/历史查询模式,请参阅跟踪解除绑定完成

每模块参考

每个预编译的完整方法列表、事件和授权规则都可以在其参考页面中找到。

下一步