target and cap, so the co-signer can only push
the payment the payer set up, never steal or redirect. Fail-closed: if the
firewall’s data source is unreachable, it withholds the signature.
Server endpoint
Expose two routes on the same origin as your app:GET /api/cosignreturns the co-signer’s public address, which the browser locks into each new account.POST /api/cosignauthorizes a spend and returns a signature or a veto.
cosign reads the account’s real policy from chain (never trusting what the
browser claims), runs a LocalCoSigner backed by the SDK poisoning check(), and
signs the exact EIP-712 Spend struct the contract will verify.
The policy the co-signer enforces
Even though the contract re-checks these, the co-signer refuses to put its name on a request that violates them:Target lock
Target lock
The co-signer reads the account’s real
target from chain and signs only for
that address; it never trusts a target the browser supplies. The browser hands
it only {account, owner, amount, action}. A script that swaps the destination
cannot get a signature, and the contract’s target is locked anyway.Amount and window
Amount and window
The amount must be within the remaining cumulative cap, and the account must
not have expired.
Risk firewall
Risk firewall
Runs
check(owner, target). Vetoes on a block verdict (drainer, lookalike,
zero-value bait, or unavailable data). Set vetoOn: 'warning' to also stop
new/fresh recipients.In-process co-signer (tests and local)
For tests or a single-process setup, useLocalCoSigner directly with a pluggable
risk source: