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은 고정된 주소의 **프리컴파일 컨트랙트(precompiled contracts)**를 통해 프로토콜 수준의 정산 로직을 노출합니다. 프리컴파일을 사용하면 EVM 코드가 Stable SDK 모듈(스테이킹, 보상 분배, STABLE 토큰 작업)을 다시 구현하지 않고 호출할 수 있습니다. 프로토콜 수준에서 실행되기 때문에 동등한 Solidity 구현보다 가스 효율이 훨씬 높습니다.

이 가이드는 Solidity와 ethers.js 양쪽에서 프리컴파일을 호출하는 방법과, 일반 컨트랙트 대신 언제 프리컴파일을 사용해야 하는지를 보여줍니다.

노출되는 항목

모듈프리컴파일 주소용도
Bank0x0000000000000000000000000000000000001003STABLE 토큰 전송 및 잔액 작업
Distribution0x0000000000000000000000000000000000000801스테이킹 보상 청구, 보상 조회, 커미션 관리
Staking0x0000000000000000000000000000000000000800위임, 위임 해제, 재위임, 검증자 조회
Gov0x0000000000000000000000000000000000000805제안, 집계 결과, 온체인 투표 기록
Slashing0x0000000000000000000000000000000000000806검증자 서명 정보 및 가동 시간
StableSystem0x0000000000000000000000000000000000009999시스템 트랜잭션(위임 해제 완료)을 위한 EVM 이벤트 발생

이 모든 것은 EVM 컨트랙트나 오프체인 클라이언트에서 호출할 수 있습니다. 주소는 안정적이며 메인넷과 테스트넷에서 동일합니다.

프리컴파일 vs 일반 컨트랙트, 언제 호출할까

  • 프리컴파일을 사용: 작업이 Stable SDK 모듈에 매핑될 때 — 스테이킹, 보상 분배, STABLE 토큰 작업. 프리컴파일 호출은 더 저렴하면서도 프로토콜 수준 동작을 트리거하는 유일한 방법입니다.
  • 일반 컨트랙트를 사용: 작업이 애플리케이션 로직일 때 — 에스크로, 가격 책정, 접근 제어. 커스텀 권한 부여나 검증이 필요한 경우 프리컴파일 호출을 직접 만든 컨트랙트로 감싸세요.

프리컴파일은 애플리케이션 컨트랙트를 대체하지 않습니다. 기반 프로토콜로 향하는 안정적인 인터페이스입니다.

Solidity에서 호출하기

필요한 메서드에 대한 인터페이스를 선언한 다음, 프리컴파일을 마치 배포된 컨트랙트처럼 호출하세요.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
 
interface IStaking {
    function delegate(
        address delegatorAddress,
        string calldata validatorAddress,
        uint256 amount
    ) external returns (bool success);
 
    function delegation(
        address delegatorAddress,
        string calldata validatorAddress
    ) external view returns (uint256 shares, uint256 balance);
}
 
contract StakingHelper {
    address constant STAKING_PRECOMPILE =
        0x0000000000000000000000000000000000000800;
 
    /// @notice Delegate STABLE tokens to a validator from this contract.
    function delegateToValidator(
        string calldata 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(string calldata validatorAddress)
        external
        view
        returns (uint256 shares, uint256 balance)
    {
        return IStaking(STAKING_PRECOMPILE).delegation(
            address(this),
            validatorAddress
        );
    }
}

Foundry나 Hardhat으로 컴파일하고 배포하세요. 프리컴파일 주소는 상수 슬롯에서 컨트랙트에 고정되므로, 배포 후 연결할 것이 없습니다.

// SAFE: precompile address is fixed on Stable and never changes.

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, string validator) view returns (uint256 shares, uint256 balance)",
  ],
  provider
);
 
const delegator = "0xDelegatorAddress";
const validator = "stablevaloper1..."; // bech32 validator operator address
 
const [shares, balance] = await staking.delegation(delegator, validator);
console.log("Delegation shares: ", shares.toString());
console.log("Delegation balance:", ethers.formatUnits(balance, 18), "STABLE");
npx tsx queryDelegation.ts
Delegation shares:  1000000000000000000000
Delegation balance: 1000.0 STABLE

시스템 트랜잭션 이벤트 구독하기

일부 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, uint256 amount)",
  ],
  provider
);
 
stableSystem.on("UnbondingCompleted", (delegator, validator, amount, event) => {
  console.log("Unbonding completed for:", delegator);
  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...
Amount: 100.0 STABLE
Tx: 0x12ab...

시스템 트랜잭션 메커니즘 전체와 사용자별 필터링 / 과거 조회 패턴은 위임 해제 완료 추적하기를 참조하세요.

모듈별 레퍼런스

각 프리컴파일의 전체 메서드 목록, 이벤트, 권한 부여 규칙은 해당 레퍼런스 페이지에 있습니다.

다음 추천