[RFC] Introducing a Subsidy Contract

Circling back to this with a more concrete design. The OP left the accounting mechanism open-ended intentionally — the conversation surfaced why per-user credit balance tracking is a naive approach.

Regarding the accounting mechanism: we need a way to avoid the state-write problem entirely to eliminate overhead, and a way to require no user action for seamless, universal UX.

I propose a novel approach — a retroactive gas rebate via epoch push:

How it works

  1. A publisher posts a Merkle root onchain by submitting a bond — anyone can do this. The computation is deterministic from public onchain event data, so any actor can independently verify or produce the correct root.
  2. A 24–48h dispute window opens — anyone can verify and challenge
  3. ETH is pushed automatically to eligible addresses

No claim step. No wallet requirement. Works for EOAs, smart accounts, multisigs — the vast majority of address types.

The only failure case is contracts that explicitly reject ETH (no receive(), or a receive() that reverts) — an edge case mostly limited to protocol treasuries and some proxy contracts.

Failed pushes don’t lose the rebate: it stays in the subsidy contract and is claimable directly by that address before the epoch expires. Push is the default; claim is the fallback.

The UX: you used ENS, ETH arrived in your wallet — contingent on a root being published each epoch. In practice this is a low-maintenance operation; the bond mechanism ensures anyone can step in.

The epoch delay is addressed by a real-time accrual dashboard — users see their pending rebate growing as they interact with ENS throughout the epoch. The delay becomes engagement, not friction.

—

Funding the subsidy contract

Originally, I’d intended to modify the Registrar Controller directly to split funds between the Treasury and the proposed Subsidy Contract. @Blockful’s Treasury Flow Automation (TFA) proposal changes that — and improves on it.

The epoch push rebate mechanism is downstream of TFA. Because TFA introduces the RegistrarManager as the single owner of all controllers — with a permissionless withdrawAll() that routes ETH to a DAO-configurable destination — we can insert a RevenueSplitter contract at that destination rather than touching the controllers at all.

The RevenueSplitter would be set as the RegistrarManager’s destination via a single setDestination() call, bundled into the same executable proposal that deploys both contracts.

Its properties:

  • Receives ETH from RegistrarManager on withdrawAll()
  • Splits by a DAO-configured ratio (e.g. 95/5) — set on deployment, adjustable by timelock
  • Routes the majority to the Endowment (endowment.ensdao.eth)
  • Routes the minority to the Subsidy Contract
  • Zero changes required to blockful’s contracts
  • Simple, auditable — ~50 lines of Solidity

—

Design Questions:

Building on Nick’s framing — rebates capped at 10% of a user’s registration fees, with expiry — the open design questions are around the mechanism itself.

  1. Bond sizing and slashing: the publisher bond needs to exceed the maximum epoch rebate to make griefing unprofitable. What’s the right floor, and who captures a slashed bond — the challenger, or does it burn?
  2. Dispute mechanism: “anyone can challenge” needs to be deterministic in practice. The standard pattern is: challenger submits a leaf, proof, and expected value that contradicts the root, and the contract verifies and slashes. Does this feel sufficient, or is there a simpler construction?
  3. Batched push execution — if an epoch has thousands of eligible addresses, a single push transaction will exceed the block gas limit. Push execution would need to be batched across multiple transactions. Worth designing for from the start; at current gas levels the execution cost is negligible.

—

If this reasoning sounds right, I’ll follow up with a more detailed spec for community feedback on the design — and if there’s rough consensus, move to a Temp Check.