← Blog
August 30, 2026 · 14 min

Who pays your agent's gas? An on-chain audit of Circle Paymaster

An agent that holds only stablecoins still needs gas to move. There are two ways to solve that, and they hand the fee decision to two very different parties. We measured one of them for twenty-four hours across seven chains.

The x402 path is the one we have written about most: the payer signs an EIP-3009 authorization, the facilitator submits the transaction and eats the gas. The agent never holds a native token. We covered that primitive in gasless stablecoin settlement.

The other path is what an agent needs the moment it wants to do anything that is not an x402 payment — approve a router, top up a channel, deploy its own account, move funds between its own addresses. For those, somebody has to pay gas in the chain's native token, and an agent funded in USDC does not have one.

Circle Paymaster is the permissionless answer: an ERC-4337 paymaster contract that pays the network fee out of its own deposit and charges the smart account in USDC. No API key, no Circle account, no off-chain dependency. For an agent wallet, that is exactly the shape you want.

It also moves the fee decision inside the payload the agent signs. So we audited it: every mainnet deployment, and then a full day of real traffic.

What the contract is

Circle publishes two deployments. Paymaster v0.7 (0x6C973eBe80dCD8660841D4356bf15c32460271C9) serves EntryPoint v0.7 on Arbitrum and Base. Paymaster v0.8 (0x0578cFB241215b77442a541325d6A4E6dFE700Ec) serves EntryPoint v0.8 on Arbitrum, Avalanche, Base, Ethereum, Optimism, Polygon and Unichain. The addresses and the event schema are documented on the addresses and events page.

We checked the deployments rather than trusting the table. On all seven mainnets the v0.8 address holds the same 141-byte proxy runtime, byte for byte — a minimal ERC-1967 proxy reading the standard implementation slot. Each chain points at its own 16,671-byte implementation; the code length is identical everywhere and only the immutables differ, which is what you expect from one compiled contract deployed with per-chain constants. The v0.7 proxy is 144 bytes over a 16,886-byte implementation.

Calling through the proxy, entryPoint() returns 0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108 and token() returns the canonical USDC of the chain. On Base, getDepositInfo reports the paymaster as staked with 0.25 ETH and an unstake delay of 86,400 seconds — the ERC-4337 reputation stake, not the gas budget. The gas budget is the deposit, and the deposit is where this audit gets interesting.

The charging model is a permit plus a prefund plus a refund. Per the quickstart, the account signs an EIP-2612 permit granting the paymaster an allowance, and packs it into paymasterData:

// Circle Paymaster quickstart, getPaymasterData()
const permitAmount = 10000000n;  // 10 USDC

const paymasterData = encodePacked(
  ["uint8", "address", "uint256", "bytes"],
  [0, usdcAddress, permitAmount, permitSignature],
);

The permit's deadline is MAX_UINT256, and the quickstart says why: "The paymaster cannot access block.timestamp due to 4337 opcode restrictions, so the deadline must be MAX_UINT256." The allowance an agent signs here does not expire. Its only bound is the value.

At validation the paymaster pulls a prefund from the account. After execution, _postOp refunds the surplus and emits UserOperationSponsored with the token, the sender, the user-op hash, nativeTokenPrice (token units per 1e18 wei), actualTokenNeeded and feeTokenAmount. We verified the identity on a live operation: sender 0xf68da023… transferred 0.065317 USDC in, received 0.046015 USDC back, and the event reported actualTokenNeeded = 0.019302 USDC. Prefund minus refund equals the charge, exactly.

Method

We collected every UserOperationSponsored event from both paymasters over a 24-hour window, 2026-08-29 09:06:47Z to 2026-08-30 09:06:47Z (Base blocks 50602530 to 50645730; the other chains are aligned to within minutes). For the same block ranges we collected the EntryPoint's own UserOperationEvent filtered on the paymaster — the indexed third topic — which gives actualGasCost and actualGasUsed per operation. We then pulled every bundle transaction receipt to get what the transaction actually cost to include, L1 data fee included.

Nine surfaces, 4,853 sponsored operations, zero failures. Public RPCs throughout; prices cross-checked against Coinbase and Kraken spot at measurement time.

