가스 면제 프로토콜
이 문서는 가스 면제 메커니즘을 설명합니다: 트랜잭션 형식, 마커 라우팅, 거버넌스 제어, 그리고 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를 특정 컨트랙트 주소와 메서드 선택자로 제한하는 정책입니다.
살펴보기
가스 면제는 래퍼 트랜잭션 패턴을 사용합니다:
- 사용자가
gasPrice = 0으로InnerTx에 서명합니다. - waiver가
InnerTx를WrapperTx로 감싸서 브로드캐스트합니다. - 검증자가 마커 트랜잭션을 감지하고, waiver 권한 부여 및 정책 제약 조건을 확인한 다음, 내장된
InnerTx를 실행합니다.
Stable은 승인된 waiver로 온체인에 등록된 waiver 서비스(Waiver Server)를 운영합니다. 서명된 InnerTx 페이로드를 제출하기 위해 Waiver Server API와 통합합니다.
프로토콜 사양
마커 주소 라우팅
트랜잭션은 다음의 경우에만 waiver 래퍼 트랜잭션으로 취급됩니다:
to == 0x000000000000000000000000000000000000f333.
프로토콜은 트랜잭션 data 필드를 인코딩된 내부 트랜잭션 페이로드로 해석하고 아래의 waiver 검증 규칙을 사용하여 처리합니다.
권한 부여 및 정책 검사
각 후보 래퍼 트랜잭션에 대해 검증자는 다음을 적용해야 합니다:
-
Waiver 권한 부여
WrapperTx.from은 거버넌스를 통해 온체인에 등록된 waiver 주소여야 합니다.
-
가스 면제
WrapperTx.gasPrice는0이어야 합니다.InnerTx.gasPrice는0이어야 합니다.
-
대상 허용 목록
InnerTx.to와InnerTx.data에서 추출한 메서드 선택자는 waiver의AllowedTarget정책에 의해 허용되어야 합니다.
-
값 제한
WrapperTx.value는0이어야 합니다.
검사 중 하나라도 실패하면 검증자는 래퍼 트랜잭션을 거부하고 내부 트랜잭션을 실행하지 않습니다.
실행 의미론
모든 검사를 통과하면:
- 프로토콜은 사용자의
from,nonce, 호출 의미론을 보존하면서InnerTx를 사용자로서 실행합니다. - 가스 정산은 waiver 메커니즘에 의해 처리됩니다: 사용자는 가스를 지불하지 않으며, waiver 트랜잭션은 이 기능의 정의에 따라
gasPrice = 0을 사용합니다. - 래퍼 트랜잭션은
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 주소만 유효한 래퍼 제출을 생성할 수 있습니다.
통합
다음과 같이 통합합니다:
- 사용자로부터 서명된
InnerTx(gasPrice = 0)를 수집합니다. - 서명된 내부 트랜잭션을 Waiver Server API에 제출합니다.
- 스트리밍된 결과를 처리하고 최종 사용자에게 트랜잭션 해시를 표시합니다.
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: 요청 시간 초과
다음 권장 사항
- 제로 가스 트랜잭션 — 가스 수수료가 0임을 보여주는 영수증과 함께하는 데모 중심 안내.
- 가스 무료 트랜잭션 활성화 — 배치 제출 및 오류 처리를 포함한 전체 호스팅 API 통합 가이드.
- 자체 호스팅 가스 면제 — 호스팅 API 없이 자체 waiver 인프라를 실행합니다.

