fix(buy-x402): unify + extend x402 auth pool expiry (default 1 month, optional never)#601
Merged
Conversation
added 2 commits
June 5, 2026 13:31
… optional never) Pre-signed pool auths were silently expiring ~5 minutes after buy: the Permit2 (OBOL) path set deadline = now + max(maxTimeoutSeconds, 300) (=300s), conflating the per-request settle window with the pool's spendability lifetime, while the ERC-3009 (USDC) path used validBefore=4294967295 (~never) — inconsistent. Introduce a single _auth_expiry() used by BOTH payment methods: - OBOL_X402_AUTH_TTL (seconds) / --auth-ttl <seconds|never> - default 30 days (1 month); floor 300s - 0/never/none -> 4294967295 (~year 2106), the uint both contracts accept Permit2 deadline and ERC-3009 validBefore now expire at the same wall-clock.
…r, fallback) Locks the unified expiry contract and the facilitator-safe MAX_SAFE_DEADLINE (0xFFFFFFFF). Run: python3 tests/test_buy_auth_expiry.py
Contributor
Author
Update — test coverage + x402 parityTest coverage added ( x402 parity (verified against the
Net: spec-aligned; the original 5-min bug produced |
OisinKyne
approved these changes
Jun 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Unifies and extends the x402 pre-signed auth pool expiry — one knob for both payment methods, default 1 month, with an optional non-expiration setting.
Bug
Pre-signed pool auths silently expired ~5 minutes after buy.
_presign_authsset the Permit2 (OBOL)deadline = now + max(maxTimeoutSeconds, 300)(= 300 s) — conflating the per-request settle window (maxTimeoutSeconds) with the pool's spendability lifetime. Meanwhile the ERC-3009 (USDC) path hardcodedvalidBefore = 4294967295(~never). So OBOL pools became unusable minutes after purchase (the first auth settled, the rest expired) while USDC pools never expired — inconsistent.Observed live: a pool intended for ongoing use had a Permit2
deadline~5 min out; later paid requests failed with seller503 "Payment verification failed"(on-chainblock.timestamp <= deadlinerejects the expired auth).Fix
A single
_auth_expiry()resolver drives both the Permit2deadlineand the ERC-3009validBefore:OBOL_X402_AUTH_TTLenv or--auth-ttl <seconds|never>flag (onbuyandpay)0/never/none→4294967295(~year 2106) = non-expiration — the uint sentinel that both USDCtransferWithAuthorization(validBefore <) and the Permit2/x402 contracts (deadline <=) accept without overflowBoth payment methods now expire at the same wall-clock.
Why this is the right (and only) place
The deadline/validBefore is set at sign time in
buy.py, carried verbatim throughPurchaseRequest → serviceoffer-controller → x402-buyer → seller(the remote-signer signs blindly; nothing downstream re-derives it), and enforced only on-chain at settle. Sobuy.py's_presign_authsis the single amendment point.Test
python3 -m py_compile✓ ·go build ./cmd/obol✓ (embed intact) · repo pre-commit ✓_auth_expiry()verified: default →30.0 days;never/0→4294967295;3600→3600 s;10→300 s(floored)Notes
OBOL_X402_AUTH_TTL=neverto restore the old behavior; both schemes are now consistent._presign_auths' deadline, so this applies cleanly on top (different code regions from feat(buy-x402): --set-default — agent self-adopts paid/<model> as its primary model #595's--set-default, which release: v0.10.0-rc12 (consolidate #593/#594/#595/#597 + review hardening) #600 already carries).Scope
Two files, additive:
internal/embed/skills/buy-x402/scripts/buy.py(+42),internal/embed/skills/buy-x402/SKILL.md(+2). No controller, RBAC, or Go changes.