chain / entrypoint    ops    USDC charged   native billed     charged/billed
base       v0.8       643      35,765.92    16.910122 ETH        0.861
base       v0.7       528      24,544.60    11.445303 ETH        0.873
arbitrum   v0.8       672      34,238.55    16.207886 ETH        0.860
arbitrum   v0.7       520      16,931.46     8.342903 ETH        0.826
ethereum   v0.8       597      33,540.57    15.876323 ETH        0.860
optimism   v0.8       623      34,080.19    16.096663 ETH        0.862
polygon    v0.8       709      12,420.68   138,220.93 POL        0.867
avalanche  v0.8       440       7,788.70     1,249.11 AVAX       0.855
unichain   v0.8       121       2,996.24     1.415386 ETH        0.862
                    -----   ------------                        ------
total               4,853     202,306.90                         0.859

The quoted price is honest. On Base the paymaster's average nativeTokenPrice over the window was 2,456.46 USDC per ETH against a Coinbase spot of 2,456.93 and a Kraken last of 2,456.78 — a gap of two hundredths of a percent. AVAX was quoted at 7.2948 against 7.3425 spot, POL at 0.10368 against 0.10343. Whatever else is happening here, nobody is marking up the oracle.

Finding 1 — the price of gas is set by the user operation

Divide actualGasCost by actualGasUsed and you get the gas price each operation actually paid. On Base that average is 224.6 gwei. The median base fee on Base during the same window was 0.005 gwei.

The same pattern holds everywhere: 253.0 gwei on Ethereum against a 0.0448 gwei base fee, 237.9 gwei on Arbitrum against 0.0200, 1,915,500 gwei on Polygon against 248.8, 27,551 gwei on Avalanche against 0.0513.

The cleanest way to state it is at the transaction level, because it needs no assumptions about L1 data costs. For every bundle in the window we summed what the EntryPoint billed the paymaster and what the transaction cost to include:

chain / entrypoint   bundles   billed          real tx cost      multiple
base       v0.8          51    16.910122 ETH   0.00923899 ETH     1,830x
base       v0.7          45    11.445303 ETH   0.00807076 ETH     1,418x
arbitrum   v0.8          41    16.207886 ETH   0.00403213 ETH     4,020x
arbitrum   v0.7          19     8.342903 ETH   0.00192193 ETH     4,341x
ethereum   v0.8          30    15.876323 ETH   0.05830830 ETH       272x
optimism   v0.8          28    16.096663 ETH   0.00927545 ETH     1,735x
polygon    v0.8          16   138,220.93 POL     750.56 POL          184x
avalanche  v0.8          16     1,249.11 AVAX      7.65 AVAX         163x
unichain   v0.8           7     1.415386 ETH   0.00065332 ETH     2,166x

Across all nine surfaces: 202,307 USDC charged to smart accounts, against 358.43 dollars of real chain fees. A factor of 564.

This is not a bug in the paymaster. It is ERC-4337 working as designed. The gas price an operation pays is min(maxFeePerGas, maxPriorityFeePerGas + baseFee), and those fields live inside the user operation. Whoever assembles the operation sets the price; the difference between that price and the block's price is collected by the bundler as the beneficiary of handleOps. When the fee is denominated in the account's USDC, that difference is denominated in the account's USDC too.

The practical shape of the risk — for an agent, the gas channel is a second spending path with a different signer, a different unit, and no cap of its own. The account signs a permit; the operation declares the price; the bundler collects the spread.

Finding 2 — the account is charged 0.86 of what the EntryPoint bills

The ratio between what the account pays in USDC and the value of what the EntryPoint bills, at the paymaster's own quoted price, sits in a narrow band: 0.826 to 0.873 across nine surfaces, 0.859 in aggregate. It is remarkably stable, which says it is mechanical rather than market-driven.

The mechanism is visible in the reference EntryPoint. In EntryPoint.sol, UNUSED_GAS_PENALTY_PERCENT = 10 and PENALTY_GAS_THRESHOLD = 40000: an operation that reserves far more execution gas or postOp gas than it uses is charged ten percent of the unused remainder. The paymaster's _postOp is invoked with the cost computed before the postOp gas and the postOp penalty are added, while the actualGasCost in the emitted event is recomputed after. The account is charged the earlier number. The paymaster's deposit pays the later one.

Two consequences follow. First, whoever writes fat gas limits into an operation shifts real value from the paymaster to the bundler, and the paymaster absorbs it. Second, the documented surcharge is not observable from outside: Circle's overview states there is "a 10% surcharge on gas fees… only applies to Arbitrum and Base (and their testnets)", but Base sits at 0.861 and Arbitrum at 0.860, inside the same band as Ethereum at 0.860 and Optimism at 0.862, while the two extremes of the band are Base v0.7 (0.873) and Arbitrum v0.7 (0.826) — both surcharge chains. The feeTokenAmount field, documented as the spread covering USDC-to-ETH slippage, was zero in all 4,853 events. The surcharge may well be computed against an internal cost basis; it is not visible in the ratio between charge and bill.

