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:
100
blockchain/scripts/deploy.ts
Normal file
100
blockchain/scripts/deploy.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { ethers } from 'hardhat';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
async function main() {
|
||||
console.log('Starting deployment to Besu network...\n');
|
||||
|
||||
const [deployer] = await ethers.getSigners();
|
||||
console.log('Deploying contracts with account:', deployer.address);
|
||||
|
||||
const balance = await ethers.provider.getBalance(deployer.address);
|
||||
console.log('Account balance:', ethers.formatEther(balance), 'ETH\n');
|
||||
|
||||
// Deploy LicenseNFT
|
||||
console.log('Deploying LicenseNFT...');
|
||||
const LicenseNFT = await ethers.getContractFactory('LicenseNFT');
|
||||
const licenseNFT = await LicenseNFT.deploy();
|
||||
await licenseNFT.waitForDeployment();
|
||||
const licenseNFTAddress = await licenseNFT.getAddress();
|
||||
console.log('LicenseNFT deployed to:', licenseNFTAddress);
|
||||
|
||||
// Deploy ApprovalManager
|
||||
console.log('\nDeploying ApprovalManager...');
|
||||
const ApprovalManager = await ethers.getContractFactory('ApprovalManager');
|
||||
const approvalManager = await ApprovalManager.deploy();
|
||||
await approvalManager.waitForDeployment();
|
||||
const approvalManagerAddress = await approvalManager.getAddress();
|
||||
console.log('ApprovalManager deployed to:', approvalManagerAddress);
|
||||
|
||||
// Deploy DocumentChain
|
||||
console.log('\nDeploying DocumentChain...');
|
||||
const DocumentChain = await ethers.getContractFactory('DocumentChain');
|
||||
const documentChain = await DocumentChain.deploy();
|
||||
await documentChain.waitForDeployment();
|
||||
const documentChainAddress = await documentChain.getAddress();
|
||||
console.log('DocumentChain deployed to:', documentChainAddress);
|
||||
|
||||
// Deploy WorkflowRegistry
|
||||
console.log('\nDeploying WorkflowRegistry...');
|
||||
const WorkflowRegistry = await ethers.getContractFactory('WorkflowRegistry');
|
||||
const workflowRegistry = await WorkflowRegistry.deploy();
|
||||
await workflowRegistry.waitForDeployment();
|
||||
const workflowRegistryAddress = await workflowRegistry.getAddress();
|
||||
console.log('WorkflowRegistry deployed to:', workflowRegistryAddress);
|
||||
|
||||
// Summary
|
||||
console.log('\n========================================');
|
||||
console.log('Deployment Complete!');
|
||||
console.log('========================================');
|
||||
console.log('Contract Addresses:');
|
||||
console.log(' LicenseNFT:', licenseNFTAddress);
|
||||
console.log(' ApprovalManager:', approvalManagerAddress);
|
||||
console.log(' DocumentChain:', documentChainAddress);
|
||||
console.log(' WorkflowRegistry:', workflowRegistryAddress);
|
||||
console.log('========================================\n');
|
||||
|
||||
// Save deployment info
|
||||
const deploymentInfo = {
|
||||
network: 'besu',
|
||||
chainId: 1337,
|
||||
deployer: deployer.address,
|
||||
timestamp: new Date().toISOString(),
|
||||
contracts: {
|
||||
LicenseNFT: licenseNFTAddress,
|
||||
ApprovalManager: approvalManagerAddress,
|
||||
DocumentChain: documentChainAddress,
|
||||
WorkflowRegistry: workflowRegistryAddress,
|
||||
},
|
||||
};
|
||||
|
||||
const deploymentPath = path.join(__dirname, '../deployments');
|
||||
if (!fs.existsSync(deploymentPath)) {
|
||||
fs.mkdirSync(deploymentPath, { recursive: true });
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(deploymentPath, 'deployment.json'),
|
||||
JSON.stringify(deploymentInfo, null, 2)
|
||||
);
|
||||
console.log('Deployment info saved to deployments/deployment.json');
|
||||
|
||||
// Generate .env updates
|
||||
console.log('\n========================================');
|
||||
console.log('Add these to your backend/.env file:');
|
||||
console.log('========================================');
|
||||
console.log(`CONTRACT_ADDRESS_LICENSE_NFT=${licenseNFTAddress}`);
|
||||
console.log(`CONTRACT_ADDRESS_APPROVAL_MANAGER=${approvalManagerAddress}`);
|
||||
console.log(`CONTRACT_ADDRESS_DOCUMENT_CHAIN=${documentChainAddress}`);
|
||||
console.log(`CONTRACT_ADDRESS_WORKFLOW_REGISTRY=${workflowRegistryAddress}`);
|
||||
console.log('========================================\n');
|
||||
|
||||
return deploymentInfo;
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
60
blockchain/scripts/update-env.ts
Normal file
60
blockchain/scripts/update-env.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
/**
|
||||
* Updates the backend .env file with deployed contract addresses
|
||||
*/
|
||||
async function main() {
|
||||
const deploymentPath = path.join(__dirname, '../deployments/deployment.json');
|
||||
|
||||
if (!fs.existsSync(deploymentPath)) {
|
||||
console.error('Deployment file not found. Run deploy.ts first.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const deployment = JSON.parse(fs.readFileSync(deploymentPath, 'utf8'));
|
||||
const backendEnvPath = path.join(__dirname, '../../backend/.env');
|
||||
|
||||
if (!fs.existsSync(backendEnvPath)) {
|
||||
console.error('Backend .env file not found at:', backendEnvPath);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let envContent = fs.readFileSync(backendEnvPath, 'utf8');
|
||||
|
||||
// Contract address mappings
|
||||
const envUpdates: Record<string, string> = {
|
||||
CONTRACT_ADDRESS_LICENSE_NFT: deployment.contracts.LicenseNFT,
|
||||
CONTRACT_ADDRESS_APPROVAL_MANAGER: deployment.contracts.ApprovalManager,
|
||||
CONTRACT_ADDRESS_DOCUMENT_CHAIN: deployment.contracts.DocumentChain,
|
||||
CONTRACT_ADDRESS_WORKFLOW_REGISTRY: deployment.contracts.WorkflowRegistry,
|
||||
};
|
||||
|
||||
// Update or append each variable
|
||||
for (const [key, value] of Object.entries(envUpdates)) {
|
||||
const regex = new RegExp(`^${key}=.*$`, 'm');
|
||||
|
||||
if (regex.test(envContent)) {
|
||||
envContent = envContent.replace(regex, `${key}=${value}`);
|
||||
console.log(`Updated ${key}`);
|
||||
} else {
|
||||
envContent += `\n${key}=${value}`;
|
||||
console.log(`Added ${key}`);
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(backendEnvPath, envContent);
|
||||
console.log('\nBackend .env file updated successfully!');
|
||||
console.log('Updated contract addresses:');
|
||||
|
||||
for (const [key, value] of Object.entries(envUpdates)) {
|
||||
console.log(` ${key}=${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user