This ERC defines Smart Credentials, blockchain-based credentials resolved onchain or offchain with onchain verification. It specifies a uniform interface for resolving credentials for onchain identities. For the purposes of this specification, "users" refers to both human users and AI agents. Credentials are records "about" a user, controlled by an issuer, as opposed to records "by" a user that the user controls directly. Credential types include KYC (Know Your Customer), KYA (Know Your Agent), Proof of Personhood, reputation, and privacy-preserving proofs. The design supports Zero Knowledge Proofs (ZKPs) for privacy-preserving credentials.
Smart contracts, when using ERC-3668, already provide a broad set of capabilities for credential issuers to issue credentials to be resolved via blockchains. However, there is a need for a unified standard such that clients can discover and resolve credentials in a uniform way. This standard is important because it allows clients, including agentic systems, to become aware of new credentials as they are added onchain, by listening for the standardized CredentialSet event.
The term "credential" in this specification includes but is not limited to W3C Verifiable Credentials. This specification defines resolution of credential records, not DID document resolution. Unlike profile data that a user controls (e.g., name, avatar), credentials are records "about" a user, controlled by third-party credential issuers. They are verifiable facts that users cannot fabricate. Examples include:
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
Smart credentials MUST implement the following interface:
interface IERC8143 {
/// @notice Emitted when a credential is set or updated
/// @param key The credential key
event CredentialSet(string key);
function getCredential(string calldata key) external view returns (bytes memory result);
}
The smart credential MUST implement ERC-165 and return true when supportsInterface() is called on it with the interface's ID, 0xd091187f.
Contracts MUST emit CredentialSet(key) when a credential is set or updated for a given key. This event allows clients, including agentic systems, to discover new credentials added onchain without prior knowledge of keys.
This specification does NOT standardize the key format or the return result. Credential issuers define their own keys and data formats. The key MAY use the ERC-8119 parameterized key format (key:param or key/param, no space after the separator), but this is not required. When credentials are stored offchain, the contract MAY revert with ERC-3668 OffchainLookup to request a gateway lookup. Compliant clients MUST follow the ERC-3668 client lookup protocol when handling such reverts.
Credential issuers SHOULD define and document the data format for the bytes they return. The unstructured bytes return supports many use cases, including verifiable credentials, ABI-encoded data, JSON, and custom formats. If there is no known format for a given credential key, clients SHOULD interpret the data as raw UTF-8 bytes.
Compliant clients MUST perform the following procedure when resolving a credential:
Call the getCredential function, using ERC-3668 (some libraries do not use ERC-3668 by default and it is necessary to make a special function call to enable ERC-3668), with a key.
Decode the return result according to the credential issuer's defined format for that key. If no format is known, interpret the bytes as raw UTF-8.
The following examples demonstrate different ways to call getCredential with various key formats:
Example 1: Resolve KYC credential using ERC-8119 parameterized key with address
const credentialBytes = await credentialContract.getCredential("kyc:0x76F1Ff0186DDb9461890bdb3094AF74A5F24a162");
const credential = decodeCredential(credentialBytes, "(string)");
// Result: "Maria Garcia /0x76F1Ff.../ ID: 146-DJH-6346-25294"
Example 2: Resolve KYC credential using ERC-8119 parameterized key with name
const credentialBytes = await credentialContract.getCredential("kyc:Maria Garcia");
const credential = decodeCredential(credentialBytes, "(string)");
// Result: "Maria Garcia /0x76F1Ff.../ ID: 146-DJH-6346-25294"
Example 3: Resolve Proof of Personhood credential
const credentialBytes = await credentialContract.getCredential("pop:0x76F1Ff0186DDb9461890bdb3094AF74A5F24a162");
const credential = decodeCredential(credentialBytes, "(bool)");
// Result: true (verified human)
Example 4: Resolve credential with struct return type
const credentialBytes = await credentialContract.getCredential("reputation:0x76F1Ff0186DDb9461890bdb3094AF74A5F24a162");
const credential = decodeCredential(credentialBytes, "((string,uint256,bytes32))");
// Result: { name: "Verified Agent", score: 95, proof: "0x..." }
Example 5: Offchain credential with ERC-3668 callback
When a credential is stored offchain, the contract reverts with OffchainLookup. The client fetches from the gateway, then calls the callback. The contract may implement a callback such as getCredentialCallback:
function getCredential(string calldata key) external view returns (bytes memory) {
revert OffchainLookup(
address(this),
[gatewayUrl],
abi.encode(key),
this.getCredentialCallback.selector,
abi.encode(key)
);
}
function getCredentialCallback(bytes calldata response, bytes calldata extraData) external view returns (bytes memory) {
string memory key = abi.decode(extraData, (string));
// Verify gateway response (e.g., signature, Merkle proof), then return credential
return _verifyAndDecode(key, response);
}
As compared to W3C Verifiable Credentials, Smart Credentials are unique in that they can support ZKPs using onchain ZKP verifiers. Smart credentials meet a long-felt need to be able to have metadata records about users, including AI agents, that are not controlled by the user. Records like KYC and PoP must be managed by secure third parties. This ERC allows credential issuers to create records about users that can be resolved by clients in a uniform way, enabling interoperability across different credential issuers and clients. The specification is intentionally simple, with the interface only including a single function, making it easy for clients to resolve credentials.
No issues.
Clients should verify that credential issuer contracts are trusted before resolving credentials. The format for the key and the decoding of the bytes value must adhere to the specification of the specific credential. It is not possible to assume a format without consulting the credential issuer's documentation.
Copyright and related rights waived via CC0.