가스 면제 프로토콜
이 문서는 가스 면제 메커니즘을 지정합니다: 트랜잭션 형식, 마커 라우팅, 거버넌스 제어 및 면제 서버 API.
개요
가스 면제는 소수의 거버넌스 승인 주소("면제자")가 gasPrice = 0으로 트랜잭션을 제출하도록 허용함으로써 Stable에서 가스 없는 최종 사용자 트랜잭션을 가능하게 합니다. Stable은 현재 면제 서비스("면제 서버")를 운영하고 있으며, 프로토콜별 래퍼 로직을 구현하지 않고도 가스 없는 UX를 제공하기 위해 통합할 수 있습니다.
범위
이 사양은 다음을 다룹니다.
- 가스 면제 트랜잭션에 대한 프로토콜 수준 규칙
- 래퍼 트랜잭션 메커니즘 및 마커 주소
- 거버넌스 제어 권한 부여 및 허용된 대상
- 서명된 사용자 트랜잭션을 제출하기 위한 면제 서버 인터페이스
정의
- 면제자: 검증자 거버넌스를 통해 온체인에 등록되어 가스 면제 트랜잭션을 제출할 권한이 부여된 이더리움 주소.
- 내부Tx: 최종 사용자의 서명된 트랜잭션(
gasPrice = 0). - 래퍼Tx: 면제자가 서명한 트랜잭션으로, 사용자의
내부Tx를 체인으로 전송하고 실행을 승인합니다. - 마커 주소: 면제 래퍼 트랜잭션을 식별하는 데 사용되는 센티넬 주소:
0x000000000000000000000000000000000000f333. - AllowedTarget: 면제자를 특정 계약 주소 및 메서드 선택기로 제한하는 정책.
개요
가스 면제는 래퍼 트랜잭션 패턴을 사용합니다.
- 사용자는
gasPrice = 0으로내부Tx에 서명합니다. - 면제자는
내부Tx를래퍼Tx로 래핑하고 브로드캐스트합니다. - 검증자는 마커 트랜잭션을 감지하고, 면제자 승인 및 정책 제약 조건을 확인한 다음, 내장된
내부Tx를 실행합니다.
Stable은 승인된 면제자로 온체인에 등록된 면제 서비스(면제 서버)를 운영합니다. 서명된 내부Tx 페이로드를 제출하기 위해 면제 서버 API와 통합합니다.
프로토콜 사양
마커 주소 라우팅
트랜잭션은 다음의 경우에만 가스 면제 래퍼 트랜잭션으로 처리됩니다.
to == 0x000000000000000000000000000000000000f333.
프로토콜은 트랜잭션 data 필드를 인코딩된 내부 트랜잭션 페이로드로 해석하고 아래의 면제 검증 규칙을 사용하여 처리합니다.
권한 부여 및 정책 확인
각 후보 래퍼 트랜잭션에 대해 검증자는 다음 사항을 적용해야 합니다.
-
면제자 권한 부여
WrapperTx.from은 거버넌스를 통해 온체인에 등록된 면제자 주소여야 합니다.
-
가스 면제
WrapperTx.gasPrice는0과 같아야 합니다.InnerTx.gasPrice는0과 같아야 합니다.
-
대상 허용 목록
InnerTx.to와InnerTx.data에서 추출된 메서드 선택기는 면제자의AllowedTarget정책에 의해 허용되어야 합니다.
-
값 제한
WrapperTx.value는0과 같아야 합니다.
어떠한 확인이라도 실패하면 검증자는 래퍼 트랜잭션을 거부하고 내부 트랜잭션을 실행하지 않습니다.
실행 시맨틱스
모든 확인이 통과하면:
- 프로토콜은 사용자의
from,nonce및 호출 시맨틱스를 보존하면서 사용자로InnerTx를 실행합니다. - 가스 회계는 면제 메커니즘으로 처리됩니다: 사용자는 가스를 지불하지 않으며, 면제 트랜잭션은 기능 정의에 따라
gasPrice = 0을 사용합니다. - 래퍼 트랜잭션은
InnerTx실행(언랩 및 검증을 위한 오버헤드 포함)을 충당하기에 충분한gasLimit을 제공해야 합니다.
트랜잭션 형식
래퍼Tx
래퍼 트랜잭션은 면제자가 서명하고 마커 주소로 전송됩니다.
WrapperTx {
from: waiver_address,
to: 0x000000000000000000000000000000000000f333,
value: 0, // 0이어야 합니다.
data: RLP(InnerTx), // RLP 인코딩된 내부 트랜잭션
gasPrice: 0, // 0이어야 합니다.
gasLimit: sufficient_for_inner, // 내부 실행 + 오버헤드를 포함해야 합니다.
nonce: waiver_nonce
}내부Tx
내부 트랜잭션은 최종 사용자가 서명합니다.
InnerTx {
from: user_address,
to: target_contract,
value: value,
data: call_data,
gasPrice: 0, // 0이어야 합니다.
gasLimit: execution_gas,
nonce: user_nonce
}거버넌스 제어 액세스
면제자 권한 부여는 검증자 거버넌스에 의해 온체인에서 제어됩니다.
거버넌스 제어는 다음을 제공합니다.
- 면제자 주소의 검토 가능한 권한 부여
- 면제자 등록 및 업데이트의 온체인 투명성
- 취소 기능
AllowedTarget을 통한 면제별 범위 지정
보안 모델
최종 사용자 서명 무결성
사용자가 InnerTx에 서명합니다. 면제자는 서명을 무효화하지 않고는 내부 트랜잭션 페이로드를 수정할 수 없습니다. 사용자가 의도한 트랜잭션 페이로드에만 서명하도록 여전히 확인해야 합니다.
트러스트 경계
가스 면제는 파트너가 면제 서버를 통해 제출물을 라우팅하는 경우 서비스 종속성을 도입합니다.
- 서비스의 가용성은 가스 없는 트랜잭션을 제출하는 능력에 영향을 미칩니다.
- 권한 부여는 온체인에 남아 있습니다. 등록된 면제자 주소만 유효한 래퍼 제출물을 생성할 수 있습니다.
통합
다음과 같이 통합합니다.
- 사용자로부터 서명된
InnerTx를 수집합니다 (gasPrice = 0). - 서명된 내부 트랜잭션을 면제 서버 API에 제출합니다.
- 스트리밍된 결과를 처리하고 최종 사용자에게 트랜잭션 해시를 노출합니다.
면제 서버
개요
면제 서버는 서명된 사용자 InnerTx 페이로드를 면제자 승인 래퍼 트랜잭션으로 래핑하고 브로드캐스트합니다. 래퍼 트랜잭션을 구성하거나 면제자 주소를 운영할 필요가 없습니다.
엔드포인트 및 기본 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, // 면제자의 경우 0이어야 합니다.
gasLimit: 100000,
nonce: nonce,
chainId: 2201, // 메인넷은 988, 테스트넷은 2201
};
return await userWallet.signTransaction(innerTx);
}오류 코드
PARSE_ERROR: 트랜잭션을 구문 분석하지 못했습니다.INVALID_REQUEST: 잘못된 요청 본문BATCH_SIZE_EXCEEDED: 배치 크기가 허용된 최대값을 초과합니다.VALIDATION_FAILED: 트랜잭션 유효성 검사 실패BROADCAST_FAILED: 체인에 브로드캐스트하지 못했습니다.RATE_LIMITED: 비율 제한 초과QUEUE_FULL: 서버 큐 용량 초과TIMEOUT: 요청 시간 초과
다음 권장 사항
- 제로 가스 트랜잭션: 제로 가스 수수료를 보여주는 영수증과 함께 데모 중심의 설명.
- 가스 없는 트랜잭션 활성화: 배치 제출 및 오류 처리가 포함된 전체 호스팅 API 통합 가이드.
- 자체 호스팅 가스 면제: 호스팅 API 없이 자체 면제 인프라 실행.

