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

가스 없는 트랜잭션 활성화

Gas Waiver는 Stable에서 가스 없는 트랜잭션을 가능하게 합니다. Gas Waiver를 사용하면 애플리케이션이 사용자를 대신해 가스 수수료를 부담하므로, 사용자는 가스용 USDT0을 보유하지 않고도 컨트랙트와 상호작용할 수 있습니다.

이 가이드는 Waiver Server API를 통한 통합을 다룹니다.

사전 준비 사항

  • Stable 팀이 발급한 Waiver Server용 API 키
  • 대상 컨트랙트 주소가 waiver의 AllowedTarget 정책에 등록되어 있어야 합니다

Waiver Server

Base URL:
  • 메인넷: TBD
  • 테스트넷: https://waiver.testnet.stable.xyz

Authorization: Bearer <your-api-key>

개요

통합 흐름은 세 단계로 구성됩니다:

  1. InnerTx 빌드: 사용자가 gasPrice = 0으로 트랜잭션에 서명합니다.
  2. Waiver Server에 제출: 서명된 트랜잭션을 Waiver Server API에 제출합니다.
  3. 응답 처리: waiver 서버가 트랜잭션을 래핑하고 브로드캐스트합니다. 스트리밍된 결과를 처리하고 트랜잭션 해시를 사용자에게 표시합니다.

1단계: 사용자의 InnerTx 생성

사용자는 gasPrice = 0으로 표준 트랜잭션에 서명합니다. to 주소와 메서드 셀렉터는 waiver의 AllowedTarget 정책에 의해 허용되어야 합니다.

// config.ts
export const CONFIG = {
  RPC_URL: "https://rpc.testnet.stable.xyz",
  CHAIN_ID: 2201, // 988 for mainnet
  WAIVER_SERVER: "https://waiver.testnet.stable.xyz",
  USDT0_ADDRESS: "0x78Cf24370174180738C5B8E352B6D14c83a6c9A9",
};
import { ethers } from "ethers";
import { CONFIG } from "./config";
 
const provider = new ethers.JsonRpcProvider(CONFIG.RPC_URL);
const usdt0 = new ethers.Contract(CONFIG.USDT0_ADDRESS, [
  "function transfer(address to, uint256 amount) returns (bool)"
], provider);
 
const callData = usdt0.interface.encodeFunctionData("transfer", [
  recipientAddress,
  ethers.parseUnits("0.01", 18)
]);
 
const gasEstimate = await provider.estimateGas({
  from: userWallet.address,
  to: CONFIG.USDT0_ADDRESS,
  data: callData,
});
 
const nonce = await provider.getTransactionCount(userWallet.address);
 
const innerTx = {
  to: CONFIG.USDT0_ADDRESS,
  data: callData,
  value: 0,
  gasPrice: 0,
  gasLimit: gasEstimate,
  nonce: nonce,
  chainId: CONFIG.CHAIN_ID,
};
 
const signedInnerTx = await userWallet.signTransaction(innerTx);

2단계: Waiver Server에 제출

import { CONFIG } from "./config";
 
const API_KEY = process.env.WAIVER_API_KEY;
 
const response = await fetch(`${CONFIG.WAIVER_SERVER}/v1/submit`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${API_KEY}`,
  },
  body: JSON.stringify({
    transactions: [signedInnerTx],
  }),
});

배치 제출

단일 요청으로 여러 개의 서명된 트랜잭션을 제출할 수 있습니다:

body: JSON.stringify({
  transactions: [signedTx1, signedTx2, signedTx3],
})

각 결과 라인에는 배열 내 트랜잭션의 위치에 해당하는 index 필드가 포함됩니다.

3단계: 응답 처리

응답은 NDJSON(개행으로 구분된 JSON)으로 스트리밍됩니다. 각 라인은 제출된 하나의 트랜잭션에 해당합니다.

const reader = response.body.getReader();
const decoder = new TextDecoder();
 
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
 
  const lines = decoder.decode(value).trim().split("\n");
  for (const line of lines) {
    const result = JSON.parse(line);
    if (result.success) {
      console.log(`tx ${result.index} confirmed: ${result.txHash}`);
    } else {
      console.error(`tx ${result.index} failed: ${result.error.message}`);
    }
  }
}
성공 응답:
{"index": 0, "id": "abc123", "success": true, "txHash": "0x..."}
실패 응답:
{"index": 1, "id": "def456", "success": false, "error": {"code": "VALIDATION_FAILED", "message": "invalid signature"}}

오류 코드

코드설명
PARSE_ERROR트랜잭션 파싱 실패
INVALID_REQUEST잘못된 형식의 요청 본문
BATCH_SIZE_EXCEEDED배치 크기가 허용된 최대치를 초과함
VALIDATION_FAILED트랜잭션 검증 실패 (예: 잘못된 서명, 허용되지 않은 대상)
BROADCAST_FAILED체인으로의 브로드캐스트 실패
RATE_LIMITED속도 제한 초과
QUEUE_FULL서버 큐가 가득 참
TIMEOUT요청 시간 초과

API 레퍼런스

GET /v1/health

상태 확인 엔드포인트. 인증: 없음.

POST /v1/submit

서명된 inner 트랜잭션의 배치를 제출합니다. 인증: 필수 (Bearer).

요청 본문:
{
  "transactions": ["0x<signedInnerTx1>", "0x<signedInnerTx2>"]
}

응답은 NDJSON으로 스트리밍됩니다. 각 라인은 제출된 트랜잭션 인덱스에 해당합니다.

GET /v1/submit

스트리밍 제출을 위한 WebSocket 인터페이스. 인증: 필수 (Bearer).

핵심 요약

  • Gas Waiver는 서버 측 통합입니다. 백엔드가 서명된 사용자 트랜잭션을 Waiver Server에 제출합니다. 사용자는 Waiver Server와 직접 상호작용하지 않습니다.
  • 사용자가 항상 InnerTx에 서명하므로 서명 무결성이 유지됩니다. waiver는 사용자의 트랜잭션을 수정할 수 없습니다.
  • 대상 컨트랙트는 waiver의 AllowedTarget 목록에 있어야 합니다.

다음 추천

  • 제로 가스 트랜잭션 — 데모 중심의 흐름과 영수증에서 제로 가스를 검증하는 방법을 확인하세요.
  • 자체 호스팅 Gas Waiver — 호스팅된 API 없이 자체 waiver를 실행하세요.
  • Gas waiver protocol — 전체 래퍼 트랜잭션 사양 및 거버넌스 모델.
  • Stable SDK — 타입이 지정된 클라이언트를 사용해 사용자 트랜잭션에 서명한 후 Waiver Server에 제출하세요.