Finding 3 — the deposit runs at zero

Circle's docs promise that it "ensures that there is always a sufficient amount of native gas token for each supported chain, managing swaps and balances behind-the-scenes." We watched that machine work.

On Base, the paymaster's EntryPoint deposit received 24 top-ups in the window, one every 450 blocks — fifteen minutes, like clockwork. Each is triggered by the same address, 0x6ef7627da1e59fbf48025c52f94084f49a429ff8, calling the paymaster with zero value: the contract swaps collected USDC into WETH on-chain and deposits it. Over the window those refills spent 35,367.38 USDC and bought 14.385970 WETH, a realized rate of 2,458.46 USDC per ETH — again, spot.

The EntryPoint billed 16.910122 ETH over the same window. The difference came out of the buffer, and the arithmetic closes exactly:

billed by EntryPoint      16.910122 ETH
bought with collected USDC 14.385970 ETH
                          ------------
drawdown                   2.524152 ETH

deposit at window start    2.524535 ETH
deposit at window end      0.000382 ETH

Every surface we could read historical state for ended the window at a deposit rounding to zero: Ethereum 2.478335 to 0.000393 ETH, Optimism 2.432414 to 0.000336, Base v0.7 1.449443 to 0.000168, Unichain 0.386124 to 0.001103, Avalanche 204.160183 to 0.000353 AVAX. Arbitrum and Polygon public RPCs would not serve archive state, so we report those two as unmeasured rather than guess.

Operations kept landing after the window closed — 23 more on Base in the following sixteen minutes, with one refill — so this is a sawtooth, not an outage. But the working buffer is roughly 0.6 ETH on Base, refilled every fifteen minutes by a swap. That is a liveness dependency an agent operator inherits: if the refill path stalls or the swap slips, sponsorship stops for accounts that hold no native token, and the failure surfaces as a validation error rather than as a payment error.

Finding 4 — this is not retail traffic

The population is small and concentrated. 34 distinct senders produced the 643 Base operations, 30 on Ethereum, 28 on Optimism, 16 on Polygon, 7 on Unichain. Fifty-one bundle transactions covered the whole Base day, and in a sample of 25 of them, ten were contract-creation transactions rather than direct handleOps calls — a bundler pattern, not a wallet pattern.

The charge distribution says the same thing. On Base v0.8 the per-operation charge ran from 0.006766 USDC at the minimum to 1,465.31 USDC at the maximum, with a median of 8.53. That maximum was a single user operation, in block 50634962, by sender 0x1979967a…; across that one bundle the same account had 24,029.41 USDC pulled as prefund and 18,633.61 returned as refund.

We are not going to attribute intent to addresses we cannot identify. The measurement stands on its own: in this window, the dominant use of the USDC gas rail was a handful of automated accounts moving six-figure sums of USDC through a fee channel whose underlying chain cost was three hundred dollars. The minimum charge, 0.0068 USDC, is what an ordinary transfer looks like. That is the number an agent operator should be budgeting against — and the reason the gap between the two matters is that nothing in the design keeps an agent's operations at the low end.

The only cap your agent has is the permit

Put the pieces together from the perspective of an autonomous wallet.

The USDC that can leave through the gas channel in a single operation is bounded by one number: the value in the EIP-2612 permit the account signed for that operation. The quickstart uses 10 USDC and re-signs per operation, which is the right default. Sign maxUint256 once — the shortcut every integration is tempted by, and the value the permit helper imports by default — and you have granted a non-expiring, unbounded USDC allowance to a contract whose charge is a function of a gas price you did not choose.

Nothing else in the stack covers it. x402's client-side spend controls cap the amount of a payment; we audited that default one-dollar cap and its escape hatches when it shipped, and it never sees a user operation. Coinbase's SpendPermissionManager accumulates a budget per period for a spender, which we measured on-chain; the paymaster is not that spender. Circle's own Agent Wallets document spending limits for outbound transfers and x402 payments, which is a different surface again. The gas channel is the seam between all of them.

What x402 does differently

The contrast is not "cheaper". It is "who holds the pen on the fee".

The x402 exact scheme on EVM opens with the design in one line: "the Facilitator (server) pays the gas, but the Client (user) controls the exact flow of funds via cryptographic signatures." The payer signs an EIP-3009 authorization for an exact amount to an exact recipient. There is no fee field in what the payer signs, so there is no fee field an adversary can inflate. The facilitator's exposure is its own gas, and the spec tells facilitators to bound it — the Starknet scheme states the property explicitly: "the facilitator/paymaster alone sets the outer INVOKE fee — so a client cannot directly inflate the sponsored gas", and instructs facilitators to cap the sponsored settlement fee and rate-limit per payer.

The two rails do not know about each other. At monorepo HEAD e398a9e5 (2026-08-28), the string "paymaster" appears in thirteen files of x402-foundation/x402, twelve of which are generated browser paywall bundles and the thirteenth is that Starknet spec. Where x402 needs to sponsor something beyond the transfer itself, it does so with its own extensions — erc20ApprovalGasSponsoring and eip2612GasSponsoring — inside the facilitator, not through a paymaster.

That is a coherent split, and it is the reason an agent stack ends up with both. x402 for the paid call. A paymaster for everything else the account has to do on-chain. The mistake is assuming the caps you configured for the first one apply to the second.

What it means for LLM4Agents

Our gateway is on the x402 side of this line. An agent pays per inference with a signed authorization for an exact amount; it never sets a gas price, never holds a native token, and never signs an allowance that outlives the request. The failure mode measured here — an account charged 1,465 USDC for one operation because the operation declared a gas price four orders of magnitude above the chain's — cannot reach a payment on that path.

It can still reach the agent, though, and that is the part worth being precise about. Agents that use us for inference also do other things on-chain: they fund themselves, they rebalance, they deploy accounts, they interact with contracts that are not x402 endpoints. The moment an agent's smart account signs a paymaster permit, its USDC balance — the same balance that funds its calls to us — is exposed through a channel our spend controls do not observe. A drained gas allowance shows up on our side as an agent that stops paying.

There is a second-order effect on our own economics. Fee-in-stablecoin infrastructure that runs a fifteen-minute swap loop with a sub-one-ETH buffer is a dependency with a duty cycle. Any component of ours that assumes a smart-account agent can always get a transaction included — settlement helpers, top-up flows, anything that waits on an on-chain confirmation — needs to treat "the shared paymaster is empty" as an expected state, not an incident.

Staying on the frontier

1. Treat gas as a spend category, not as plumbing. Wherever we help an agent construct a user operation, the permit value is the cap and it must be set per operation from an estimate, never maxUint256. That is a five-line change with the same weight as a payment cap, and it is the only enforcement point that exists.

2. Bound the declared gas price, not just the amount. An operation whose maxFeePerGas is orders of magnitude above the chain's base fee is the signature of the pattern we measured. Rejecting operations above a multiple of the current base fee — the same discipline the x402 Starknet spec prescribes to facilitators — is cheap to implement and catches both hostile bundlers and buggy estimators.

3. Instrument the gas channel next to the payment channel. We already emit OpenTelemetry GenAI attributes for inference cost, which we audited in August. Charges from UserOperationSponsored belong in the same ledger, per agent, in the same unit. An operator who can see "this agent spent 4 USDC on inference and 40 on gas" will fix it in a day; one who sees only the first will not.

4. Do not make a shared paymaster a hard dependency. Where an agent needs a native-token transaction, prefer the facilitator-pays path first, fall back to the paymaster, and fail loudly rather than silently retrying against an empty deposit. Publish the check: deposit balance and time-since-last-refill are both readable with two RPC calls.

5. Push the cap upstream. The gap this audit exposes is structural, not Circle-specific: ERC-4337 has no per-operation fee ceiling that the account can express, so the only lever is an ERC-20 allowance with no deadline. A paymaster mode that accepts a signed maximum token charge — the analogue of x402's exact amount — would close it. That is a proposal worth writing rather than a workaround worth shipping.

The general lesson repeats one we have hit before in this series. Agent stacks keep growing channels that move money without moving through the payment layer: approvals, delegations, sponsorships, gas. Each is signed once, bounded loosely, and audited by nobody. The payment rail is the part everyone is watching. It is not the part with the largest number in it.

Pay per call, in stablecoins, with an OpenAI-compatible gateway

Exact amounts, signed per request. No gas price to get wrong.

Register agent