IERC735 Interface

Overview

The IERC735 interface defines the Claim Holder standard for decentralized identity management within the Gemforce platform. This interface implements the ERC-735 standard for managing identity claims, enabling attestations, verifications, and credential management through cryptographically signed claims from trusted issuers.

Key Features

  • Identity Claims Management: Add, modify, and remove identity claims
  • Cryptographic Verification: Support for multiple signature schemes
  • Trusted Issuer System: Claims issued by verified and trusted entities
  • Topic-Based Organization: Claims categorized by topics (KYC, credentials, etc.)
  • URI-Based Metadata: Support for off-chain claim data and documentation
  • Event Tracking: Comprehensive event emission for claim lifecycle operations

Interface Definition

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

interface IERC735 {
    // Events
    event ClaimRequested(uint256 indexed claimRequestId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
    event ClaimAdded(bytes32 indexed claimId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
    event ClaimRemoved(bytes32 indexed claimId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
    event ClaimChanged(bytes32 indexed claimId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);

    // Core Functions
    function getClaim(bytes32 _claimId) external returns(uint256 topic, uint256 scheme, address issuer, bytes memory signature, bytes memory data, string memory uri);
    function getClaimIdsByTopic(uint256 _topic) external returns(bytes32[] memory claimIds);
    function addClaim(uint256 _topic, uint256 _scheme, address _issuer, bytes memory _signature, bytes memory _data, string memory _uri) external returns (uint256 claimRequestId);
    function changeClaim(bytes32 _claimId, uint256 _topic, uint256 _scheme, address _issuer, bytes memory _signature, bytes memory _data, string memory _uri) external returns (bool success);
    function removeClaim(bytes32 _claimId) external returns (bool success);
}

Claim Topic Constants

// Standard claim topics as defined in ERC-735
uint256 public constant BIOMETRIC_TOPIC = 1;        // Biometric verification
uint256 public constant RESIDENCE_TOPIC = 2;        // Proof of residence
uint256 public constant REGISTRY_TOPIC = 3;         // Registry inclusion
uint256 public constant PROFILE_TOPIC = 4;          // Profile information
uint256 public constant CONTRACT_TOPIC = 5;         // Contract interaction
uint256 public constant KYC_TOPIC = 10001;          // Know Your Customer
uint256 public constant AML_TOPIC = 10002;          // Anti-Money Laundering
uint256 public constant ACCREDITED_INVESTOR_TOPIC = 10003; // Accredited investor status
uint256 public constant PROFESSIONAL_TOPIC = 10004;  // Professional credentials

Signature Scheme Constants

// Standard signature schemes
uint256 public constant ECDSA_SCHEME = 1;           // ECDSA signature
uint256 public constant RSA_SCHEME = 2;             // RSA signature
uint256 public constant CONTRACT_SCHEME = 3;        // Contract-based verification
uint256 public constant MULTISIG_SCHEME = 4;        // Multi-signature scheme

Core Functions

Claim Management

addClaim()

function addClaim(uint256 _topic, uint256 _scheme, address _issuer, bytes memory _signature, bytes memory _data, string memory _uri) external returns (uint256 claimRequestId)

Purpose: Add a new identity claim to the claim holder.

Parameters: - _topic (uint256): The claim topic identifier (KYC, AML, etc.) - _scheme (uint256): The signature scheme used for verification - _issuer (address): The address of the claim issuer - _signature (bytes): The cryptographic signature of the claim - _data (bytes): The claim data payload - _uri (string): URI pointing to additional claim metadata

Returns: - claimRequestId (uint256): Unique identifier for the claim request

Requirements: - Issuer must be authorized for the claim topic - Signature must be valid for the claim data - Claim topic must be supported - Caller must have appropriate permissions

Events Emitted: - ClaimRequested initially when claim is submitted - ClaimAdded when claim is approved and added

Example Usage:

// Add a KYC claim from a trusted issuer
uint256 topic = KYC_TOPIC;
uint256 scheme = ECDSA_SCHEME;
address issuer = 0x742d35Cc6634C0532925a3b8D4C9db96590c6C8C;
bytes memory signature = abi.encodePacked(r, s, v); // ECDSA signature components
bytes memory data = abi.encode("John Doe", "US", block.timestamp);
string memory uri = "https://kyc-provider.com/claims/12345";

uint256 requestId = IERC735(identityContract).addClaim(
    topic, scheme, issuer, signature, data, uri
);
console.log("KYC claim request ID:", requestId);

changeClaim()

function changeClaim(bytes32 _claimId, uint256 _topic, uint256 _scheme, address _issuer, bytes memory _signature, bytes memory _data, string memory _uri) external returns (bool success)

Purpose: Modify an existing identity claim.

Parameters: - _claimId (bytes32): The unique identifier of the claim to modify - _topic (uint256): The updated claim topic - _scheme (uint256): The updated signature scheme - _issuer (address): The updated issuer address - _signature (bytes): The updated cryptographic signature - _data (bytes): The updated claim data - _uri (string): The updated metadata URI

Returns: Boolean indicating success of the operation

Requirements: - Claim must exist - Caller must have permission to modify the claim - New signature must be valid - Issuer must be authorized for the topic

Events Emitted: - ClaimChanged with old and new claim details

Example Usage:

// Update an existing KYC claim with new information
bytes32 claimId = 0x1234567890abcdef...;
uint256 topic = KYC_TOPIC;
uint256 scheme = ECDSA_SCHEME;
address issuer = 0x742d35Cc6634C0532925a3b8D4C9db96590c6C8C;
bytes memory newSignature = abi.encodePacked(r, s, v);
bytes memory newData = abi.encode("John Doe", "US", block.timestamp, "updated");
string memory newUri = "https://kyc-provider.com/claims/12345-updated";

bool success = IERC735(identityContract).changeClaim(
    claimId, topic, scheme, issuer, newSignature, newData, newUri
);
console.log("Claim update success:", success);

removeClaim()

function removeClaim(bytes32 _claimId) external returns (bool success)

Purpose: Remove an identity claim from the claim holder.

Parameters: - _claimId (bytes32): The unique identifier of the claim to remove

Returns: Boolean indicating success of the operation

Requirements: - Claim must exist - Caller must have permission to remove the claim - Some claims may be required and cannot be removed

Events Emitted: - ClaimRemoved with claim details

Example Usage:

// Remove an expired or invalid claim
bytes32 claimId = 0x1234567890abcdef...;

bool success = IERC735(identityContract).removeClaim(claimId);
console.log("Claim removal success:", success);

Query Functions

Claim Information

getClaim()

function getClaim(bytes32 _claimId) external returns(uint256 topic, uint256 scheme, address issuer, bytes memory signature, bytes memory data, string memory uri)

Purpose: Retrieve detailed information about a specific claim.

Parameters: - _claimId (bytes32): The unique identifier of the claim to query

Returns: - topic (uint256): The claim topic identifier - scheme (uint256): The signature scheme used - issuer (address): The address of the claim issuer - signature (bytes): The cryptographic signature - data (bytes): The claim data payload - uri (string): The metadata URI

Example Usage:

// Get detailed claim information
bytes32 claimId = 0x1234567890abcdef...;
(
    uint256 topic,
    uint256 scheme,
    address issuer,
    bytes memory signature,
    bytes memory data,
    string memory uri
) = IERC735(identityContract).getClaim(claimId);

console.log("Claim topic:", topic);
console.log("Claim issuer:", issuer);
console.log("Claim URI:", uri);

getClaimIdsByTopic()

function getClaimIdsByTopic(uint256 _topic) external returns(bytes32[] memory claimIds)

Purpose: Get all claim IDs associated with a specific topic.

Parameters: - _topic (uint256): The topic to query claims for

Returns: Array of claim IDs for the specified topic

Example Usage:

// Get all KYC claims for an identity
uint256 topic = KYC_TOPIC;
bytes32[] memory kycClaims = IERC735(identityContract).getClaimIdsByTopic(topic);

console.log("KYC claims count:", kycClaims.length);
for (uint256 i = 0; i < kycClaims.length; i++) {
    console.log("KYC claim ID:", kycClaims[i]);
}

Integration Examples

KYC/AML Verification System

// KYC/AML verification system using ERC-735 claims
contract KYCAMLVerification {
    IERC735 public claimHolder;

    struct VerificationRequirement {
        uint256[] requiredTopics;
        address[] trustedIssuers;
        uint256 minValidityPeriod;
        bool active;
    }

    mapping(bytes32 => VerificationRequirement) public verificationLevels;
    mapping(address => mapping(uint256 => bool)) public issuerTopicAuthorization;
    mapping(bytes32 => uint256) public claimExpirationTime;

    event VerificationLevelCreated(bytes32 indexed levelId, uint256[] requiredTopics);
    event IssuerAuthorized(address indexed issuer, uint256 indexed topic, bool authorized);
    event IdentityVerified(address indexed identity, bytes32 indexed levelId, uint256 timestamp);
    event VerificationFailed(address indexed identity, bytes32 indexed levelId, string reason);

    constructor(address _claimHolder) {
        claimHolder = IERC735(_claimHolder);
    }

    function createVerificationLevel(
        bytes32 levelId,
        uint256[] memory requiredTopics,
        address[] memory trustedIssuers,
        uint256 minValidityPeriod
    ) external onlyAdmin {
        verificationLevels[levelId] = VerificationRequirement({
            requiredTopics: requiredTopics,
            trustedIssuers: trustedIssuers,
            minValidityPeriod: minValidityPeriod,
            active: true
        });

        emit VerificationLevelCreated(levelId, requiredTopics);
    }

    function authorizeIssuerForTopic(
        address issuer,
        uint256 topic,
        bool authorized
    ) external onlyAdmin {
        issuerTopicAuthorization[issuer][topic] = authorized;
        emit IssuerAuthorized(issuer, topic, authorized);
    }

    function verifyIdentity(
        address identity,
        bytes32 levelId
    ) external returns (bool verified) {
        VerificationRequirement memory requirement = verificationLevels[levelId];
        require(requirement.active, "Verification level not active");

        // Check each required topic
        for (uint256 i = 0; i < requirement.requiredTopics.length; i++) {
            uint256 topic = requirement.requiredTopics[i];

            bytes32[] memory claimIds = claimHolder.getClaimIdsByTopic(topic);
            if (claimIds.length == 0) {
                emit VerificationFailed(identity, levelId, "Missing required claim topic");
                return false;
            }

            bool validClaimFound = false;
            for (uint256 j = 0; j < claimIds.length; j++) {
                if (_isClaimValid(claimIds[j], requirement)) {
                    validClaimFound = true;
                    break;
                }
            }

            if (!validClaimFound) {
                emit VerificationFailed(identity, levelId, "No valid claim found for topic");
                return false;
            }
        }

        emit IdentityVerified(identity, levelId, block.timestamp);
        return true;
    }

    function _isClaimValid(
        bytes32 claimId,
        VerificationRequirement memory requirement
    ) internal returns (bool) {
        (
            uint256 topic,
            uint256 scheme,
            address issuer,
            bytes memory signature,
            bytes memory data,
            string memory uri
        ) = claimHolder.getClaim(claimId);

        // Check if issuer is authorized for this topic
        if (!issuerTopicAuthorization[issuer][topic]) {
            return false;
        }

        // Check if claim is not expired
        uint256 expirationTime = claimExpirationTime[claimId];
        if (expirationTime > 0 && block.timestamp > expirationTime) {
            return false;
        }

        // Verify signature (simplified - would implement full signature verification)
        if (signature.length == 0) {
            return false;
        }

        return true;
    }

    function getVerificationStatus(
        address identity,
        bytes32 levelId
    ) external view returns (
        bool canVerify,
        uint256[] memory missingTopics,
        uint256[] memory expiredClaims
    ) {
        VerificationRequirement memory requirement = verificationLevels[levelId];

        uint256[] memory missing = new uint256[](requirement.requiredTopics.length);
        uint256[] memory expired = new uint256[](requirement.requiredTopics.length);
        uint256 missingCount = 0;
        uint256 expiredCount = 0;

        canVerify = true;

        for (uint256 i = 0; i < requirement.requiredTopics.length; i++) {
            uint256 topic = requirement.requiredTopics[i];
            bytes32[] memory claimIds = claimHolder.getClaimIdsByTopic(topic);

            if (claimIds.length == 0) {
                missing[missingCount++] = topic;
                canVerify = false;
            } else {
                bool hasValidClaim = false;
                for (uint256 j = 0; j < claimIds.length; j++) {
                    uint256 expirationTime = claimExpirationTime[claimIds[j]];
                    if (expirationTime == 0 || block.timestamp <= expirationTime) {
                        hasValidClaim = true;
                        break;
                    }
                }

                if (!hasValidClaim) {
                    expired[expiredCount++] = topic;
                    canVerify = false;
                }
            }
        }

        // Resize arrays to actual counts
        missingTopics = new uint256[](missingCount);
        expiredClaims = new uint256[](expiredCount);

        for (uint256 i = 0; i < missingCount; i++) {
            missingTopics[i] = missing[i];
        }

        for (uint256 i = 0; i < expiredCount; i++) {
            expiredClaims[i] = expired[i];
        }
    }

    modifier onlyAdmin() {
        // Implementation would check for admin role
        _;
    }
}

Professional Credentials System

```solidity // Professional credentials and certification system contract ProfessionalCredentials { IERC735 public claimHolder;

struct Credential {
    string name;
    string description;
    uint256 topic;
    address issuingAuthority;
    uint256 validityPeriod;
    bool requiresRenewal;
    uint256 renewalPeriod;
}

struct IssuedCredential {
    bytes32 credentialId;
    address holder;
    uint256 issuedAt;
    uint256 expiresAt;
    bool active;
    bytes32 claimId;
}

mapping(bytes32 => Credential) public credentials;
mapping(bytes32 => IssuedCredential) public issuedCredentials;
mapping(address => bytes32[]) public holderCredentials;
mapping(address => bool) public authorizedIssuers;

event CredentialDefined(bytes32 indexed credentialId, string name, uint256 topic);
event CredentialIssued(bytes32 indexed credentialId, address indexed holder, bytes32 claimId);
event CredentialRevoked(bytes32 indexed credentialId, address indexed holder, string reason);
event CredentialRenewed(bytes32 indexed credentialId, address indexed holder, uint256 newExpirationTime);

constructor(address _gameCards) {
    claimHolder = IERC735(_gameCards);
}

function defineCredential(
    bytes32 credentialId,
    string memory name,
    string memory description,
    uint256 topic,
    address issuingAuthority,
    uint256 validityPeriod,
    bool requiresRenewal,
    uint256 renewalPeriod
) external onlyAdmin {
    credentials[credentialId] = Credential({
        name: name,
        description: description,
        topic: topic,
        issuingAuthority: issuingAuthority,
        validityPeriod: validityPeriod,
        requiresRenewal: requiresRenewal,
        renewalPeriod: renewalPeriod
    });

    authorizedIssuers[issuingAuthority] = true;
    emit CredentialDefined(credentialId, name, topic);
}

function issueCredential(
    bytes32 credentialId,
    address holder,
    bytes memory credentialData,
    bytes memory signature,
    string memory uri
) external onlyAuthorizedIssuer(credentialId) {
    Credential memory credential = credentials[credentialId];
    require(bytes(credential.name).length > 0, "Credential not defined");