Sponsor Gas

Gas fees are a significant barrier to entry for new user of your app. With Account Kit you can remove this barrier by sponsoring gas fees for transactions via the Gas Manager. This guide explains how to sponsor gas by creating a gas policy, linking it to your client, and sending sponsored UserOperations (UOs) from a smart account.

After setting up Account Kit in your project, follow these steps to sponsor gas.

Create a Gas Manager policy

A gas manager policy is a set of rules that define which UOs are eligible for gas sponsorship. You can control which operations are eligible for sponsorship by defining rules:

  • Spending rules: limit the amount of money or the number of user ops that can be sponsored by this policy
  • Allowlist: restrict wallet addresses that are eligible for sponsorship. The policy will only sponsor gas for UOs that were sent by addresses on this list.
  • Blocklist: ban certain addresses from receiving sponsorship under this policy
  • Policy duration: define the duration of your policy and the sponsorship expiry period. This is the period for which the Gas Manager signature (paymaster data) will remain valid once it is generated.

To learn more about policy configuration, refer to the guide on setting up a gas manager policy.

Once you have decided on policy rules for your app, create a policy in the Gas Manager dashboard.

Now you should have a Gas policy created with a policy id you can use to sponsor gas for your users.

Policy ID

Set the Policy ID globally

When creating your Account Kit config, you can optionally pass in a Gas Policy ID. This will enable all UOs sent by the sendUserOperation method to be sponsored by the policy you created.

Policy ID

Copy it and then replace the GAS_MANAGER_POLICY_ID in the snippet below.

Remember to replace ALCHEMY_API_KEY with your Alchemy API key. If you don’t have one yet, you can create an API key on the Alchemy dashboard.

import { 
const createConfig: (params: CreateConfigProps) => AlchemyAccountsConfig

Creates an AlchemyAccountsConfig object that can be used in conjunction with the actions exported from @account-kit/core.

The config contains core and client stores that can be used to manage account state in your application.

createConfig
} from "@account-kit/core";
import {
const sepolia: Chain
sepolia
,
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.

alchemy
} from "@account-kit/infra";
export const
const config: AlchemyAccountsConfig
config
=
function createConfig(params: CreateConfigProps): AlchemyAccountsConfig

Creates an AlchemyAccountsConfig object that can be used in conjunction with the actions exported from @account-kit/core.

The config contains core and client stores that can be used to manage account state in your application.

createConfig
({
transport: AlchemyTransport
transport
:
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.

alchemy
({
apiKey: string
apiKey
: "ALCHEMY_API_KEY" }),
chain: Chain
chain
:
const sepolia: Chain
sepolia
,
policyId?: string | string[] | undefined
policyId
: "GAS_MANAGER_POLICY_ID",
});

Now you can follow the guide for Sending user operations to send sponsored UOs from your smart account!

Set the gas policy ID per Client

If you want more control over which UOs are sponsored, then you can set the policy ID on a specific instance of the Smart Account Client returned by the watchSmartAccountClient function.

import { 
function watchSmartAccountClient<TAccount extends SupportedAccountTypes, TChain extends Chain | undefined = Chain | undefined>(params: GetSmartAccountClientParams<TChain, TAccount>, config: AlchemyAccountsConfig): (onChange: (client: GetSmartAccountClientResult<TChain, SupportedAccount<TAccount>>) => void) => () => void

Watches for changes to the smart account client and triggers the provided callback when a change is detected.

watchSmartAccountClient
} from "@account-kit/core";
import {
import config
config
} from "./config";
// How you actually store this state variable // depends on the framework you're using let
let clientState: any
clientState
;
// The watch smart account client will handle all of the possible state changes // that can impact this client: // - Signer status // - Account instantiation // - Chain changes const
const clientSubscription: () => void
clientSubscription
=
watchSmartAccountClient<"LightAccount", Chain | undefined>(params: GetSmartAccountClientParams<Chain | undefined, "LightAccount">, config: AlchemyAccountsConfig): (onChange: (client: GetSmartAccountClientResult<...>) => void) => () => void

Watches for changes to the smart account client and triggers the provided callback when a change is detected.

watchSmartAccountClient
(
{
type: "LightAccount"
type
: "LightAccount",
policyId?: string | string[] | undefined
policyId
: "GAS_MANAGER_POLICY_ID",
},
import config
config
,
)((
clientState_: GetSmartAccountClientResult<Chain | undefined, LightAccount<AlchemySigner>>
clientState_
) => {
let clientState: any
clientState
=
clientState_: GetSmartAccountClientResult<Chain | undefined, LightAccount<AlchemySigner>>
clientState_
;
}); // .. do stuff with the client state
import { 
const createConfig: (params: CreateConfigProps) => AlchemyAccountsConfig

Creates an AlchemyAccountsConfig object that can be used in conjunction with the actions exported from @account-kit/core.

The config contains core and client stores that can be used to manage account state in your application.

createConfig
} from "@account-kit/core";
import {
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.

alchemy
,
const sepolia: Chain
sepolia
} from "@account-kit/infra";
export const
const config: AlchemyAccountsConfig
config
=
function createConfig(params: CreateConfigProps): AlchemyAccountsConfig

Creates an AlchemyAccountsConfig object that can be used in conjunction with the actions exported from @account-kit/core.

The config contains core and client stores that can be used to manage account state in your application.

createConfig
({
transport: AlchemyTransport
transport
:
function alchemy(config: AlchemyTransportConfig): AlchemyTransport

Creates an Alchemy transport with the specified configuration options. When sending all traffic to Alchemy, you must pass in one of rpcUrl, apiKey, or jwt. If you want to send Bundler and Paymaster traffic to Alchemy and Node traffic to a different RPC, you must pass in alchemyConnection and nodeRpcUrl.

alchemy
({
apiKey: string
apiKey
: "YOUR_API_KEY" }),
chain: Chain
chain
:
const sepolia: Chain
sepolia
,
// optional if you want to sponsor gas
policyId?: string | string[] | undefined
policyId
: "YOUR_POLICY_ID",
});

This client is now configured to sponsor gas using your gas policy. You can now send sponsored UOs from this client using the sendUserOperation method.