mirror of
https://github.com/emo2007/block-accounting.git
synced 2025-01-18 15:36:27 +00:00
multisig ready, deploy and interact controller
This commit is contained in:
parent
01371286d0
commit
ed2f6b9eca
43
chain-api/package-lock.json
generated
43
chain-api/package-lock.json
generated
@ -17,6 +17,8 @@
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@nestjs/swagger": "^7.3.1",
|
||||
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
"dotenv": "^16.4.5",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.1"
|
||||
@ -28,7 +30,7 @@
|
||||
"@nomicfoundation/hardhat-ethers": "^3.0.5",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/node": "^20.12.11",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
@ -5138,9 +5140,9 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.12.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.10.tgz",
|
||||
"integrity": "sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==",
|
||||
"version": "20.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz",
|
||||
"integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==",
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
@ -5235,6 +5237,11 @@
|
||||
"@types/superagent": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/validator": {
|
||||
"version": "13.11.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.9.tgz",
|
||||
"integrity": "sha512-FCTsikRozryfayPuiI46QzH3fnrOoctTjvOYZkho9BTFLCOZ2rgZJHMOVgCOfttjPJcgOx52EpkY0CMfy87MIw=="
|
||||
},
|
||||
"node_modules/@types/yargs": {
|
||||
"version": "17.0.32",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz",
|
||||
@ -6714,6 +6721,21 @@
|
||||
"integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/class-transformer": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
|
||||
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw=="
|
||||
},
|
||||
"node_modules/class-validator": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.1.tgz",
|
||||
"integrity": "sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==",
|
||||
"dependencies": {
|
||||
"@types/validator": "^13.11.8",
|
||||
"libphonenumber-js": "^1.10.53",
|
||||
"validator": "^13.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/clean-stack": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
||||
@ -11544,6 +11566,11 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/libphonenumber-js": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.1.tgz",
|
||||
"integrity": "sha512-Wze1LPwcnzvcKGcRHFGFECTaLzxOtujwpf924difr5zniyYv1C2PiW0419qDR7m8lKDxsImu5mwxFuXhXpjmvw=="
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
@ -16173,6 +16200,14 @@
|
||||
"spdx-expression-parse": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/validator": {
|
||||
"version": "13.12.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz",
|
||||
"integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
|
@ -28,6 +28,8 @@
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@nestjs/swagger": "^7.3.1",
|
||||
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
"dotenv": "^16.4.5",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.1"
|
||||
@ -39,7 +41,7 @@
|
||||
"@nomicfoundation/hardhat-ethers": "^3.0.5",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/node": "^20.12.11",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
|
@ -11,6 +11,7 @@ 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 {
|
||||
@ -18,8 +19,8 @@ export class ContractFactoryController {
|
||||
private readonly contractFactoryService: ContractFactoryService,
|
||||
) {}
|
||||
|
||||
@Post('')
|
||||
create(@Body() createContractFactoryDto: CreateContractFactoryDto) {
|
||||
return this.contractFactoryService.create(createContractFactoryDto);
|
||||
@Post('multi-sig')
|
||||
create(@Body() createContractFactoryDto: MultiSigWalletDto) {
|
||||
return this.contractFactoryService.createMultiSig(createContractFactoryDto);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { HardhatModule } from '../hardhat/module/hardhat.module';
|
||||
import { HardhatModule } from '../hardhat/modules/hardhat.module';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ContractFactoryService } from './contract-factory.service';
|
||||
import { ContractFactoryController } from './contract-factory.controller';
|
||||
|
@ -1,11 +1,21 @@
|
||||
import { HardhatService } from '../hardhat/module/hardhat.service';
|
||||
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 hhService: HardhatService) {}
|
||||
async create(createContractFactoryDto: CreateContractFactoryDto) {
|
||||
return await this.hhService.deploySalaryContract();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1,49 +0,0 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
} from '@nestjs/common';
|
||||
import { ContractInteractService } from './contract-interact.service';
|
||||
import { CreateContractInteractDto } from './dto/create-contract-interact.dto';
|
||||
import { UpdateContractInteractDto } from './dto/update-contract-interact.dto';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
|
||||
@ApiTags('contract-interact')
|
||||
@Controller('contract-interact')
|
||||
export class ContractInteractController {
|
||||
constructor(
|
||||
private readonly contractInteractService: ContractInteractService,
|
||||
) {}
|
||||
|
||||
@Post()
|
||||
create(@Body() createContractInteractDto: CreateContractInteractDto) {
|
||||
return this.contractInteractService.create(createContractInteractDto);
|
||||
}
|
||||
|
||||
@Get()
|
||||
findAll() {
|
||||
return this.contractInteractService.findAll();
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.contractInteractService.findOne(+id);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
update(
|
||||
@Param('id') id: string,
|
||||
@Body() updateContractInteractDto: UpdateContractInteractDto,
|
||||
) {
|
||||
return this.contractInteractService.update(+id, updateContractInteractDto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
remove(@Param('id') id: string) {
|
||||
return this.contractInteractService.remove(+id);
|
||||
}
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ContractInteractService } from './contract-interact.service';
|
||||
import { ContractInteractController } from './contract-interact.controller';
|
||||
|
||||
import { HardhatModule } from 'src/hardhat/modules/hardhat.module';
|
||||
import { MultiSigInteractController } from './multi-sig-interact.controller';
|
||||
|
||||
@Module({
|
||||
controllers: [ContractInteractController],
|
||||
imports: [HardhatModule],
|
||||
controllers: [MultiSigInteractController],
|
||||
providers: [ContractInteractService],
|
||||
})
|
||||
export class ContractInteractModule {}
|
||||
|
18
chain-api/src/contract-interact/dto/multi-sig.dto.ts
Normal file
18
chain-api/src/contract-interact/dto/multi-sig.dto.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export class SubmitTransactionDto {
|
||||
@IsString()
|
||||
@ApiProperty()
|
||||
contractAddress: string;
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
destination: string;
|
||||
@IsString()
|
||||
@ApiProperty()
|
||||
value: string;
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
// @ApiProperty()
|
||||
data: string;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
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);
|
||||
}
|
||||
}
|
0
chain-api/src/hardhat/contracts/Agreement.sol
Normal file
0
chain-api/src/hardhat/contracts/Agreement.sol
Normal file
@ -8,7 +8,7 @@ pragma solidity ^0.8.19;
|
||||
contract MultiSigWallet {
|
||||
event Deposit(address indexed sender, uint amount, uint balance);
|
||||
event SubmitTransaction(
|
||||
address indexed owener,
|
||||
address indexed owner,
|
||||
uint indexed txIndex,
|
||||
address indexed to,
|
||||
uint value,
|
||||
@ -38,36 +38,36 @@ contract MultiSigWallet {
|
||||
Transaction[] public transactions;
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(isOwner[msg.sender], "not owner");
|
||||
require(isOwner[msg.sender], 'not owner');
|
||||
_;
|
||||
}
|
||||
|
||||
modifier txExists(uint _txIndex) {
|
||||
require(_txIndex < transactions.length, "tx does not exist");
|
||||
require(_txIndex < transactions.length, 'tx does not exist');
|
||||
_;
|
||||
}
|
||||
|
||||
modifier notConfirmed(uint _txIndex) {
|
||||
require(!isConfirmed[_txIndex][msg.sender], "tx already confirmed");
|
||||
require(!isConfirmed[_txIndex][msg.sender], 'tx already confirmed');
|
||||
_;
|
||||
}
|
||||
|
||||
modifier notExecuted(uint _txIndex) {
|
||||
require(!transactions[_txIndex].executed, "tx already confirmed");
|
||||
require(!transactions[_txIndex].executed, 'tx already confirmed');
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(address[] memory _owners, uint _numConfirmationsRequired) {
|
||||
require(_owners.length > 0, "owners required");
|
||||
require(_owners.length > 0, 'owners required');
|
||||
require(
|
||||
_numConfirmationsRequired > 0 &&
|
||||
_numConfirmationsRequired <= _owners.length,
|
||||
"invalid number of required confirmations"
|
||||
'invalid number of required confirmations'
|
||||
);
|
||||
for (uint i = 0; i < _owners.length; i++) {
|
||||
address owner = _owners[i];
|
||||
require(owner != address(0), "invalid owner");
|
||||
require(!isOwner[owner], "owner not unique");
|
||||
require(owner != address(0), 'invalid owner');
|
||||
require(!isOwner[owner], 'owner not unique');
|
||||
isOwner[owner] = true;
|
||||
owners.push(owner);
|
||||
}
|
||||
@ -117,13 +117,13 @@ contract MultiSigWallet {
|
||||
Transaction storage transaction = transactions[_txIndex];
|
||||
require(
|
||||
transaction.numConfirmations >= numConfirmationsRequired,
|
||||
"cannot execute tx"
|
||||
'cannot execute tx'
|
||||
);
|
||||
transaction.executed = true;
|
||||
(bool success, ) = transaction.to.call{value: transaction.value}(
|
||||
transaction.data
|
||||
);
|
||||
require(success, "tx failed");
|
||||
require(success, 'tx failed');
|
||||
emit ExecuteTransaction(msg.sender, _txIndex);
|
||||
}
|
||||
|
||||
@ -131,7 +131,7 @@ contract MultiSigWallet {
|
||||
uint _txIndex
|
||||
) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) {
|
||||
Transaction storage transaction = transactions[_txIndex];
|
||||
require(isConfirmed[_txIndex][msg.sender], "tx not confirmed");
|
||||
require(isConfirmed[_txIndex][msg.sender], 'tx not confirmed');
|
||||
transaction.numConfirmations -= 1;
|
||||
isConfirmed[_txIndex][msg.sender] = false;
|
||||
|
||||
|
@ -1,26 +1,62 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.7;
|
||||
|
||||
import {AggregatorV3Interface} from '@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol';
|
||||
|
||||
contract Salaries {
|
||||
AggregatorV3Interface internal dataFeed;
|
||||
address public multisigWallet;
|
||||
mapping(address => uint) public salaries;
|
||||
|
||||
constructor() {
|
||||
dataFeed = AggregatorV3Interface(
|
||||
0xF0d50568e3A7e8259E16663972b11910F89BD8e7
|
||||
);
|
||||
constructor(address _multisigWallet, address _priceFeedAddress) {
|
||||
multisigWallet = _multisigWallet;
|
||||
dataFeed = AggregatorV3Interface(_priceFeedAddress);
|
||||
}
|
||||
|
||||
function getChainlinkDataFeedLatestAnswer() public view returns (int) {
|
||||
// prettier-ignore
|
||||
modifier onlyMultisig() {
|
||||
require(msg.sender == multisigWallet, 'Unauthorized');
|
||||
_;
|
||||
}
|
||||
|
||||
function getLatestUSDTPriceInETH() public view returns (int) {
|
||||
(
|
||||
/* uint80 roundID */,
|
||||
int answer,
|
||||
/*uint startedAt*/,
|
||||
/*uint timeStamp*/,
|
||||
/*uint80 answeredInRound*/
|
||||
,
|
||||
/* uint80 roundID */ int answer /* uint startedAt */ /* uint timeStamp */ /* uint80 answeredInRound */,
|
||||
,
|
||||
,
|
||||
|
||||
) = dataFeed.latestRoundData();
|
||||
return answer;
|
||||
}
|
||||
|
||||
function setSalary(
|
||||
address employee,
|
||||
uint salaryInUSDT
|
||||
) external onlyMultisig {
|
||||
salaries[employee] = salaryInUSDT;
|
||||
}
|
||||
|
||||
function payoutInETH(address employee) external onlyMultisig {
|
||||
uint salaryInUSDT = salaries[employee];
|
||||
require(salaryInUSDT > 0, 'No salary set');
|
||||
|
||||
int ethToUSDT = getLatestUSDTPriceInETH();
|
||||
require(ethToUSDT > 0, 'Invalid price data');
|
||||
|
||||
// Convert salary from USDT to ETH based on the latest price
|
||||
uint salaryInETH = uint(salaryInUSDT * 1e18) / uint(ethToUSDT);
|
||||
|
||||
// Check sufficient balance
|
||||
require(
|
||||
address(this).balance >= salaryInETH,
|
||||
'Insufficient contract balance'
|
||||
);
|
||||
|
||||
salaries[employee] = 0; // Reset salary after payment
|
||||
payable(employee).transfer(salaryInETH);
|
||||
}
|
||||
|
||||
// Fallback to receive ETH
|
||||
receive() external payable {}
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { HardhatService } from './hardhat.service';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [],
|
||||
providers: [HardhatService],
|
||||
exports: [HardhatService],
|
||||
})
|
||||
export class HardhatModule {}
|
12
chain-api/src/hardhat/modules/base-contract.service.ts
Normal file
12
chain-api/src/hardhat/modules/base-contract.service.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { ProviderService } from 'src/provider/provider.service';
|
||||
|
||||
@Injectable()
|
||||
export abstract class BaseContractService {
|
||||
constructor(
|
||||
public readonly configService: ConfigService,
|
||||
public readonly providerService: ProviderService,
|
||||
) {}
|
||||
abstract deploy(dto: object): Promise<any>;
|
||||
}
|
11
chain-api/src/hardhat/modules/dto/multi-sig.dto.ts
Normal file
11
chain-api/src/hardhat/modules/dto/multi-sig.dto.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsArray, IsNumber } from 'class-validator';
|
||||
|
||||
export class MultiSigWalletDto {
|
||||
@IsArray()
|
||||
@ApiProperty()
|
||||
owners: string[];
|
||||
@IsNumber()
|
||||
@ApiProperty()
|
||||
confirmations: number;
|
||||
}
|
15
chain-api/src/hardhat/modules/hardhat.module.ts
Normal file
15
chain-api/src/hardhat/modules/hardhat.module.ts
Normal file
@ -0,0 +1,15 @@
|
||||
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';
|
||||
|
||||
@Module({
|
||||
imports: [ProviderModule, MultiSigModule],
|
||||
controllers: [],
|
||||
providers: [HardhatService, SalariesService],
|
||||
exports: [HardhatService, SalariesService, MultiSigModule],
|
||||
})
|
||||
export class HardhatModule {}
|
4
chain-api/src/hardhat/modules/hardhat.service.ts
Normal file
4
chain-api/src/hardhat/modules/hardhat.service.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class HardhatService {}
|
15
chain-api/src/hardhat/modules/multi-sig/multi-sig.module.ts
Normal file
15
chain-api/src/hardhat/modules/multi-sig/multi-sig.module.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
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';
|
||||
|
||||
@Module({
|
||||
imports: [ProviderModule],
|
||||
controllers: [],
|
||||
providers: [MultiSigWalletService],
|
||||
exports: [MultiSigWalletService],
|
||||
})
|
||||
export class MultiSigModule {}
|
68
chain-api/src/hardhat/modules/multi-sig/multi-sig.service.ts
Normal file
68
chain-api/src/hardhat/modules/multi-sig/multi-sig.service.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import { MultiSigWallet } from '../../typechain-types/contracts/MultiSigWallet';
|
||||
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';
|
||||
import { MultiSigWalletDto } from '../dto/multi-sig.dto';
|
||||
import { SubmitTransactionDto } from 'src/contract-interact/dto/multi-sig.dto';
|
||||
|
||||
export class MultiSigWalletService extends BaseContractService {
|
||||
async deploy(dto: MultiSigWalletDto) {
|
||||
const { abi, bytecode } =
|
||||
await hre.artifacts.readArtifact('MultiSigWallet');
|
||||
|
||||
const signer = await this.providerService.getSigner();
|
||||
|
||||
const salaryContract = new ethers.ContractFactory(abi, bytecode, signer);
|
||||
|
||||
const myContract = await salaryContract.deploy(
|
||||
dto.owners,
|
||||
dto.confirmations,
|
||||
);
|
||||
await myContract.waitForDeployment();
|
||||
|
||||
console.log(
|
||||
'🚀 ~ HardhatService ~ deploySalaryContract ~ myContract:',
|
||||
myContract,
|
||||
);
|
||||
const address = myContract.getAddress();
|
||||
console.log('🚀 ~ SalariesService ~ deploy ~ address:', address);
|
||||
}
|
||||
|
||||
async getOwners(address: string) {
|
||||
const { abi } = await hre.artifacts.readArtifact('MultiSigWallet');
|
||||
const multiSigContract = new ethers.Contract(address, abi);
|
||||
|
||||
const signer = await this.providerService.getSigner();
|
||||
|
||||
const contract = new ethers.Contract(address, abi, signer);
|
||||
|
||||
const owners = await contract.getOwners();
|
||||
|
||||
return owners;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return tx;
|
||||
}
|
||||
}
|
@ -1,25 +1,19 @@
|
||||
// const hre = require('hardhat');
|
||||
import * as hre from 'hardhat';
|
||||
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 HardhatService {
|
||||
constructor(private readonly configService: ConfigService) {}
|
||||
async deploySalaryContract() {
|
||||
const provider = new ethers.JsonRpcProvider(
|
||||
'https://polygon-amoy.g.alchemy.com/v2/pEtFFy_Qr_NrM1vMnlzSXmYXkozVNzLy',
|
||||
80002,
|
||||
);
|
||||
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;
|
||||
console.log('🚀 ~ HardhatService ~ deploySalaryContract ~ abi:', abi);
|
||||
const bytecode = salary.deployedBytecode;
|
||||
console.log(
|
||||
'🚀 ~ HardhatService ~ deploySalaryContract ~ bytecode:',
|
||||
bytecode,
|
||||
);
|
||||
const signer = new ethers.Wallet(
|
||||
this.configService.getOrThrow('POLYGON_PK'),
|
||||
provider,
|
||||
@ -31,12 +25,17 @@ export class HardhatService {
|
||||
signer,
|
||||
);
|
||||
|
||||
const myContract = await salaryContract.deploy();
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
@ -11,7 +12,9 @@ async function bootstrap() {
|
||||
.build();
|
||||
const document = SwaggerModule.createDocument(app, config);
|
||||
SwaggerModule.setup('api', app, document);
|
||||
app.useGlobalPipes(new ValidationPipe());
|
||||
await app.listen(3000);
|
||||
|
||||
console.log('Swagger avaliable at http://localhost:3000/api');
|
||||
}
|
||||
bootstrap();
|
||||
|
10
chain-api/src/provider/provider.module.ts
Normal file
10
chain-api/src/provider/provider.module.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ProviderService } from './provider.service';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [],
|
||||
providers: [ProviderService],
|
||||
exports: [ProviderService],
|
||||
})
|
||||
export class ProviderModule {}
|
38
chain-api/src/provider/provider.service.ts
Normal file
38
chain-api/src/provider/provider.service.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ethers } from 'ethers';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
@Injectable()
|
||||
export class ProviderService {
|
||||
public provider: ethers.JsonRpcProvider;
|
||||
public networkId: number;
|
||||
private nodeUrl: string;
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
this.networkId = parseInt(
|
||||
this.configService.getOrThrow('POLYGON_NETWORK_ID'),
|
||||
);
|
||||
this.nodeUrl = this.configService.getOrThrow('POLYGON_NODE');
|
||||
}
|
||||
|
||||
async getProvider() {
|
||||
if (this.provider) {
|
||||
return this.provider;
|
||||
}
|
||||
const polygonProvider = new ethers.JsonRpcProvider(
|
||||
this.nodeUrl,
|
||||
this.networkId,
|
||||
);
|
||||
this.provider = polygonProvider;
|
||||
return this.provider;
|
||||
}
|
||||
|
||||
async getSigner() {
|
||||
if (!this.provider) {
|
||||
await this.getProvider();
|
||||
}
|
||||
const signer = new ethers.Wallet(
|
||||
this.configService.getOrThrow('POLYGON_PK'),
|
||||
this.provider,
|
||||
);
|
||||
return signer;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user