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
The default paymaster whitelist is built once, at deploy time, in OrgDeployer._buildDefaultPaymasterRules → _appendTaskManagerRules etc. After that, an org's PaymasterHub rules are frozen — they only change when somebody manually calls setRules on that org's hub.
That made sense when the rule set was static. But every time we ship a new user-facing function on a core contract (e.g. createTasksBatch — see #153), every already-deployed org silently breaks for that flow until an admin runs a one-off fix script. We've already got script/fixes/FixTest6OrgMetaRules.s.sol, FixTest6EducationRules.s.sol, FixKubiEducationRules.s.sol — that's the smell. The pattern doesn't scale, and orgs that opted into mirror-mode beacons specifically said "please apply protocol changes to me automatically" — but right now they only get the implementation upgrade, not the paymaster rule change that goes with it.
Ask
When a ContractInfo.autoUpgrade == true (i.e. the org's beacon is in Mirror mode for that module), the org should automatically pick up additions to the protocol's default paymaster rule set for that module — the same way it already picks up implementation upgrades.
Static-mode orgs (autoUpgrade == false) deliberately pinned an old impl and should not receive new whitelist entries; their rule set stays frozen.
Sketch
Three pieces, smallest blast radius first:
Extract the canonical rule set into a callable view. Move the body of _buildDefaultPaymasterRules (and its _appendXxxRules helpers) into a stateless library — DefaultPaymasterRulesLib — so the same logic is reachable both from OrgDeployer (deploy-time) and from a sweeper / PaymasterHub.syncRules() (post-deploy). Today it's internal pure on OrgDeployer, unreachable after bootstrap.
Add a permissionless PaymasterHub.syncRules(orgId) that diffs against the canonical set. For each (target, selector) pair returned by the lib that isn't already allowed for this org, AND whose target is registered in OrgRegistry with autoUpgrade == true, append it (allowed = true, default gas hint). Existing rules and any rules the org executor manually disabled are left alone (don't clobber executor decisions — only add). Emit a RulesSynced(orgId, addedCount) event so dashboards / Slack can flag spend changes.
A sweeper script for the rollout backfill.script/upgrades/SweepPaymasterRulesForAutoUpgradeOrgs.s.sol iterates OrgRegistry, calls syncRules(orgId) on each org's hub. Run once after each protocol release that ships new whitelisted selectors. Replaces the per-org Fix*Rules.s.sol pattern.
Open questions
Should rule additions to mirror-mode orgs be silent, or require an opt-in confirmation per change? Protocol-pushed paymaster rules expand what the org pays for, which is a quietly load-bearing economic decision. Mirror mode arguably already covers this (org said yes to auto-following) but we may want a per-org autoSyncPaymasterRules flag separate from the beacon mode for finer control.
Rule removals / disabling. If a future protocol release wants to remove a default selector (e.g. deprecating an entry point), do mirror orgs follow that too? Probably yes for consistency, but the framing is different ("the protocol revoked sponsorship" vs "the org executor revoked sponsorship") — worth a paragraph in PAYMASTER_HUB.md.
Gas budgets per selector._buildDefaultPaymasterRules currently passes gasHints[i] = 0 (use default). If the protocol later wants to set custom hints, the lib needs to grow a (uint32 gasHint) per rule and the sync diff has to consider hint mismatches as updates, not just additions.
Problem
The default paymaster whitelist is built once, at deploy time, in
OrgDeployer._buildDefaultPaymasterRules→_appendTaskManagerRulesetc. After that, an org'sPaymasterHubrules are frozen — they only change when somebody manually callssetRuleson that org's hub.That made sense when the rule set was static. But every time we ship a new user-facing function on a core contract (e.g.
createTasksBatch— see #153), every already-deployed org silently breaks for that flow until an admin runs a one-off fix script. We've already gotscript/fixes/FixTest6OrgMetaRules.s.sol,FixTest6EducationRules.s.sol,FixKubiEducationRules.s.sol— that's the smell. The pattern doesn't scale, and orgs that opted into mirror-mode beacons specifically said "please apply protocol changes to me automatically" — but right now they only get the implementation upgrade, not the paymaster rule change that goes with it.Ask
When a
ContractInfo.autoUpgrade == true(i.e. the org's beacon is in Mirror mode for that module), the org should automatically pick up additions to the protocol's default paymaster rule set for that module — the same way it already picks up implementation upgrades.Static-mode orgs (
autoUpgrade == false) deliberately pinned an old impl and should not receive new whitelist entries; their rule set stays frozen.Sketch
Three pieces, smallest blast radius first:
Extract the canonical rule set into a callable view. Move the body of
_buildDefaultPaymasterRules(and its_appendXxxRuleshelpers) into a stateless library —DefaultPaymasterRulesLib— so the same logic is reachable both fromOrgDeployer(deploy-time) and from a sweeper /PaymasterHub.syncRules()(post-deploy). Today it'sinternal pureonOrgDeployer, unreachable after bootstrap.Add a permissionless
PaymasterHub.syncRules(orgId)that diffs against the canonical set. For each(target, selector)pair returned by the lib that isn't already allowed for this org, AND whosetargetis registered inOrgRegistrywithautoUpgrade == true, append it (allowed = true, default gas hint). Existing rules and any rules the org executor manually disabled are left alone (don't clobber executor decisions — only add). Emit aRulesSynced(orgId, addedCount)event so dashboards / Slack can flag spend changes.A sweeper script for the rollout backfill.
script/upgrades/SweepPaymasterRulesForAutoUpgradeOrgs.s.soliteratesOrgRegistry, callssyncRules(orgId)on each org's hub. Run once after each protocol release that ships new whitelisted selectors. Replaces the per-org Fix*Rules.s.sol pattern.Open questions
autoSyncPaymasterRulesflag separate from the beacon mode for finer control.PAYMASTER_HUB.md._buildDefaultPaymasterRulescurrently passesgasHints[i] = 0(use default). If the protocol later wants to set custom hints, the lib needs to grow a(uint32 gasHint)per rule and the sync diff has to consider hint mismatches as updates, not just additions.Related
createTasksBatchto default paymaster auto-whitelist (the trigger for this gap)script/fixes/Fix*Rules.s.sol— current manual workaroundSWITCHABLE_BEACON.md— defines the mirror-mode opt-in semantics this issue extends to paymaster config🤖 Generated with Claude Code