Thanks for opening this. Quick comment on item 2 (predicate ERC-165 dispatch + composability): the existing pinned IRequirementTypes markers (IERC721Holding, IERC1155Holding, ISubscription) cleanly cover on-chain holdings — same EVM chain as the registry, single Solidity read. There’s a fourth shape that the data parameter on IAccessPredicate.hasAccess already supports natively but no marker yet describes: off-chain-signed wallet-state attestations.
The case for it as a distinct kind:
-
Cross-chain wallet state cannot be expressed as a native EVM predicate. Wallet state on non-EVM chains (Solana, XRPL, Bitcoin) can’t be evaluated from a Solidity predicate. The natural shape is for an off-chain issuer to evaluate the condition set against the relevant chain data, sign a verdict, and have the on-chain predicate verify the signature. The spec’s
dataparameter (“Opaque context bytes (e.g., tokenId, proof, signature)”) is designed for exactly this. -
It’s distinct from the
AccessProofpattern in §“Account Parameter Is Advisory.” That pattern is requester-self-signed — the wallet signs a challenge to prove it isaccount. The attestation pattern here is issuer-signed — an external service signs a verdict aboutaccount’s wallet state. Identity-binding and state-binding are orthogonal; a complete access scheme may want both, and conflating them at the marker layer would lose that distinction. -
Gas fits comfortably. ECDSA P-256 verification via the RIP-7212 precompile is ~3,450 gas; ABI decode of a seven-tuple proof is another few thousand. Well under the 200k cap.
Concrete proposal:
/// @dev kind for off-chain-signed wallet-state attestation requirements.
/// data = abi.encode(string issuerJWKSURI, bytes32 conditionHash)
/// interfaceId = 0x7a111640
interface IWalletStateAttestation {
function walletStateAttestation() external;
}
Selector 0x7a111640 = bytes4(keccak256("walletStateAttestation()")), verified non-colliding with the three pinned IDs.
The getRequirements.data layout abi.encode(string issuerJWKSURI, bytes32 conditionHash) tells an agent two things: where to fetch the issuer’s public-key set (a JWKS document at a well-known URL — same trust-anchor pattern as the spec’s manifest origin-binding), and which condition set the predicate enforces. The hasAccess.data payload then carries the proof itself: abi.encode(bool pass, address wallet, bytes32 conditionHash, uint256 blockNumber, bytes32 r, bytes32 s, bytes32 messageHash).
A working reference predicate that matches this layout, verifies P-256 via RIP-7212, advertises IAccessPredicate + IERC165 for registration validation, and returns false (rather than reverts) on any check failure is at:
Tests in the same repo (InsumerAccessPredicate.t.sol) include a happy-path case that runs real ECDSA P-256 verification of a live signed attestation through the precompile, plus eight failure modes (tampered signature, tampered message hash, wrong account, wrong condition hash, pass=false, stale, future-dated, empty data).
Happy to fold the marker into a PR against IRequirementTypes.sol if it’s useful, or leave it as a third-party marker per the spec’s extension guidance — whichever fits the cadence you’re running.