> For the complete documentation index, see [llms.txt](https://docs.soniclabs.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.soniclabs.com/technology/release-2.2/gas-subsidies.md).

# Gas Subsidies

Gas Subsidies let a project pay the gas fees on behalf of its users.

Users interact with your app without holding any native S tokens. You decide which transactions get covered, and the network deducts the fee straight from a fund you top up.

## Why it matters

Native gas tokens are the single biggest onboarding blocker for new users. With Gas Subsidies, a wallet with zero S balance can still call your contract, mint an NFT, or complete an onboarding flow. The transaction fee is settled directly on-chain, not by a relayer or a separate meta-transaction layer.

```mermaid
flowchart LR
    A["Sponsor\ndeposits funds into a registry"] --> B["User\nsends tx with gasPrice = 0"] --> C["Sonic node\nmatches a fund, deducts the fee"]
```

## How a transaction gets sponsored

A user simply signs and sends a transaction with `gasPrice = 0`. The Sonic node checks whether any active fund covers it. If one does, the fee is paid from that fund instead of being rejected for insufficient balance. Funds are matched by increasingly broad rules, checked in this order:

1. **Account + nonce** — Covers one specific transaction, identified by sender and nonce. Useful for sponsoring a single, pre-approved action.
2. **Account + operation** — Covers a specific account calling a specific function on a specific contract.
3. **ERC-20 approval** — Covers a token approval, but only once per spender and only while the user's current allowance is zero and their balance is non-zero — prevents repeated free approvals.
4. **Operation** — Covers any account calling a specific function on a specific contract — e.g. every call to `mint()` on your NFT contract.
5. **Bootstrap** — Covers a new account's first three transactions network-wide, regardless of destination — a general on-ramp for newcomers.
6. **Contract** — Covers every transaction sent to a given contract, whichever function is called.
7. **Account** — Covers every transaction sent from a given account, wherever it's headed.

The node stops at the first matching fund that has enough balance to cover the fee, so narrower, more targeted funds always take priority over broad ones.

## Funding and withdrawing

Anyone can contribute native tokens to a fund — there's no need to be its creator. Each fund tracks the total available balance and every contributor's share of it.

| Action                      | What happens                                                                                                                                                                  |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sponsor(fundId)`           | Sends native tokens into the chosen fund. The sender's contribution is recorded proportionally.                                                                               |
| `withdraw(fundId, amount)`  | Withdraws up to your proportional share of what's left in the fund. Blocked from inside a sponsored transaction itself, to prevent draining a fund it's currently paying for. |
| `getAvailableFunds(fundId)` | Reads the current balance available to cover sponsored transactions.                                                                                                          |

> **Fund IDs are just hashes.** Each sponsorship rule (account, contract, operation, …) has a matching helper — e.g. `contractSponsorshipFundId(address)` — that derives its `fundId` deterministically. To sponsor "all calls to my contract," you call that helper to get the ID, then send funds to it.

## Code examples

The examples below demonstrate usage with `ethers.js`. A sponsor deposits into the fund matching the rule it wants to cover. A user sends the transaction with `gasPrice = 0` like normal, using whatever library or wallet they prefer.

### Sponsor: funding an ERC-20 approval

This funds the **ERC-20 approval** rule for a specific `(token, spender)` pair, by deriving its `fundId` from the exact `approve` calldata being sponsored.

```javascript
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();

const registry = new ethers.Contract(
  "0x7d0E23398b6CA0eC7Cdb5b5Aad7F1b11215012d2",
  [
    "function sponsor(bytes32 fundId) payable",
    "function approvalSponsorshipFundId(address to, bytes callData) pure returns (bytes32)"
  ],
  signer
);

const token = new ethers.Contract(tokenAddress, ["function approve(address,uint256) returns (bool)"], signer);
const calldata = token.interface.encodeFunctionData("approve", [spenderAddress, ethers.MaxUint256]);
const fundId = await registry.approvalSponsorshipFundId(tokenAddress, calldata);

await registry.sponsor(fundId, { value: ethers.parseEther("0.1") });
```

### User: sending the sponsored (zero-gas) transaction

The user's side needs no awareness of the fund at all. Set `gasPrice: 0n` and send the call as usual. If a matching fund has balance, the Sonic node covers the fee; otherwise the transaction is rejected like an underpriced tx.

```javascript
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();

const token = new ethers.Contract(tokenAddress, ["function approve(address,uint256) returns (bool)"], signer);

await token.approve(spenderAddress, ethers.parseUnits("100", 6), { gasPrice: 0n });
```

## Operational notes

Fees paid out of a fund are burned through the SFC contract, the same as ordinary gas fees — subsidies change who pays, not how the fee is settled.
