177 lines
5.1 KiB
Solidity
177 lines
5.1 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.20;
|
|
|
|
import "@openzeppelin/contracts/access/AccessControl.sol";
|
|
|
|
/**
|
|
* @title IndyVerifier
|
|
* @notice Verifies Hyperledger Indy credentials before allowing bridge operations
|
|
* @dev Uses zero-knowledge proofs for privacy-preserving credential verification
|
|
*/
|
|
contract IndyVerifier is AccessControl {
|
|
bytes32 public constant VERIFIER_ROLE = keccak256("VERIFIER_ROLE");
|
|
bytes32 public constant ISSUER_ROLE = keccak256("ISSUER_ROLE");
|
|
|
|
enum CredentialType {
|
|
KYC,
|
|
AccreditedInvestor,
|
|
Institution,
|
|
Jurisdiction,
|
|
Compliance
|
|
}
|
|
|
|
struct CredentialSchema {
|
|
string schemaId; // Indy schema ID
|
|
string credDefId; // Credential definition ID
|
|
bool required;
|
|
CredentialType credType;
|
|
uint256 minScore; // Minimum verification score (0-100)
|
|
}
|
|
|
|
struct VerificationResult {
|
|
bool verified;
|
|
uint256 score;
|
|
uint256 verifiedAt;
|
|
string proofId;
|
|
}
|
|
|
|
mapping(address => mapping(CredentialType => VerificationResult)) public userCredentials;
|
|
mapping(CredentialType => CredentialSchema) public schemas;
|
|
mapping(string => bool) public verifiedProofs; // proofId => verified
|
|
|
|
event CredentialVerified(
|
|
address indexed user,
|
|
CredentialType credType,
|
|
uint256 score,
|
|
string proofId
|
|
);
|
|
|
|
event CredentialRevoked(
|
|
address indexed user,
|
|
CredentialType credType
|
|
);
|
|
|
|
event SchemaRegistered(
|
|
CredentialType credType,
|
|
string schemaId,
|
|
string credDefId
|
|
);
|
|
|
|
constructor(address admin) {
|
|
_grantRole(DEFAULT_ADMIN_ROLE, admin);
|
|
_grantRole(VERIFIER_ROLE, admin);
|
|
_grantRole(ISSUER_ROLE, admin);
|
|
}
|
|
|
|
/**
|
|
* @notice Register credential schema
|
|
*/
|
|
function registerSchema(
|
|
CredentialType credType,
|
|
string calldata schemaId,
|
|
string calldata credDefId,
|
|
bool required,
|
|
uint256 minScore
|
|
) external onlyRole(ISSUER_ROLE) {
|
|
schemas[credType] = CredentialSchema({
|
|
schemaId: schemaId,
|
|
credDefId: credDefId,
|
|
required: required,
|
|
credType: credType,
|
|
minScore: minScore
|
|
});
|
|
|
|
emit SchemaRegistered(credType, schemaId, credDefId);
|
|
}
|
|
|
|
/**
|
|
* @notice Verify credential proof (called by oracle/agent)
|
|
* @dev Off-chain: Verify ZK proof with Indy
|
|
* On-chain: Store verification result
|
|
*/
|
|
function verifyCredentialProof(
|
|
address user,
|
|
CredentialType credType,
|
|
bytes calldata zkProof,
|
|
uint256 score,
|
|
string calldata proofId
|
|
) external onlyRole(VERIFIER_ROLE) returns (bool) {
|
|
require(bytes(schemas[credType].schemaId).length > 0, "Schema not registered");
|
|
require(!verifiedProofs[proofId], "Proof already used");
|
|
require(score >= schemas[credType].minScore, "Score too low");
|
|
|
|
// Mark proof as used (prevent replay)
|
|
verifiedProofs[proofId] = true;
|
|
|
|
// Store verification result
|
|
userCredentials[user][credType] = VerificationResult({
|
|
verified: true,
|
|
score: score,
|
|
verifiedAt: block.timestamp,
|
|
proofId: proofId
|
|
});
|
|
|
|
emit CredentialVerified(user, credType, score, proofId);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @notice Check if user has required credential
|
|
*/
|
|
function hasCredential(
|
|
address user,
|
|
CredentialType credType
|
|
) external view returns (bool) {
|
|
VerificationResult memory result = userCredentials[user][credType];
|
|
if (!result.verified) return false;
|
|
|
|
CredentialSchema memory schema = schemas[credType];
|
|
return result.score >= schema.minScore;
|
|
}
|
|
|
|
/**
|
|
* @notice Get credential verification details
|
|
*/
|
|
function getCredentialDetails(
|
|
address user,
|
|
CredentialType credType
|
|
) external view returns (VerificationResult memory) {
|
|
return userCredentials[user][credType];
|
|
}
|
|
|
|
/**
|
|
* @notice Revoke credential (for compliance)
|
|
*/
|
|
function revokeCredential(
|
|
address user,
|
|
CredentialType credType
|
|
) external onlyRole(VERIFIER_ROLE) {
|
|
delete userCredentials[user][credType];
|
|
emit CredentialRevoked(user, credType);
|
|
}
|
|
|
|
/**
|
|
* @notice Batch verify credentials (for efficiency)
|
|
*/
|
|
function batchVerifyCredentials(
|
|
address[] calldata users,
|
|
CredentialType[] calldata credTypes,
|
|
bytes[] calldata zkProofs,
|
|
uint256[] calldata scores,
|
|
string[] calldata proofIds
|
|
) external onlyRole(VERIFIER_ROLE) {
|
|
require(
|
|
users.length == credTypes.length &&
|
|
credTypes.length == zkProofs.length &&
|
|
zkProofs.length == scores.length &&
|
|
scores.length == proofIds.length,
|
|
"Array length mismatch"
|
|
);
|
|
|
|
for (uint256 i = 0; i < users.length; i++) {
|
|
this.verifyCredentialProof(users[i], credTypes[i], zkProofs[i], scores[i], proofIds[i]);
|
|
}
|
|
}
|
|
}
|