/** * Blockchain Service * Enterprise Ethereum Alliance (EEA) blockchain integration * For identity verification, resource tracking, and compliance */ import { logger } from '../lib/logger.js' import { ethers } from 'ethers' export interface BlockchainConfig { rpcUrl?: string networkId?: string contractAddress?: string privateKey?: string enabled: boolean } export interface IdentityVerificationResult { verified: boolean address?: string timestamp?: Date error?: string } class BlockchainService { private config: BlockchainConfig private initialized: boolean = false private provider: ethers.JsonRpcProvider | null = null private wallet: ethers.Wallet | null = null private identityContract: ethers.Contract | null = null constructor() { this.config = { enabled: process.env.BLOCKCHAIN_ENABLED === 'true', rpcUrl: process.env.BLOCKCHAIN_RPC_URL, networkId: process.env.BLOCKCHAIN_NETWORK_ID, contractAddress: process.env.BLOCKCHAIN_IDENTITY_CONTRACT_ADDRESS, privateKey: process.env.BLOCKCHAIN_PRIVATE_KEY, } } /** * Initialize blockchain service */ async initialize(): Promise { if (!this.config.enabled) { logger.info('Blockchain service is disabled') this.initialized = true return } if (!this.config.rpcUrl) { logger.warn('Blockchain RPC URL not configured, service will operate in mock mode') this.initialized = true return } try { if (!this.config.rpcUrl) { throw new Error('Blockchain RPC URL is required when blockchain is enabled') } // Initialize Ethers.js provider this.provider = new ethers.JsonRpcProvider(this.config.rpcUrl) // Initialize wallet if private key is provided if (this.config.privateKey) { this.wallet = new ethers.Wallet(this.config.privateKey, this.provider) logger.info('Blockchain wallet initialized', { address: this.wallet.address, }) } // Load identity contract if address is provided if (this.config.contractAddress) { // Basic ABI for identity verification contract // In production, this would be loaded from contract artifacts const identityABI = [ 'function isVerified(address user) external view returns (bool)', 'function registerIdentity(address user, bytes32 userIdHash) external returns (bool)', 'function revokeIdentity(address user) external returns (bool)', ] const contractAddress = this.config.contractAddress const signer = this.wallet || this.provider this.identityContract = new ethers.Contract( contractAddress, identityABI, signer ) // Verify contract is deployed const code = await this.provider.getCode(contractAddress) if (code === '0x') { throw new Error(`Contract not deployed at address ${contractAddress}`) } logger.info('Identity contract loaded', { contractAddress }) } logger.info('Blockchain service initialized', { networkId: this.config.networkId, contractAddress: this.config.contractAddress, providerUrl: this.config.rpcUrl, }) this.initialized = true } catch (error) { logger.error('Failed to initialize blockchain service', { error }) throw error } } /** * Verify blockchain identity * Checks if a user's blockchain address is registered and verified */ async verifyIdentity( userId: string, blockchainAddress: string ): Promise { if (!this.initialized) { await this.initialize() } if (!this.config.enabled) { logger.info('Blockchain verification skipped (disabled)', { userId, blockchainAddress }) return { verified: true, // Allow when blockchain is disabled address: blockchainAddress, timestamp: new Date(), } } if (!blockchainAddress || !blockchainAddress.match(/^0x[a-fA-F0-9]{40}$/)) { logger.warn('Invalid blockchain address format', { userId, blockchainAddress }) return { verified: false, address: blockchainAddress, error: 'Invalid blockchain address format', } } try { if (!this.provider) { throw new Error('Blockchain provider not initialized') } if (!this.identityContract) { // If contract is not configured, verify address format only logger.info('Blockchain identity verification (no contract)', { userId, blockchainAddress, }) return { verified: true, address: blockchainAddress, timestamp: new Date(), } } // Query identity contract for verification status const isVerified = await this.identityContract.isVerified(blockchainAddress) as boolean logger.info('Blockchain identity verification', { userId, blockchainAddress, verified: isVerified, networkId: this.config.networkId, }) return { verified: isVerified, address: blockchainAddress, timestamp: new Date(), ...(isVerified ? {} : { error: 'Address not verified on blockchain' }), } } catch (error) { logger.error('Blockchain verification failed', { userId, blockchainAddress, error }) return { verified: false, address: blockchainAddress, error: error instanceof Error ? error.message : 'Unknown error', } } } /** * Register identity on blockchain * Registers a user's blockchain address in the identity contract */ async registerIdentity( userId: string, blockchainAddress: string, metadata?: Record ): Promise<{ success: boolean; transactionHash?: string; error?: string }> { if (!this.initialized) { await this.initialize() } if (!this.config.enabled) { logger.info('Blockchain registration skipped (disabled)', { userId, blockchainAddress }) return { success: true } } try { if (!this.provider) { throw new Error('Blockchain provider not initialized') } if (!this.identityContract) { throw new Error('Identity contract not configured') } if (!this.wallet) { throw new Error('Blockchain wallet not configured (private key required for registration)') } // Create hash of userId for on-chain storage const userIdHash = ethers.id(userId) // Prepare and send transaction logger.info('Registering identity on blockchain', { userId, blockchainAddress, userIdHash, }) const tx = await this.identityContract.registerIdentity(blockchainAddress, userIdHash) logger.info('Blockchain registration transaction sent', { transactionHash: tx.hash, userId, blockchainAddress, }) // Wait for transaction confirmation const receipt = await tx.wait() if (!receipt) { throw new Error('Transaction receipt not received') } logger.info('Blockchain identity registered', { transactionHash: receipt.hash, blockNumber: receipt.blockNumber, userId, blockchainAddress, }) return { success: true, transactionHash: receipt.hash, } } catch (error) { logger.error('Blockchain registration failed', { userId, blockchainAddress, error }) return { success: false, error: error instanceof Error ? error.message : 'Unknown error', } } } /** * Check if blockchain service is enabled */ isEnabled(): boolean { return this.config.enabled } /** * Check if blockchain service is initialized */ isInitialized(): boolean { return this.initialized } } // Singleton instance export const blockchainService = new BlockchainService() /** Called from server startup; wraps singleton initialize. */ export async function initBlockchainService(): Promise { await blockchainService.initialize() }