payout ready, but needs fixes

This commit is contained in:
emochka2007 2024-05-16 01:34:49 +03:00
parent 0a74e430b8
commit 958bf670ae
8 changed files with 140 additions and 33 deletions

View File

@ -34,7 +34,7 @@ export class GetTransactionCount {}
export class GetTransactionDto extends ConfirmTransactionDto {}
export class DepositMultiSigDto {
export class DepositContractDto {
@IsString()
@ApiProperty()
contractAddress: string;

View File

@ -1,4 +1,5 @@
// SPDX-License-Identifier: MIT
// 0x74f11486DB0FCAA2dCDE0aEB477e1F37fCAa510A
pragma solidity ^0.8.19;
// The wallet owners can
@ -18,6 +19,9 @@ contract MultiSigWallet {
event ConfirmTransaction(address indexed owner, uint indexed txIndex);
event RevokeConfirmation(address indexed owner, uint indexed txIndex);
event ExecuteTransaction(address indexed owner, uint indexed txIndex);
event ExecuteTransactionFailed(address indexed owner, uint indexed txIndex, string reason);
event Payout(address indexed employee, uint salaryInETH);
event PayoutFailed(address indexed employee, uint salaryInETH, string reason);
address[] public owners;
@ -111,20 +115,63 @@ contract MultiSigWallet {
emit ConfirmTransaction(msg.sender, _txIndex);
}
function executeTransaction(
uint _txIndex
) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) {
function executeTransaction(uint _txIndex)
public
onlyOwner
txExists(_txIndex)
notExecuted(_txIndex)
{
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');
emit ExecuteTransaction(msg.sender, _txIndex);
(bool success, bytes memory returnData) = transaction.to.call{value: transaction.value}(transaction.data);
if (success) {
transaction.executed = true;
emit ExecuteTransaction(msg.sender, _txIndex);
if (returnData.length > 0) {
emitEventFromReturnData(returnData);
}
} else {
// Get the revert reason and emit it
if (returnData.length > 0) {
// The call reverted with a message
assembly {
let returndata_size := mload(returnData)
revert(add(32, returnData), returndata_size)
}
} else {
// The call reverted without a message
emit ExecuteTransactionFailed(msg.sender, _txIndex, "Transaction failed without a reason");
}
}
}
function emitEventFromReturnData(bytes memory returnData) internal {
// Decode the selector from returnData
bytes4 selector;
assembly {
selector := mload(add(returnData, 32))
}
// Match the selector to the known events
if (selector == Payout.selector) {
(address employee, uint salaryInETH) = abi.decode(slice(returnData, 4, returnData.length), (address, uint));
emit Payout(employee, salaryInETH);
} else if (selector == PayoutFailed.selector) {
(address employee, uint salaryInETH, string memory reason) = abi.decode(slice(returnData, 4, returnData.length), (address, uint, string));
emit PayoutFailed(employee, salaryInETH, reason);
}
}
function slice(bytes memory data, uint start, uint length) internal pure returns (bytes memory) {
bytes memory result = new bytes(length);
for (uint i = 0; i < length; i++) {
result[i] = data[start + i];
}
return result;
}
function revokeConfirmation(

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// 0x2F9442900d067a3D37A1C2aE99462E055e32c741
pragma solidity ^0.8.7;
import {AggregatorV3Interface} from '@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol';
@ -8,7 +8,8 @@ contract Salaries {
AggregatorV3Interface internal dataFeed;
address public multisigWallet;
mapping(address => uint) public salaries;
event Payout(address indexed employee, uint salaryInETH);
event PayoutFailed(address indexed employee, uint salaryInETH, string reason);
//0xF0d50568e3A7e8259E16663972b11910F89BD8e7
constructor(address _multisigWallet, address _priceFeedAddress) {
multisigWallet = _multisigWallet;
@ -42,7 +43,7 @@ contract Salaries {
salaries[employee] = salaryInUSDT;
}
function payoutInETH(address employee) external onlyMultisig {
function payoutInETH(address payable employee) external onlyMultisig {
uint salaryInUSDT = salaries[employee];
require(salaryInUSDT > 0, 'No salary set');
@ -58,8 +59,16 @@ contract Salaries {
'Insufficient contract balance'
);
salaries[employee] = 0; // Reset salary after payment
payable(employee).transfer(salaryInETH);
(bool success, ) = employee.call{value: salaryInETH}("");
if (success) {
emit Payout(employee, salaryInETH);
} else {
emit PayoutFailed(employee, salaryInETH, "Transfer failed");
}
}
function dummy() public pure returns (uint){
return 1337;
}
// Fallback to receive ETH

View File

@ -3,7 +3,7 @@ import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
import { MultiSigWalletService } from 'src/hardhat/modules/multi-sig/multi-sig.service';
import {
ConfirmTransactionDto,
DepositMultiSigDto,
DepositContractDto,
ExecuteTransactionDto,
GetTransactionDto,
RevokeConfirmationDto,
@ -59,7 +59,7 @@ export class MultiSigInteractController {
}
@Post('deposit')
async deposit(@Body() dto: DepositMultiSigDto) {
async deposit(@Body() dto: DepositContractDto) {
return this.multiSigWalletService.deposit(dto);
}
}

View File

@ -1,22 +1,16 @@
import { TransactionReceipt, ethers } from 'ethers';
import { TransactionReceipt, ethers, parseEther } from 'ethers';
import { ConfigService } from '@nestjs/config';
import * as hre from 'hardhat';
import { BaseContractService } from '../base-contract.service';
import { MultiSigWalletDto } from './multi-sig.dto';
import {
ConfirmTransactionDto,
DepositMultiSigDto,
DepositContractDto,
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 {
@ -102,6 +96,7 @@ export class MultiSigWalletService extends BaseContractService {
const tx = await contract.executeTransaction(index);
const txResponse: TransactionReceipt = await tx.wait();
console.log('=>(multi-sig.service.ts:99) txResponse', txResponse.logs);
const eventParse = parseLogs(txResponse, contract);
return {
txHash: txResponse.hash,
@ -145,8 +140,9 @@ export class MultiSigWalletService extends BaseContractService {
return tx;
}
async deposit(dto: DepositMultiSigDto) {
async deposit(dto: DepositContractDto) {
const { contractAddress, value } = dto;
const convertValue = parseEther(value);
const signer = await this.providerService.getSigner();
const { abi } = await hre.artifacts.readArtifact('MultiSigWallet');
@ -154,7 +150,7 @@ export class MultiSigWalletService extends BaseContractService {
const tx = await signer.sendTransaction({
to: contractAddress,
value: BigInt(value),
value: convertValue,
});
const txResponse: TransactionReceipt = await tx.wait();

View File

@ -1,11 +1,13 @@
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
import { SalariesService } from './salaries.service';
import {
CreatePayoutDto,
GetEmployeeSalariesDto,
SalariesDeployDto,
SetSalaryDto,
} from './salaries.dto';
import { ApiTags } from '@nestjs/swagger';
import { DepositContractDto } from '../../../contract-interact/dto/multi-sig.dto';
@ApiTags('salaries')
@Controller('salaries')
export class SalariesController {
@ -30,4 +32,14 @@ export class SalariesController {
async getSalary(@Body() dto: GetEmployeeSalariesDto) {
return this.salariesService.getSalary(dto);
}
@Post('payout')
async createPayout(@Body() dto: CreatePayoutDto) {
return this.salariesService.createPayout(dto);
}
@Post('deposit')
async deposit(@Body() dto: DepositContractDto) {
return this.salariesService.deposit(dto);
}
}

View File

@ -21,8 +21,7 @@ export class SetSalaryDto {
@IsNumber()
salary: number;
}
export class GetEmployeeSalariesDto {
export class GeneralEmpoyeeSalaryDto {
@ApiProperty()
@IsString()
contractAddress: string;
@ -30,3 +29,9 @@ export class GetEmployeeSalariesDto {
@IsString()
employeeAddress: string;
}
export class GetEmployeeSalariesDto extends GeneralEmpoyeeSalaryDto {}
export class CreatePayoutDto extends GeneralEmpoyeeSalaryDto {
@IsString()
multiSigWallet: string;
}

View File

@ -1,7 +1,8 @@
import { Injectable } from '@nestjs/common';
import { BaseContractService } from '../base-contract.service';
import { ethers } from 'ethers';
import { ethers, parseEther, TransactionReceipt } from 'ethers';
import {
CreatePayoutDto,
GetEmployeeSalariesDto,
SalariesDeployDto,
SetSalaryDto,
@ -9,6 +10,7 @@ import {
import * as hre from 'hardhat';
import { MultiSigWalletService } from '../multi-sig/multi-sig.service';
import { ProviderService } from '../../../provider/provider.service';
import { DepositContractDto } from '../../../contract-interact/dto/multi-sig.dto';
@Injectable()
export class SalariesService extends BaseContractService {
@ -69,7 +71,43 @@ export class SalariesService extends BaseContractService {
const contract = new ethers.Contract(contractAddress, abi, signer);
const answer: string = await contract.getSalary(employeeAddress);
return answer;
const answer: BigInt = await contract.getSalary(employeeAddress);
return {
salaryInUsd: answer.toString(),
};
}
async createPayout(dto: CreatePayoutDto) {
const { employeeAddress, contractAddress, multiSigWallet } = dto;
console.log('=>(salaries.service.ts:82) employeeAddress', employeeAddress);
const ISubmitMultiSig = new ethers.Interface([
'function payoutInETH(address employee)',
]);
const data = ISubmitMultiSig.encodeFunctionData('payoutInETH', [
employeeAddress,
]);
return await this.multiSigWalletService.submitTransaction({
contractAddress: multiSigWallet,
destination: contractAddress,
value: '0',
data,
});
}
async deposit(dto: DepositContractDto) {
const { contractAddress, value } = dto;
const signer = await this.providerService.getSigner();
const convertValue = parseEther(value);
const tx = await signer.sendTransaction({
to: contractAddress,
value: convertValue,
});
const txResponse: TransactionReceipt = await tx.wait();
return txResponse;
}
}