paymasterOptions lives in your application’s client code. Anyone using your application can read it, and so can anyone who never intends to use your application at all.
Every ERC-7677 integration shares this. The consequence is that an unscoped paymaster will pay for whatever it is asked to pay for, by whoever asks, until it is empty.
Startale forwards paymaster requests and nothing more. It applies no policy on your behalf, has no visibility into your sponsorship decisions, and cannot recover funds a drained paymaster has spent.
Keep the provider credential server-side
Hosted gas managers authenticate with an API key, usually embedded in the URL. Putting that URL straight intopaymasterOptions publishes the key, and a key that can sign sponsorships can spend your balance from outside your application entirely.
Run a thin endpoint of your own and point paymasterOptions at that instead. Your endpoint holds the credential, applies your rules, and forwards to the provider.
Scope what you sponsor
isSponsorable in the sketch above is where the real protection lives. Decide it from the UserOperation itself, inside pm_getPaymasterData, before you sign anything. Do not apply it to pm_getPaymasterStubData: the Startale App requests the stub with a placeholder operation (zero-address sender, empty callData), so any sender or contract rule would reject it and the transaction would fail. See the stub request.
An allowlist on contract and method also rejects, by construction, operations that do nothing useful. An account can be made to submit an operation that performs no meaningful work while still burning real gas at a high fee, and a paymaster that sponsors anything will pay for every one of them. Scoping to your own methods removes that whole class of abuse without having to detect it.
Check what your provider’s policy layer can actually express before relying on it. Hosted controls usually cover spending limits and per-account allowlists, but scoping by contract address or method selector is frequently missing, and some providers offer it only through a webhook back into your own service. Where the provider cannot express a rule, implement it in your proxy.
Cap the blast radius
Set your numbers on the assumption that everything above will eventually be bypassed by something you did not anticipate. Fund incrementally. A paymaster holding a week of expected spend has a bounded worst case; one holding a year of spend does not. Alert on burn rate rather than balance, since a drain shows up as an unusual rate long before the balance runs out. Keep a kill switch you can reach in minutes, which with your own proxy is a flag that makesisSponsorable return false, and make sure someone other than you knows how to flip it.
Reconcile as well. Log every signature you issue against the resulting UserOperation hash and compare that against the gas your paymaster actually paid. A gap between the two is how you find out something is being sponsored that you did not intend.
Fail honestly
When you decline to sponsor, return a JSON-RPC error rather than a malformed result, so the transaction fails cleanly. Your error message does not reach your application. The Startale App reports the failure to yourwallet_sendCalls request as -32603 with a short category such as paymaster_error, not your paymaster’s own text. Your interface can show a generic “not sponsored” state, but not your specific reason. See Failure modes.
Design that declined path as deliberately as the happy path. A user told “this action is not sponsored, and your account needs ETH to continue” can act on it. A user who sees an unexplained failure files a support ticket, or leaves.
Related
Paymaster wire format
The methods your proxy has to implement, and the limits applied when forwarding to it.
Configure paymasterOptions
Where the URL goes, and why only batched calls carry it.
Who pays for gas
The division of responsibility between Startale and your application.
Errors
Surfacing a declined sponsorship to the user.