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

가스 면제 프로토콜

이 문서는 가스 면제 메커니즘을 설명합니다: 트랜잭션 형식, 마커 라우팅, 거버넌스 제어, 그리고 Waiver Server API.

개요

가스 면제는 거버넌스에서 승인된 소수의 주소 집합("waivers")이 gasPrice = 0으로 트랜잭션을 제출할 수 있도록 허용하여 Stable에서 가스 없는 최종 사용자 트랜잭션을 가능하게 합니다. Stable은 현재 프로토콜별 래퍼 로직을 구현하지 않고도 가스 없는 UX를 제공하기 위해 통합할 수 있는 waiver 서비스("Waiver Server")를 운영합니다.

범위

이 사양은 다음을 다룹니다:

  • 가스가 면제된 트랜잭션에 대한 프로토콜 수준 규칙
  • 래퍼 트랜잭션 메커니즘과 마커 주소
  • 거버넌스가 제어하는 권한 부여 및 허용된 대상
  • 서명된 사용자 트랜잭션을 제출하기 위한 Waiver Server 인터페이스

정의

  • Waiver: 가스가 면제된 트랜잭션을 제출할 수 있도록 검증자 거버넌스를 통해 온체인에 등록된 이더리움 주소입니다.
  • InnerTx: gasPrice = 0으로 최종 사용자가 서명한 트랜잭션입니다.
  • WrapperTx: 사용자의 InnerTx를 체인으로 전송하고 실행을 승인하기 위해 waiver가 서명한 트랜잭션입니다.
  • 마커 주소: waiver 래퍼 트랜잭션을 식별하는 데 사용되는 센티넬 주소입니다: 0x000000000000000000000000000000000000f333.
  • AllowedTarget: waiver를 특정 컨트랙트 주소와 메서드 선택자로 제한하는 정책입니다.

살펴보기

가스 면제는 래퍼 트랜잭션 패턴을 사용합니다:

  1. 사용자가 gasPrice = 0으로 InnerTx에 서명합니다.
  2. waiver가 InnerTxWrapperTx로 감싸서 브로드캐스트합니다.
  3. 검증자가 마커 트랜잭션을 감지하고, waiver 권한 부여 및 정책 제약 조건을 확인한 다음, 내장된 InnerTx를 실행합니다.

Stable은 승인된 waiver로 온체인에 등록된 waiver 서비스(Waiver Server)를 운영합니다. 서명된 InnerTx 페이로드를 제출하기 위해 Waiver Server API와 통합합니다.

프로토콜 사양

마커 주소 라우팅

트랜잭션은 다음의 경우에만 waiver 래퍼 트랜잭션으로 취급됩니다:

  • to == 0x000000000000000000000000000000000000f333.

프로토콜은 트랜잭션 data 필드를 인코딩된 내부 트랜잭션 페이로드로 해석하고 아래의 waiver 검증 규칙을 사용하여 처리합니다.

권한 부여 및 정책 검사

각 후보 래퍼 트랜잭션에 대해 검증자는 다음을 적용해야 합니다:

  1. Waiver 권한 부여
    • WrapperTx.from은 거버넌스를 통해 온체인에 등록된 waiver 주소여야 합니다.
  2. 가스 면제
    • WrapperTx.gasPrice0이어야 합니다.
    • InnerTx.gasPrice0이어야 합니다.
  3. 대상 허용 목록
    • InnerTx.toInnerTx.data에서 추출한 메서드 선택자는 waiver의 AllowedTarget 정책에 의해 허용되어야 합니다.
  4. 값 제한
    • WrapperTx.value0이어야 합니다.

검사 중 하나라도 실패하면 검증자는 래퍼 트랜잭션을 거부하고 내부 트랜잭션을 실행하지 않습니다.

실행 의미론

모든 검사를 통과하면:

  1. 프로토콜은 사용자의 from, nonce, 호출 의미론을 보존하면서 InnerTx를 사용자로서 실행합니다.
  2. 가스 정산은 waiver 메커니즘에 의해 처리됩니다: 사용자는 가스를 지불하지 않으며, waiver 트랜잭션은 이 기능의 정의에 따라 gasPrice = 0을 사용합니다.
  3. 래퍼 트랜잭션은 InnerTx의 실행(언래핑 및 검증에 대한 오버헤드 포함)을 처리하기에 충분한 gasLimit을 제공해야 합니다.

트랜잭션 형식

WrapperTx

래퍼 트랜잭션은 waiver가 서명하여 마커 주소로 전송됩니다.

WrapperTx {
  from:     waiver_address,
  to:       0x000000000000000000000000000000000000f333,
  value:    0,                          // must be zero
  data:     RLP(InnerTx),               // RLP-encoded inner transaction
  gasPrice: 0,                          // must be zero
  gasLimit: sufficient_for_inner,       // must cover inner execution + overhead
  nonce:    waiver_nonce
}

