From 9ec370c8f6e1d8e168ff22de38b32fcf5ee902bb Mon Sep 17 00:00:00 2001 From: emochka2007 Date: Mon, 13 May 2024 02:12:50 +0300 Subject: [PATCH] multisig fully ready + salaries almost ready. refactor contracts and refactor structure of app. swagger update --- chain-api/src/app.module.ts | 3 +- .../contract-factory.controller.spec.ts | 20 --- .../contract-factory.controller.ts | 26 --- .../contract-factory.module.ts | 11 -- .../contract-factory.service.spec.ts | 18 --- .../contract-factory.service.ts | 21 --- .../dto/create-contract-factory.dto.ts | 12 -- .../dto/update-contract-factory.dto.ts | 4 - .../contract-interact.controller.spec.ts | 20 --- .../contract-interact.module.ts | 7 +- .../contract-interact.service.spec.ts | 18 --- .../contract-interact.service.ts | 26 --- .../contract-interact/dto/multi-sig.dto.ts | 28 +++- .../src/contract-interact/ethers.helpers.ts | 10 ++ .../multi-sig-interact.controller.ts | 20 --- chain-api/src/filters/http.filter.ts | 33 ++++ chain-api/src/hardhat/contracts/Agreement.sol | 10 ++ chain-api/src/hardhat/contracts/Salaries.sol | 5 + .../src/hardhat/ignition/modules/Lock.ts | 17 -- .../ignition/modules/MultiSigWallet.ts | 17 -- .../src/hardhat/ignition/modules/Salaries.ts | 11 -- .../hardhat/modules/base-contract.service.ts | 5 +- .../src/hardhat/modules/dto/ethers.dto.ts | 60 +++++++ .../src/hardhat/modules/hardhat.module.ts | 10 +- .../multi-sig-interact.controller.ts | 65 ++++++++ .../{dto => multi-sig}/multi-sig.dto.ts | 0 .../modules/multi-sig/multi-sig.module.ts | 3 +- .../modules/multi-sig/multi-sig.service.ts | 149 +++++++++++++++--- .../salaries/salaries-interact.controller.ts | 33 ++++ .../hardhat/modules/salaries/salaries.dto.ts | 32 ++++ .../modules/salaries/salaries.module.ts | 13 ++ .../modules/salaries/salaries.service.ts | 75 +++++++++ .../src/hardhat/modules/salary.service.ts | 41 ----- chain-api/src/main.ts | 4 +- 34 files changed, 502 insertions(+), 325 deletions(-) delete mode 100644 chain-api/src/contract-factory/contract-factory.controller.spec.ts delete mode 100644 chain-api/src/contract-factory/contract-factory.controller.ts delete mode 100644 chain-api/src/contract-factory/contract-factory.module.ts delete mode 100644 chain-api/src/contract-factory/contract-factory.service.spec.ts delete mode 100644 chain-api/src/contract-factory/contract-factory.service.ts delete mode 100644 chain-api/src/contract-factory/dto/create-contract-factory.dto.ts delete mode 100644 chain-api/src/contract-factory/dto/update-contract-factory.dto.ts delete mode 100644 chain-api/src/contract-interact/contract-interact.controller.spec.ts delete mode 100644 chain-api/src/contract-interact/contract-interact.service.spec.ts delete mode 100644 chain-api/src/contract-interact/contract-interact.service.ts create mode 100644 chain-api/src/contract-interact/ethers.helpers.ts delete mode 100644 chain-api/src/contract-interact/multi-sig-interact.controller.ts create mode 100644 chain-api/src/filters/http.filter.ts delete mode 100644 chain-api/src/hardhat/ignition/modules/Lock.ts delete mode 100644 chain-api/src/hardhat/ignition/modules/MultiSigWallet.ts delete mode 100644 chain-api/src/hardhat/ignition/modules/Salaries.ts create mode 100644 chain-api/src/hardhat/modules/dto/ethers.dto.ts create mode 100644 chain-api/src/hardhat/modules/multi-sig/multi-sig-interact.controller.ts rename chain-api/src/hardhat/modules/{dto => multi-sig}/multi-sig.dto.ts (100%) create mode 100644 chain-api/src/hardhat/modules/salaries/salaries-interact.controller.ts create mode 100644 chain-api/src/hardhat/modules/salaries/salaries.dto.ts create mode 100644 chain-api/src/hardhat/modules/salaries/salaries.module.ts create mode 100644 chain-api/src/hardhat/modules/salaries/salaries.service.ts delete mode 100644 chain-api/src/hardhat/modules/salary.service.ts diff --git a/chain-api/src/app.module.ts b/chain-api/src/app.module.ts index 7185a27..214054f 100644 --- a/chain-api/src/app.module.ts +++ b/chain-api/src/app.module.ts @@ -1,7 +1,7 @@ import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { ContractFactoryModule } from './contract-factory/contract-factory.module'; + import { ContractInteractModule } from './contract-interact/contract-interact.module'; import { ConfigModule } from '@nestjs/config'; @@ -10,7 +10,6 @@ import { ConfigModule } from '@nestjs/config'; ConfigModule.forRoot({ isGlobal: true, }), - ContractFactoryModule, ContractInteractModule, ], controllers: [AppController], diff --git a/chain-api/src/contract-factory/contract-factory.controller.spec.ts b/chain-api/src/contract-factory/contract-factory.controller.spec.ts deleted file mode 100644 index 42eedd4..0000000 --- a/chain-api/src/contract-factory/contract-factory.controller.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { ContractFactoryController } from './contract-factory.controller'; -import { ContractFactoryService } from './contract-factory.service'; - -describe('ContractFactoryController', () => { - let controller: ContractFactoryController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [ContractFactoryController], - providers: [ContractFactoryService], - }).compile(); - - controller = module.get(ContractFactoryController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/chain-api/src/contract-factory/contract-factory.controller.ts b/chain-api/src/contract-factory/contract-factory.controller.ts deleted file mode 100644 index c8a5db5..0000000 --- a/chain-api/src/contract-factory/contract-factory.controller.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { - Controller, - Get, - Post, - Body, - Patch, - Param, - Delete, -} from '@nestjs/common'; -import { ContractFactoryService } from './contract-factory.service'; -import { CreateContractFactoryDto } from './dto/create-contract-factory.dto'; -import { UpdateContractFactoryDto } from './dto/update-contract-factory.dto'; -import { ApiTags } from '@nestjs/swagger'; -import { MultiSigWalletDto } from 'src/hardhat/modules/dto/multi-sig.dto'; -@ApiTags('contract-factory') -@Controller('contract-factory') -export class ContractFactoryController { - constructor( - private readonly contractFactoryService: ContractFactoryService, - ) {} - - @Post('multi-sig') - create(@Body() createContractFactoryDto: MultiSigWalletDto) { - return this.contractFactoryService.createMultiSig(createContractFactoryDto); - } -} diff --git a/chain-api/src/contract-factory/contract-factory.module.ts b/chain-api/src/contract-factory/contract-factory.module.ts deleted file mode 100644 index a671464..0000000 --- a/chain-api/src/contract-factory/contract-factory.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { HardhatModule } from '../hardhat/modules/hardhat.module'; -import { Module } from '@nestjs/common'; -import { ContractFactoryService } from './contract-factory.service'; -import { ContractFactoryController } from './contract-factory.controller'; - -@Module({ - imports: [HardhatModule], - controllers: [ContractFactoryController], - providers: [ContractFactoryService], -}) -export class ContractFactoryModule {} diff --git a/chain-api/src/contract-factory/contract-factory.service.spec.ts b/chain-api/src/contract-factory/contract-factory.service.spec.ts deleted file mode 100644 index cff59d1..0000000 --- a/chain-api/src/contract-factory/contract-factory.service.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { ContractFactoryService } from './contract-factory.service'; - -describe('ContractFactoryService', () => { - let service: ContractFactoryService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ContractFactoryService], - }).compile(); - - service = module.get(ContractFactoryService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/chain-api/src/contract-factory/contract-factory.service.ts b/chain-api/src/contract-factory/contract-factory.service.ts deleted file mode 100644 index cb4487a..0000000 --- a/chain-api/src/contract-factory/contract-factory.service.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { HardhatService } from '../hardhat/modules/hardhat.service'; -import { Injectable } from '@nestjs/common'; -import { CreateContractFactoryDto } from './dto/create-contract-factory.dto'; -import { SalariesService } from 'src/hardhat/modules/salary.service'; -import { MultiSigWalletService } from 'src/hardhat/modules/multi-sig/multi-sig.service'; -import { MultiSigWalletDto } from 'src/hardhat/modules/dto/multi-sig.dto'; - -@Injectable() -export class ContractFactoryService { - constructor( - private readonly salaryService: SalariesService, - private readonly multiSigService: MultiSigWalletService, - ) {} - async createSalary(createContractFactoryDto: CreateContractFactoryDto) { - return await this.salaryService.deploy(); - } - - async createMultiSig(dto: MultiSigWalletDto) { - return await this.multiSigService.deploy(dto); - } -} diff --git a/chain-api/src/contract-factory/dto/create-contract-factory.dto.ts b/chain-api/src/contract-factory/dto/create-contract-factory.dto.ts deleted file mode 100644 index 4fe0997..0000000 --- a/chain-api/src/contract-factory/dto/create-contract-factory.dto.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -export enum ContractType { - SALARY, - AGREEMENT, -} - -export class CreateContractFactoryDto { - @ApiProperty({ - enum: ContractType, - }) - contractType: ContractType; -} diff --git a/chain-api/src/contract-factory/dto/update-contract-factory.dto.ts b/chain-api/src/contract-factory/dto/update-contract-factory.dto.ts deleted file mode 100644 index 0fbfa0a..0000000 --- a/chain-api/src/contract-factory/dto/update-contract-factory.dto.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PartialType } from '@nestjs/mapped-types'; -import { CreateContractFactoryDto } from './create-contract-factory.dto'; - -export class UpdateContractFactoryDto extends PartialType(CreateContractFactoryDto) {} diff --git a/chain-api/src/contract-interact/contract-interact.controller.spec.ts b/chain-api/src/contract-interact/contract-interact.controller.spec.ts deleted file mode 100644 index 0ca68e9..0000000 --- a/chain-api/src/contract-interact/contract-interact.controller.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { ContractInteractController } from './contract-interact.controller'; -import { ContractInteractService } from './contract-interact.service'; - -describe('ContractInteractController', () => { - let controller: ContractInteractController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [ContractInteractController], - providers: [ContractInteractService], - }).compile(); - - controller = module.get(ContractInteractController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/chain-api/src/contract-interact/contract-interact.module.ts b/chain-api/src/contract-interact/contract-interact.module.ts index 2063f80..1e55000 100644 --- a/chain-api/src/contract-interact/contract-interact.module.ts +++ b/chain-api/src/contract-interact/contract-interact.module.ts @@ -1,12 +1,9 @@ import { Module } from '@nestjs/common'; -import { ContractInteractService } from './contract-interact.service'; - import { HardhatModule } from 'src/hardhat/modules/hardhat.module'; -import { MultiSigInteractController } from './multi-sig-interact.controller'; @Module({ imports: [HardhatModule], - controllers: [MultiSigInteractController], - providers: [ContractInteractService], + controllers: [], + providers: [], }) export class ContractInteractModule {} diff --git a/chain-api/src/contract-interact/contract-interact.service.spec.ts b/chain-api/src/contract-interact/contract-interact.service.spec.ts deleted file mode 100644 index fa58751..0000000 --- a/chain-api/src/contract-interact/contract-interact.service.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { ContractInteractService } from './contract-interact.service'; - -describe('ContractInteractService', () => { - let service: ContractInteractService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ContractInteractService], - }).compile(); - - service = module.get(ContractInteractService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/chain-api/src/contract-interact/contract-interact.service.ts b/chain-api/src/contract-interact/contract-interact.service.ts deleted file mode 100644 index 5249e46..0000000 --- a/chain-api/src/contract-interact/contract-interact.service.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { CreateContractInteractDto } from './dto/create-contract-interact.dto'; -import { UpdateContractInteractDto } from './dto/update-contract-interact.dto'; - -@Injectable() -export class ContractInteractService { - create(createContractInteractDto: CreateContractInteractDto) { - return 'This action adds a new contractInteract'; - } - - findAll() { - return `This action returns all contractInteract`; - } - - findOne(id: number) { - return `This action returns a #${id} contractInteract`; - } - - update(id: number, updateContractInteractDto: UpdateContractInteractDto) { - return `This action updates a #${id} contractInteract`; - } - - remove(id: number) { - return `This action removes a #${id} contractInteract`; - } -} diff --git a/chain-api/src/contract-interact/dto/multi-sig.dto.ts b/chain-api/src/contract-interact/dto/multi-sig.dto.ts index 290ae54..d124f50 100644 --- a/chain-api/src/contract-interact/dto/multi-sig.dto.ts +++ b/chain-api/src/contract-interact/dto/multi-sig.dto.ts @@ -1,5 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsOptional, IsString } from 'class-validator'; +import { IsNumber, IsOptional, IsString } from 'class-validator'; export class SubmitTransactionDto { @IsString() @@ -16,3 +16,29 @@ export class SubmitTransactionDto { // @ApiProperty() data: string; } + +export class ConfirmTransactionDto { + @IsString() + @ApiProperty() + contractAddress: string; + @ApiProperty() + @IsNumber() + index: number; +} + +export class ExecuteTransactionDto extends ConfirmTransactionDto {} + +export class RevokeConfirmationDto extends ConfirmTransactionDto {} + +export class GetTransactionCount {} + +export class GetTransactionDto extends ConfirmTransactionDto {} + +export class DepositMultiSigDto { + @IsString() + @ApiProperty() + contractAddress: string; + @IsString() + @ApiProperty() + value: string; +} diff --git a/chain-api/src/contract-interact/ethers.helpers.ts b/chain-api/src/contract-interact/ethers.helpers.ts new file mode 100644 index 0000000..f77b017 --- /dev/null +++ b/chain-api/src/contract-interact/ethers.helpers.ts @@ -0,0 +1,10 @@ +import { TransactionReceipt, ethers } from 'ethers'; + +export const parseLogs = ( + txReceipt: TransactionReceipt, + contract: ethers.Contract, +) => { + return txReceipt.logs + .map((log) => contract.interface.parseLog(log)) + .find((log) => !!log); +}; diff --git a/chain-api/src/contract-interact/multi-sig-interact.controller.ts b/chain-api/src/contract-interact/multi-sig-interact.controller.ts deleted file mode 100644 index e396448..0000000 --- a/chain-api/src/contract-interact/multi-sig-interact.controller.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Body, Controller, Get, Param, Post } from '@nestjs/common'; -import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; -import { MultiSigWalletService } from 'src/hardhat/modules/multi-sig/multi-sig.service'; -import { SubmitTransactionDto } from './dto/multi-sig.dto'; -@ApiTags('multi-sig-interact') -@Controller() -export class MultiSigInteractController { - constructor(private readonly multiSigWalletService: MultiSigWalletService) {} - - @Get('owners/:address') - async getOwners(@Param('address') address: string) { - return this.multiSigWalletService.getOwners(address); - } - - @ApiOkResponse() - @Post('submit-transaction') - async submitTransaction(@Body() dto: SubmitTransactionDto) { - return this.multiSigWalletService.submitTransaction(dto); - } -} diff --git a/chain-api/src/filters/http.filter.ts b/chain-api/src/filters/http.filter.ts new file mode 100644 index 0000000..ce33efe --- /dev/null +++ b/chain-api/src/filters/http.filter.ts @@ -0,0 +1,33 @@ +import { + ArgumentsHost, + Catch, + ExceptionFilter, + HttpException, + HttpStatus, +} from '@nestjs/common'; +import { error } from 'console'; +import { Request, Response } from 'express'; + +@Catch() +export class AllExceptionsFilter implements ExceptionFilter { + // constructor(private readonly httpAdapterHost: HttpAdapterHost) {} + + catch(exception: any, host: ArgumentsHost): void { + console.log('🚀 ~ AllExceptionsFilter ~ exception:', exception); + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + const request = ctx.getRequest(); + const httpStatus = + exception instanceof HttpException + ? exception.getStatus() + : HttpStatus.INTERNAL_SERVER_ERROR; + + const responseBody = { + statusCode: httpStatus, + error: exception?.info?.error.message || exception.toString(), + timestamp: new Date().toISOString(), + }; + + response.status(500).json(responseBody); + } +} diff --git a/chain-api/src/hardhat/contracts/Agreement.sol b/chain-api/src/hardhat/contracts/Agreement.sol index e69de29..026e656 100644 --- a/chain-api/src/hardhat/contracts/Agreement.sol +++ b/chain-api/src/hardhat/contracts/Agreement.sol @@ -0,0 +1,10 @@ +// + +/** + +License +sender +receiver + + + */ \ No newline at end of file diff --git a/chain-api/src/hardhat/contracts/Salaries.sol b/chain-api/src/hardhat/contracts/Salaries.sol index 3c343c8..e7b9c0c 100644 --- a/chain-api/src/hardhat/contracts/Salaries.sol +++ b/chain-api/src/hardhat/contracts/Salaries.sol @@ -9,6 +9,7 @@ contract Salaries { address public multisigWallet; mapping(address => uint) public salaries; + //0xF0d50568e3A7e8259E16663972b11910F89BD8e7 constructor(address _multisigWallet, address _priceFeedAddress) { multisigWallet = _multisigWallet; dataFeed = AggregatorV3Interface(_priceFeedAddress); @@ -19,6 +20,10 @@ contract Salaries { _; } + function getSalary(address employee) public view returns(uint) { + return salaries[employee]; + } + function getLatestUSDTPriceInETH() public view returns (int) { ( , diff --git a/chain-api/src/hardhat/ignition/modules/Lock.ts b/chain-api/src/hardhat/ignition/modules/Lock.ts deleted file mode 100644 index eda0eba..0000000 --- a/chain-api/src/hardhat/ignition/modules/Lock.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; - -const JAN_1ST_2030 = 1893456000; -const ONE_GWEI: bigint = 1_000_000_000n; - -const LockModule = buildModule("LockModule", (m) => { - const unlockTime = m.getParameter("unlockTime", JAN_1ST_2030); - const lockedAmount = m.getParameter("lockedAmount", ONE_GWEI); - - const lock = m.contract("Lock", [unlockTime], { - value: lockedAmount, - }); - - return { lock }; -}); - -export default LockModule; diff --git a/chain-api/src/hardhat/ignition/modules/MultiSigWallet.ts b/chain-api/src/hardhat/ignition/modules/MultiSigWallet.ts deleted file mode 100644 index 77ddc51..0000000 --- a/chain-api/src/hardhat/ignition/modules/MultiSigWallet.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; - -const JAN_1ST_2030 = 1893456000; -const ONE_GWEI: bigint = 1_000_000_000n; - -const owners = ["0xfE87F7EF2a58a1f363a444332df6c131C683e35f"]; - -const MultiSigModule = buildModule("MultiSigWallet", (m) => { - const ownerP = m.getParameter("owners", owners); - const confirmationsP = m.getParameter("_numConfirmationsRequired", 1); - - const deploy = m.contract("MultiSigWallet", [ownerP, confirmationsP]); - - return { deploy }; -}); - -export default MultiSigModule; diff --git a/chain-api/src/hardhat/ignition/modules/Salaries.ts b/chain-api/src/hardhat/ignition/modules/Salaries.ts deleted file mode 100644 index b802d35..0000000 --- a/chain-api/src/hardhat/ignition/modules/Salaries.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; -//npx hardhat ignition deploy ignition/modules/Salaries.ts --network amoy -//SalariesModule#Salaries - 0xac45e95Dd5C7F9B1a6C3e4883d04952B9C974b05 -const SalariesModule = buildModule("SalariesModule", (m) => { - const salaryContract = m.contract("Salaries"); - - const answer = m.call(salaryContract, "getChainlinkDataFeedLatestAnswer", []); - console.log("🚀 ~ SalariesModule ~ answer:", answer); - return { salaryContract }; -}); -export default SalariesModule; diff --git a/chain-api/src/hardhat/modules/base-contract.service.ts b/chain-api/src/hardhat/modules/base-contract.service.ts index 5a9209f..293b490 100644 --- a/chain-api/src/hardhat/modules/base-contract.service.ts +++ b/chain-api/src/hardhat/modules/base-contract.service.ts @@ -4,9 +4,6 @@ import { ProviderService } from 'src/provider/provider.service'; @Injectable() export abstract class BaseContractService { - constructor( - public readonly configService: ConfigService, - public readonly providerService: ProviderService, - ) {} + constructor(public readonly providerService: ProviderService) {} abstract deploy(dto: object): Promise; } diff --git a/chain-api/src/hardhat/modules/dto/ethers.dto.ts b/chain-api/src/hardhat/modules/dto/ethers.dto.ts new file mode 100644 index 0000000..69ec37a --- /dev/null +++ b/chain-api/src/hardhat/modules/dto/ethers.dto.ts @@ -0,0 +1,60 @@ +import { ethers } from 'ethers'; + +// Define a TypeScript type for the EventLog based on the provided structure +export type TransactionLogs = { + provider: ethers.JsonRpcApiProvider; + transactionHash: string; + blockHash: string; + blockNumber: number; + removed: boolean | undefined; + address: string; + data: string; + topics: string[]; + index: number; + transactionIndex: number; + interface: Interface; + fragment: EventFragment; +}; + +type Interface = { + fragments: Fragment[]; + deploy: ConstructorFragment[]; + fallback: any | null; + receive: boolean; +}; + +type Fragment = {}; + +type ConstructorFragment = {}; + +type EventFragment = { + type: string; + inputs: any[]; + name: string; + anonymous: boolean; +}; + +type SubmitArgs = { + args: [ + owner: string, + txIndex: bigint, + to: string, + value: bigint, + data: string, + ]; +}; + +type ConfirmArgs = { + args: [owner: string, txIndex: bigint]; +}; +type ExecuteArgs = { + args: [owner: string, txIndex: bigint]; +}; +type DepositArgs = { + args: [owner: string, value: bigint, address: string]; +}; + +export type SubmitTransactionLogs = TransactionLogs & SubmitArgs; +export type ConfirmTransactionLogs = TransactionLogs & ConfirmArgs; +export type ExecuteTransactionLogs = TransactionLogs & ExecuteArgs; +export type DepositLogs = TransactionLogs & DepositArgs; diff --git a/chain-api/src/hardhat/modules/hardhat.module.ts b/chain-api/src/hardhat/modules/hardhat.module.ts index 164093f..577d8c7 100644 --- a/chain-api/src/hardhat/modules/hardhat.module.ts +++ b/chain-api/src/hardhat/modules/hardhat.module.ts @@ -1,15 +1,13 @@ import { Module } from '@nestjs/common'; import { HardhatService } from './hardhat.service'; import { ProviderModule } from 'src/provider/provider.module'; -import { MultiSigWalletService } from './multi-sig/multi-sig.service'; -import { SalariesService } from './salary.service'; -import { BaseContractService } from './base-contract.service'; import { MultiSigModule } from './multi-sig/multi-sig.module'; +import { SalariesModule } from './salaries/salaries.module'; @Module({ - imports: [ProviderModule, MultiSigModule], + imports: [ProviderModule, MultiSigModule, SalariesModule], controllers: [], - providers: [HardhatService, SalariesService], - exports: [HardhatService, SalariesService, MultiSigModule], + providers: [HardhatService], + exports: [HardhatService, MultiSigModule, SalariesModule], }) export class HardhatModule {} diff --git a/chain-api/src/hardhat/modules/multi-sig/multi-sig-interact.controller.ts b/chain-api/src/hardhat/modules/multi-sig/multi-sig-interact.controller.ts new file mode 100644 index 0000000..f434be2 --- /dev/null +++ b/chain-api/src/hardhat/modules/multi-sig/multi-sig-interact.controller.ts @@ -0,0 +1,65 @@ +import { Body, Controller, Get, Param, Post } from '@nestjs/common'; +import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; +import { MultiSigWalletService } from 'src/hardhat/modules/multi-sig/multi-sig.service'; +import { + ConfirmTransactionDto, + DepositMultiSigDto, + ExecuteTransactionDto, + GetTransactionDto, + RevokeConfirmationDto, + SubmitTransactionDto, +} from '../../../contract-interact/dto/multi-sig.dto'; +import { MultiSigWalletDto } from './multi-sig.dto'; +@ApiTags('multi-sig') +@Controller('multi-sig') +export class MultiSigInteractController { + constructor(private readonly multiSigWalletService: MultiSigWalletService) {} + + @Post('deploy') + async deploy(@Body() dto: MultiSigWalletDto) { + return this.multiSigWalletService.deploy(dto); + } + @Get('owners/:address') + async getOwners(@Param('address') address: string) { + return this.multiSigWalletService.getOwners(address); + } + + @ApiOkResponse() + @Post('submit-transaction') + async submitTransaction(@Body() dto: SubmitTransactionDto) { + return this.multiSigWalletService.submitTransaction(dto); + } + + @ApiOkResponse() + @Post('confirm-transaction') + async confirmTransaction(@Body() dto: ConfirmTransactionDto) { + return this.multiSigWalletService.confirmTransaction(dto); + } + + @ApiOkResponse() + @Post('execute-transaction') + async executeTransaction(@Body() dto: ExecuteTransactionDto) { + return this.multiSigWalletService.executeTransaction(dto); + } + + @ApiOkResponse() + @Post('revoke-confirmation') + async revokeConfirmation(@Body() dto: RevokeConfirmationDto) { + return this.multiSigWalletService.revokeConfirmation(dto); + } + + @Get('transaction-count/:contractAddress') + async getTransactionCount(@Param('contractAddress') contractAddress: string) { + return this.multiSigWalletService.getTransactionCount(contractAddress); + } + + @Get('transaction') + async getTransaction(@Body() dto: GetTransactionDto) { + return this.multiSigWalletService.getTransaction(dto); + } + + @Post('deposit') + async deposit(@Body() dto: DepositMultiSigDto) { + return this.multiSigWalletService.deposit(dto); + } +} diff --git a/chain-api/src/hardhat/modules/dto/multi-sig.dto.ts b/chain-api/src/hardhat/modules/multi-sig/multi-sig.dto.ts similarity index 100% rename from chain-api/src/hardhat/modules/dto/multi-sig.dto.ts rename to chain-api/src/hardhat/modules/multi-sig/multi-sig.dto.ts diff --git a/chain-api/src/hardhat/modules/multi-sig/multi-sig.module.ts b/chain-api/src/hardhat/modules/multi-sig/multi-sig.module.ts index 0b197fd..c2d621d 100644 --- a/chain-api/src/hardhat/modules/multi-sig/multi-sig.module.ts +++ b/chain-api/src/hardhat/modules/multi-sig/multi-sig.module.ts @@ -5,10 +5,11 @@ import { ProviderModule } from 'src/provider/provider.module'; import { BaseContractService } from '../base-contract.service'; import { ProviderService } from 'src/provider/provider.service'; import { MultiSigWalletService } from './multi-sig.service'; +import { MultiSigInteractController } from './multi-sig-interact.controller'; @Module({ imports: [ProviderModule], - controllers: [], + controllers: [MultiSigInteractController], providers: [MultiSigWalletService], exports: [MultiSigWalletService], }) diff --git a/chain-api/src/hardhat/modules/multi-sig/multi-sig.service.ts b/chain-api/src/hardhat/modules/multi-sig/multi-sig.service.ts index b3e7a2e..02bcfe3 100644 --- a/chain-api/src/hardhat/modules/multi-sig/multi-sig.service.ts +++ b/chain-api/src/hardhat/modules/multi-sig/multi-sig.service.ts @@ -1,11 +1,23 @@ -import { MultiSigWallet } from '../../typechain-types/contracts/MultiSigWallet'; -import { Injectable } from '@nestjs/common'; -import { ethers } from 'ethers'; +import { TransactionReceipt, ethers } from 'ethers'; import { ConfigService } from '@nestjs/config'; import * as hre from 'hardhat'; import { BaseContractService } from '../base-contract.service'; -import { MultiSigWalletDto } from '../dto/multi-sig.dto'; -import { SubmitTransactionDto } from 'src/contract-interact/dto/multi-sig.dto'; +import { MultiSigWalletDto } from './multi-sig.dto'; +import { + ConfirmTransactionDto, + DepositMultiSigDto, + ExecuteTransactionDto, + GetTransactionDto, + RevokeConfirmationDto, + SubmitTransactionDto, +} from 'src/contract-interact/dto/multi-sig.dto'; +import { + ConfirmTransactionLogs, + DepositLogs, + ExecuteTransactionLogs, + SubmitTransactionLogs, +} from 'src/hardhat/modules/dto/ethers.dto'; +import { parseLogs } from 'src/contract-interact/ethers.helpers'; export class MultiSigWalletService extends BaseContractService { async deploy(dto: MultiSigWalletDto) { @@ -21,13 +33,8 @@ export class MultiSigWalletService extends BaseContractService { dto.confirmations, ); await myContract.waitForDeployment(); - - console.log( - '🚀 ~ HardhatService ~ deploySalaryContract ~ myContract:', - myContract, - ); const address = myContract.getAddress(); - console.log('🚀 ~ SalariesService ~ deploy ~ address:', address); + return address; } async getOwners(address: string) { @@ -46,23 +53,119 @@ export class MultiSigWalletService extends BaseContractService { async submitTransaction(dto: SubmitTransactionDto) { const { destination, value, data, contractAddress } = dto; const { abi } = await hre.artifacts.readArtifact('MultiSigWallet'); - const multiSigContract = new ethers.Contract(contractAddress, abi); - const signer = await this.providerService.getSigner(); const contract = new ethers.Contract(contractAddress, abi, signer); - console.log( - '🚀 ~ MultiSigWalletService ~ submitTransaction ~ contract:', - contract.interface, - ); - const tx = await contract.submitTransaction( - destination, - value, - new TextEncoder().encode(data), - ); - console.log('🚀 ~ MultiSigWalletService ~ submitTransaction ~ tx:', tx); + const tx = await contract.submitTransaction(destination, value, data); + const txResponse: TransactionReceipt = await tx.wait(); + + const eventParse = parseLogs(txResponse, contract); + + return { + txHash: txResponse.hash, + sender: eventParse.args[0].toString(), + txIndex: eventParse.args[1].toString(), + to: eventParse.args[2].toString(), + value: eventParse.args[3].toString(), + data: eventParse.args[4].toString(), + }; + } + + async confirmTransaction(dto: ConfirmTransactionDto) { + const { contractAddress, index } = dto; + const { abi } = await hre.artifacts.readArtifact('MultiSigWallet'); + const signer = await this.providerService.getSigner(); + + const contract = new ethers.Contract(contractAddress, abi, signer); + + const tx = await contract.confirmTransaction(index); + + const txResponse: TransactionReceipt = await tx.wait(); + + const eventParse = parseLogs(txResponse, contract); + + return { + txHash: txResponse.hash, + sender: eventParse.args[0].toString(), + txIndex: eventParse.args[1].toString(), + }; + } + + async executeTransaction(dto: ExecuteTransactionDto) { + const { index, contractAddress } = dto; + const { abi } = await hre.artifacts.readArtifact('MultiSigWallet'); + const signer = await this.providerService.getSigner(); + + const contract = new ethers.Contract(contractAddress, abi, signer); + + const tx = await contract.executeTransaction(index); + + const txResponse: TransactionReceipt = await tx.wait(); + const eventParse = parseLogs(txResponse, contract); + return { + txHash: txResponse.hash, + sender: eventParse.args[0].toString(), + txIndex: eventParse.args[1].toString(), + }; + } + + async revokeConfirmation(dto: RevokeConfirmationDto) { + const { index, contractAddress } = dto; + const { abi } = await hre.artifacts.readArtifact('MultiSigWallet'); + const signer = await this.providerService.getSigner(); + + const contract = new ethers.Contract(contractAddress, abi, signer); + + const tx = await contract.revokeConfirmation(index); return tx; } + + async getTransactionCount(contractAddress: string) { + const { abi } = await hre.artifacts.readArtifact('MultiSigWallet'); + const signer = await this.providerService.getSigner(); + + const contract = new ethers.Contract(contractAddress, abi, signer); + + const txCount = await contract.getTransactionCount(); + + return txCount; + } + + async getTransaction(dto: GetTransactionDto) { + const { index, contractAddress } = dto; + const { abi } = await hre.artifacts.readArtifact('MultiSigWallet'); + const signer = await this.providerService.getSigner(); + + const contract = new ethers.Contract(contractAddress, abi, signer); + + const tx = await contract.getTransaction(index); + + return tx; + } + + async deposit(dto: DepositMultiSigDto) { + const { contractAddress, value } = dto; + const signer = await this.providerService.getSigner(); + + const { abi } = await hre.artifacts.readArtifact('MultiSigWallet'); + const contract = new ethers.Contract(contractAddress, abi, signer); + + const tx = await signer.sendTransaction({ + to: contractAddress, + value: BigInt(value), + }); + + const txResponse: TransactionReceipt = await tx.wait(); + + const eventParse = parseLogs(txResponse, contract); + + return { + txHash: txResponse.hash, + sender: eventParse.args[0].toString(), + value: eventParse.args[1].toString(), + contractBalance: eventParse.args[2].toString(), + }; + } } diff --git a/chain-api/src/hardhat/modules/salaries/salaries-interact.controller.ts b/chain-api/src/hardhat/modules/salaries/salaries-interact.controller.ts new file mode 100644 index 0000000..2c89238 --- /dev/null +++ b/chain-api/src/hardhat/modules/salaries/salaries-interact.controller.ts @@ -0,0 +1,33 @@ +import { Body, Controller, Get, Param, Post } from '@nestjs/common'; +import { SalariesService } from './salaries.service'; +import { + GetEmployeeSalariesDto, + SalariesDeployDto, + SetSalaryDto, +} from './salaries.dto'; +import { ApiTags } from '@nestjs/swagger'; +@ApiTags('salaries') +@Controller('salaries') +export class SalariesController { + constructor(private readonly salariesService: SalariesService) {} + + @Post('deploy') + async deploy(@Body() dto: SalariesDeployDto) { + return this.salariesService.deploy(dto); + } + + @Get('usdt-price/:contractAddress') + async getUsdtPrice(@Param('contractAddress') contractAddress: string) { + return this.salariesService.getLatestUSDTPrice(contractAddress); + } + + @Post('set-salary') + async setSalary(@Body() dto: SetSalaryDto) { + return this.salariesService.setSalary(dto); + } + + @Get('salary') + async getSalary(@Body() dto: GetEmployeeSalariesDto) { + return this.salariesService.getSalary(dto); + } +} diff --git a/chain-api/src/hardhat/modules/salaries/salaries.dto.ts b/chain-api/src/hardhat/modules/salaries/salaries.dto.ts new file mode 100644 index 0000000..4875918 --- /dev/null +++ b/chain-api/src/hardhat/modules/salaries/salaries.dto.ts @@ -0,0 +1,32 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsNumber, IsString } from 'class-validator'; + +export class SalariesDeployDto { + @ApiProperty() + @IsString() + multiSigWallet: string; +} + +export class SetSalaryDto { + @ApiProperty() + @IsString() + multiSigWallet: string; + @ApiProperty() + @IsString() + contractAddress: string; + @ApiProperty() + @IsString() + employeeAddress: string; + @ApiProperty() + @IsNumber() + salary: number; +} + +export class GetEmployeeSalariesDto { + @ApiProperty() + @IsString() + contractAddress: string; + @ApiProperty() + @IsString() + employeeAddress: string; +} diff --git a/chain-api/src/hardhat/modules/salaries/salaries.module.ts b/chain-api/src/hardhat/modules/salaries/salaries.module.ts new file mode 100644 index 0000000..bb8d5fc --- /dev/null +++ b/chain-api/src/hardhat/modules/salaries/salaries.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { SalariesService } from './salaries.service'; +import { ProviderModule } from 'src/provider/provider.module'; +import { SalariesController } from './salaries-interact.controller'; +import { MultiSigModule } from '../multi-sig/multi-sig.module'; + +@Module({ + imports: [ProviderModule, MultiSigModule], + controllers: [SalariesController], + providers: [SalariesService], + exports: [SalariesService], +}) +export class SalariesModule {} diff --git a/chain-api/src/hardhat/modules/salaries/salaries.service.ts b/chain-api/src/hardhat/modules/salaries/salaries.service.ts new file mode 100644 index 0000000..43af1b7 --- /dev/null +++ b/chain-api/src/hardhat/modules/salaries/salaries.service.ts @@ -0,0 +1,75 @@ +import { Injectable } from '@nestjs/common'; +import { BaseContractService } from '../base-contract.service'; +import { ethers } from 'ethers'; +import { + GetEmployeeSalariesDto, + SalariesDeployDto, + SetSalaryDto, +} from './salaries.dto'; +import * as hre from 'hardhat'; +import { MultiSigWalletService } from '../multi-sig/multi-sig.service'; +import { ProviderService } from '../../../provider/provider.service'; + +@Injectable() +export class SalariesService extends BaseContractService { + constructor( + private readonly multiSigWalletService: MultiSigWalletService, + public readonly providerService: ProviderService, + ) { + super(providerService); + } + async deploy(dto: SalariesDeployDto): Promise { + const { abi, bytecode } = await hre.artifacts.readArtifact('Salaries'); + + const signer = await this.providerService.getSigner(); + + const salaryContract = new ethers.ContractFactory(abi, bytecode, signer); + + const myContract = await salaryContract.deploy( + dto.multiSigWallet, + '0xF0d50568e3A7e8259E16663972b11910F89BD8e7', + ); + await myContract.waitForDeployment(); + return await myContract.getAddress(); + } + + async getLatestUSDTPrice(contractAddress: string) { + const { abi } = await hre.artifacts.readArtifact('Salaries'); + const signer = await this.providerService.getSigner(); + + const contract = new ethers.Contract(contractAddress, abi, signer); + + const answer: string = await contract.getLatestUSDTPriceInETH(); + return parseInt(answer) / 1e8; + } + + async setSalary(dto: SetSalaryDto) { + const { employeeAddress, salary, contractAddress, multiSigWallet } = dto; + const ISubmitMultiSig = new ethers.Interface([ + 'function setSalary(address employee, uint salaryInUSDT)', + ]); + + const data = ISubmitMultiSig.encodeFunctionData('setSalary', [ + employeeAddress, + salary, + ]); + + return await this.multiSigWalletService.submitTransaction({ + contractAddress: multiSigWallet, + destination: contractAddress, + value: '0', + data, + }); + } + + async getSalary(dto: GetEmployeeSalariesDto) { + const { employeeAddress, contractAddress } = dto; + const { abi } = await hre.artifacts.readArtifact('Salaries'); + const signer = await this.providerService.getSigner(); + + const contract = new ethers.Contract(contractAddress, abi, signer); + + const answer: string = await contract.getSalary(employeeAddress); + return answer; + } +} diff --git a/chain-api/src/hardhat/modules/salary.service.ts b/chain-api/src/hardhat/modules/salary.service.ts deleted file mode 100644 index ebded0c..0000000 --- a/chain-api/src/hardhat/modules/salary.service.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { ethers } from 'ethers'; -import { ConfigService } from '@nestjs/config'; -import * as hre from 'hardhat'; -import { BaseContractService } from './base-contract.service'; - -@Injectable() -export class SalariesService extends BaseContractService { - getSalaries() {} - - async deploy() { - const provider = await this.providerService.getProvider(); - - const salary = await hre.artifacts.readArtifact('Salaries'); - const abi = salary.abi; - const bytecode = salary.deployedBytecode; - const signer = new ethers.Wallet( - this.configService.getOrThrow('POLYGON_PK'), - provider, - ); - - const salaryContract = new ethers.ContractFactory( - abi, - salary.bytecode, - signer, - ); - - const myContract = await salaryContract.deploy( - 'multisig address', - this.configService.getOrThrow('CHAINLINK_AGGREGATOR_V3'), - ); - await myContract.waitForDeployment(); - - console.log( - '🚀 ~ HardhatService ~ deploySalaryContract ~ myContract:', - myContract, - ); - const address = myContract.getAddress(); - console.log('🚀 ~ SalariesService ~ deploy ~ address:', address); - } -} diff --git a/chain-api/src/main.ts b/chain-api/src/main.ts index 9ccc209..4c6012f 100644 --- a/chain-api/src/main.ts +++ b/chain-api/src/main.ts @@ -1,7 +1,8 @@ -import { NestFactory } from '@nestjs/core'; +import { HttpAdapterHost, NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { ValidationPipe } from '@nestjs/common'; +import { AllExceptionsFilter } from './filters/http.filter'; async function bootstrap() { const app = await NestFactory.create(AppModule); @@ -13,6 +14,7 @@ async function bootstrap() { const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api', app, document); app.useGlobalPipes(new ValidationPipe()); + app.useGlobalFilters(new AllExceptionsFilter()); await app.listen(3000); console.log('Swagger avaliable at http://localhost:3000/api');