Add ERC-8176 descriptor attestation support - #65
Open
manuelwedler wants to merge 2 commits into
Open
Conversation
Wallets can now define which auditors (EAS attesters) they trust and format only through attested descriptors: - New attestations.ts: computeDescriptorHash (RFC 8785 JCS + keccak256 over the includes-resolved descriptor), verifyAttestation (offline EAS offchain attestation verification: canonical schema UID, attested hash, domain pin, expiration, ECDSA recovery, offchain UID recomputation), and the registry sigs/ path convention. - New attestations option on the resolver options: trustedAttesters plus a wallet-delegated checkRevocation callback. Enforced by applyAttestationPolicy in resolver.ts after includes resolution; failure surfaces as NO_TRUSTED_ATTESTATION / ATTESTATIONS_NOT_SUPPORTED. - GitHub and filesystem resolvers implement the optional DescriptorResolver.fetchAttestation; custom resolvers can supply their own. Bundled trusted-token descriptors stay exempt. - Tests against the registry's real Tether USD attestation plus test-key-signed edge cases; docs updated (README, GUIDE, AGENTS). Closes #61 Co-Authored-By: Manuel Wedler <manuel@wedler.dev>
manuelwedler
force-pushed
the
claude/clear-signing-attestations-5xchjp
branch
from
August 19, 2026 08:15
e259148 to
7269695
Compare
Replace the wallet-implemented checkRevocation callback with a raw eth_call hook (ExternalDataProvider.chainClient). The library now encodes getRevokeOffchain(attester, uid) for the mainnet EAS contract and decodes the result itself; format() passes only the chain client to the resolver layer. A policy without a chain client fails with ATTESTATION_OPTIONS_INCOMPLETE, which also replaces ATTESTATIONS_NOT_SUPPORTED. verifyAttestation is internal now, synchronous, and throws on the first failed check; applyAttestationPolicy catches the error and runs the revocation read afterwards, so transport errors still surface as DESCRIPTOR_FETCH_ERROR. TypedDataDomain.chainId accepts number | string and is normalized with parseChainId; the attestation domain reuses TypedDataDomain. utf8ToBytes replaces asciiToBytes. OffchainAttestationSignature is renamed to EcdsaSignature. Co-Authored-By: Manuel Wedler <manuel@wedler.dev>
kuzdogan
approved these changes
Aug 21, 2026
kuzdogan
left a comment
Member
There was a problem hiding this comment.
Approve.
The code is correct and the tests are thorough. The EAS offchain UID, the signature recovery, the revocation read, and the JCS descriptor hash all match ERC-8176.
One caveat for rollout, not a code fix: against the live registry today, the gate rejects every descriptor that uses includes. The cause is external. The registry's attestations were made by clearsig, which hashes the raw descriptor file and does not resolve includes first. ERC-8176 requires the hash over the resolved descriptor, which is what this PR computes. So the two hashes differ and verification fails for 135 of the 181 attestations.
Filed upstream: Cyfrin/clearsig#16.
Posted with Claude Code
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.
Closes #61
Adds ERC-8176 attestation support: a wallet defines which auditors it trusts, and the library then formats only through descriptors that hold a valid attestation from one of them.
attestationspolicy on the shared resolver options (BaseResolverOptions):trustedAttesters, the auditor addresses the wallet trusts.ExternalDataProvider.chainClient(ChainClient): a raweth_callhook. The library uses it to read the revocation state itself (getRevokeOffchain(attester, uid)on the EAS contract on Ethereum mainnet). The library selects the contract, encodes the call, and decodes the result; the wallet only supplies the RPC connection.format()/formatTypedData()pass only the chain client to the resolver layer. The client is required when a policy is set.src/attestations.ts:computeDescriptorHash(keccak256 of the RFC 8785 / JCS canonical JSON of the includes-resolved descriptor),verifyAttestation(offline checks: canonical schema UID, attested hash, EIP-712 domain pin to the mainnet EAS contract, expiration, ECDSA recovery, recomputation of the EAS v2 offchain UID; throws on the first failed check),isAttestationRevoked(the EAS read), andattestationPathForDescriptor(the registry'ssigs/file convention).computeDescriptorHashandattestationPathForDescriptorare public for custom resolvers and tooling.resolver.ts(applyAttestationPolicy) after includes resolution, on both the calldata and the EIP-712 path. Failures surface asNO_TRUSTED_ATTESTATION(with per-attester reasons) orATTESTATION_OPTIONS_INCOMPLETE(missingchainClient, or a resolver withoutfetchAttestation);format()then falls back torawCalldataFallbacklikeNO_DESCRIPTOR.chainClienttransport errors surface asDESCRIPTOR_FETCH_ERROR.DescriptorResolver.fetchAttestation(404 / ENOENT → no attestation). Bundled trusted-token descriptors are exempt from the policy.TypedDataDomain.chainIdis nownumber | string, normalized withparseChainIdeverywhere it is read. The same type describes the EIP-712 domain of an attestation.utf8ToBytesreplacesasciiToBytes(ASCII is a subset of UTF-8; the attestation hashes need full UTF-8).attestationsoption the behavior is unchanged; README and GUIDE mark that mode as testing-only.@noble/curves1.x (secp256k1 recovery; same family as the existing@noble/hashes, versions dedupe).chainClientcall encoding and transport errors,trustedTokensbypass) with test-key-signed attestations.Limitations (documented): only EAS offchain attestation version 2 with EOA signatures; onchain attestations and ERC-1271 contract attesters are out of scope.
TODO
attest()/attestByDelegation()on the EAS contract) and ERC-1271 contract attesters. Both can use the newChainClient.🤖 Generated with Claude Code