You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When an onboarding op's first postOp call reverts (e.g., solidarity fund drained by earlier ops in the same bundle), EntryPoint retries with PostOpMode.postOpReverted. The current code calls _updateOnboardingUsage for all modes, which contains if (solidarity.balance < actualGasCost) revert InsufficientFunds() — the exact same revert that caused the first failure. The second postOp also reverts, and the EntryPoint penalizes the paymaster (charges it for gas with no accounting update).
Code Location
src/PaymasterHub.sol, postOp function:
if (isOnboarding) {
_updateOnboardingUsage(actualGasCost, mode == IPaymaster.PostOpMode.opSucceeded);
}
_updateOnboardingUsage (line 1892):
if (solidarity.balance < actualGasCost) revertInsufficientFunds();
solidarity.balance -=uint128(actualGasCost);
There is no postOpReverted branch for onboarding, unlike org ops which have _postOpFallback.
if (isOnboarding) {
if (mode == IPaymaster.PostOpMode.postOpReverted) {
// Solidarity was insufficient. Paymaster absorbs the loss.// Refund daily counter since the op effectively failed.
OnboardingConfig storage onboarding =_getOnboardingStorage();
if (onboarding.attemptsToday >0) onboarding.attemptsToday--;
return;
}
_updateOnboardingUsage(actualGasCost, mode == IPaymaster.PostOpMode.opSucceeded);
}
Tradeoff: This skips the solidarity deduction, creating a discrepancy between solidarity.balance and the paymaster's actual EntryPoint deposit. The paymaster was already charged by EntryPoint, so the funds are gone, but solidarity's accounting doesn't reflect it. This phantom surplus could cause future ops to validate against non-existent funds, cascading the same failure.
Better long-term fix: Add solidarity reservation during validation for onboarding ops (related to #123), preventing the root cause entirely.
Summary
When an onboarding op's first
postOpcall reverts (e.g., solidarity fund drained by earlier ops in the same bundle), EntryPoint retries withPostOpMode.postOpReverted. The current code calls_updateOnboardingUsagefor all modes, which containsif (solidarity.balance < actualGasCost) revert InsufficientFunds()— the exact same revert that caused the first failure. The second postOp also reverts, and the EntryPoint penalizes the paymaster (charges it for gas with no accounting update).Code Location
src/PaymasterHub.sol,postOpfunction:_updateOnboardingUsage(line 1892):There is no
postOpRevertedbranch for onboarding, unlike org ops which have_postOpFallback.How This Can Happen
validatePaymasterUserOppasses thesolidarity.balance >= maxCostcheckactualGasCostfromsolidarity.balance_updateOnboardingUsagerevertspostOpReverted— same revertImpact
balanceis not decremented (shows phantom surplus)solidarity.balancediverges from actual available fundsattemptsToday) is not refunded for the failed opPractical risk is low because:
dailyCreationLimit)initCode(deploying a new Passkey account)maxGasPerCreationbounds per-op costsolidarity.balance / maxGasPerCreationconcurrent account deploymentsSuggested Fix
Add a
postOpRevertedbranch for onboarding:Tradeoff: This skips the solidarity deduction, creating a discrepancy between
solidarity.balanceand the paymaster's actual EntryPoint deposit. The paymaster was already charged by EntryPoint, so the funds are gone, but solidarity's accounting doesn't reflect it. This phantom surplus could cause future ops to validate against non-existent funds, cascading the same failure.Better long-term fix: Add solidarity reservation during validation for onboarding ops (related to #123), preventing the root cause entirely.
Related
Labels
Security, Enhancement, PaymasterHub