How to conditionally sponsor a user operation
With permissionless.js and Viem, you can conditionally sponsor a user operation. This can be useful in situations like:
- Sponsor only first 10 transactions
- Sponsor if they have a specific NFT
Let's take an example where you want to sponsor only the first 10 transactions.
Create the clients
First we must create the public, (optionally) pimlico paymaster clients that will be used to interact with the SimpleAccount.
import { createPublicClient, Hex, http, zeroAddress } from "viem"
import { decodeNonce } from "permissionless/utils"
import { createPimlicoClient } from "permissionless/clients/pimlico"
import { entryPoint07Address } from "viem/account-abstraction"
const publicClient = createPublicClient({
chain: sepolia,
transport: http("https://sepolia.rpc.thirdweb.com"),
})
const pimlicoUrl = `https://api.pimlico.io/v2/sepolia/rpc?apikey=${apiKey}`
const pimlicoClient = createPimlicoClient({
transport: http(pimlicoUrl),
entryPoint: {
address: entryPoint07Address,
version: "0.7",
},
})
Create an account
Now, create an account. This can any of the accounts supported by permissionless.js or custom accounts conforming to the interface.
import { toSimpleSmartAccount } from "permissionless/accounts"
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"
export const simpleSmartAccount = await toSimpleSmartAccount({
client: publicClient,
owner: privateKeyToAccount(generatePrivateKey()),
entryPoint: {
address: entryPoint07Address,
version: "0.7",
},
})
Create the smart account client with the custom paymaster logic
We can sponsor a user operation conditionally by setting the paymaster field in sendTransaction only when the sponsorship conditions are met.
import { sepolia } from "viem/chains"
import { createSmartAccountClient } from "permissionless"
import { getAccountNonce } from "permissionless/actions"
const smartAccountClient = createSmartAccountClient({
client: publicClient,
account: simpleSmartAccount,
chain: sepolia,
bundlerTransport: http(pimlicoUrl),
userOperation: {
estimateFeesPerGas: async () => {
return (await pimlicoClient.getUserOperationGasPrice()).fast
},
},
})
// Only sponsor userOps with nonce sequence < 10
const nonce = await getAccountNonce(publicClient, {
address: simpleSmartAccount.address,
entryPointAddress: entryPoint07Address,
})
const { sequence } = decodeNonce(nonce)
let txHash: Hex
if (sequence < 10) {
txHash = await smartAccountClient.sendTransaction({
calls: [
{
to: zeroAddress,
value: 0n,
data: "0x",
},
],
paymaster: pimlicoClient
});
} else {
txHash = await smartAccountClient.sendTransaction({
calls: [
{
to: zeroAddress,
value: 0n,
data: "0x",
},
]
});
}