208 lines
5.9 KiB
TypeScript
208 lines
5.9 KiB
TypeScript
/**
|
|
* Indy Verifier Agent
|
|
* Verifies Hyperledger Indy credentials and updates on-chain verifier contract
|
|
*/
|
|
|
|
import * as indy from 'indy-sdk';
|
|
import { ethers } from 'ethers';
|
|
|
|
export interface ProofRequest {
|
|
name: string;
|
|
version: string;
|
|
requested_attributes: Record<string, any>;
|
|
requested_predicates: Record<string, any>;
|
|
}
|
|
|
|
export interface IndyConfig {
|
|
poolName: string;
|
|
genesisPath: string;
|
|
walletName: string;
|
|
walletKey: string;
|
|
did: string;
|
|
verifierContractAddress: string;
|
|
verifierAbi: any[];
|
|
}
|
|
|
|
export class IndyVerifierAgent {
|
|
private poolHandle: number | null = null;
|
|
private walletHandle: number | null = null;
|
|
private provider: ethers.JsonRpcProvider;
|
|
private verifierContract: ethers.Contract;
|
|
private signer: ethers.Wallet;
|
|
|
|
constructor(
|
|
private config: IndyConfig,
|
|
rpcUrl: string
|
|
) {
|
|
this.provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
this.verifierContract = new ethers.Contract(
|
|
config.verifierContractAddress,
|
|
config.verifierAbi,
|
|
this.provider
|
|
);
|
|
this.signer = new ethers.Wallet(
|
|
process.env.INDY_VERIFIER_PRIVATE_KEY!,
|
|
this.provider
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Initialize Indy pool and wallet
|
|
*/
|
|
async initialize(): Promise<void> {
|
|
// Create pool
|
|
await indy.createPoolLedgerConfig(this.config.poolName, {
|
|
genesis_txn: this.config.genesisPath
|
|
});
|
|
|
|
this.poolHandle = await indy.openPoolLedger(this.config.poolName, null);
|
|
|
|
// Create wallet
|
|
try {
|
|
await indy.createWallet(
|
|
{ id: this.config.walletName },
|
|
{ key: this.config.walletKey }
|
|
);
|
|
} catch (error: any) {
|
|
if (!error.message.includes('already exists')) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
this.walletHandle = await indy.openWallet(
|
|
{ id: this.config.walletName },
|
|
{ key: this.config.walletKey }
|
|
);
|
|
|
|
console.log('Indy pool and wallet initialized');
|
|
}
|
|
|
|
/**
|
|
* Verify credential proof
|
|
*/
|
|
async verifyCredentialProof(
|
|
userAddress: string,
|
|
proof: any,
|
|
proofRequest: ProofRequest,
|
|
schemas: any,
|
|
credDefs: any
|
|
): Promise<{ verified: boolean; score: number }> {
|
|
if (!this.poolHandle || !this.walletHandle) {
|
|
throw new Error('Indy not initialized');
|
|
}
|
|
|
|
// Verify the zero-knowledge proof
|
|
const valid = await indy.verifierVerifyProof(
|
|
proofRequest,
|
|
proof,
|
|
schemas,
|
|
credDefs,
|
|
{}, // revoc reg defs
|
|
{} // revoc regs
|
|
);
|
|
|
|
// Calculate score (0-100) based on proof validity and attributes
|
|
const score = valid ? 100 : 0;
|
|
|
|
// Update on-chain verifier contract
|
|
if (valid) {
|
|
const proofId = ethers.id(JSON.stringify(proof));
|
|
const verifierWithSigner = this.verifierContract.connect(this.signer);
|
|
|
|
// Determine credential type from proof request
|
|
const credType = this.getCredentialType(proofRequest);
|
|
|
|
await verifierWithSigner.verifyCredentialProof(
|
|
userAddress,
|
|
credType,
|
|
ethers.AbiCoder.defaultAbiCoder().encode(['string'], [JSON.stringify(proof)]),
|
|
score,
|
|
proofId
|
|
);
|
|
}
|
|
|
|
return { verified: valid, score };
|
|
}
|
|
|
|
/**
|
|
* Create proof request for KYC
|
|
*/
|
|
createKYCProofRequest(): ProofRequest {
|
|
return {
|
|
name: 'Bridge KYC Verification',
|
|
version: '1.0',
|
|
requested_attributes: {
|
|
'attr1_referent': {
|
|
name: 'kyc_status',
|
|
restrictions: [{
|
|
schema_id: 'did:indy:sovrin:...:schema:kyc:1.0',
|
|
cred_def_id: 'did:indy:sovrin:...:creddef:...'
|
|
}]
|
|
},
|
|
'attr2_referent': {
|
|
name: 'jurisdiction',
|
|
restrictions: []
|
|
}
|
|
},
|
|
requested_predicates: {
|
|
'predicate1_referent': {
|
|
name: 'age',
|
|
p_type: '>=',
|
|
p_value: 18
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create proof request for accredited investor
|
|
*/
|
|
createAccreditedInvestorProofRequest(): ProofRequest {
|
|
return {
|
|
name: 'Accredited Investor Verification',
|
|
version: '1.0',
|
|
requested_attributes: {
|
|
'attr1_referent': {
|
|
name: 'accredited_status',
|
|
restrictions: [{
|
|
schema_id: 'did:indy:sovrin:...:schema:accredited:1.0',
|
|
cred_def_id: 'did:indy:sovrin:...:creddef:...'
|
|
}]
|
|
}
|
|
},
|
|
requested_predicates: {}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get credential type from proof request
|
|
*/
|
|
private getCredentialType(proofRequest: ProofRequest): number {
|
|
if (proofRequest.name.includes('KYC')) {
|
|
return 0; // KYC
|
|
} else if (proofRequest.name.includes('Accredited')) {
|
|
return 1; // AccreditedInvestor
|
|
} else if (proofRequest.name.includes('Institution')) {
|
|
return 2; // Institution
|
|
} else if (proofRequest.name.includes('Jurisdiction')) {
|
|
return 3; // Jurisdiction
|
|
}
|
|
return 4; // Compliance
|
|
}
|
|
|
|
/**
|
|
* Close wallet and pool
|
|
*/
|
|
async close(): Promise<void> {
|
|
if (this.walletHandle) {
|
|
await indy.closeWallet(this.walletHandle);
|
|
this.walletHandle = null;
|
|
}
|
|
|
|
if (this.poolHandle) {
|
|
await indy.closePoolLedger(this.poolHandle);
|
|
this.poolHandle = null;
|
|
}
|
|
}
|
|
}
|