> ## 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.

# Implement Fee Delegation

> Use StableNet's transaction type 0x16 to let a separate account pay gas so your users never need to hold WKRC.

> Build a two-signature flow where a fee payer account covers gas costs on behalf of a transaction sender.

## What you'll learn

By the end of this tutorial, you'll be able to:

* Build and sign a fee-delegated transaction (type `0x16`) with ethers.js
* Add the fee payer's signature to a partially signed transaction
* Broadcast the completed transaction and verify gas was charged to the fee payer

## How fee delegation works

StableNet's fee delegation separates transaction signing from gas payment using transaction type `0x16`.

| Role                   | Signs                              | Pays                  |
| ---------------------- | ---------------------------------- | --------------------- |
| Sender (`From`)        | Transaction intent (`v`, `r`, `s`) | Transfer value only   |
| Fee Payer (`FeePayer`) | Gas consent (`fv`, `fr`, `fs`)     | `gasLimit × gasPrice` |

Both signatures are required. The node validates both before accepting the transaction into the mempool. After execution, unused gas is refunded to the fee payer — not the sender.

<Note>
  Fee delegation requires the **Applepie fork** to be active. Transactions of type `0x16` submitted before the fork activate are rejected immediately.
</Note>

## Prerequisites

* Node.js ≥ 18 and `npm install ethers` (v6)
* Two funded testnet accounts: one sender wallet, one fee payer wallet
* Get testnet WKRC for both accounts at the [Faucet](https://faucet.stablenet.network)

## Build and sign the transaction

The sender builds the transaction, sets `feePayer` to the fee payer's address, and signs it.

```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. Build the unsigned transaction (type 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. Sender signs
const senderSig = await senderWallet.signTransaction(unsignedTx);
```

## Add the fee payer's signature

The fee payer receives the partially signed transaction, reviews the contents, and adds their signature.

```typescript theme={null}
// 3. Fee payer reviews and signs
const decoded = ethers.Transaction.from(senderSig);

// Verify the transaction before signing — the fee payer is authorizing gas payment
console.log("to:", decoded.to);
console.log("value:", ethers.formatEther(decoded.value), "WKRC");

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

<Tip>
  The fee payer should verify `to`, `value`, `data`, and `gas` before signing to avoid paying for unintended operations.
</Tip>

## Broadcast the completed transaction

```typescript theme={null}
// 4. Broadcast the fully signed transaction
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
```

## Verify gas was charged to the fee payer

Check the fee payer's balance before and after to confirm gas was deducted from their account, not the sender's.

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

On the Explorer, search the transaction hash at [explorer.stablenet.network](https://explorer.stablenet.network). The `feePayer` field in the transaction details confirms which account paid gas.

## Key invariants

* `tx.origin` is always the sender. Existing contracts that check `msg.sender` or `tx.origin` work without modification.
* The fee payer's balance cannot be used for value transfer — only gas is at risk.
* Unused gas is refunded to the fee payer automatically.
* The fee payer's address is not exposed inside EVM execution — smart contracts cannot detect that fee delegation was used.

## Next steps

<CardGroup cols={2}>
  <Card title="Fee Delegation Use Case" href="/en/v0.3/fee-delegation">Build a gasless dApp flow with fee delegation.</Card>
  <Card title="RPC API Reference" href="/en/v0.3/reference/rpc-api">personal\_signRawFeeDelegateTransaction and related methods.</Card>
  <Card title="Deploy with Foundry" href="/en/v0.3/build/tutorials/deploy-with-foundry">Deploy the contract your fee payer will interact with.</Card>
  <Card title="Listen to Events" href="/en/v0.3/build/tutorials/listen-to-events">Subscribe to events emitted by fee-delegated transactions.</Card>
</CardGroup>
