Grants & delegation

How JoPay gets permission to route your money without holding a key. Two native paths, signed by your wallet, enforced on-chain.

In one line

When you authorize a feature like auto-forward or recurring billing, your own wallet signs a small on-chain permission slip (a "grant"). JoPay never holds the key that signed it. On-chain enforcer contracts verify every later action against what you signed — if the grant doesn't cover the action, the transaction reverts, regardless of who submitted it.

This is the engineering primitive behind the non-custody claim. The short version lives there; this page is the "how does it actually work" follow-up.

Two native paths, one outcome

JoPay supports three wallet types in v1 — Sequence WaaS (email / Google sign-in), Bucket A (Safe, Coinbase Smart Wallet, Argent, Ambire) and Bucket B (MetaMask Delegator, EIP-7702 EOAs). They all end in the same place (your wallet still owns the funds; JoPay signs nothing), but the protocol used to authorize JoPay-coordinated actions is wallet-native:

WalletUser-initiated outbound
(silent send, send)
Cross-wallet delegation
(auto-forward, recurring, scheduled send)
Sequence WaaSNative SessionPermissions / ExplicitSession. Sequence signer signs; no JoPay translation layer.Canonical ERC-7715 typed-data signed by the Sequence signer directly. Redeemed via ERC-7710.
Bucket A (Safe, Coinbase SW, Argent, Ambire)ERC-7715 grant to the public outbound executor, signed via the wallet's native account-abstraction flow.Same canonical ERC-7715 flow as Sequence — wire format is identical on-chain.
Bucket B (MetaMask Delegator, EIP-7702)ERC-7715 grant signed natively by the delegator.Same ERC-7715 flow.

Hardware wallets (Ledger, Trezor) are not supported in v1. Full wallet scope is tracked in the Wallets concept when that page ships.

You don't need to know which path your wallet uses — the dashboard shows the same "approve" prompt either way, and the on-chain result (funds forwarded, subscription charged) is the same.

What a grant contains

A grant is a short structured message your wallet signs. It binds the authority you're giving out to specific caveats, all enforced on-chain:

  • Grantee — the address allowed to redeem it. Always a public executor contract(auto-forward, recurring-pull, outbound) or a partner address. Never JoPay.
  • Token — typically USDC. Grants on other tokens revert.
  • Caps — per-transaction cap (default €70) and rolling / cumulative cap (default €5k; see three-tier UX below).
  • Allowlist — whose address the funds can go to. For auto-forward this pins your withdraw address; for recurring this pins the merchant.
  • Expiry — default 90 days. You get renewal nudges at T-14, T-3, and T-0 so the flow never breaks silently.
  • Nonce policy — optional once-per-period semantics for recurring-style pulls.

Each of those caveats is a separate on-chain contract (token allowlist enforcer, period transfer enforcer, timestamp enforcer, etc.). The suite is collectively known as the caveat-enforcer suite. When a keeper tries to redeem your grant, the DelegationManager contract calls every caveat enforcer — any single one saying no reverts the entire redeem.

Three-tier approval UX

Not every action asks you to approve manually. Grants power a frictionless "silent" zone for small, normal-looking transactions while keeping bigger or unusual ones gated on an explicit user action:

ZoneTriggerWhat you see
SilentAmount < €70 per-tx and running daily total + tx ≤ €5kNothing. The grant covers it on-chain and a permissionless keeper redeems. Venmo-style.
BiometricAmount ≥ €70 but running daily total + tx ≤ €5kFace ID / passkey tap. The grant still covers the action on-chain; the prompt is UX, not a permission gate.
Email approvalAmount > €5k or would push running total past daily capFace ID + 5-minute email confirm-link. The transaction falls out of the existing grant's scope; you either sign it directly or re-issue a grant with higher caps.
One Sequence-specific subtlety: WaaS wallets use cumulative caps over the 90-day session, not daily-rolling caps. Your €5k allowance is total for the session lifetime; renewing the session resets it. External wallets (Bucket A / B) use true rolling-daily enforcement via the caveat suite. Dashboard copy says "allowance per authorisation period" rather than "per day" to avoid the divergence confusing anyone.

Grant lifecycle

Each grant you sign moves through a small state machine, observable in your merchant dashboard and via the grant webhook events:

  • Issued — you signed the grant. It exists on-chain (or in your wallet's native session store, for WaaS) and in the merchant_grantsrecord on JoPay's side. Webhook: grant_issued.
  • Active — the caveat enforcers will approve redeems. This is the default state between issue and expiry.
  • Expiring soon — 14 days, 3 days, and 0 days before expiry you receive renewal nudges. Webhook: grant_expiring.
  • Expired — the deadline caveat starts rejecting redeems. Any in-flight redeem after this point reverts.
  • Revoked — you revoked it manually (one click in Settings). The revocation registry rejects any redeem. Webhook: grant_revoked.

Who can actually redeem a grant?

Anyone. That is the point. JoPay runs keepers as a courtesy so things happen quickly, but the grantee field only tells the caveat enforcer what kind of transaction it's checking — not who may submit it. Any partner, any third-party relayer, or you yourself can call DelegationManager.redeemDelegations(). If the caveats approve, the transaction goes through; if they don't, it reverts. JoPay's keeper has no special privilege.

The consequence: if JoPay goes offline, you don't lose access to any feature that's already authorised. Any keeper can crank recurring charges or auto-forward sweeps from your pending grants. Your funds move regardless of whether Labs is reachable.

What Labs cannot do with your grant

  • Submit a transaction outside the caveats.The enforcer suite rejects it on-chain. There is no bypass.
  • Change a grant's caveats after you signed it.Grants are immutable; tighter or looser scope requires a new grant signed by you.
  • Revoke for you. Revocation requires your signature. Labs can observe and display a revoked grant but cannot cancel one for you.
  • Hold a signing key that could redeem any grant. JoPay is not a grantee on any grant in v1. Public executor contracts are.

What next?