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

# Solana Gas Sponsorship

> Pay Solana transaction fees for your users with svmSponsor: a sponsor account you fund becomes the fee payer, and the user signs only for their tokens.

Solana gas sponsorship lets a user swap or bridge from Solana without holding SOL for the transaction fee. You pass the public key of a Solana account you control as `svmSponsor`. LI.FI builds the transaction with that account as the fee payer. Your sponsor account and the user's wallet both sign the same transaction, and the sponsor pays the network fees.

This is fee-payer substitution, not a relayer. LI.FI does not hold the sponsor key, does not fund the sponsor account, and does not submit the transaction for you. You fund the account, you sign with it, and you pay for what it covers.

> [!NOTE]
>
> Sponsorship applies to transactions that start on Solana. For the EVM equivalent, where LI.FI relays and recovers the cost from the input amount, see [Gasless Transactions](https://docs.li.fi/guides/gasless-transactions.md). For a comparison of every gas mechanism, see [Gas Options](https://docs.li.fi/guides/gas-options.md).

***

## How it works

**1. Request with svmSponsor**

Add the sponsor's public key to the quote, or to both the routes request and the stepTransaction request. The response is an unsigned, base64-encoded Solana transaction in `transactionRequest.data`, with the sponsor as the fee payer.

**2. Check the fee payer**

Deserialize the transaction and confirm that the fee payer, the first account key, is your sponsor. If it is the user's address, the request was built without the sponsor. See [Pass it on every request](#pass-it-on-every-request).

**3. Collect the signatures**

The sponsor and the user sign the same message, in any order. Each signature fills its own slot. Do not rebuild or change the transaction between signatures.

**4. Submit before the blockhash expires**

Send the fully signed transaction to a Solana RPC, then track it with `GET /v1/status` as for any other transfer.

***

## Pass it on every request

`svmSponsor` takes a base58 Solana public key. Any other format returns `400`.

| Request | Where `svmSponsor` goes |
| - | - |
| `GET /v1/quote` | Query parameter. The returned transaction is ready for both signatures. |
| `GET /v1/quote/toAmount` | Query parameter, as above. |
| `POST /v1/advanced/routes` | `options.svmSponsor` in the request body. Routing uses it to filter bridges. See [Bridges from Solana](#bridges-from-solana). |
| `POST /v1/advanced/stepTransaction` | Query parameter: `?svmSponsor=<pubkey>`. Required again here. |
| SDK | `routeOptions.svmSponsor` in `createConfig`. See [SDK](#sdk). |

> [!WARNING]
>
> Omitting `svmSponsor` from `stepTransaction` does not return an error. The transaction comes back with the user as the fee payer. The routes response repeats the sponsor inside `includedSteps[].action`, but stepTransaction does not read it from the posted step. It reads only the query parameter.

```bash Quote with a sponsor theme={"system"}
curl -G "https://li.quest/v1/quote" \
  -H "x-lifi-api-key: $LIFI_API_KEY" \
  --data-urlencode "fromChain=SOL" \
  --data-urlencode "toChain=SOL" \
  --data-urlencode "fromToken=USDC" \
  --data-urlencode "toToken=USDT" \
  --data-urlencode "fromAmount=5000000" \
  --data-urlencode "fromAddress=<USER_PUBKEY>" \
  --data-urlencode "svmSponsor=<SPONSOR_PUBKEY>"
```

```bash Routes, then stepTransaction theme={"system"}
# 1. Request routes with the sponsor in options
curl -X POST "https://li.quest/v1/advanced/routes" \
  -H "Content-Type: application/json" \
  -H "x-lifi-api-key: $LIFI_API_KEY" \
  -d '{
    "fromChainId": 1151111081099710,
    "toChainId": 42161,
    "fromTokenAddress": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "toTokenAddress": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
    "fromAmount": "20000000",
    "fromAddress": "<USER_PUBKEY>",
    "toAddress": "<EVM_RECIPIENT>",
    "options": { "svmSponsor": "<SPONSOR_PUBKEY>" }
  }'

# 2. Post the chosen step, and pass the sponsor again as a query parameter
curl -X POST "https://li.quest/v1/advanced/stepTransaction?svmSponsor=<SPONSOR_PUBKEY>" \
  -H "Content-Type: application/json" \
  -H "x-lifi-api-key: $LIFI_API_KEY" \
  -d @step.json
```

***

## Sign without rebuilding

The transaction is a versioned (v0) Solana transaction. Its required signers are the first accounts in the message:

* the sponsor, as the fee payer;
* the user, who owns the input tokens;
* on some routes, an extra one-time key whose signature is already in the transaction when you receive it. We observed this on `mayanFastMCTP`.

Do not assume exactly two signatures, and do not assume an empty signature list.

Solana signatures cover the serialized message, so every signer signs the same bytes. Deserialize, add your signature, serialize, and pass the bytes on. Never recompile the message: a changed message invalidates every signature already present, including a signature added by LI.FI.

```typescript Sponsor signing service (sketch) theme={"system"}
import { Keypair, VersionedTransaction } from '@solana/web3.js'

export function sponsorSign(base64Tx: string, sponsor: Keypair): string {
  const tx = VersionedTransaction.deserialize(Buffer.from(base64Tx, 'base64'))

  // Refuse anything where your sponsor is not the fee payer
  if (!tx.message.staticAccountKeys[0].equals(sponsor.publicKey)) {
    throw new Error('Sponsor is not the fee payer')
  }

  tx.sign([sponsor]) // fills the sponsor's slot, keeps the other signatures
  return Buffer.from(tx.serialize()).toString('base64')
}
```

A sponsor signing service pays for every transaction it signs. Sign only transactions your own backend requested from LI.FI for a user you serve, and check the fee payer before signing.

### Signing window

The transaction carries a recent blockhash from when LI.FI built it. Solana rejects a transaction whose blockhash is more than 150 blocks old, which the [Solana documentation](https://solana.com/developers/cookbook/transactions/confirmation) puts at about 60 to 90 seconds. Collect both signatures and submit inside that window. If it expires, request the quote or the stepTransaction again and sign the new transaction. Keep the sponsor signing step fast and automatic.

***

## What the sponsor pays

| Cost | Who pays |
| - | - |
| Transaction base fee (5,000 lamports per signature) | The sponsor, as fee payer. Solana charges the whole base fee to the fee payer. |
| Priority fee, set by `svmPriorityFeeLevel` | The sponsor, as fee payer. |
| Rent for accounts the route creates, such as the recipient's token account | The sponsor, where the route lets it fund the account. |
| Pump volume account deposit on routes that call Pump directly | The sponsor. Pump requires the user to pay for this account, so LI.FI adds a SOL transfer from the sponsor to the user for exactly that amount. It appears in `estimate.feeCosts` as `Pump Volume Account Deposit`. |
| LI.FI fees, integrator fees, bridge and relayer fees | The user, in the input token, as on any route. They are itemized in `estimate.feeCosts`. |

`estimate.gasCosts` gives the SOL cost of sending the transaction. Use it, together with `estimate.feeCosts`, to meter what each user costs you. Both are estimates from when the transaction was built.

***

## Bridges from Solana

When `svmSponsor` is set and the input token is not native SOL, routing keeps only bridges from Solana that support a separate fee payer. At the time of writing these are `relaydepository`, `across`, `gasZipBridge`, `unit`, `near`, `mayanFastMCTP`, `layerswap`, `lifiIntents` and `cctp`. The list changes as bridges add support.

To see why a bridge was dropped for your request, inspect `unavailableRoutes.filteredOut[].reason` in the routes response. A dropped bridge has a reason like this:

```
Bridge mayan from Solana is not supported when gasless transactions (svmSponsor) are requested. Only relaydepository, across, gasZipBridge, unit, near, mayanFastMCTP, layerswap, lifiIntents, cctp support gasless transactions.
```

Do not parse the reason text programmatically. A bridge on the list is eligible, not guaranteed: it still has to support the token pair and amount.

Same-chain Solana swaps are not filtered: LI.FI treats every Solana exchange it routes through as able to take a separate fee payer.

***

## Native SOL input

When the input token is native SOL, routing does not apply the bridge filter above. The user already holds SOL, and the route can use bridges that do not support a separate fee payer, such as `mayan` or `chainflip`.

For a flow where the user holds no SOL, use an SPL token such as USDC as the input. When native SOL is the output token, the sponsor is still the fee payer.

***

## SDK

Set the sponsor once in `createConfig`:

```typescript theme={"system"}
import { createConfig } from '@lifi/sdk'

createConfig({
  integrator: 'your-integrator-name',
  routeOptions: {
    svmSponsor: '<SPONSOR_PUBKEY>',
  },
})
```

The SDK merges `routeOptions` into `getRoutes`. `getStepTransaction`, which `executeRoute` uses, reads `svmSponsor` only from this config and adds it to the stepTransaction request for Solana steps. If you pass `svmSponsor` only in the options of one `getRoutes` call, routing filters for the sponsor, but the transaction you execute is built with the user as fee payer. For `getQuote`, pass `svmSponsor` as a request parameter.

When `executeRoute` runs a Solana step, it sends the transaction to the wallet from your `SolanaProvider`'s `getWallet`. It expects the transaction back with the fee payer's signature in it. With a sponsor, the user's wallet alone cannot provide that. Give the provider a wallet whose `signTransaction` also gets the sponsor's signature, for example from your sponsor signing service, before it returns the transaction.

***

## Limits to plan for

> [accordion] No sponsor balance check at quote time
>
> LI.FI does not check the sponsor's balance when it builds the transaction. A sponsor with 0 SOL still gets a quote. The failure comes at submission. Monitor the sponsor account and top it up before it runs low.

> [accordion] The fee payer is decided per request
>
> Each transaction is built for the sponsor named in that request. A routes request with the sponsor and a stepTransaction request without it give a user-paid transaction. Check the fee payer of every transaction before you sign it.

> [accordion] Solana origin only
>
> `svmSponsor` affects only transactions that start on Solana. A transfer from another chain to Solana is sent on the source chain and is not affected.

> [accordion] Exchange behavior can change
>
> Sponsorship depends on how each exchange and bridge builds its instructions. If a sponsored transaction behaves unexpectedly, for example the user's SOL balance changes, report it to LI.FI with the transaction signature.

***

## Next steps

> [card] [Gas Options](https://docs.li.fi/guides/gas-options.md)
>
> Every gas mechanism, and who pays for each.

> [card] [Solana Ecosystem](https://docs.li.fi/introduction/solana-ecosystem.md)
>
> Bridges, exchanges and features available on Solana.

> [card] [Gas and fee costs](https://docs.li.fi/guides/gas-and-fee-costs.md)
>
> How to read `gasCosts` and `feeCosts` in a quote.

> [card] [Status tracking](https://docs.li.fi/introduction/user-flows-and-examples/status-tracking.md)
>
> Following a transfer after you submit it.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.