mirror of
https://github.com/emo2007/block-accounting.git
synced 2025-01-18 15:36:27 +00:00
payout ready, but needs fixes
This commit is contained in:
parent
0a74e430b8
commit
958bf670ae
@ -34,7 +34,7 @@ export class GetTransactionCount {}
|
|||||||
|
|
||||||
export class GetTransactionDto extends ConfirmTransactionDto {}
|
export class GetTransactionDto extends ConfirmTransactionDto {}
|
||||||
|
|
||||||
export class DepositMultiSigDto {
|
export class DepositContractDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
contractAddress: string;
|
contractAddress: string;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
// 0x74f11486DB0FCAA2dCDE0aEB477e1F37fCAa510A
|
||||||
|
|
||||||
pragma solidity ^0.8.19;
|
pragma solidity ^0.8.19;
|
||||||
// The wallet owners can
|
// The wallet owners can
|
||||||
@ -18,6 +19,9 @@ contract MultiSigWallet {
|
|||||||
event ConfirmTransaction(address indexed owner, uint indexed txIndex);
|
event ConfirmTransaction(address indexed owner, uint indexed txIndex);
|
||||||
event RevokeConfirmation(address indexed owner, uint indexed txIndex);
|
event RevokeConfirmation(address indexed owner, uint indexed txIndex);
|
||||||
event ExecuteTransaction(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;
|
address[] public owners;
|
||||||
|
|
||||||
@ -111,20 +115,63 @@ contract MultiSigWallet {
|
|||||||
emit ConfirmTransaction(msg.sender, _txIndex);
|
emit ConfirmTransaction(msg.sender, _txIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeTransaction(
|
function executeTransaction(uint _txIndex)
|
||||||
uint _txIndex
|
public
|
||||||
) public onlyOwner txExists(_txIndex) notExecuted(_txIndex) {
|
onlyOwner
|
||||||
|
txExists(_txIndex)
|
||||||
|
notExecuted(_txIndex)
|
||||||
|
{
|
||||||
Transaction storage transaction = transactions[_txIndex];
|
Transaction storage transaction = transactions[_txIndex];
|
||||||
require(
|
require(
|
||||||
transaction.numConfirmations >= numConfirmationsRequired,
|
transaction.numConfirmations >= numConfirmationsRequired,
|
||||||
'cannot execute tx'
|
"cannot execute tx"
|
||||||
);
|
);
|
||||||
transaction.executed = true;
|
|
||||||
(bool success, ) = transaction.to.call{value: transaction.value}(
|
|
||||||
transaction.data
|
(bool success, bytes memory returnData) = transaction.to.call{value: transaction.value}(transaction.data);
|
||||||
);
|
if (success) {
|
||||||
require(success, 'tx failed');
|
transaction.executed = true;
|
||||||
emit ExecuteTransaction(msg.sender, _txIndex);
|
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(
|
function revokeConfirmation(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
// 0x2F9442900d067a3D37A1C2aE99462E055e32c741
|
||||||
pragma solidity ^0.8.7;
|
pragma solidity ^0.8.7;
|
||||||
|
|
||||||
import {AggregatorV3Interface} from '@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol';
|
import {AggregatorV3Interface} from '@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol';
|
||||||
@ -8,7 +8,8 @@ contract Salaries {
|
|||||||
AggregatorV3Interface internal dataFeed;
|
AggregatorV3Interface internal dataFeed;
|
||||||
address public multisigWallet;
|
address public multisigWallet;
|
||||||
mapping(address => uint) public salaries;
|
mapping(address => uint) public salaries;
|
||||||
|
event Payout(address indexed employee, uint salaryInETH);
|
||||||
|
event PayoutFailed(address indexed employee, uint salaryInETH, string reason);
|
||||||
//0xF0d50568e3A7e8259E16663972b11910F89BD8e7
|
//0xF0d50568e3A7e8259E16663972b11910F89BD8e7
|
||||||
constructor(address _multisigWallet, address _priceFeedAddress) {
|
constructor(address _multisigWallet, address _priceFeedAddress) {
|
||||||
multisigWallet = _multisigWallet;
|
multisigWallet = _multisigWallet;
|
||||||
@ -42,7 +43,7 @@ contract Salaries {
|
|||||||
salaries[employee] = salaryInUSDT;
|
salaries[employee] = salaryInUSDT;
|
||||||
}
|
}
|
||||||
|
|
||||||
function payoutInETH(address employee) external onlyMultisig {
|
function payoutInETH(address payable employee) external onlyMultisig {
|
||||||
uint salaryInUSDT = salaries[employee];
|
uint salaryInUSDT = salaries[employee];
|
||||||
require(salaryInUSDT > 0, 'No salary set');
|
require(salaryInUSDT > 0, 'No salary set');
|
||||||
|
|
||||||
@ -58,8 +59,16 @@ contract Salaries {
|
|||||||
'Insufficient contract balance'
|
'Insufficient contract balance'
|
||||||
);
|
);
|
||||||
|
|
||||||
salaries[employee] = 0; // Reset salary after payment
|
(bool success, ) = employee.call{value: salaryInETH}("");
|
||||||
payable(employee).transfer(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
|
// Fallback to receive ETH
|
||||||
|
@ -3,7 +3,7 @@ import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
|||||||
import { MultiSigWalletService } from 'src/hardhat/modules/multi-sig/multi-sig.service';
|
import { MultiSigWalletService } from 'src/hardhat/modules/multi-sig/multi-sig.service';
|
||||||
import {
|
import {
|
||||||
ConfirmTransactionDto,
|
ConfirmTransactionDto,
|
||||||
DepositMultiSigDto,
|
DepositContractDto,
|
||||||
ExecuteTransactionDto,
|
ExecuteTransactionDto,
|
||||||
GetTransactionDto,
|
GetTransactionDto,
|
||||||
RevokeConfirmationDto,
|
RevokeConfirmationDto,
|
||||||
@ -59,7 +59,7 @@ export class MultiSigInteractController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Post('deposit')
|
@Post('deposit')
|
||||||
async deposit(@Body() dto: DepositMultiSigDto) {
|
async deposit(@Body() dto: DepositContractDto) {
|
||||||
return this.multiSigWalletService.deposit(dto);
|
return this.multiSigWalletService.deposit(dto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,16 @@
|
|||||||
import { TransactionReceipt, ethers } from 'ethers';
|
import { TransactionReceipt, ethers, parseEther } from 'ethers';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import * as hre from 'hardhat';
|
import * as hre from 'hardhat';
|
||||||
import { BaseContractService } from '../base-contract.service';
|
import { BaseContractService } from '../base-contract.service';
|
||||||
import { MultiSigWalletDto } from './multi-sig.dto';
|
import { MultiSigWalletDto } from './multi-sig.dto';
|
||||||
import {
|
import {
|
||||||
ConfirmTransactionDto,
|
ConfirmTransactionDto,
|
||||||
DepositMultiSigDto,
|
DepositContractDto,
|
||||||
ExecuteTransactionDto,
|
ExecuteTransactionDto,
|
||||||
GetTransactionDto,
|
GetTransactionDto,
|
||||||
RevokeConfirmationDto,
|
RevokeConfirmationDto,
|
||||||
SubmitTransactionDto,
|
SubmitTransactionDto,
|
||||||
} from 'src/contract-interact/dto/multi-sig.dto';
|
} 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';
|
import { parseLogs } from 'src/contract-interact/ethers.helpers';
|
||||||
|
|
||||||
export class MultiSigWalletService extends BaseContractService {
|
export class MultiSigWalletService extends BaseContractService {
|
||||||
@ -102,6 +96,7 @@ export class MultiSigWalletService extends BaseContractService {
|
|||||||
const tx = await contract.executeTransaction(index);
|
const tx = await contract.executeTransaction(index);
|
||||||
|
|
||||||
const txResponse: TransactionReceipt = await tx.wait();
|
const txResponse: TransactionReceipt = await tx.wait();
|
||||||
|
console.log('=>(multi-sig.service.ts:99) txResponse', txResponse.logs);
|
||||||
const eventParse = parseLogs(txResponse, contract);
|
const eventParse = parseLogs(txResponse, contract);
|
||||||
return {
|
return {
|
||||||
txHash: txResponse.hash,
|
txHash: txResponse.hash,
|
||||||
@ -145,8 +140,9 @@ export class MultiSigWalletService extends BaseContractService {
|
|||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
async deposit(dto: DepositMultiSigDto) {
|
async deposit(dto: DepositContractDto) {
|
||||||
const { contractAddress, value } = dto;
|
const { contractAddress, value } = dto;
|
||||||
|
const convertValue = parseEther(value);
|
||||||
const signer = await this.providerService.getSigner();
|
const signer = await this.providerService.getSigner();
|
||||||
|
|
||||||
const { abi } = await hre.artifacts.readArtifact('MultiSigWallet');
|
const { abi } = await hre.artifacts.readArtifact('MultiSigWallet');
|
||||||
@ -154,7 +150,7 @@ export class MultiSigWalletService extends BaseContractService {
|
|||||||
|
|
||||||
const tx = await signer.sendTransaction({
|
const tx = await signer.sendTransaction({
|
||||||
to: contractAddress,
|
to: contractAddress,
|
||||||
value: BigInt(value),
|
value: convertValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
const txResponse: TransactionReceipt = await tx.wait();
|
const txResponse: TransactionReceipt = await tx.wait();
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
|
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
|
||||||
import { SalariesService } from './salaries.service';
|
import { SalariesService } from './salaries.service';
|
||||||
import {
|
import {
|
||||||
|
CreatePayoutDto,
|
||||||
GetEmployeeSalariesDto,
|
GetEmployeeSalariesDto,
|
||||||
SalariesDeployDto,
|
SalariesDeployDto,
|
||||||
SetSalaryDto,
|
SetSalaryDto,
|
||||||
} from './salaries.dto';
|
} from './salaries.dto';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiTags } from '@nestjs/swagger';
|
||||||
|
import { DepositContractDto } from '../../../contract-interact/dto/multi-sig.dto';
|
||||||
@ApiTags('salaries')
|
@ApiTags('salaries')
|
||||||
@Controller('salaries')
|
@Controller('salaries')
|
||||||
export class SalariesController {
|
export class SalariesController {
|
||||||
@ -30,4 +32,14 @@ export class SalariesController {
|
|||||||
async getSalary(@Body() dto: GetEmployeeSalariesDto) {
|
async getSalary(@Body() dto: GetEmployeeSalariesDto) {
|
||||||
return this.salariesService.getSalary(dto);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,7 @@ export class SetSalaryDto {
|
|||||||
@IsNumber()
|
@IsNumber()
|
||||||
salary: number;
|
salary: number;
|
||||||
}
|
}
|
||||||
|
export class GeneralEmpoyeeSalaryDto {
|
||||||
export class GetEmployeeSalariesDto {
|
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@IsString()
|
@IsString()
|
||||||
contractAddress: string;
|
contractAddress: string;
|
||||||
@ -30,3 +29,9 @@ export class GetEmployeeSalariesDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
employeeAddress: string;
|
employeeAddress: string;
|
||||||
}
|
}
|
||||||
|
export class GetEmployeeSalariesDto extends GeneralEmpoyeeSalaryDto {}
|
||||||
|
|
||||||
|
export class CreatePayoutDto extends GeneralEmpoyeeSalaryDto {
|
||||||
|
@IsString()
|
||||||
|
multiSigWallet: string;
|
||||||
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { BaseContractService } from '../base-contract.service';
|
import { BaseContractService } from '../base-contract.service';
|
||||||
import { ethers } from 'ethers';
|
import { ethers, parseEther, TransactionReceipt } from 'ethers';
|
||||||
import {
|
import {
|
||||||
|
CreatePayoutDto,
|
||||||
GetEmployeeSalariesDto,
|
GetEmployeeSalariesDto,
|
||||||
SalariesDeployDto,
|
SalariesDeployDto,
|
||||||
SetSalaryDto,
|
SetSalaryDto,
|
||||||
@ -9,6 +10,7 @@ import {
|
|||||||
import * as hre from 'hardhat';
|
import * as hre from 'hardhat';
|
||||||
import { MultiSigWalletService } from '../multi-sig/multi-sig.service';
|
import { MultiSigWalletService } from '../multi-sig/multi-sig.service';
|
||||||
import { ProviderService } from '../../../provider/provider.service';
|
import { ProviderService } from '../../../provider/provider.service';
|
||||||
|
import { DepositContractDto } from '../../../contract-interact/dto/multi-sig.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SalariesService extends BaseContractService {
|
export class SalariesService extends BaseContractService {
|
||||||
@ -69,7 +71,43 @@ export class SalariesService extends BaseContractService {
|
|||||||
|
|
||||||
const contract = new ethers.Contract(contractAddress, abi, signer);
|
const contract = new ethers.Contract(contractAddress, abi, signer);
|
||||||
|
|
||||||
const answer: string = await contract.getSalary(employeeAddress);
|
const answer: BigInt = await contract.getSalary(employeeAddress);
|
||||||
return answer;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user