InnerTx

내부 트랜잭션은 최종 사용자가 서명합니다.

InnerTx {
  from:     user_address,
  to:       target_contract,
  value:    value,
  data:     call_data,
  gasPrice: 0,                          // must be zero
  gasLimit: execution_gas,
  nonce:    user_nonce
}

거버넌스가 제어하는 접근

waiver 권한 부여는 검증자 거버넌스에 의해 온체인에서 관리됩니다.

거버넌스 제어는 다음을 제공합니다:

  • waiver 주소의 검토 가능한 권한 부여
  • waiver 등록 및 업데이트의 온체인 투명성
  • 취소 기능
  • AllowedTarget을 통한 waiver별 범위 지정

보안 모델

최종 사용자 서명 무결성

사용자는 InnerTx에 서명합니다. waiver는 서명을 무효화하지 않고는 내부 트랜잭션 페이로드를 수정할 수 없습니다. 사용자가 의도한 트랜잭션 페이로드에만 서명하도록 여전히 보장해야 합니다.

신뢰 경계

가스 면제는 파트너가 Waiver Server를 통해 제출을 라우팅하는 경우 서비스 의존성을 도입합니다:

  • 서비스의 가용성은 가스 없는 트랜잭션을 제출하는 능력에 영향을 미칩니다.
  • 권한 부여는 온체인에 남아 있습니다. 등록된 waiver 주소만 유효한 래퍼 제출을 생성할 수 있습니다.

통합

다음과 같이 통합합니다:

  1. 사용자로부터 서명된 InnerTx(gasPrice = 0)를 수집합니다.
  2. 서명된 내부 트랜잭션을 Waiver Server API에 제출합니다.
  3. 스트리밍된 결과를 처리하고 최종 사용자에게 트랜잭션 해시를 표시합니다.

Waiver server

살펴보기

Waiver Server는 서명된 사용자 InnerTx 페이로드를 waiver가 승인한 래퍼 트랜잭션으로 감싸서 브로드캐스트합니다. 래퍼 트랜잭션을 구성하거나 waiver 주소를 운영할 필요가 없습니다.

엔드포인트 및 기본 URL

기본 URL:

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

인증

health를 제외한 모든 엔드포인트는 베어러 토큰 인증이 필요합니다:

Authorization: Bearer <your-api-key>

API

GET /v1/health

상태 확인 엔드포인트.

인증: 없음.

POST /v1/submit

서명된 내부 트랜잭션 배치를 제출합니다.

인증: 필수 (Bearer).

요청 본문:

{
  "transactions": ["0x<signedInnerTx1>", "0x<signedInnerTx2>"]
}

응답은 NDJSON(줄바꿈으로 구분된 JSON)으로 스트리밍됩니다. 각 줄은 제출된 트랜잭션 인덱스에 해당합니다.

예시:

{"index":0,"id":"abc123","success":true,"txHash":"0x..."}
{"index":1,"id":"def456","success":false,"error":{"code":"VALIDATION_FAILED","message":"invalid signature"}}

GET /v1/submit

스트리밍 제출을 위한 WebSocket 인터페이스.

인증: 필수 (Bearer).

통합 예시

const WAIVER_SERVER = "https://waiver.testnet.stable.xyz";
 
async function submitGaslessTransaction(signedInnerTxHex, apiKey) {
  const response = await fetch(`${WAIVER_SERVER}/v1/submit`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${apiKey}`,
    },
    body: JSON.stringify({
      transactions: [signedInnerTxHex],
    }),
  });
 
  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);
      console.log(result);
    }
  }
}

사용자 InnerTx 생성

gasPrice = 0으로 InnerTx를 구성한 다음 사용자 서명을 수집할 책임이 있습니다.

예시:

import { ethers } from "ethers";
 
async function createInnerTx(userWallet, contractAddress, callData, nonce) {
  const innerTx = {
    to: contractAddress,
    data: callData,
    value: value,
    gasPrice: 0,              // must be 0 for waiver
    gasLimit: 100000,
    nonce: nonce,
    chainId: 2201,            // 988 for mainnet, 2201 for testnet
  };
 
  return await userWallet.signTransaction(innerTx);
}

오류 코드

  • PARSE_ERROR: 트랜잭션 파싱 실패
  • INVALID_REQUEST: 잘못된 형식의 요청 본문
  • BATCH_SIZE_EXCEEDED: 배치 크기가 허용된 최대값 초과
  • VALIDATION_FAILED: 트랜잭션 검증 실패
  • BROADCAST_FAILED: 체인으로 브로드캐스트 실패
  • RATE_LIMITED: 속도 제한 초과
  • QUEUE_FULL: 서버 큐가 용량에 도달
  • TIMEOUT: 요청 시간 초과

다음 권장 사항