test: EIP-712 per-key SessionGrant reference (addresses #1) - #2
Conversation
Additive reference test only — does NOT touch SessionHandler. Demonstrates an owner-signed, account-verified (no service) EIP-712 grant that extends the session allowlist from address-granular to (target, selector)-granular, against the same ERC7579Utils decodeMode/decodeBatch path used by _guardSessionExecution. 8/8 pass under the repo's solc 0.8.33 toolchain.
…tLib.sol (addresses Conrad-sudo#1) Harden PR Conrad-sudo#2 from a reference test into a reusable library implementing per-key (target, selector) scope for session keys, verified against the real ERC-7579 Execution[]/ERC7579Utils decode path SessionHandler._guardSessionExecution uses. - src/SessionGrantLib.sol: owner-signed EIP-712 SessionGrant (merkle root over (target,selector) leaves) + checkScope() decode/admission; fail-closed, atomic batch revert, delegatecall refused. NatSpec shows the _guardSessionExecution seam. - test: MockGrantedAccount now consumes the library (domain/key/expiry/nonce/owner-sig in the account; per-call admission in the lib). 9/9 pass under solc 0.8.33 + viaIR, incl. single + batch pass, out-of-scope/mixed-batch/expiry/wrong-account/stale-nonce/ bad-sig/delegatecall reverts.
|
Hardened this PR from a reference test into a merge-ready reference implementation, per your ask on #1 for "an EIP-712 grant-verification sketch against the real New:
Tests: the mock now consumes the library; 9/9 pass under your Happy to go the last step and wire it into |
|
Thanks for this. Merging. To be clear about how we'll use it: this goes in as a reference for our ERC-7715 / Smart Sessions work, not as a live feature. Nothing in The part we'll carry forward:
|
Follow-up to #1. You said an EIP-712 grant-verification sketch against the real
Execution[]shape would be a concrete starting point "whenever we pick it up" — so here it is as an additive reference test, take-it-or-leave-it. It does not touchSessionHandler; it's a self-contained harness so you can lift the logic into_guardSessionExecutionyour own way (and keep writing the real test yourself if you'd rather — no dependency imposed).What it demonstrates — an owner-signed, account-verified (no service in the loop) EIP-712 grant that extends the session allowlist from address-granular to (target, selector)-granular, verified from calldata against the same
ERC7579Utils.decodeMode→decodeSingle/decodeBatchpath_guardSessionExecutionalready uses:SessionGrant{account, sessionKey, callsRoot, validUntil, grantNonce}, EIP-712 typed, domain-bound to the account.callsRoot= a merkle root overkeccak256(bytes20(target) ++ bytes4(selector))leaves, so the grant is O(1) calldata regardless of how many calls are allowed.ECDSA.recover(_hashTypedDataV4(...)) == owner(), then per-execution merkle membership, failing closed on the first ungranted(target, selector)— atomic with the batch.grantNonceis owner-bumpable → instant revoke of a whole grant.usd_valueis deliberately untouched (stays metered in the module'spostCheck).Verified green under your toolchain (
solc 0.8.33, your pinned OZ,viaIR):forge test --match-contract SessionGrantReferenceTest→ 8/8 pass:Not addressed here (on purpose): where the grant + proofs travel in a real
execute. The two no-service options are in #1 (thread through the session-key signature envelope in_validateUserOp+ an EIP-1153 transient flag, for fail-fast in the 4337 window; or carry them in the executor path and verify in the guard). That's your architectural call — this PR just proves the verification shape holds against yourExecution[]decode. And as noted in #1, selector scope narrows a compromised key's reach; it does not close the §3.13 netting gap.Happy to close this unmerged if you'd rather own the test file end-to-end — the point was to hand you a working starting point, not a dependency.