Skip to content

feat: per-key spending-rule enforcement for Lambda parity (PRs 1-3)#477

Open
clawdbot-glitch003 wants to merge 5 commits into
mainfrom
glitch003/lambda-parity-payments-storage
Open

feat: per-key spending-rule enforcement for Lambda parity (PRs 1-3)#477
clawdbot-glitch003 wants to merge 5 commits into
mainfrom
glitch003/lambda-parity-payments-storage

Conversation

@clawdbot-glitch003

Copy link
Copy Markdown
Collaborator

Implements the Chipotle gateway controls that make a usage API key safe to embed in a frontend, with blast-radius parity to a public AWS Lambda URL (see plans/chipotle-lambda-parity.md). One branch, three logical layers as separate commits.

PR 1 — lit-payments storage. New spending_rules + spending_usage tables (migration) and a spending module: Operator-authed CRUD under /api/spending-rules for the admin UI, and ServiceAuth-authed /internal endpoints for the gateway to fetch rules and record rolling spend. Disabled (503) unless INTERNAL_SERVICE_TOKEN is set.

PR 3 — AccountConfig contract (source only). Adds the on-chain hasSpendingRules gate: a new mapping appended to the end of root storage (storage-safe), a setSpendingRulesFlag writer, and a canExecuteActionWithSpendingRules view returning (canExecute, hasSpendingRules) so the gateway reads both in one RPC. forge build passes; regenerate bindings + diamond-cut deploy are ops steps.

PR 2 — gateway enforcement. Reads the flag in the same multicall as the execute check (cached in BlockchainCache), so keys without rules pay zero extra work. For a flagged key it enforces a rolling spend cap (402), a per-node token-bucket rate limit (429), and a per-node concurrency cap (429), recording spend off the response path. Inert unless LIT_PAYMENTS_INTERNAL_URL + INTERNAL_SERVICE_TOKEN are set and the key's flag is on. The new view is called via a scoped sol! interface so it tracks the workspace alloy version rather than the regenerated giant binding.

cargo check is clean for both crates; 13 unit tests pass. Not yet wired: the "set rule in DB → flip the on-chain flag" path, the binding regen + Safe diamond-cut deploy, origin allowlist (P2.1), and SWR background refresh for the rules cache (currently TTL + inline cold-miss fetch).

🤖 Generated with Claude Code

glitch003 and others added 3 commits June 4, 2026 18:02
… PR 1)

First slice of the Lambda-parity work (plans/chipotle-lambda-parity.md): the
durable home for per-key blast-radius controls the gateway will enforce.

- Migration: spending_rules (rolling spend cap+window, rate rps+burst,
  concurrency, origin allowlist, enabled) and spending_usage (rolling spend
  counter with in-SQL window reset).
- New `spending` module: typed rows + validated upsert request, sqlx db layer
  (upsert/get/list/delete rules, atomic record_charge with window reset),
  ServiceAuth bearer guard for gateway calls, and routes.
- Operator-authed CRUD under /api/spending-rules (admin UI) and
  ServiceAuth-authed /internal endpoints (gateway: fetch rules for its cache,
  record spend off the response path).
- INTERNAL_SERVICE_TOKEN config; /internal endpoints disabled (503) when unset.

No production behavior change — nothing reads these tables yet. 9 unit tests
cover request validation, hash canonicalization, and the token comparison.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…parity PR 3)

The on-chain zero-latency gate for per-key spending rules. All additive and
storage-safe: a new mapping appended to the END of root AccountConfigStorage
(not a field on the inline-embedded UsageApiKey struct, which would shift the
Account layout).

- AppStorage: append `mapping(uint256 => bool) usageKeyHasSpendingRules`.
- ViewsFacet: `getSpendingRulesFlag(apiKeyHash)` and
  `canExecuteActionWithSpendingRules(apiKeyHash, cidHash) -> (canExecute,
  hasSpendingRules)` so the gateway reads both in one RPC.
- WritesFacet: `setSpendingRulesFlag(accountApiKeyHash, usageApiKeyHash, bool)`
  + event, same account-access control as setUsageApiKey.

Source only; `forge build` passes. Regenerate the Rust bindings + diamond ABI
with `make generate` on the canonical toolchain, then deploy via Safe diamond-cut
on Base (both ops steps). The gateway reads the new view through a scoped sol!
interface, so it does not depend on the regenerated giant binding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(lambda-parity PR 2)

Gateway side of the Lambda-parity work. Reads the on-chain hasSpendingRules gate
in the same multicall as the execute-permission check; keys without rules pay
zero extra work.

- accounts: can_execute_action_with_spending_rules -> (can_execute,
  has_spending_rules), cached in BlockchainCache (new execute_and_spending
  entry, same generation invalidation). Reads the new view via a scoped sol!
  interface (read_only_client_and_address helper) so it tracks the workspace
  alloy version instead of the regenerated giant binding.
- core::spending_rules: flag-gated enforcer. On a flagged key it fetches rules
  (cached, TTL) from lit-payments /internal, then enforces a rolling spend cap
  (402), a per-node token-bucket rate limit (429), and a per-node concurrency
  cap (429). Spend is recorded off the response path (in-memory + fire-and-
  forget POST). Inert unless LIT_PAYMENTS_INTERNAL_URL + INTERNAL_SERVICE_TOKEN
  are set AND the key's on-chain flag is on.
- Wired into core_features::lit_action + the /lit_action route + main state.
- 429 (too_many_requests) ApiStatus helper.

Origin allowlist (P2.1) deferred. SWR background refresh for the rules cache is
a marked follow-up (currently TTL with inline cold-miss fetch). cargo check
clean; 4 unit tests for the token bucket, window reset, and hash format.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@clawdbot-glitch003
clawdbot-glitch003 requested a review from a team June 10, 2026 01:13
glitch003 and others added 2 commits June 11, 2026 15:32
…ty-payments-storage

# Conflicts:
#	lit-api-server/src/accounts/signable_contract.rs
#	lit-api-server/src/main.rs
#	lit-payments/src/config.rs
#	lit-payments/src/main.rs
Brings the two design plans from PR #446 into this branch so they ship with the
lambda-parity implementation they describe, and #446 can be closed.

- plans/chipotle-lambda-parity.md — prioritized gateway work (this PR implements
  P0.0/P0.1/P0.2/P1) for per-key blast-radius parity with a public Lambda URL.
- plans/private-apps-backend.md — the backend-as-Lit-Actions framework these
  gateway controls unlock (relay becomes optional).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants