# Sponsor Gas on Solana (/smart-accounts/sponsor-gas/solana)

> For the complete documentation index, see [llms.txt](/llms.txt)



## How Solana fee sponsorship works [#how-solana-fee-sponsorship-works]

Unlike EVM chains, Solana doesn't need ERC-4337 or paymasters for fee sponsorship. Every Solana transaction has a **fee payer** field that can be set to any account — it doesn't have to be the same account that initiates the transaction. ZeroDev takes advantage of this by setting the fee payer to a ZeroDev-managed wallet that covers two types of costs:

* **Transaction fees** — the cost of including and executing the transaction on the network.
* **Rent** — the minimum SOL deposit required to create new accounts or token accounts on-chain (e.g. when calling `createAccount` or `createAssociatedTokenAccount`).

Your users sign the transaction normally, and ZeroDev's sponsorship server co-signs as the fee payer and broadcasts the transaction — all in a single step.

<Callout type="info">
  Solana doesn't have a notion of chain ID, but we use sentinel values for consistency in our RPC endpoints. Currently supported networks:

  * **Solana mainnet** — `9034109930`
  * **Solana devnet** — `9034109931`
</Callout>

## Paying for sponsored gas [#paying-for-sponsored-gas]

When you sponsor gas through ZeroDev, there are two ways to pay for the gas:

* Put down your credit card. We front the gas for your users, and then at the end of the billing cycle (once a month) we charge your credit card.

* Buy gas credits from us.

## Setting up gas sponsoring policies [#setting-up-gas-sponsoring-policies]

To avoid over-spending on sponsoring, you must set up gas-sponsoring policies. Sign up on the [ZeroDev dashboard](https://dashboard.zerodev.app/) if you haven't already, then [set up gas policies](/api-and-toolings/infrastructure/gas-policies).

Note that you MUST set up a gas policy to begin sponsoring. Without setting up a gas policy, there won't be any gas sponsored.

## Installation [#installation]

Install the ZeroDev Solana sponsorship SDK along with its peer dependencies:

<Tabs items="[&#x22;npm&#x22;,&#x22;yarn&#x22;,&#x22;pnpm&#x22;,&#x22;bun&#x22;]">
  <Tab value="npm">
    ```bash
    npm i @zerodev/solana-sponsorship-sdk @solana/kit @solana-program/system
    ```
  </Tab>

  <Tab value="yarn">
    ```bash
    yarn add @zerodev/solana-sponsorship-sdk @solana/kit @solana-program/system
    ```
  </Tab>

  <Tab value="pnpm">
    ```bash
    pnpm add @zerodev/solana-sponsorship-sdk @solana/kit @solana-program/system
    ```
  </Tab>

  <Tab value="bun">
    ```bash
    bun add @zerodev/solana-sponsorship-sdk @solana/kit @solana-program/system
    ```
  </Tab>
</Tabs>

## Quick Start [#quick-start]

<div className="fd-steps">
  <div className="fd-step">
    ### Get your RPC endpoint [#get-your-rpc-endpoint]

    Go to the [ZeroDev dashboard](https://dashboard.zerodev.app/) and create a Solana project. Copy the RPC endpoint for the correct Solana network (mainnet or devnet), e.g. `https://rpc.zerodev.app/api/v3/svm/YOUR_PROJECT_ID/chain/9034109930`.
  </div>

  <div className="fd-step">
    ### Create the sponsorship and Solana RPC clients [#create-the-sponsorship-and-solana-rpc-clients]

    Get a Solana RPC URL from a provider like [Alchemy](https://www.alchemy.com/) or [Helius](https://www.helius.dev/), or use the public endpoint `https://api.mainnet-beta.solana.com` (restrictively rate-limited and not advisable for production).

    ```typescript
    import { createSolanaRpc, mainnet } from "@solana/kit";
    import { createSponsorshipRpc } from "@zerodev/solana-sponsorship-sdk";

    const sponsorshipRpc = createSponsorshipRpc({
      endpoint: "https://rpc.zerodev.app/api/v3/svm/YOUR_PROJECT_ID/chain/9034109930",
    });

    const solanaRpc = createSolanaRpc(mainnet("YOUR_SOLANA_RPC_URL"));
    ```
  </div>

  <div className="fd-step">
    ### Get a recent blockhash [#get-a-recent-blockhash]

    ```typescript
    const { value: { blockhash: recentBlockhash, lastValidBlockHeight } } =
      await solanaRpc.getLatestBlockhash({ commitment: "finalized" }).send();
    ```
  </div>

  <div className="fd-step">
    ### Create your transaction instruction(s) [#create-your-transaction-instructions]

    This can be any Solana instruction. Here we use a simple SOL transfer as an example:

    ```typescript
    import { lamports } from "@solana/kit";
    import { getTransferSolInstruction } from "@solana-program/system";

    const transferInstruction = getTransferSolInstruction({
      source: userKeypair,          // your user's keypair signer
      destination: toAddress,       // destination address
      amount: lamports(1_000_000n), // 0.001 SOL
    });
    ```
  </div>

  <div className="fd-step">
    ### Get the sponsor fee payer and build the transaction [#get-the-sponsor-fee-payer-and-build-the-transaction]

    Fetch ZeroDev's fee payer address and set it as the transaction's fee payer. We use a `NoopSigner` as a placeholder because the fee payer's private key lives on ZeroDev's server, not the client. The real fee payer signature is added server-side when you call `sponsorTransaction` in the next step.

    ```typescript
    import {
      createTransactionMessage,
      pipe,
      setTransactionMessageLifetimeUsingBlockhash,
      address,
      blockhash,
      appendTransactionMessageInstructions,
      setTransactionMessageFeePayerSigner,
      createNoopSigner,
    } from "@solana/kit";

    const feePayer = await sponsorshipRpc.getFeePayer().send();

    const message = pipe(
      createTransactionMessage({ version: "legacy" }),
      (msg) => setTransactionMessageFeePayerSigner(createNoopSigner(address(feePayer)), msg),
      (msg) => appendTransactionMessageInstructions([transferInstruction], msg),
      (msg) => setTransactionMessageLifetimeUsingBlockhash(
        { blockhash: blockhash(recentBlockhash), lastValidBlockHeight },
        msg
      ),
    );
    ```
  </div>

  <div className="fd-step">
    ### Sign and sponsor the transaction [#sign-and-sponsor-the-transaction]

    The user signs the transaction, then ZeroDev co-signs as the fee payer and broadcasts it to the network:

    ```typescript
    import { partiallySignTransactionMessageWithSigners } from "@solana/kit";
    import { sponsorTransaction } from "@zerodev/solana-sponsorship-sdk";

    const signedMessage = await partiallySignTransactionMessageWithSigners(message);
    const response = await sponsorTransaction(sponsorshipRpc, signedMessage);

    console.log(`Transaction sponsored: https://explorer.solana.com/tx/${response.signature}`);
    ```
  </div>
</div>

## Using with external wallets [#using-with-external-wallets]

If your users sign with an external wallet provider, replace step 6 above: compile the transaction to bytes, sign with the wallet, then decode the signed bytes back for sponsorship.

### Privy [#privy]

```typescript
import { compileTransaction, getTransactionEncoder, getTransactionDecoder } from "@solana/kit";
import { sponsorTransaction } from "@zerodev/solana-sponsorship-sdk";
import { useSignTransaction } from "@privy-io/react-auth/solana";

const { signTransaction } = useSignTransaction();

// Build the transaction message with pipe() as shown in steps 2–5, then:
const unsignedTx = compileTransaction(message);
const encoded = new Uint8Array(getTransactionEncoder().encode(unsignedTx));

const { signedTransaction } = await signTransaction({ transaction: encoded, wallet });
const decoded = getTransactionDecoder().decode(signedTransaction);
const result = await sponsorTransaction(sponsorshipRpc, decoded);
```

### Dynamic [#dynamic]

```typescript
import { compileTransaction, getTransactionEncoder, getTransactionDecoder } from "@solana/kit";
import { sponsorTransaction } from "@zerodev/solana-sponsorship-sdk";
import { isSolanaWallet } from "@dynamic-labs/solana";
import { useDynamicContext } from "@dynamic-labs/sdk-react-core";

const { primaryWallet } = useDynamicContext();
if (!primaryWallet || !isSolanaWallet(primaryWallet)) throw new Error("No Solana wallet");

// Build the transaction message with pipe() as shown in steps 2–5, then:
const unsignedTx = compileTransaction(message);
const encoded = new Uint8Array(getTransactionEncoder().encode(unsignedTx));

const { VersionedTransaction } = await import("@solana/web3.js");
const signer = await primaryWallet.getSigner();
const versionedTx = VersionedTransaction.deserialize(encoded);
const signedTx = await (signer.signTransaction as any)(versionedTx);

const decoded = getTransactionDecoder().decode((signedTx as any).serialize());
const result = await sponsorTransaction(sponsorshipRpc, decoded);
```

## Error Handling [#error-handling]

If sponsorship fails (e.g., you've hit a policy limit), the SDK throws a `SponsorshipError`:

```typescript
import { sponsorTransaction, SponsorshipError } from "@zerodev/solana-sponsorship-sdk";

try {
  const response = await sponsorTransaction(sponsorshipRpc, signedMessage);
} catch (error) {
  if (error instanceof SponsorshipError) {
    console.error(`Sponsorship failed (code ${error.code}): ${error.message}`);
  }
}
```
