Skip to content

feat: RecurringPaymentHook – ERC-8191 × ERC-8183 subscription integration#4

Open
chasseurmic wants to merge 1 commit intoerc-8183:mainfrom
chasseurmic:feat/recurring-payment-hook
Open

feat: RecurringPaymentHook – ERC-8191 × ERC-8183 subscription integration#4
chasseurmic wants to merge 1 commit intoerc-8183:mainfrom
chasseurmic:feat/recurring-payment-hook

Conversation

@chasseurmic
Copy link
Copy Markdown

What this hook does

RecurringPaymentHook bridges ERC-8183 agentic jobs with ERC-8191 onchain
recurring payment subscriptions, enabling subscription-gated pricing and
access control in the ACP job lifecycle.

Use case

Agents offering tiered, subscription-based services need to:

  • price jobs differently for recurring subscribers vs. one-off clients
  • block job funding if a client's subscription has lapsed

Profile

B — Advanced Escrow: multi-phase flow, maintains job↔subscription state,
integrates an external ERC standard (ERC-8191).

Hook callbacks used

Callback Role
_preSetBudget Tiered pricing — subscribers meet subscriberMinBudget, others nonSubscriberMinBudget
_preFund Subscription gate — reverts if registered subscription is not Active
_postFund Links jobId → subId in storage for lifecycle correlation
_postComplete Emits JobCompletedForSubscriber for off-chain services
_postReject Emits JobRejectedForSubscriber for dunning / retry logic

Trust assumptions

  • Trusts the ERC-8191 SubscriptionManager at the address supplied in the constructor
  • registerSubscription validates that caller is the subscriber and merchant matches
  • No token custody — all value flows through the ACP core contract
  • _postComplete / _postReject are informational only, no external state-changing calls

Related

cc

@psmiratisu — this implements the subscription-gated pricing flow you sketched
in the ERC-8183 Ethereum Magicians thread (check subscription status at
setBudget / fund for tiered pricing).

@ThoughtProof — the _postReject / _postComplete events are designed to
feed the same kind of off-chain continuation logic you described with
beforeSettle in pot-x402. Would love your thoughts on the trust model.

@ThoughtProof
Copy link
Copy Markdown

Great work — the trust model is exactly right. Reading subscription status live at _preFund rather than caching it is the correct call; stale state would be a silent security issue.

On _postComplete/_postReject: these map cleanly to our afterSettle pattern in pot-x402. The events give off-chain verification services (like ThoughtProof) the hook they need to report outcomes back to reputation systems after settlement — without being able to block the on-chain flow.

One thought on the trust model: the hook currently trusts the SubscriptionManager address at deploy time. For long-lived subscriptions it might be worth considering whether the SubscriptionManager address should be upgradeable or locked — a compromised oracle at that address could unilaterally gate or ungate all jobs.

We're building complementary infrastructure — if useful we'd be happy to add a ThoughtProofVerificationHook example to this repo that shows how off-chain reasoning verification feeds back into the ACP lifecycle alongside your subscription gating.

@psmiratisu
Copy link
Copy Markdown
Contributor

Thanks for the RecurringPaymentHook! I see you're proposing ERC-8191 as a companion standard for on-chain recurring payments.

Architecture question for open standard alignment:
The current implementation creates a direct dependency between ERC-8183 and ERC-8191. Do you think it made sense to keep decouple both standard so that it would be easier to maintain?

We can extract ISubscription interface and have ERC 8191 as the reference implementation

interface ISubscription {
    function getStatus(bytes32 subId) external view returns (SubscriptionStatus);
    function getSubscriber(bytes32 subId) external view returns (address);
    function getMerchant(bytes32 subId) external view returns (address);
    function processPayment(bytes32 subId) external returns (bool);
    // ...
}

@ThoughtProof
Copy link
Copy Markdown

+1 on decoupling. From our experience implementing ThoughtProofReasoningHook, keeping the interface narrow and the standard dependency loose makes hooks much easier to maintain. A minimal ISubscription capability interface sounds right."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants