Files
smom-dbis-138/services/indy-verifier/indy-agent.ts
2026-03-02 12:14:09 -08:00

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;
}
}
}