> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stablenet.network/llms.txt
> Use this file to discover all available pages before exploring further.

# 수수료 위임 구현하기

> StableNet의 트랜잭션 타입 0x16으로 별도 계정이 가스를 대신 납부해 사용자가 WKRC를 보유하지 않아도 되게 합니다.

> 수수료 지불자 계정이 트랜잭션 발신자 대신 가스 비용을 부담하는 이중 서명 흐름을 구현합니다.

## 배우는 내용

이 튜토리얼을 완료하면 다음을 할 수 있습니다:

* ethers.js로 수수료 위임 트랜잭션(타입 `0x16`) 빌드 및 서명
* 부분 서명된 트랜잭션에 수수료 지불자 서명 추가
* 완성된 트랜잭션을 브로드캐스트하고 가스가 수수료 지불자에게 청구됐는지 확인

## 수수료 위임 작동 방식

StableNet의 수수료 위임은 트랜잭션 타입 `0x16`을 사용해 트랜잭션 서명과 가스 납부를 분리합니다.

| 역할                   | 서명                       | 납부                    |
| -------------------- | ------------------------ | --------------------- |
| 발신자 (`From`)         | 트랜잭션 의도 (`v`, `r`, `s`)  | 전송 가치만                |
| 수수료 지불자 (`FeePayer`) | 가스 동의 (`fv`, `fr`, `fs`) | `gasLimit × gasPrice` |

두 서명 모두 필수입니다. 노드는 트랜잭션을 멤풀에 수락하기 전에 양쪽 서명을 모두 검증합니다. 실행 후 미사용 가스는 발신자가 아닌 수수료 지불자에게 환불됩니다.

<Note>
  수수료 위임은 **Applepie 포크** 활성화가 필요합니다. 포크 활성화 전에 제출된 타입 `0x16` 트랜잭션은 즉시 거부됩니다.
</Note>

## 사전 준비

* Node.js ≥ 18 및 `npm install ethers` (v6)
* 테스트넷 계정 두 개: 발신자 지갑, 수수료 지불자 지갑
* 두 계정 모두 [Faucet](https://faucet.stablenet.network)에서 테스트넷 WKRC 받기

## 트랜잭션 빌드 및 서명

발신자가 트랜잭션을 빌드하고, `feePayer`를 수수료 지불자 주소로 설정한 후 서명합니다.

```typescript theme={null}
import { ethers } from "ethers";

const SENDER_PRIVATE_KEY = process.env.SENDER_PRIVATE_KEY!;
const FEE_PAYER_PRIVATE_KEY = process.env.FEE_PAYER_PRIVATE_KEY!;

const provider = new ethers.JsonRpcProvider("https://api.test.stablenet.network");
const senderWallet = new ethers.Wallet(SENDER_PRIVATE_KEY, provider);
const feePayerWallet = new ethers.Wallet(FEE_PAYER_PRIVATE_KEY, provider);

// 1. 미서명 트랜잭션 빌드 (타입 0x16)
const unsignedTx = {
  type: 0x16,
  chainId: 8283,
  nonce: await provider.getTransactionCount(senderWallet.address),
  to: "0xRecipientAddress",
  value: ethers.parseEther("1.0"),
  gas: 30400n,
  maxFeePerGas: ethers.parseUnits("80000", "gwei"),
  maxPriorityFeePerGas: ethers.parseUnits("27600", "gwei"),
  feePayer: feePayerWallet.address,
  input: "0x",
  accessList: [],
};

// 2. 발신자 서명
const senderSig = await senderWallet.signTransaction(unsignedTx);
```

## 수수료 지불자 서명 추가

수수료 지불자가 부분 서명된 트랜잭션을 받아 내용을 확인한 후 서명을 추가합니다.

```typescript theme={null}
// 3. 수수료 지불자 확인 및 서명
const decoded = ethers.Transaction.from(senderSig);

// 서명 전 트랜잭션 확인 — 수수료 지불자는 가스 납부를 승인하는 것입니다
console.log("to:", decoded.to);
console.log("value:", ethers.formatEther(decoded.value), "WKRC");

const feePayerSig = await feePayerWallet.signTransaction(decoded);
```

<Tip>
  수수료 지불자는 서명 전에 `to`, `value`, `data`, `gas`를 반드시 확인하세요 — 의도치 않은 작업에 가스를 납부하는 것을 방지합니다.
</Tip>

## 완성된 트랜잭션 브로드캐스트

```typescript theme={null}
// 4. 완전히 서명된 트랜잭션 브로드캐스트
const txResponse = await provider.broadcastTransaction(feePayerSig);
console.log("tx hash:", txResponse.hash);

const receipt = await txResponse.wait();
console.log("Confirmed in block", receipt.blockNumber);
console.log("Gas used:", receipt.gasUsed.toString());
```

```text theme={null}
tx hash: 0xabc...
Confirmed in block 1234567
Gas used: 21000
```

## 수수료 지불자에게 가스가 청구됐는지 확인

수수료 지불자의 잔액을 트랜잭션 전후로 확인해 발신자가 아닌 수수료 지불자 계정에서 가스가 차감됐는지 검증합니다.

```typescript theme={null}
const feePayerBalance = await provider.getBalance(feePayerWallet.address);
console.log("Fee payer balance:", ethers.formatEther(feePayerBalance), "WKRC");
```

Explorer에서 트랜잭션 해시를 검색하면([explorer.stablenet.network](https://explorer.stablenet.network)) 트랜잭션 상세 정보의 `feePayer` 필드에서 가스를 납부한 계정을 확인할 수 있습니다.

## 핵심 불변 조건

* `tx.origin`은 항상 발신자입니다. `msg.sender` 또는 `tx.origin`을 확인하는 기존 컨트랙트는 수정 없이 동작합니다.
* 수수료 지불자의 잔액은 가치 전송에 사용될 수 없습니다 — 가스만 위험에 노출됩니다.
* 미사용 가스는 수수료 지불자에게 자동으로 환불됩니다.
* EVM 실행 내부에서는 수수료 위임이 사용됐는지 감지할 수 없습니다 — 스마트 컨트랙트는 수수료 위임 여부를 알 수 없습니다.

## 다음 단계

<CardGroup cols={2}>
  <Card title="수수료 위임 사용 사례" href="/ko/v0.3/fee-delegation">수수료 위임으로 가스리스 dApp 흐름을 구현합니다.</Card>
  <Card title="RPC API 레퍼런스" href="/ko/v0.3/reference/rpc-api">personal\_signRawFeeDelegateTransaction 및 관련 메서드.</Card>
  <Card title="Foundry로 배포하기" href="/ko/v0.3/build/tutorials/deploy-with-foundry">수수료 지불자가 상호작용할 컨트랙트를 배포합니다.</Card>
  <Card title="이벤트 구독하기" href="/ko/v0.3/build/tutorials/listen-to-events">수수료 위임 트랜잭션이 발생시키는 이벤트를 구독합니다.</Card>
</CardGroup>
