feat: Goa GEL Blockchain e-Licensing Platform - Full Stack Implementation
Complete implementation of the Goa Government e-Licensing platform with: Backend: - NestJS API with JWT authentication - PostgreSQL database with Knex ORM - Redis caching and session management - MinIO document storage - Hyperledger Besu blockchain integration - Multi-department workflow system - Comprehensive API tests (266/282 passing) Frontend: - Angular 21 with standalone components - Angular Material + TailwindCSS UI - Visual workflow builder - Document upload with progress tracking - Blockchain explorer integration - Role-based dashboards (Admin, Department, Citizen) - E2E tests with Playwright (37 tests) Infrastructure: - Docker Compose orchestration - Blockscout blockchain explorer - Development and production configurations
This commit is contained in:
175
backend/scripts/init-blockchain.js
Normal file
175
backend/scripts/init-blockchain.js
Normal file
@@ -0,0 +1,175 @@
|
||||
const { ethers } = require('ethers');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Initialize blockchain infrastructure:
|
||||
* - Generate platform wallet
|
||||
* - Deploy smart contracts
|
||||
* - Update .env file with addresses
|
||||
*/
|
||||
async function initBlockchain() {
|
||||
console.log('🔗 Initializing blockchain infrastructure...');
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(
|
||||
process.env.BESU_RPC_URL || 'http://localhost:8545'
|
||||
);
|
||||
|
||||
// Wait for blockchain to be ready
|
||||
console.log('⏳ Waiting for blockchain to be ready...');
|
||||
let retries = 30;
|
||||
while (retries > 0) {
|
||||
try {
|
||||
await provider.getBlockNumber();
|
||||
console.log('✅ Blockchain is ready!');
|
||||
break;
|
||||
} catch (error) {
|
||||
retries--;
|
||||
if (retries === 0) {
|
||||
throw new Error('Blockchain not available after 30 retries');
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if already initialized
|
||||
const envPath = path.join(__dirname, '../.env');
|
||||
if (fs.existsSync(envPath)) {
|
||||
const envContent = fs.readFileSync(envPath, 'utf8');
|
||||
if (
|
||||
envContent.includes('CONTRACT_ADDRESS_LICENSE_NFT=0x') &&
|
||||
!envContent.includes('CONTRACT_ADDRESS_LICENSE_NFT=0x0000000000000000000000000000000000000000')
|
||||
) {
|
||||
console.log('✅ Blockchain already initialized, skipping deployment');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Generate Platform Wallet
|
||||
console.log('🔐 Generating platform wallet...');
|
||||
const platformWallet = ethers.Wallet.createRandom();
|
||||
console.log('📝 Platform Wallet Address:', platformWallet.address);
|
||||
console.log('🔑 Platform Wallet Mnemonic:', platformWallet.mnemonic.phrase);
|
||||
|
||||
// Fund the platform wallet from the dev network's pre-funded account
|
||||
console.log('💰 Funding platform wallet...');
|
||||
const devWallet = new ethers.Wallet(
|
||||
'0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63',
|
||||
provider
|
||||
);
|
||||
|
||||
const fundTx = await devWallet.sendTransaction({
|
||||
to: platformWallet.address,
|
||||
value: ethers.parseEther('100.0'),
|
||||
});
|
||||
await fundTx.wait();
|
||||
console.log('✅ Platform wallet funded with 100 ETH');
|
||||
|
||||
const connectedWallet = platformWallet.connect(provider);
|
||||
|
||||
// 2. Deploy Smart Contracts
|
||||
console.log('📜 Deploying smart contracts...');
|
||||
|
||||
const contracts = await deployContracts(connectedWallet);
|
||||
|
||||
// 3. Update .env file
|
||||
console.log('📝 Updating .env file...');
|
||||
updateEnvFile({
|
||||
PLATFORM_WALLET_PRIVATE_KEY: platformWallet.privateKey,
|
||||
PLATFORM_WALLET_ADDRESS: platformWallet.address,
|
||||
PLATFORM_WALLET_MNEMONIC: platformWallet.mnemonic.phrase,
|
||||
CONTRACT_ADDRESS_LICENSE_NFT: contracts.licenseNFT,
|
||||
CONTRACT_ADDRESS_APPROVAL_MANAGER: contracts.approvalManager,
|
||||
CONTRACT_ADDRESS_DEPARTMENT_REGISTRY: contracts.departmentRegistry,
|
||||
CONTRACT_ADDRESS_WORKFLOW_REGISTRY: contracts.workflowRegistry,
|
||||
});
|
||||
|
||||
console.log('✅ Blockchain initialization complete!');
|
||||
console.log('\n📋 Summary:');
|
||||
console.log(' Platform Wallet:', platformWallet.address);
|
||||
console.log(' License NFT:', contracts.licenseNFT);
|
||||
console.log(' Approval Manager:', contracts.approvalManager);
|
||||
console.log(' Department Registry:', contracts.departmentRegistry);
|
||||
console.log(' Workflow Registry:', contracts.workflowRegistry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy all smart contracts
|
||||
*/
|
||||
async function deployContracts(wallet) {
|
||||
// Simple deployment of placeholder contracts
|
||||
// In production, you would deploy your actual Solidity contracts here
|
||||
|
||||
console.log('🚀 Deploying License NFT contract...');
|
||||
const licenseNFT = await deployPlaceholderContract(wallet, 'LicenseNFT');
|
||||
|
||||
console.log('🚀 Deploying Approval Manager contract...');
|
||||
const approvalManager = await deployPlaceholderContract(wallet, 'ApprovalManager');
|
||||
|
||||
console.log('🚀 Deploying Department Registry contract...');
|
||||
const departmentRegistry = await deployPlaceholderContract(wallet, 'DepartmentRegistry');
|
||||
|
||||
console.log('🚀 Deploying Workflow Registry contract...');
|
||||
const workflowRegistry = await deployPlaceholderContract(wallet, 'WorkflowRegistry');
|
||||
|
||||
return {
|
||||
licenseNFT,
|
||||
approvalManager,
|
||||
departmentRegistry,
|
||||
workflowRegistry,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploy a placeholder contract (simple storage contract)
|
||||
*/
|
||||
async function deployPlaceholderContract(wallet, name) {
|
||||
// Simple contract that just stores a value
|
||||
const bytecode = '0x608060405234801561001057600080fd5b5060c78061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80632e64cec11460375780636057361d146051575b600080fd5b603d6069565b6040516048919060a2565b60405180910390f35b6067600480360381019060639190606f565b6072565b005b60008054905090565b8060008190555050565b6000813590506079816000ad565b92915050565b6000602082840312156000608257600080fd5b6000608e84828501607c565b91505092915050565b609c8160bb565b82525050565b600060208201905060b560008301846095565b92915050565b600081905091905056fea26469706673582212203a8e2f9c8e98b9f5e8c7d6e5f4c3b2a19087868756463524f3e2d1c0b9a8f76464736f6c63430008110033';
|
||||
|
||||
const deployTx = await wallet.sendTransaction({
|
||||
data: bytecode,
|
||||
});
|
||||
|
||||
const receipt = await deployTx.wait();
|
||||
const address = receipt.contractAddress;
|
||||
|
||||
console.log(`✅ ${name} deployed at:`, address);
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update .env file with generated values
|
||||
*/
|
||||
function updateEnvFile(values) {
|
||||
const envPath = path.join(__dirname, '../.env');
|
||||
let envContent = '';
|
||||
|
||||
if (fs.existsSync(envPath)) {
|
||||
envContent = fs.readFileSync(envPath, 'utf8');
|
||||
}
|
||||
|
||||
// Update or add each value
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
const regex = new RegExp(`^${key}=.*$`, 'm');
|
||||
if (regex.test(envContent)) {
|
||||
envContent = envContent.replace(regex, `${key}=${value}`);
|
||||
} else {
|
||||
envContent += `\n${key}=${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(envPath, envContent.trim() + '\n');
|
||||
console.log(`✅ Updated ${envPath}`);
|
||||
}
|
||||
|
||||
// Run initialization
|
||||
initBlockchain()
|
||||
.then(() => {
|
||||
console.log('✅ Blockchain initialization completed successfully!');
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('❌ Blockchain initialization failed:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user