From 65a515dc72d27311b60ea51119aedd1389206df0 Mon Sep 17 00:00:00 2001 From: kilianglas Date: Fri, 15 May 2026 12:34:18 +0200 Subject: [PATCH] feat: add wip-1004 subsidy enforcement via handler hooks --- wips/README.md | 1 + wips/wip-1004.md | 238 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+) create mode 100644 wips/wip-1004.md diff --git a/wips/README.md b/wips/README.md index 1f1145fe5..a82bf2b22 100644 --- a/wips/README.md +++ b/wips/README.md @@ -27,6 +27,7 @@ WIPs are modeled after [Ethereum Improvement Proposals (EIPs)](https://github.co | ------ | ---------------------------------- | ------ | -------- | ---------- | | [1001](./wip-1001.md) | WorldID Native Account Abstraction | Draft | Core | 2026-03-27 | | [1002](./wip-1002.md) | WorldID Subsidy Accounting | Draft | Core | 2026-04-21 | +| [1004](./wip-1004.md) | Subsidy Enforcement via Handler Hooks | Draft | Core | 2026-05-13 | --- diff --git a/wips/wip-1004.md b/wips/wip-1004.md new file mode 100644 index 000000000..bb5229424 --- /dev/null +++ b/wips/wip-1004.md @@ -0,0 +1,238 @@ +--- +wip: 1004 +title: Subsidy Enforcement via Handler Hooks +description: An alternative realization of World ID transaction-fee subsidies for WIP-1001 transactions that, on OP-Stack, models the subsidy as skipped credits to the L2 fee vaults and a skipped caller pre-charge — no ETH ever moves for the subsidized portion, and the per-nullifier WIP-1002 budget caps the operator's forgone fee revenue. +author: Kilian Glas (@kilianglas), Alessandro Mazza (@alessandromazza98) +status: Draft +type: Standards Track +category: Core +created: 2026-05-13 +requires: WIP-1001, WIP-1002, EIP-1559 +--- + +## Abstract + +This WIP specifies an alternative realization of **Subsidy Enforcement** for World Chain — the mechanism that turns a verified World ID's remaining gas budget (tracked in [WIP-1002](./wip-1002.md)) into a discounted transaction at inclusion time. It stands as an alternative to [WIP-1003](./wip-1003.md), which realizes the same subsidy through builder policy and a virtual fee market with the protocol base fee pinned to `0`. + +The mechanism is scoped to [WIP-1001](./wip-1001.md) `0x1D` transactions and is realized as three overrides of the revm `Handler` trait: `validate_against_state_and_deduct_caller`, `reimburse_caller`, and `reward_beneficiary`. + +Because World Chain runs on the OP-Stack, where every L2 fee component (base fee, priority fee, L1 data fee, operator fee) is credited to an operator-controlled predeploy vault rather than burned, the subsidy is realized as a **no-op for the chain's ETH ledger**: the caller is not pre-charged for the subsidized fraction of the fee, and the corresponding vault credits in the standard `reward_beneficiary` are skipped. The per-nullifier WIP-1002 budget caps the wei the chain operator forgoes per credential per period. No treasury is required, no ETH is minted, and no validator compensation gap is introduced under the centralized-sequencer model. + +A 0x1D transaction whose framed sender is authorized under a WIP-1002 nullifier with sufficient remaining budget can be sent with zero ETH held by the sender. When budget is insufficient or absent, the transaction falls back to standard EIP-1559 / OP-Stack charging. + +## Motivation + +[WIP-1002](./wip-1002.md) defines per-credential, wei-denominated subsidy budgets for verified World IDs and exposes an on-chain consumption hook, but deliberately leaves the *enforcement* mechanism — how that budget is actually applied at transaction inclusion time — out of scope. + +[WIP-1003](./wip-1003.md) is the existing proposal for that mechanism. It introduces chain-wide protocol `baseFeePerGas` pinning to `0`, an out-of-protocol virtual fee market with deterministic per-block parameters, wallet-facing RPC overrides so non-subsidized traffic still sees a quoted fee, and a builder-owned end-of-block transaction that pushes per-period subsidy deltas into WIP-1002. These changes touch all traffic on World Chain, not only subsidy-eligible traffic, and the §6 settlement formula in WIP-1003 is ambiguous between `gasLimit` and `gasUsed`. + +This WIP is motivated by the observation that, once World Chain has [WIP-1001](./wip-1001.md) (a new transaction type with a dedicated execution path) and WIP-1002 (an on-chain consumption hook), and given the OP-Stack fee-vault model, subsidy enforcement can be expressed as a small handler override on the new transaction type alone. The protocol fee market, the wallet RPC surface, and non-`0x1D` traffic remain unaffected. The subsidy can fully fund a 0x1D transaction — base fee, priority fee, L1 data fee, operator fee — from a sender holding zero ETH, without any ETH transfer or minting. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) and [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174). + +### Scope + +Subsidy enforcement under this WIP applies to [WIP-1001](./wip-1001.md) transactions only (type flag `0x1D`). All other transaction types follow standard OP-Stack charging, unchanged by this WIP. The protocol `baseFeePerGas` retains its EIP-1559 semantics for all transaction types. + +This WIP relies on the OP-Stack fee model. The funding analysis in [Fee Accounting on OP-Stack](#fee-accounting-on-op-stack) and the no-op realization in [Handler Overrides](#handler-overrides) presume that the chain operator owns the L2 fee vaults named below; they do not apply unchanged on non-OP-Stack deployments. + +### Fee Accounting on OP-Stack + +On the OP-Stack, none of the L2 transaction fee components are burned. Each component is credited to an operator-controlled predeploy: + +- **Priority fee** → `block.coinbase`, set by the L2 derivation pipeline to `SequencerFeeVault` (`0x4200…0011`); credited by the mainnet `reward_beneficiary` path the op-revm handler calls through to. +- **Base fee** → `BaseFeeVault` (`0x4200…0019`); credited by op-revm via an explicit `balance_incr(BASE_FEE_RECIPIENT, base_fee * gas_used)` in `reward_beneficiary`. +- **L1 data fee** → `L1FeeVault` (`0x4200…001A`); deducted from the caller in `validate_against_state_and_deduct_caller` via the L1-block info accounting, and credited in `reward_beneficiary`. +- **Operator fee** (Isthmus+) → `OPERATOR_FEE_RECIPIENT` (`0x4200…001B`); same pattern as L1 fee. + +The chain operator owns all four vaults and withdraws their accumulated balances to L1 via `OptimismPortal`. EIP-1559's burn-to-`address(0)` does not occur on the OP-Stack — base fee is *collected*, not destroyed. + +Consequently, "subsidizing the fee" can be modeled as **skipping the caller deduction and skipping the corresponding vault credits**, with no ETH transferred anywhere. The cost of the subsidy is the chain operator's opportunity cost — forgone fee revenue on the subsidized fraction. The per-nullifier WIP-1002 budget is the hard cap on that opportunity cost per credential per period. + +### Subsidy Resolution + +For a `0x1D` transaction whose framed sender is `account`, subsidy eligibility is resolved deterministically against [WIP-1002](./wip-1002.md) Subsidy Accounting: + +1. Resolve `account` to a `nullifier` via the WIP-1002 authorization map. If `account` is authorized under multiple nullifiers, the WIP-1002 deterministic nullifier-selection rule MUST be used to choose exactly one record. +2. If no authorized `nullifier` exists for `account` in the current WIP-1002 period, the transaction is **not subsidy-eligible** and standard OP-Stack charging applies for all phases below. +3. If an authorized `nullifier` exists, let `budget = ISubsidyAccounting.getBudget(nullifier)`. The transaction is **subsidy-eligible** if and only if `budget > 0`. + +The resolution result (eligibility flag and chosen `nullifier`) MUST be computed once per transaction and reused at every site that consults it (the [WIP-1001 pre-validation balance check](#wip-1001-pre-validation-balance-check), all three handler hooks, RPC). + +### Subsidy Coverage + +For a subsidy-eligible transaction, let `pre_total` be the wei amount the standard OP-Stack pre-charge would deduct from the caller in `validate_against_state_and_deduct_caller`: + +``` +pre_total = gas_limit * effective_gas_price + tx_l1_cost + operator_fee_charge +``` + +where `effective_gas_price = min(max_fee_per_gas, base_fee_per_gas + max_priority_fee_per_gas)`. Let `priority_fee_per_gas = effective_gas_price - base_fee_per_gas`. + +The subsidy MAY cover any prefix of this total. The pre-execution upper bound is: + +``` +pre_subsidy = min(budget, pre_total) +pre_sender = pre_total - pre_subsidy +``` + +The final post-execution settlement (in `reimburse_caller`) computes the equivalent quantities against the actual `used_total = gas_used * effective_gas_price + tx_l1_cost + operator_fee_charge`: + +``` +final_subsidy = min(pre_subsidy, used_total) +final_sender = used_total - final_subsidy +``` + +Both base fee and priority fee are subsidisable; L1 data fee and operator fee are likewise subsidisable through the same vault-credit-skip mechanism. Governance MAY tune per-credential budgets to account for the operator's real L1 cost (see [Security Considerations](#security-considerations)). + +### Handler Overrides + +This WIP overrides three methods of the revm `Handler` trait on the `0x1D` execution path. All other handler methods follow their op-revm default implementation. The override semantics below are normative; field names match the revm trait signatures. + +#### `validate_against_state_and_deduct_caller` (pre-execution) + +The pre-charge MUST split `pre_total` between the WIP-1002 budget and the caller balance: + +1. Standard EIP-1559 envelope-validity checks (`max_fee_per_gas >= base_fee_per_gas`, `max_priority_fee_per_gas <= max_fee_per_gas`) MUST be performed first. Nonce and code checks proceed as in the op-revm default. +2. The caller balance check MUST require only `pre_sender` (not the full `pre_total`). If the balance is insufficient to cover `pre_sender`, the transaction MUST be rejected with the standard "lack of funds" error. +3. The caller balance MUST be debited by `pre_sender` only. The subsidized fraction is NOT taken from the caller and is NOT moved anywhere — it is held as a virtual conditional debit `pre_subsidy` against the chosen `nullifier`, carried through to [`reimburse_caller`](#reimburse_caller-post-execution) on the execution context. +4. The L1 block info accounting that records the tx's L1 cost MUST still be performed; subsidizing the L1 fee changes only whether the caller is debited and whether `L1FeeVault` is credited, not the L1 cost computation itself. + +Non-subsidy-eligible `0x1D` transactions take the op-revm default path with no modifications. + +#### `reimburse_caller` (post-execution) + +Once `gas_used` is known, the post-charge MUST settle the subsidy and caller contributions to their exact final values: + +1. Compute `used_total` per [Subsidy Coverage](#subsidy-coverage). Let `final_subsidy = min(pre_subsidy, used_total)` and `final_sender = used_total - final_subsidy`. +2. The WIP-1002 budget for the chosen `nullifier` MUST end this transaction having been decremented by exactly `final_subsidy`. Implementations realize this by calling the WIP-1002 consumption interface with `final_subsidy` as the wei amount (the existing `consumeBudget(nullifier, gasUsed, baseFee)` signature is insufficient to express a general wei amount; see [Interaction with WIP-1002](#interaction-with-wip-1002)). +3. The caller balance MUST end this transaction having been debited by exactly `final_sender`. Any excess of `pre_sender` over `final_sender` MUST be credited back to the caller. + +For non-subsidy-eligible transactions, the op-revm default refund path applies. + +#### `reward_beneficiary` (post-execution) + +The vault credits MUST be reduced by exactly the subsidized fraction of each component: + +1. Let `subsidy_fraction = final_subsidy / used_total` (taken as a rational fraction; implementations MUST compute the per-component subsidized amounts without intermediate rounding, e.g. by debiting components in a fixed priority order; see [Rationale](#rationale)). +2. For each fee component otherwise credited in op-revm's `reward_beneficiary` (base fee → `BaseFeeVault`, priority fee → `block.coinbase`, L1 cost → `L1FeeVault`, operator fee → `OPERATOR_FEE_RECIPIENT`), the credited amount MUST equal the sender-paid portion of that component, i.e. `default_credit * (1 - subsidy_fraction_for_component)`. +3. The omitted credits (the `subsidy_fraction_for_component * default_credit` portion) MUST NOT be credited to any other address, MUST NOT be burned, and MUST NOT be minted. They are skipped — the chain operator forgoes the corresponding vault inflow. + +Conservation: + +- Non-subsidy-eligible 0x1D tx: indistinguishable from op-revm default. +- Fully subsidized 0x1D tx with `budget ≥ used_total`: caller balance unchanged, no vault credits issued, WIP-1002 budget debited by `used_total`. +- Partial subsidy: caller debited by `final_sender`; vault credits sum to `final_sender`; WIP-1002 budget debited by `final_subsidy`. + +### WIP-1001 Pre-validation Balance Check + +[WIP-1001](./wip-1001.md) §"Validation, Execution, and Failure Semantics" requires the chain to "require the account balance to cover the worst-case payload gas charge and `MIN_VALIDATION_FAILURE_FEE`". For this WIP to admit subsidy-eligible transactions from accounts holding zero ETH, that check MUST be subsidy-aware: + +1. Before the WIP-1001 balance check runs, perform [Subsidy Resolution](#subsidy-resolution) against WIP-1002 to determine eligibility and the remaining `budget`. +2. The "worst-case payload gas charge" used in the WIP-1001 check MUST be reduced by `min(budget, gas_limit * effective_gas_price + tx_l1_cost + operator_fee_charge)`. +3. `MIN_VALIDATION_FAILURE_FEE` MAY be subsidy-covered (see [Failed Validation](#failed-validation)); if so, the WIP-1001 check MUST reduce its `MIN_VALIDATION_FAILURE_FEE` requirement by the corresponding subsidisable portion. + +This is the only required modification to WIP-1001 by this WIP. WIP-1001's envelope-validity rules, signing hash, and session-verifier execution model are unchanged. + +### Failed Validation + +If a `0x1D` transaction fails validation (per WIP-1001 §"Validation, Execution, and Failure Semantics") *after* envelope decoding, signature recovery, and session-verifier dispatch have all succeeded — i.e. a real, well-formed transaction whose execution-phase validation produced a halt or invalid result — the validation-failure fee MAY be subsidy-covered using the same vault-credit-skip mechanism as a successful transaction. + +If the transaction fails *before* the session verifier returns (malformed envelope, signature recovery failure, unauthorized session verifier, exhausted block validation budget), the validation-failure fee MUST be charged to the sender in the standard sender-paid manner — the budget is not yet known to be associated with a genuine WIP-1001 signing key holder, so subsidizing this path opens a low-cost mempool spam vector that does not consume the attacker's own resources. + +Implementations realize this split by treating the result of the session-verifier dispatch as the gating signal: the chosen `nullifier` and `pre_subsidy` are committed to the execution context only after that dispatch succeeds, and the post-failure fee accounting MUST consult that commitment. + +### Interaction with WIP-1002 + +This WIP requires WIP-1002 to expose a wei-amount consumption call. The existing `consumeBudget(nullifier, gasUsed, baseFee)` signature in WIP-1002 §"Subsidy Accounting Interface" assumes the subsidisable cost equals `gasUsed * baseFee`; under this WIP the consumed amount is general (covers priority fee, L1 fee, operator fee, and validation-failure fee). The required addition is either: + +- a new entry point `consumeBudget(uint256 nullifier, uint256 weiAmount)`, or +- a redefinition of the existing call to interpret its third argument as a generic wei-per-gas-unit price. + +WIP-1002 is otherwise unchanged. The consumption call MUST be invoked exactly once per included subsidy-eligible 0x1D transaction (success or post-session-verifier failure), with the wei amount equal to `final_subsidy`. The externally observable WIP-1002 state after a transaction MUST be identical to a single such call having been made. + +### Wallet RPC + +Standard EIP-1559 fee RPCs (`eth_maxPriorityFeePerGas`, `eth_gasPrice`, `eth_feeHistory`, block-header `baseFeePerGas`) continue to return their normal protocol-derived values; the protocol fee market is unchanged. Subsidy-aware wallets MAY additionally query WIP-1002 directly for the framed `account`'s remaining budget and select `max_fee_per_gas` / `max_priority_fee_per_gas` accordingly — including zero priority fee, since the subsidy now covers it. No wallet-facing RPC overrides are mandated by this WIP. + +## Rationale + +### Comparison to WIP-1003 + +[WIP-1003](./wip-1003.md) reaches the same end state — subsidized verified traffic, market-priced other traffic — by moving the fee market out of protocol. This WIP reaches it by moving subsidy enforcement into the existing `0x1D` execution path and exploiting the OP-Stack fee-vault model. The trade is: + +- **Protocol `baseFeePerGas`** stays at its EIP-1559 value here; WIP-1003 pins it to `0` chain-wide. +- **Virtual fee market and `VirtualFeeOracle`** are not introduced here; WIP-1003 requires them. +- **Per-block builder-owned accounting transaction** is not introduced here; WIP-1003 requires one. +- **`gasLimit` vs `gasUsed` ambiguity** in WIP-1003 §6 is resolved by construction here: the final debit is computed in `reimburse_caller`, after `gas_used` is known. +- **Wallet RPC overrides** are not required here; WIP-1003 requires them so wallets see the virtual base fee instead of the pinned-`0` header value. +- **Priority fee, L1 fee, operator fee coverage** are explicit here; WIP-1003 only covers the (virtual) base fee. + +The cost of the trade is scope: this WIP applies only to `0x1D` transactions, while WIP-1003 applies to all transaction types. Non-`0x1D` traffic on World Chain is not subsidy-eligible under either proposal in practice, since WIP-1002 authorization is keyed to WIP-1001 accounts in the expected deployment. + +### Why no-op funding works on OP-Stack + +On L1 Ethereum, EIP-1559 burns the base fee, so a "subsidy that covers the base fee" cannot be realized without either (a) a treasury that holds the wei the user does not pay, (b) minting, or (c) violating EIP-1559's burn invariant. On the OP-Stack none of these tensions exist: every fee component is credited to an operator-controlled predeploy, and the operator already has unilateral control over how those vaults are subsequently used. Skipping the credit is therefore a clean reduction of the operator's claim on the chain's value flow, not a manipulation of validator economics or supply. This makes the subsidy a pure no-op at the ETH-ledger level. + +### Why three handler hooks + +The three overrides correspond exactly to the three points in the revm execution pipeline where fee state moves between accounts on the OP-Stack: pre-execution deduction from the caller, post-execution refund to the caller, and post-execution crediting of the L2 fee vaults. Overriding any fewer of them leaves an asymmetry that is hard to keep consistent under refunds and gas-used variability. Overriding any more is unnecessary — no other phase touches fee state. + +### Pre-charge over-estimation + +The pre-charge uses worst-case gas (`gas_limit`) as the subsidy upper bound rather than waiting for `gas_used`. This matches the op-revm default behavior (which pre-charges `gas_limit * effective_gas_price` plus L1 cost from the caller) and is corrected exactly in `reimburse_caller`. Deferring all subsidy interaction to post-execution would require the caller to hold enough balance to cover `gas_limit * effective_gas_price + L1 cost` in addition to having a non-zero subsidy budget, which negates the zero-ETH-sender property this WIP is designed to deliver. + +### Subsidy covers the full effective gas price (not just base fee) + +A natural first cut subsidizes only the base-fee portion, on the reasoning that priority fee is real validator compensation that the chain cannot freely waive. On OP-Stack that constraint does not bind: the priority fee credits `SequencerFeeVault`, owned by the operator, not an external validator. Subsidizing it is the same no-op as subsidizing base fee. Restricting the subsidy to base fee would force a zero-ETH user to send transactions with `max_priority_fee_per_gas = 0` and still rely on the verified-lane policy for inclusion — workable but strictly weaker UX, and asymmetric for no real reason on this stack. + +### Component apportionment + +When the subsidy partially covers `used_total`, the per-component apportionment (how much of base fee vs. priority fee vs. L1 fee is subsidized) is observable through the per-vault credits. Implementations SHOULD use a fixed priority order — e.g. base fee → priority fee → L1 fee → operator fee — so that traces are deterministic. The choice of order does not affect the user-visible outcome (sender pays `final_sender`, budget pays `final_subsidy`); it affects only which vault sees the partial credit at the boundary. + +### Scope to `0x1D` + +Constraining subsidy enforcement to the WIP-1001 execution path keeps the protocol fee market, wallet RPC surface, and non-`0x1D` traffic unchanged. WIP-1002 authorization is keyed to WIP-1001 accounts in the expected deployment, so subsidy-eligible traffic is in practice a subset of `0x1D` traffic; widening the scope would expand surface area without expanding the set of subsidized transactions. + +### Third-party gas sponsorship + +Generic third-party gas sponsorship (an external EOA paying for an unrelated user's transaction) is not in scope for this WIP. If sponsorship becomes a requirement, it is an envelope-additive extension over this proposal: a Tempo-style `fee_payer_signature` field on `0x1D` with an additional charge tier between subsidy and sender. The handler structure above generalizes naturally to a three-tier (subsidy → sponsor → sender) charge without changing the per-tier semantics. + +## Backwards Compatibility + +- The protocol fee market and EIP-1559 / OP-Stack semantics are unchanged for all non-`0x1D` traffic and for non-subsidy-eligible `0x1D` traffic. +- The `0x1D` envelope encoding, signing-hash construction, and validation rules from [WIP-1001](./wip-1001.md) are unchanged; the only WIP-1001 modification is the subsidy-aware reading of the pre-validation balance check (see [WIP-1001 Pre-validation Balance Check](#wip-1001-pre-validation-balance-check)). +- WIP-1002's `consumeBudget` interface requires the wei-amount addition described in [Interaction with WIP-1002](#interaction-with-wip-1002). +- This WIP requires activation alongside (or after) WIP-1001 and WIP-1002. Activating it independently is meaningless. +- Block-header `baseFeePerGas` continues to follow EIP-1559, so wallets and indexers reading the block header are not affected. +- This WIP and [WIP-1003](./wip-1003.md) are mutually exclusive realizations of Subsidy Enforcement; only one can ship. +- This WIP presumes the OP-Stack centralized-sequencer fee-vault model; see [Security Considerations](#security-considerations). + +## Test Cases + +Test cases SHOULD exercise at minimum: + +- `0x1D` transaction with no WIP-1002 authorization — full caller pre-charge, full caller post-refund, all vault credits as in op-revm default, no WIP-1002 interaction. +- `0x1D` transaction with subsidy fully covering `used_total` and a caller balance of zero — caller balance untouched, no vault credits issued, WIP-1002 budget debited by `used_total`. +- `0x1D` transaction with subsidy partially covering `used_total` (`0 < budget < used_total`) — caller debited by `used_total - budget`, vault credits sum to that amount under the chosen priority order, WIP-1002 budget debited to zero. +- `0x1D` transaction with `gas_used < gas_limit` and subsidy budget — both the caller-pre-charge excess and the budget-pre-charge excess refunded; WIP-1002 budget ends at exactly `budget_initial - final_subsidy`. +- `0x1D` transaction failing in the session-verifier dispatch (envelope OK, signature recovery OK, verifier returns wrong magic) — validation-failure fee subsidy-covered if budget present; otherwise sender-paid. +- `0x1D` transaction failing before session-verifier dispatch (bad signature, unauthorized verifier) — validation-failure fee sender-paid regardless of budget. +- `0x1D` transaction whose framed sender is authorized under multiple nullifiers — the chosen nullifier matches the WIP-1002 deterministic selection rule; only that nullifier's budget is debited. + +## Reference Implementation + +No reference implementation is included in this draft. The expected shape is an op-revm `Handler` variant for `0x1D` transactions overriding the three methods named in [Handler Overrides](#handler-overrides); the variant dispatches on the WIP-1002 resolution result at pre-execution and stores the `(nullifier, pre_subsidy)` pair on the execution context for use in `reimburse_caller` and `reward_beneficiary`. The `reward_beneficiary` override calls through to op-revm's default to perform the standard vault credits, then issues compensating debits for the subsidized component shares. + +## Security Considerations + +- **Operator opportunity cost as the security boundary.** Under the no-op design the subsidy never spends real ETH the operator does not already implicitly hold; the worst-case loss is forgone fee revenue. The per-nullifier WIP-1002 budget per period is the hard cap on that loss per credential. +- **Grief via co-authorized addresses.** A human's WIP-1002 nullifier may have multiple authorized addresses (per WIP-1002 `updateAddresses`). A co-authorized address can drain the human's per-period budget by issuing failing transactions or transactions whose `used_total` is high. The human still benefits from the operator's forgone revenue but loses their budget for the period. Mitigations belong in WIP-1002 (authorization-revocation flow, per-address sub-caps) rather than here. +- **Pre-session-verifier failure fees stay sender-paid.** Subsidizing the fee for transactions that fail before the session verifier returns would let any address spam failing 0x1D txs against the authorized account's budget at zero marginal cost. Keeping that path sender-paid retains a small mempool-economic floor without blocking zero-ETH first transactions on real WIP-1001-signed traffic. +- **L1 fee is a real outflow, not just opportunity cost.** Base fee and priority fee subsidies forgo *future* operator revenue. L1 fee subsidy forgoes vault revenue that itself was meant to repay the operator's *already-paid* L1 DA cost. Governance should size per-credential budgets with this asymmetry in mind; budgets that fund only L2 fee components MAY be specified by setting `tx_l1_cost` outside the subsidisable prefix (see [Subsidy Coverage](#subsidy-coverage), apportionment order). +- **Centralized-sequencer assumption.** The no-op realization depends on the entity setting subsidy policy being the same as the entity owning the L2 fee vaults. Under World Chain's current centralized-sequencer model this holds by construction. A future decentralized sequencer model would require external compensation for the priority-fee portion of subsidized transactions (the priority fee normally compensates sequencers); that extension is out of scope. +- **Deterministic nullifier selection.** All sites that resolve an account to a nullifier (WIP-1001 pre-validation balance check, pre-execution, post-execution, RPC) MUST use the WIP-1002 deterministic selection rule so they agree on which budget is debited. +- **Pre-charge / post-refund consistency.** `final_subsidy + final_sender = used_total` is an invariant. Implementations MUST enforce it in tests; a divergence silently drains either user balances or the operator's vault revenue without surface symptoms. +- **Re-entrancy with WIP-1002 as predeploy.** If WIP-1002 is realized as a predeploy rather than a precompile, the consumption call in `reimburse_caller` runs after `gas_used` is finalized and cannot re-enter the executing transaction. Deferred / batched consumption calls MUST be applied atomically with block production so observable WIP-1002 state remains consistent with executed transactions.