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

# Fee Delegation

This page documents StableNet’s **WEMIX-style fee delegation mechanism**.\
Fee delegation allows a separate account (`FeePayer`) to pay the transaction gas costs, while the transaction sender (`From`) only provides the value transfer.\
This feature enables use cases where application operators subsidize transaction fees for users.

For gas fee policies and tip requirements, refer to [Gas Fee Policy](/en/transaction-processing/6.4-gas-fee-policy).\
For the general transaction processing flow, refer to [Transaction Lifecycle](/en/transaction-processing/6.1-transaction-lifecycle).

## Purpose and Scope

Fee delegation clearly separates the financial responsibilities of a transaction between two parties.

* **Sender (`From`)**\
  Signs the transaction intent, provides the `Value` to be transferred, and must hold a valid nonce.
* **Fee Payer (`FeePayer`)**\
  Separately signs to approve gas payment and must hold sufficient balance to cover gas costs.

This mechanism is implemented via a dedicated transaction type, `FeeDelegateDynamicFeeTxType = 0x16`, and requires the **Applepie fork** to be active.

## Transaction Type and Structure

### Transaction Type Definition

Fee delegation uses transaction type `0x16` (decimal 22).

| Constant                      | Value  | Description                              |
| ----------------------------- | ------ | ---------------------------------------- |
| `FeeDelegateDynamicFeeTxType` | `0x16` | Fee-delegated EIP-1559 style transaction |

### Core Data Structures

The `Message` structure includes fee delegation fields.

```
Message {
  From common.Address       // Transaction sender (signs transaction intent)
  To *common.Address        // Recipient
  Value *big.Int            // Value to transfer from sender
  GasLimit uint64
  GasPrice *big.Int
  GasFeeCap *big.Int
  GasTipCap *big.Int
  FeePayer *common.Address  // Account paying for gas (optional)
  ...
}
```

The `TxData` interface includes fee delegation–related methods.

```
type TxData interface {
  feePayer() *common.Address
  rawFeePayerSignatureValues() (v, r, s *big.Int)
  ...
}
```

## Dual Signature Requirement

Fee-delegated transactions require **two independent signatures**.

### Signature 1: Transaction Sender

* Signs the transaction data (to, value, data, gas parameters, nonce).
* Signature values: `V`, `R`, `S`
* Proves transaction intent and authorization.

### Signature 2: Fee Payer

* Signs consent to pay gas for the transaction.
* Signature values: `FV`, `FR`, `FS`
* Retrieved via the `rawFeePayerSignatureValues()` method.

This dual-signature structure guarantees that both the sender and the fee payer explicitly agree to their respective responsibilities.

## State Transition Process

### Transaction-to-Message Conversion

A fee-delegated transaction is converted into a `Message` upon entering the state transition.

```
FeeDelegateDynamicFeeTx            Message
+--------------------------+       +---------------------------+
| SenderTx.Nonce           | ----> | Nonce                     |
| SenderTx.GasFeeCap       | ----> | GasFeeCap                 |
| SenderTx.GasTipCap       | ----> | GasTipCap                 |
| SenderTx.Gas             | ----> | GasLimit                  |
| SenderTx.To              | ----> | To                        |
| SenderTx.Value           | ----> | Value                     |
| SenderTx.Data            | ----> | Data                      |
| SenderTx.AccessList      | ----> | AccessList                |
| FeePayer                 | ----> | FeePayer                  |
+--------------------------+       +---------------------------+
                                   | From = recovered sender   |
                                   | GasPrice = effectivePrice |
                                   +---------------------------+
```

`TransactionToMessage` recovers the `From` address from the sender’s signature (`V/R/S`) and sets the `FeePayer` field via `tx.FeePayer()`.\
The fee payer’s signature is used only to authorize gas payment and is **not** used to derive the `From` address.

### Gas Purchase (`buyGas`)

When fee delegation is active, `buyGas` performs separated balance checks and deductions.

#### Balance Validation Rules

| Scenario              | FeePayer Balance Check              | Sender Balance Check                          |
| --------------------- | ----------------------------------- | --------------------------------------------- |
| Fee Delegation Active | ≥ `gasLimit × gasPrice` + blob fees | ≥ `value`                                     |
| Standard Transaction  | N/A                                 | ≥ `gasLimit × gasPrice` + `value` + blob fees |

## EVM Execution Context

Fee delegation does not alter EVM execution semantics.

* **tx.origin**: Always the transaction sender (`From`)
* **Top-level caller**: Transaction sender
* **FeePayer**: Not exposed to the EVM context

As a result, smart contracts cannot directly distinguish whether fee delegation was used.

## Gas Refund Process

After execution, unused gas is refunded to the account that actually paid for gas.

```
func (st *StateTransition) refundGas(refundQuotient uint64) uint64 {
    refund := st.gasUsed() / refundQuotient
    if refund > st.state.GetRefund() {
        refund = st.state.GetRefund()
    }
    st.gasRemaining += refund
    remaining := uint256.NewInt(st.gasRemaining)
    remaining = remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice))
    if st.msg.FeePayer != nil {
        st.state.AddBalance(*st.msg.FeePayer, remaining)
    } else {
        st.state.AddBalance(st.msg.From, remaining)
    }
    st.gp.AddGas(st.gasRemaining)
    return refund
}
```

## Fee Payment to Coinbase

Validators receive fees based on actual gas usage.\
Fee payment is processed in the later stages of state transition and includes blacklist checks for the fee payer.

## Fork Activation Requirement

Fee delegation is **only permitted after the Applepie fork**.

```
if isFeeDelegation && !st.evm.ChainConfig().IsApplepie(st.evm.Context.BlockNumber) {
    return ErrTxTypeNotSupported
}
```

For blocks prior to Applepie, fee-delegated transactions are immediately rejected during the `preCheck` stage.

## Transaction Construction via RPC

### TransactionArgs Fields

| Field          | Type              | Purpose            |
| -------------- | ----------------- | ------------------ |
| `From`         | `*common.Address` | Transaction sender |
| `FeePayer`     | `*common.Address` | Optional fee payer |
| `V`,`R`,`S`    | `*hexutil.Big`    | Sender signature   |
| `FV`,`FR`,`FS` | raw tx only       | FeePayer signature |

### JSON Representation

```
{
  "type": "0x16",
  "chainId": "0x2052",
  "nonce": "0x1",
  "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
  "gas": "0x76c0",
  "maxFeePerGas": "0x9184e72a000",
  "maxPriorityFeePerGas": "0x5f5e100",
  "value": "0xde0b6b3a7640000",
  "input": "0x",
  "accessList": [],
  "v": "0x0",
  "r": "0x...",
  "s": "0x...",
  "feePayer": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
  "fv": "0x0",
  "fr": "0x...",
  "fs": "0x..."
}
```

## Key Invariants

1. **Balance Isolation**\
   The fee payer covers gas only, while the sender covers value only.
2. **Origin Preservation**\
   `tx.origin` is always the sender.
3. **Dual Consent**\
   Both accounts must sign for the transaction to be valid.
4. **Fork Gate**\
   Available only after Applepie activation.
5. **Refund Consistency**\
   Unused gas is refunded to the actual payer.
