Skip to content

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync - #818

Open
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock
Open

feat(helm): template authCaptureUnlock so the paid unlock gate survives a sync#818
bussyjd wants to merge 1 commit into
mainfrom
feat/helm-authcapture-unlock

Conversation

@bussyjd

@bussyjd bussyjd commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Problem

x402-pricing is a Helm-managed static ConfigMap (internal/embed/infrastructure/base/templates/x402.yaml) shipping routes: [] and no authCaptureUnlock. The only way to turn the paid unlock gate on was to patch the live ConfigMap by hand — which the next obol stack up reverts to the chart default, silently disabling the fee split.

This is not hypothetical. On a live stack the ConfigMap's last-applied-configuration still carries a fully configured canary:

authCaptureUnlock:
  enabled: true
  offerPrefix: "/services/authcap-canary"
  price: "0.01"
  minFeeBps: 50
  maxFeeBps: 50

…while the live data is the untouched chart default. The configured fee address holds exactly 0.000050 USDC — precisely 50 bps of one 0.01 unlock — and nothing since. The mechanism worked; a reconcile turned it off and nobody noticed.

Change

authCaptureUnlock and facilitatorURL now render from values, defaulted off in both base/values.yaml and the helmfile's state values, and passed through to the base release.

With the defaults the rendered pricing.yaml is byte-identical to what ships today, so no existing stack changes behaviour.

facilitatorURL is templated in the same change because it is load-bearing for this feature — see below.

The mainnet trap

The hosted facilitator advertises auth-capture on Base Sepolia only. Straight from its /supported:

auth-capture       @ eip155:84532     ← testnet only
batch-settlement   @ eip155:8453
exact              @ eip155:8453

So enabling the unlock on network: base while pointed at https://x402.gcp.obol.tech lands on a facilitator that cannot settle the scheme. Mainnet needs the in-cluster sidecar (http://localhost:8090), whose config declares v2-eip155-auth-capture for eip155:8453 — which is exactly how the canary worked.

Worth flagging: the rc2 notes said the hosted facilitator made the gate "usable on this release". True for testnet, not mainnet. The docs added here state the constraint explicitly.

Docs

The seller-facing x402-pricing.md reference had no mention of this feature at all, which is why it has been read as "an opt-in platform fee on everything the seller receives".

It isn't. It turns one gate: auth offer from free wallet sign-in into pay-once-to-mint-a-session, and splits that single payment two ways. It does not apply to normal paid requests, and it cannot route a share to an upstream provider — the split has exactly two legs (payTo, feeRecipient) and fires only on the unlock.

The doc also records both current ceilings, so they stop being rediscovered:

  • One unlock offer per stackofferPrefix is global, matched by exact string comparison (unlockgate.go:23).
  • Per-offer config is impossible todayServiceOfferPayment.Scheme is +kubebuilder:validation:Enum=exact, with TODO(auth-capture) above it (monetizeapi/types.go:307).

Verification

  • helm template with defaults reproduces the current pricing.yaml byte-for-byte.
  • With the canary values it reproduces the exact config that produced the real on-chain fee.
  • The CI helm-template-smoke command (placeholder substitution + full chart render) exits 0 at 3407 lines.
  • go build ./... and go test ./internal/embed/... ./internal/x402/... pass.

Not in scope

Per-offer authCaptureUnlock via the CRD, which the TODO(auth-capture) names as the follow-up.

…es a sync

x402-pricing is a Helm-managed static ConfigMap that ships `routes: []` and
no authCaptureUnlock. The only way to turn the unlock gate on was to patch
the live ConfigMap by hand — which the next `obol stack up` reverts to the
chart default, silently disabling the fee split.

That already happened on a live stack: the ConfigMap's
last-applied-configuration still carries a fully configured canary
(offerPrefix /services/authcap-canary, 50/50 bps) while the live data is the
untouched chart default. The fee address collected exactly one payment —
0.000050 USDC, precisely 50 bps of one 0.01 unlock — and nothing since.

authCaptureUnlock and facilitatorURL now render from values, defaulted off
in both base/values.yaml and the helmfile's state values, and passed through
to the base release. With the defaults the rendered pricing.yaml is
byte-identical to what ships today, so no existing stack changes behaviour.

facilitatorURL is templated in the same change because it is load-bearing
for this feature: the hosted facilitator advertises auth-capture on Base
Sepolia ONLY (eip155:84532, confirmed against its /supported), so a mainnet
unlock must point at the in-cluster sidecar on :8090. Enabling the gate
without that lands you on a facilitator that cannot settle the scheme.

Also documents the feature in the seller-facing x402-pricing reference,
which had no mention of it at all. That gap is why it has been read as "an
opt-in platform fee on everything the seller receives". It is not: it turns
ONE `gate: auth` offer from free wallet sign-in into pay-once-to-mint-a-
session, and splits that single payment two ways. It cannot route a share to
an upstream provider. The doc records both current ceilings — one unlock
offer per stack, and ServiceOffer.scheme being enum=exact so per-offer
config is impossible today.

Verified: `helm template` with defaults reproduces the current pricing.yaml
byte-for-byte; with the canary values it reproduces the exact config that
produced the real on-chain fee; and the CI helm-template-smoke command
renders the whole chart clean (3407 lines, exit 0).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant