Add OwnerApprovalHook (Profile A) — human spending-approval gate via off-chain owner signature#49
Open
with0utwhy wants to merge 1 commit into
Open
Conversation
…off-chain owner signature
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.
OwnerApprovalHook — Profile A (Simple Policy)
A policy hook that blocks
fund()until a designated owner has approved thejob's budget, where approval is an off-chain EIP-712 signature presented in the
fundoptParams. No token custody.Use case
An AI agent's human operator wants to gate the agent's spending: the agent can
create and run jobs, but money only moves once the human signs off on the
budget. This adds a human-in-the-loop oversight lane to ERC-8183 without a
trusted intermediary — useful for spend controls and regulatory human-oversight
requirements.
Flow
setBudgetoptParams carryabi.encode(owner). The hook records the ownerfrom optParams; if none is supplied the job stays owner-less and cannot be
funded (fail-closed). Once an owner is set, it emits
ApprovalRequested(jobId, owner, client, budget)for an off-chain notifier.Approval(uint256 jobId,uint256 budget, uint256 deadline)under this contract'sEIP712("OwnerApprovalHook","1")domain — gasless, in a wallet. The wallet shows the named fields, not an
opaque hash.
fundoptParams carryabi.encode(signature, deadline)._preFundvalidatesthe signature against the recorded owner — an EOA (ECDSA) or a smart-contract
wallet (ERC-1271), via OpenZeppelin
SignatureChecker— and requires thedeadline to be in the future and within a bounded window. A missing or invalid
signature reverts, blocking the funding.
requiredSelectors()returns[setBudget, fund]because the owner is capturedat
setBudgetand consumed atfund.Trust model / assumptions
outside the ERC-8183 callbacks. Only a valid signature from the recorded owner
(EOA or ERC-1271 wallet) can unblock funding. No admin, no upgradeability.
setBudget(no later swap). The budget is boundinto the signed payload, so raising the budget invalidates a prior approval
(no escalation). The EIP-712 domain binds the signature to this hook on this
chain, and
jobIdbinds it to one job (no cross-job/chain/hook replay). The jobis flagged funded in
_postFund, so the same approval can't be replayed even ifthe core ever permitted a second
fund()(no same-job replay).MAX_APPROVAL_WINDOW(30 days) ahead, so an approval cannot accidentally bemade effectively non-expiring.
Off-chain integration
The hook is intentionally thin: it emits
ApprovalRequestedand verifies asignature. The owner-facing pieces live off-chain and follow a simple pattern any
integrator can implement:
ApprovalRequested(jobId, owner, client, budget); notify the owner.Approvalpayload (wallet shows the fields).abi.encode(signature, deadline)as
fundoptParams.A minimal integration is just two off-chain steps — no relay infrastructure required:
A reference implementation of this layer — an event listener with
Telegram / ntfy / web-push notifications and a one-click owner approval UI — is
hosted at https://humantaste.app/gatekeeper, so integrators don't have to build
the notification + signature-relay plumbing themselves.
Conformance checklist
BaseERC8183Hook+IERC8183HookMetadata;supportsInterfaceadvertises bothrequiredSelectors(); overrides only_postSetBudget,_preFund, and_postFundBaseERC8183Hook)SignatureChecker(EOA + ERC-1271); deadline lower- and upper-bounded_fundedguard in_postFundblocks same-job replay.sol,^0.8.20,SPDX MIT, named imports, vendor-neutral, no test filesonlyERC8183guard)Deployed + exercised end-to-end (setBudget → off-chain owner signature → fund) on
Base Sepolia; mainnet instance at
0xB2d871a9cE05ABE8B4A4Ea2BBbD666bE4aF4CBbF.