fix(aip18): make pure buyers gasless via buyer-link gate marker (DEC-8)#21
Merged
Conversation
…C-8)
The SDK auto-wallet gate (ACTPClient) only granted the gas-sponsored wallet
when `configHash != 0 || hasPendingPublish`. A pure buyer (intent: pay) links
instead of registering (DEC-3/DEC-4), so it has NEITHER — the gate dropped it
to the EOA wallet, forcing the buyer to fund ETH. That contradicts DEC-8
("buyers are gasless; they need only USDC").
Fix — a buyer-link marker, mirroring the existing pending-publish escape hatch:
- New `config/buyerLink.ts`: a tiny, network-agnostic `.actp/buyer-link.json`
marker (atomic write, 0o600, symlink-safe, corrupt-tolerant).
- `actp publish` (pay-only branch) writes the marker on link. It triggers NO
lazy on-chain activation (a buyer never registers).
- ACTPClient gate adds a third leg: `... || isLinkedBuyer` in both the normal
and fail-open (RPC-down) paths.
Why this opens no free-gas vector: a buyer's only costly on-chain action —
pay() — locks USDC in escrow, which is the anti-DOS backstop (threat-model).
The marker is the same trust posture as the already-trusted pending-publish
local file.
Note: the SDK now grants the sponsored wallet; the paymaster policy must also
allow-list the contracts a buyer touches (kernel + vault + USDC approve /
Permit2) for end-to-end gasless — an ops follow-up, tracked separately.
Tests: new buyerLink suite (6) + 2 gate tests (linked buyer → auto;
unregistered non-buyer → eoa). Full SDK suite: 2914/2914.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DamirAGI
added a commit
that referenced
this pull request
Jun 5, 2026
Ships the buyer-link gate marker: a pure buyer (intent: pay) now uses the gas-sponsored auto wallet instead of falling back to the ETH-funded EOA. Source merged in #21. Bump kept separate from the in-flight 4.5.0 delivery work. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Problem (code-verified)
The SDK auto-wallet gate (ACTPClient.ts) granted the gas-sponsored wallet only when
configHash != 0 || hasPendingPublish. A pure buyer (intent: pay) links instead of registering (DEC-3/DEC-4) → it has neither → the gate dropped it to the EOA wallet, forcing the buyer to fund ETH. That directly contradicts DEC-8 ("buyers are gasless; they need only USDC").This was surfaced by the budget-privacy fix (#20): making buyer publish link-only means a buyer has no configHash and no pending-publish, so the gate never granted it the sponsored wallet.
Fix — a buyer-link marker (mirrors the existing pending-publish escape hatch)
config/buyerLink.ts: a tiny, network-agnostic.actp/buyer-link.jsonmarker — atomic write,0o600, symlink-safe, corrupt-tolerant.actp publish(pay-only branch) writes the marker on link. No lazy on-chain activation is triggered (a buyer never registers).... || isLinkedBuyerin both the normal and fail-open (RPC-down) paths.Why this opens no free-gas vector
A buyer's only costly on-chain action —
pay()— locks USDC in escrow, which is the anti-DOS backstop (threat-model). The marker carries the same trust posture as the already-trustedpending-publishlocal file.⚠ Ops follow-up (not in this PR)
The SDK now grants the sponsored wallet; the paymaster policy must also allow-list the contracts a buyer touches — kernel + vault + USDC
approve/ Permit2 — for true end-to-end gasless. Tracked separately.Tests
New
buyerLinksuite (6) + 2 gate tests (linked buyer →auto; unregistered non-buyer →eoa). Full SDK suite: 2914/2914.Builds on #20. Implements agirails/aips#3 DEC-8.
🤖 Generated with Claude Code