# Gas Sponsorship with Paymaster

Sponsor gas fees for UserOperations using Candide's Paymaster [InstaGas](https://docs.candide.dev/instagas/overview.md) with public and private gas policies.

> For smart account basics, see the [Getting Started Guide](https://docs.candide.dev/wallet/guides/getting-started.md).

![](/img/gasless-transaction-screen.png)

## Getting Started[​](#getting-started "Direct link to Getting Started")

### Setup Gas Policy[​](#setup-gas-policy "Direct link to Setup Gas Policy")

To create a private gas policy for sponsoring specific transactions:

1. Create an account on the [Candide Dashboard](https://dashboard.candide.dev)
2. Navigate to Gas Policies and create a new private policy
3. Configure sponsorship [rules and conditions](https://docs.candide.dev/instagas/gas-policies.md) for transaction sponsorship
4. Fund your policy by depositing native tokens to cover gas costs
5. Copy the Policy ID for referencing your policy

#### Environment Configuration[​](#environment-configuration "Direct link to Environment Configuration")

Add the paymaster configuration to your `.env`:

.env

```
# Paymaster service endpoint

PAYMASTER_RPC=https://api.candide.dev/public/v3/sepolia



# Optional: Your private gas policy ID (if you created one)

SPONSORSHIP_POLICY_ID=
```

### Getting Paymaster Data[​](#getting-paymaster-data "Direct link to Getting Paymaster Data")

Try public policies first, then fallback to private if no public policy matches

> You can also [fork the complete code](https://github.com/candidelabs/abstractionkit-examples/blob/main/sponsor-gas/sponsor-gas.ts) and follow along.

* index.ts
* .env

Public first, private fallback

```
import { CandidePaymaster } from "abstractionkit";



const paymasterRPC = process.env.PAYMASTER_RPC as string;

const paymaster = new CandidePaymaster(paymasterRPC);

const sponsorshipPolicyId = process.env.SPONSORSHIP_POLICY_ID;



let paymasterUserOperation;

let sponsorMetadata;



try {

  // First, try public gas policies

  ({ userOperation: paymasterUserOperation, sponsorMetadata } =

    await paymaster.createSponsorPaymasterUserOperation(

      smartAccount,

      userOperation,

      bundlerUrl

    ));

  console.log("Sponsored by public gas policy!");

} catch (error) {

  try {

    // Fallback to private gas policy

    ({ userOperation: paymasterUserOperation, sponsorMetadata } =

      await paymaster.createSponsorPaymasterUserOperation(

        smartAccount,

        userOperation,

        bundlerUrl,

        sponsorshipPolicyId

      ));

    console.log("Sponsored by your private gas policy!");

  } catch (finalError) {

    console.log("No gas sponsorship available");

    throw finalError;

  }

}



userOperation = paymasterUserOperation;
```

```
# Paymaster service endpoint

PAYMASTER_RPC=https://api.candide.dev/public/v3/sepolia



# Optional: Your private gas policy ID (if you created one)

SPONSORSHIP_POLICY_ID=
```

#### Complete Runnable Example[​](#complete-runnable-example "Direct link to Complete Runnable Example")

Below is a complete example that demonstrates gas sponsorship with public and private policy fallback:

Full Working Example

* index.ts
* .env

```
import * as dotenv from 'dotenv'



import {

    SafeAccountV0_3_0 as SafeAccount,

    MetaTransaction,

    CandidePaymaster,

    getFunctionSelector,

    createCallData,

} from "abstractionkit";



async function main(): Promise<void> {

    // Load environment variables

    dotenv.config()

    const chainId = BigInt(process.env.CHAIN_ID as string)

    const bundlerUrl = process.env.BUNDLER_URL as string

    const jsonRpcNodeProvider = process.env.JSON_RPC_NODE_PROVIDER as string

    const paymasterRPC = process.env.PAYMASTER_RPC as string

    const sponsorshipPolicyId = process.env.SPONSORSHIP_POLICY_ID

    const ownerPublicAddress = process.env.PUBLIC_ADDRESS as string

    const ownerPrivateKey = process.env.PRIVATE_KEY as string

    

    // Create smart account

    let smartAccount = SafeAccount.initializeNewAccount([ownerPublicAddress])

    console.log("Smart Account Address:", smartAccount.accountAddress)



    // Create example transactions (minting NFTs)

    const nftContractAddress = "0x9a7af758aE5d7B6aAE84fe4C5Ba67c041dFE5336";

    const mintFunctionSignature = 'mint(address)';

    const mintFunctionSelector = getFunctionSelector(mintFunctionSignature);

    const mintTransactionCallData = createCallData(

        mintFunctionSelector, 

        ["address"],

        [smartAccount.accountAddress]

    );

    

    const transaction1: MetaTransaction = {

        to: nftContractAddress,

        value: 0n,

        data: mintTransactionCallData,

    }



    const transaction2: MetaTransaction = {

        to: nftContractAddress,

        value: 0n,

        data: mintTransactionCallData,

    }



    // Create UserOperation

    let userOperation = await smartAccount.createUserOperation(

        [transaction1, transaction2],

        jsonRpcNodeProvider,

        bundlerUrl

    )



    // Add paymaster sponsorship - try public first, fallback to private

    const paymaster = new CandidePaymaster(paymasterRPC)

    

    let paymasterUserOperation;

    let sponsorMetadata;

    

    try {

        // Try public gas policies first

        console.log("🔍 Checking for public gas policies...")

        ({ userOperation: paymasterUserOperation, sponsorMetadata } =

            await paymaster.createSponsorPaymasterUserOperation(

                smartAccount,

                userOperation,

                bundlerUrl

            ));

        console.log("✅ Sponsored by public gas policy!")

        

    } catch (error) {

        try {

            // Fallback to private gas policy

            console.log("🔍 Trying private gas policy fallback...")

            ({ userOperation: paymasterUserOperation, sponsorMetadata } =

                await paymaster.createSponsorPaymasterUserOperation(

                    smartAccount,

                    userOperation,

                    bundlerUrl,

                    sponsorshipPolicyId

                ));

            console.log("✅ Sponsored by private gas policy!")

            

        } catch (finalError) {

            console.log("❌ No gas sponsorship available");

            throw finalError;

        }

    }

    

    userOperation = paymasterUserOperation;

    console.log("💰 Transaction will be gasless for the user!")



    // Sign the UserOperation

    userOperation.signature = smartAccount.signUserOperation(

        userOperation,

        [ownerPrivateKey],

        chainId

    )



    // Submit the sponsored UserOperation

    const sendUserOperationResponse = await smartAccount.sendUserOperation(

        userOperation, 

        bundlerUrl

    )



    console.log("📤 Sponsored UserOperation sent. Waiting for confirmation...")

    

    // Wait for transaction to be included

    let userOperationReceiptResult = await sendUserOperationResponse.included()



    console.log("📋 UserOperation receipt received.")

    console.log(userOperationReceiptResult)

    

    if (userOperationReceiptResult.success) {

        console.log("🎉 Gasless transaction successful! Hash:", userOperationReceiptResult.receipt.transactionHash)

    } else {

        console.log("❌ UserOperation execution failed")

    }

}



main().catch(console.error)
```

```
CHAIN_ID=11155111

BUNDLER_URL=https://api.candide.dev/public/v3/sepolia

JSON_RPC_NODE_PROVIDER=https://ethereum-sepolia-rpc.publicnode.com

PAYMASTER_RPC=https://api.candide.dev/public/v3/sepolia



# Optional: Your private gas policy ID

SPONSORSHIP_POLICY_ID=



# Your EOA credentials

PRIVATE_KEY=your_private_key_here

PUBLIC_ADDRESS=your_public_address_here
```

## Gas Policies Overview[​](#gas-policies-overview "Direct link to Gas Policies Overview")

Candide's Paymaster supports two types of gas policies:

### Public Gas Policies[​](#public-gas-policies "Direct link to Public Gas Policies")

* Set up by external applications - Apps like PoolTogether and Revoke.cash sponsor gas for their users
* Application-specific - Each policy targets specific contract interactions or user flows
* No setup required - Available automatically when your UserOperation matches their criteria
* Best for - Users interacting with supported dApps and protocols

### Private Gas Policies[​](#private-gas-policies "Direct link to Private Gas Policies")

* Your custom rules - You create and fund policies for your specific application
* Full control - Set custom sponsorship conditions, limits, and restrictions
* Your funding - You deposit native tokens to sponsor transactions that match your criteria
* Best for - Wallets wanting to sponsor their users' transactions
