feat: add core and common modules with PostgreSQL integration
- Introduced CommonModule for shared services and configurations. - Added CoreModule to manage database connections and configurations. - Implemented PostgresService for PostgreSQL operations. - Created configuration files for database and network provider. - Integrated ethers.js for Ethereum interactions. - Added validation pipes globally in the main application. - Created DeployerModule with initial controller and service structure. - Updated package.json with necessary dependencies for new features.
This commit is contained in:
parent
c6c947a402
commit
228b06f4c0
18
.gitignore
vendored
18
.gitignore
vendored
|
|
@ -54,3 +54,21 @@ pids
|
|||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
node_modules
|
||||
.env
|
||||
|
||||
# Hardhat files
|
||||
/cache
|
||||
/artifacts
|
||||
|
||||
# TypeChain files
|
||||
/typechain
|
||||
/typechain-types
|
||||
|
||||
# solidity-coverage files
|
||||
/coverage
|
||||
/coverage.json
|
||||
|
||||
# Hardhat Ignition default folder for deployments against a local node
|
||||
ignition/deployments/chain-31337
|
||||
|
|
|
|||
32
contracts/main.sol
Normal file
32
contracts/main.sol
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
contract P2PTransferProject {
|
||||
address public owner;
|
||||
string public name;
|
||||
modifier onlyOwner() {
|
||||
require(msg.sender == owner, "Only owner");
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(string memory _name) {
|
||||
owner = msg.sender;
|
||||
name = _name;
|
||||
}
|
||||
|
||||
function getBalance() external view returns (uint256) {
|
||||
return address(this).balance;
|
||||
}
|
||||
|
||||
function setName(string memory _name) external onlyOwner {
|
||||
name = _name;
|
||||
}
|
||||
|
||||
function getName() external view returns (string memory) {
|
||||
return name;
|
||||
}
|
||||
|
||||
function getOwner() external view returns (address) {
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
8
hardhat.config.ts
Normal file
8
hardhat.config.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { HardhatUserConfig } from "hardhat/config";
|
||||
import "@nomicfoundation/hardhat-toolbox";
|
||||
|
||||
const config: HardhatUserConfig = {
|
||||
solidity: "0.8.28",
|
||||
};
|
||||
|
||||
export default config;
|
||||
5688
package-lock.json
generated
5688
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
|
|
@ -23,26 +23,36 @@
|
|||
"@nestjs/common": "^11.0.1",
|
||||
"@nestjs/core": "^11.0.1",
|
||||
"@nestjs/platform-express": "^11.0.1",
|
||||
"@nomicfoundation/hardhat-toolbox": "^6.0.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.2",
|
||||
"ethers": "^6.15.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@nestjs/class-validator": "^0.13.4",
|
||||
"@nestjs/cli": "^11.0.0",
|
||||
"@nestjs/config": "^4.0.2",
|
||||
"@nestjs/schematics": "^11.0.0",
|
||||
"@nestjs/testing": "^11.0.1",
|
||||
"@openzeppelin/contracts": "^5.3.0",
|
||||
"@swc/cli": "^0.6.0",
|
||||
"@swc/core": "^1.10.7",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^22.10.7",
|
||||
"@types/pg": "^8.15.5",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-prettier": "^5.2.2",
|
||||
"globals": "^16.0.0",
|
||||
"hardhat": "^2.25.0",
|
||||
"jest": "^29.7.0",
|
||||
"pg": "^8.16.3",
|
||||
"prettier": "^3.4.2",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,16 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { ModulesModule } from './modules/module.module';
|
||||
import { CoreModule } from './core/core.module';
|
||||
import { CommonModule } from './common/common.module';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
imports: [
|
||||
ConfigModule.forRoot({isGlobal:true}),
|
||||
CommonModule,
|
||||
CoreModule,
|
||||
ModulesModule
|
||||
],
|
||||
controllers: [],
|
||||
providers: [],
|
||||
})
|
||||
|
|
|
|||
15
src/common/common.module.ts
Normal file
15
src/common/common.module.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { Global, Module } from "@nestjs/common";
|
||||
import { ProviderService } from "./utils";
|
||||
import { ConfigModule } from "@nestjs/config";
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [ConfigModule],
|
||||
providers: [
|
||||
ProviderService
|
||||
],
|
||||
exports: [
|
||||
ProviderService
|
||||
],
|
||||
})
|
||||
export class CommonModule {}
|
||||
6
src/common/config/db.config.ts
Normal file
6
src/common/config/db.config.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { registerAs } from "@nestjs/config";
|
||||
import { Database } from "../types";
|
||||
|
||||
export default registerAs<Database>('Database', () => ({
|
||||
url: process.env.DATABASE_URL || null,
|
||||
}));
|
||||
7
src/common/config/provider.config.ts
Normal file
7
src/common/config/provider.config.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { registerAs } from "@nestjs/config";
|
||||
import { NetworkProvider } from "../types";
|
||||
|
||||
export default registerAs<NetworkProvider>('NetworkProvider', ()=>({
|
||||
providerUrl: process.env.NETWORK_PROVIDER || null,
|
||||
walletKey: process.env.WALLET_KEY || null,
|
||||
}));
|
||||
8
src/common/types/env.type.ts
Normal file
8
src/common/types/env.type.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export interface NetworkProvider {
|
||||
providerUrl: string | null;
|
||||
walletKey: string | null;
|
||||
}
|
||||
|
||||
export interface Database{
|
||||
url:string | null;
|
||||
}
|
||||
1
src/common/types/index.ts
Normal file
1
src/common/types/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './env.type';
|
||||
100
src/common/utils/abis/P2PTransferProject.json
Normal file
100
src/common/utils/abis/P2PTransferProject.json
Normal file
File diff suppressed because one or more lines are too long
1
src/common/utils/index.ts
Normal file
1
src/common/utils/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './provider.service';
|
||||
35
src/common/utils/provider.service.ts
Normal file
35
src/common/utils/provider.service.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { Injectable } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { ethers } from "ethers";
|
||||
import * as P2PTransferProject from "./abis/P2PTransferProject.json";
|
||||
|
||||
@Injectable()
|
||||
export class ProviderService {
|
||||
|
||||
constructor(private readonly config: ConfigService) {}
|
||||
|
||||
async getProviderAndWallet(): Promise<{ provider: ethers.JsonRpcProvider, wallet: ethers.Wallet }> {
|
||||
try{
|
||||
const providerUrl = this.config.get<string>('NetworkProvider.providerUrl');
|
||||
const walletKey = this.config.get<string>('NetworkProvider.walletKey');
|
||||
|
||||
if (!providerUrl || !walletKey) {
|
||||
throw new Error('Provider URL or Wallet Key is not configured');
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(providerUrl);
|
||||
const wallet = new ethers.Wallet(walletKey, provider);
|
||||
return { provider, wallet };
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to create provider or wallet: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getAbiAndBytecode(){
|
||||
return {
|
||||
abi: P2PTransferProject.abi,
|
||||
bytecode: P2PTransferProject.bytecode
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
25
src/core/core.module.ts
Normal file
25
src/core/core.module.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { Global, Module } from "@nestjs/common";
|
||||
import { PostgresService } from "./psql/postgres.service";
|
||||
import { PostgresModule } from "./psql/postgres.module";
|
||||
import { ConfigModule } from "@nestjs/config";
|
||||
import providerConfig from "src/common/config/provider.config";
|
||||
import dbConfig from "src/common/config/db.config";
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
load: [
|
||||
dbConfig,
|
||||
providerConfig
|
||||
],
|
||||
cache: true,
|
||||
expandVariables: true,
|
||||
}),
|
||||
PostgresModule
|
||||
],
|
||||
exports: [PostgresModule],
|
||||
})
|
||||
|
||||
export class CoreModule {}
|
||||
9
src/core/psql/postgres.module.ts
Normal file
9
src/core/psql/postgres.module.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { Global, Module } from "@nestjs/common";
|
||||
import { PostgresService } from "./postgres.service";
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers:[PostgresService],
|
||||
exports: [PostgresService],
|
||||
})
|
||||
export class PostgresModule {}
|
||||
85
src/core/psql/postgres.service.ts
Normal file
85
src/core/psql/postgres.service.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import { Injectable } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { Client } from 'pg'
|
||||
|
||||
@Injectable()
|
||||
export class PostgresService {
|
||||
private client: Client;
|
||||
constructor(private readonly config: ConfigService) {
|
||||
const connStr = this.config.get<string>('DATABASE_URL');
|
||||
if (!connStr) {
|
||||
throw new Error('DATABASE_URL is missing from configuration.');
|
||||
}
|
||||
|
||||
this.client = new Client({
|
||||
connectionString: connStr,
|
||||
});
|
||||
}
|
||||
|
||||
async onModuleInit() {
|
||||
console.log('Connecting to Postgres...');
|
||||
await this.connect(); // or initialize pool
|
||||
}
|
||||
|
||||
async onModuleDestroy() {
|
||||
await this.disconnect();
|
||||
}
|
||||
|
||||
async connect() {
|
||||
await this.client.connect();
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
await this.client.end();
|
||||
}
|
||||
|
||||
async getAll<T = any>(table: string, filters?: Record<string, any>): Promise<T[]> {
|
||||
let query = `SELECT * FROM ${table}`;
|
||||
const values: any[] = [];
|
||||
|
||||
if (filters && Object.keys(filters).length > 0) {
|
||||
const conditions = Object.entries(filters).map(([key, value], idx) => {
|
||||
values.push(value);
|
||||
// use LOWER() for Ethereum address comparison
|
||||
return `LOWER(${key}) = LOWER($${idx + 1})`;
|
||||
});
|
||||
query += ` WHERE ` + conditions.join(' AND ');
|
||||
}
|
||||
|
||||
const res = await this.client.query(query, values);
|
||||
return res.rows;
|
||||
}
|
||||
|
||||
async insert<T = any>(table: string, data: Record<string, any>): Promise<T> {
|
||||
const keys = Object.keys(data)
|
||||
const values = Object.values(data)
|
||||
const placeholders = keys.map((_, i) => `$${i + 1}`).join(', ')
|
||||
|
||||
const res = await this.client.query(
|
||||
`INSERT INTO ${table} (${keys.join(', ')}) VALUES (${placeholders}) RETURNING *`,
|
||||
values
|
||||
)
|
||||
return res.rows[0]
|
||||
}
|
||||
|
||||
async update<T = any>(table: string, id: number, data: Record<string, any>): Promise<T> {
|
||||
const keys = Object.keys(data)
|
||||
const values = Object.values(data)
|
||||
const setClause = keys.map((key, i) => `${key} = $${i + 1}`).join(', ')
|
||||
|
||||
const res = await this.client.query(
|
||||
`UPDATE ${table} SET ${setClause} WHERE id = $${keys.length + 1} RETURNING *`,
|
||||
[...values, id]
|
||||
)
|
||||
return res.rows[0]
|
||||
}
|
||||
|
||||
async delete<T = any>(table: string, id: number): Promise<T> {
|
||||
const res = await this.client.query(
|
||||
`DELETE FROM ${table} WHERE id = $1 RETURNING *`,
|
||||
[id]
|
||||
)
|
||||
return res.rows[0]
|
||||
}
|
||||
|
||||
}
|
||||
17
src/main.ts
17
src/main.ts
|
|
@ -1,8 +1,25 @@
|
|||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({
|
||||
whitelist:true,
|
||||
transform:true,
|
||||
forbidNonWhitelisted:true
|
||||
}),
|
||||
);
|
||||
|
||||
//CORS configuration
|
||||
// app.enableCors({
|
||||
// origin: process.env.FRONTEND_URL,
|
||||
// credentials: true,
|
||||
// });
|
||||
// app.setGlobalPrefix('api');
|
||||
|
||||
await app.listen(process.env.PORT ?? 3000);
|
||||
}
|
||||
bootstrap();
|
||||
|
|
|
|||
6
src/modules/deployer/controllers/deployer.controller.ts
Normal file
6
src/modules/deployer/controllers/deployer.controller.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { Controller } from "@nestjs/common";
|
||||
|
||||
@Controller()
|
||||
export class DeployerController {
|
||||
// Controller methods go here
|
||||
}
|
||||
1
src/modules/deployer/controllers/index.ts
Normal file
1
src/modules/deployer/controllers/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./deployer.controller";
|
||||
9
src/modules/deployer/deployer.module.ts
Normal file
9
src/modules/deployer/deployer.module.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { Module } from "@nestjs/common";
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [],
|
||||
providers: [],
|
||||
exports: [],
|
||||
})
|
||||
export class DeployerModule {}
|
||||
0
src/modules/deployer/dtos/index.ts
Normal file
0
src/modules/deployer/dtos/index.ts
Normal file
6
src/modules/deployer/services/deployer.service.ts
Normal file
6
src/modules/deployer/services/deployer.service.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
@Injectable()
|
||||
export class DeployerService {
|
||||
// Service methods go here
|
||||
}
|
||||
1
src/modules/deployer/services/index.ts
Normal file
1
src/modules/deployer/services/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './deployer.service'
|
||||
4
src/modules/deployer/types/contract.type.ts
Normal file
4
src/modules/deployer/types/contract.type.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export type Contract = {
|
||||
contractaddress: string;
|
||||
useraddress: string;
|
||||
}
|
||||
1
src/modules/deployer/types/index.ts
Normal file
1
src/modules/deployer/types/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './contract.type';
|
||||
6
src/modules/module.module.ts
Normal file
6
src/modules/module.module.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { Module } from "@nestjs/common";
|
||||
|
||||
@Module({
|
||||
imports: []
|
||||
})
|
||||
export class ModulesModule {}
|
||||
|
|
@ -6,6 +6,8 @@
|
|||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"target": "ES2023",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
|
|
@ -14,8 +16,8 @@
|
|||
"skipLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitAny": false,
|
||||
"noImplicitAny": true,
|
||||
"strictBindCallApply": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
"noFallthroughCasesInSwitch": true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user