컨트랙트 이벤트 인덱싱
인덱싱은 온체인 이벤트를 애플리케이션이 반응할 수 있는 데이터(잔액 업데이트, 거래 내역, UI 알림)로 변환합니다. 이 가이드는 ethers.js를 사용하여 배포된 Stable 컨트랙트에서 이벤트를 구독하는 방법과 서비스가 오프라인일 때 발생한 이벤트를 놓치지 않도록 기록 이벤트를 백필하는 방법을 보여줍니다.
전제 조건
1. 설치 및 구성
npm install ethers// config.ts
import { ethers } from "ethers";
export const STABLE_TESTNET_RPC = "https://rpc.testnet.stable.xyz";
export const STABLE_TESTNET_WS = "wss://rpc.testnet.stable.xyz";
export const CONTRACT_ADDRESS = "0xDeployedContractAddress";
// Minimal ABI: only the events you want to index.
export const CONTRACT_ABI = [
"event NumberUpdated(address indexed caller, uint256 oldValue, uint256 newValue)",
];2. 실시간 이벤트 구독
유효성 검사기가 각 블록을 확정하자마자 이벤트를 수신할 수 있도록 WebSocket 공급자를 사용하십시오. WebSocket은 폴링 오버헤드를 방지하고 알림 대기 시간을 블록 시간(~Stable에서 0.7초)에 가깝게 유지합니다.
// watchLive.ts
import { ethers } from "ethers";
import { STABLE_TESTNET_WS, CONTRACT_ADDRESS, CONTRACT_ABI } from "./config";
const provider = new ethers.WebSocketProvider(STABLE_TESTNET_WS);
const contract = new ethers.Contract(CONTRACT_ADDRESS, CONTRACT_ABI, provider);
contract.on("NumberUpdated", (caller, oldValue, newValue, event) => {
console.log("NumberUpdated:");
console.log(" caller: ", caller);
console.log(" oldValue: ", oldValue.toString());
console.log(" newValue: ", newValue.toString());
console.log(" tx: ", event.log.transactionHash);
console.log(" block: ", event.log.blockNumber);
});
console.log("NumberUpdated 이벤트 청취 중...");npx tsx watchLive.tsNumberUpdated 이벤트 청취 중...
NumberUpdated:
caller: 0x1234...abcd
oldValue: 0
newValue: 42
tx: 0x8f3a...2d41
block: 1284371호출자가 컨트랙트를 호출하면 이벤트가 실시간으로 도착합니다.
3. 기록 이벤트 백필
서비스가 시작될 때 일반적으로 오프라인 중에 발생한 이벤트를 따라잡아야 합니다. 블록 범위를 사용하여 queryFilter를 사용하십시오.
// backfill.ts
import { ethers } from "ethers";
import { STABLE_TESTNET_RPC, CONTRACT_ADDRESS, CONTRACT_ABI } from "./config";
const provider = new ethers.JsonRpcProvider(STABLE_TESTNET_RPC);
const contract = new ethers.Contract(CONTRACT_ADDRESS, CONTRACT_ABI, provider);
const latest = await provider.getBlockNumber();
const fromBlock = Math.max(0, latest - 10_000); // 지난 ~1만 블록
const events = await contract.queryFilter(
contract.filters.NumberUpdated(),
fromBlock,
latest
);
for (const event of events) {
console.log(
`[block ${event.blockNumber}]`,
event.args.caller,
"숫자를 다음으로 설정:",
event.args.newValue.toString()
);
}
console.log(`${fromBlock}에서 ${latest}까지 ${events.length}개의 이벤트를 백필했습니다.`);npx tsx backfill.ts[block 1282351] 0x1234...abcd 숫자를 10으로 설정
[block 1283092] 0xef01...2345 숫자를 25로 설정
[block 1284371] 0x1234...abcd 숫자를 42로 설정
1282351에서 1284371까지 3개의 이벤트를 백필했습니다.4. 인덱싱된 인수에 따라 이벤트 필터링
indexed 매개변수(위의 caller와 같은)가 있는 이벤트는 서버 측에서 필터링할 수 있습니다. 모든 이벤트를 읽고 앱에서 필터링하는 대신 필터 값을 전달합니다.
// watchUser.ts
import { ethers } from "ethers";
import { STABLE_TESTNET_WS, CONTRACT_ADDRESS, CONTRACT_ABI } from "./config";
const provider = new ethers.WebSocketProvider(STABLE_TESTNET_WS);
const contract = new ethers.Contract(CONTRACT_ADDRESS, CONTRACT_ABI, provider);
const userAddress = "0x1234...abcd";
const filter = contract.filters.NumberUpdated(userAddress);
contract.on(filter, (caller, oldValue, newValue, event) => {
console.log(`${caller}가 숫자를 ${newValue.toString()}로 설정했습니다.`);
});
console.log(`${userAddress}의 NumberUpdated를 지켜보고 있습니다...`);npx tsx watchUser.ts0x1234...abcd의 NumberUpdated를 지켜보고 있습니다...
0x1234...abcd가 숫자를 42로 설정했습니다.연결 끊김 처리
WebSocket 연결이 끊길 수 있습니다. 프로덕션 인덱서의 경우 이벤트를 놓치지 않도록 재연결 로직을 구현하십시오.
// resilientWatch.ts
import { ethers } from "ethers";
import { STABLE_TESTNET_WS, CONTRACT_ADDRESS, CONTRACT_ABI } from "./config";
let reconnectAttempts = 0;
const MAX_RECONNECT = 5;
function setupWatcher() {
const provider = new ethers.WebSocketProvider(STABLE_TESTNET_WS);
const contract = new ethers.Contract(CONTRACT_ADDRESS, CONTRACT_ABI, provider);
contract.on("NumberUpdated", (caller, oldValue, newValue) => {
console.log(`${caller}가 숫자를 ${newValue.toString()}로 설정했습니다.`);
});
provider.websocket.onerror = (err: any) => {
console.error("공급자 오류:", err);
if (reconnectAttempts < MAX_RECONNECT) {
reconnectAttempts++;
setTimeout(setupWatcher, 5000);
}
};
}
setupWatcher();다음 권장 사항
- 언본딩 완료 추적: 프로토콜에서 발행한 시스템 트랜잭션 이벤트(언본딩 완료)를 인덱싱합니다.
- P2P 결제 앱 구축: USDT0 전송 이벤트에 인덱싱을 적용하고 결제 내역 보기를 구축합니다.
- JSON-RPC 참조: Stable이 지원하는
eth_getLogs및 관련 메서드를 확인하십시오.

