I fully admit that while most of the work in the actual feature was my own, and the paid/private retrievals is mostly human with just AI assistance, this design is almost entirely Claude-generated with prompts and refinement from me. I have reviewed and edited the whole thing, I stand by it, but I apologise for the classic AI format and flow which you all must be tired of by now.

How a storage provider (Curio) decides which IDataSetAuthorizer contracts it is willing to spend gas on when relaying authorizer-gated operations, without forcing every client onto a single shared authorizer instance.

Despite its length this is a reasonably compact design and doesn’t require much in Curio to make it work.


1. Motivation

filecoin-services PR #536 lets a data set's payer attach an authorizer contract that becomes the sole gate for add-pieces / schedule-removals / immediate-terminate. When the SP relays one of those operations that smart contract call happens in their context, so the SP's transaction pays for the authorizer's isAuthorized call — up to the AUTHORIZER_GAS_LIMIT of 150M gas (a full P256/passkey verification is ~110–123M), and the SP is at risk of DoS and other creative attacks that can arise from code injection by the client.

OIn other words, a hostile or buggy authorizer can burn max gas or DoS the SP on every relay.

The SP therefore needs an off-chain policy: only relay for authorizers whose logic I trust. This document specifies that policy and how it lands in Curio.

2. Principles

P0 — SP’s risk, SP’s choice

This design aims to provide protection for the SPs and makes recommendations for which types of Authorizer contracts should be trusted, but ultimately it is completely up to the SP which Authorizers they choose to accept. The contract restrictions described below will be added to documentation, and I recommend that FoC never officially endorse any Authorizer contract that violates these principles, but in principle SPs can accept whatever risk they want.

P1 — Identify authorizers by code, not by address

Allowlisting a specific contract address creates pressure in undesirable directions. Either:

Both of these are bad and so instance-based whitelisting has been rejected.

Instead, the allowlist keys on the authorizer's code identity. "This logic is approved; run your own instance." Two clients running the same approved code at different addresses — each with its own owner and its own state — are both accepted.

Here I explicitly recognise the drawback of this approach: that the Authorizer whitelist cannot express “I approve this client to cause lots of gas but not others”. I think that’s fine because in the FoC pool model SPs shouldn’t really be able to reject clients (within reasonable bounds).

P2 — Bind to immutable code

The danger is not shared instances; it is mutable ones. An upgradeable proxy (UUPS / Transparent / Beacon) has a stable address and stable proxy bytecode, but its actual logic lives in a storage slot the owner can change at any time. Bless a proxy and its owner can swap in a gas bomb after approval.