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:
- Create an account on the Candide Dashboard
- Navigate to Gas Policies and create a new private policy
- Configure sponsorship rules - Set rules and conditions for which transactions to sponsor
- Fund your policy - Deposit Native Tokens to cover the gas costs
- 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.
- 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
[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;
# 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
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...")
[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)
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
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