Skip to main content

Gas Sponsorship with Paymaster

Learn how to sponsor gas fees for UserOperations using Candide's Paymaster InstaGas, with both public and private gas policies.

If you need help with the basics of smart accounts, start with the Getting Started Guide.

Getting Started

Setup Gas Policy

If you want to create your own private gas policy to sponsor specific transactions:

  1. Create an account on the Candide Dashboard
  2. Navigate to Gas Policies and create a new private policy
  3. Configure sponsorship rules - Set rules and conditions for which transactions to sponsor
  4. Fund your policy - Deposit Native Tokens to cover the gas costs
  5. Copy the Policy ID - You'll need this to reference your policy

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

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

You can also fork the complete code and follow along.

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
[paymasterUserOperation, sponsorMetadata] =
await paymaster.createSponsorPaymasterUserOperation(
userOperation,
bundlerUrl
);
console.log("Sponsored by public gas policy!");
} catch (error) {
try {
// Fallback to private gas policy
[paymasterUserOperation, sponsorMetadata] =
await paymaster.createSponsorPaymasterUserOperation(
userOperation,
bundlerUrl,
sponsorshipPolicyId
);
console.log("Sponsored by your private gas policy!");
} catch (finalError) {
console.log("No gas sponsorship available");
throw finalError;
}
}

userOperation = paymasterUserOperation;

Complete Runnable Example

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

Full Working Example
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...")
[paymasterUserOperation, sponsorMetadata] =
await paymaster.createSponsorPaymasterUserOperation(
userOperation,
bundlerUrl
);
console.log("✅ Sponsored by public gas policy!")

} catch (error) {
try {
// Fallback to private gas policy
console.log("🔍 Trying private gas policy fallback...")
[paymasterUserOperation, sponsorMetadata] =
await paymaster.createSponsorPaymasterUserOperation(
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)

Gas Policies Overview

Candide's Paymaster supports two types of gas policies:

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

  • 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