前言本文编写的分账合约,主要为了解决现实生活中的分配不均等相关的信任问题。分账合约定义:一种智能合约,用于将收到的款项自动分配给多个预设的地址。这种合约在多种场景下非常有用,例如在多个投资者、团队成员或合作伙伴之间公平分配收益。分账合约可以确保资金的透明分配,减少信任问题,并自动化资金管理
本文编写的分账合约,主要为了解决现实生活中的分配不均等相关的信任问题。
分账合约
定义:一种智能合约,用于将收到的款项自动分配给多个预设的地址。这种合约在多种场景下非常有用,例如在多个投资者、团队成员或合作伙伴之间公平分配收益。分账合约可以确保资金的透明分配,减少信任问题,并自动化资金管理。
功能
- 自动分配:当合约收到资金时,自动按照预设的比例将资金分配给多个地址。
- 透明性:所有分配记录都在区块链上公开,确保透明度。
- 灵活性:可以设置不同的分配比例,满足不同的需求。
- 安全性:通过智能合约的代码确保资金分配的正确性和安全性。
场景
- 多签名钱包:多个团队成员共同管理资金,每次收到资金时自动分配。
- 投资组合:多个投资者共同投资一个项目,收益按比例分配。
- 合作伙伴关系:多个合作伙伴共同运营一个项目,收入按协议分配。
- 众筹项目:将众筹资金按比例分配给多个受益者。
合约说明:本合约主要包含一下功能:查看受益人地址、份额、应得受益、已领取的受益、合约总份额、合约支出金额、账号当下应该领取的金额,领取收益方法;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;
import "hardhat/console.sol";
/**
* 分账合约
* @dev 这个合约会把收到的ETH按事先定好的份额分给几个账户。收到ETH会存在分账合约中,需要每个受益人调用release()函数来领取。
*/
contract PaymentSplit{
// 事件
event PayeeAdded(address account, uint256 shares); // 增加受益人事件
event PaymentReleased(address to, uint256 amount); // 受益人提款事件
event PaymentReceived(address from, uint256 amount); // 合约收款事件
uint256 public totalShares; // 总份额
uint256 public totalReleased; // 总支付
mapping(address => uint256) public shares; // 每个受益人的份额
mapping(address => uint256) public released; // 支付给每个受益人的金额
address[] public payees; // 受益人数组
/**
* @dev 初始化受益人数组_payees和分账份额数组_shares
* 数组长度不能为0,两个数组长度要相等。_shares中元素要大于0,_payees中地址不能为0地址且不能有重复地址
*/
constructor(address[] memory _payees, uint256[] memory _shares) payable {
// 检查_payees和_shares数组长度相同,且不为0
require(_payees.length == _shares.length, "PaymentSplitter: payees and shares length mismatch");
require(_payees.length > 0, "PaymentSplitter: no payees");
// 调用_addPayee,更新受益人地址payees、受益人份额shares和总份额totalShares
for (uint256 i = 0; i < _payees.length; i++) {
_addPayee(_payees[i], _shares[i]);
}
}
/**
* @dev 回调函数,收到ETH释放PaymentReceived事件
*/
receive() external payable virtual {
emit PaymentReceived(msg.sender, msg.value);
}
/**
* @dev 为有效受益人地址_account分帐,相应的ETH直接发送到受益人地址。任何人都可以触发这个函数,但钱会打给account地址。
* 调用了releasable()函数。
*/
function release(address payable _account) public virtual {
// account必须是有效受益人
require(shares[_account] > 0, "PaymentSplitter: account has no shares");
// 计算account应得的eth
uint256 payment = releasable(_account);
// 应得的eth不能为0
require(payment != 0, "PaymentSplitter: account is not due payment");
// 更新总支付totalReleased和支付给每个受益人的金额released
totalReleased += payment;
released[_account] += payment;
// 转账
_account.transfer(payment);
emit PaymentReleased(_account, payment);
}
/**
* @dev 计算一个账户能够领取的eth。
* 调用了pendingPayment()函数。
*/
function releasable(address _account) public view returns (uint256) {
// 计算分账合约总收入totalReceived
uint256 totalReceived = address(this).balance + totalReleased;
// 调用_pendingPayment计算account应得的ETH
return pendingPayment(_account, totalReceived, released[_account]);
}
/**
* @dev 根据受益人地址`_account`, 分账合约总收入`_totalReceived`和该地址已领取的钱`_alreadyReleased`,计算该受益人现在应分的`ETH`。
*/
function pendingPayment(
address _account,
uint256 _totalReceived,
uint256 _alreadyReleased
) public view returns (uint256) {
console.log(_account, _totalReceived, _alreadyReleased);
// account应得的ETH = 总应得ETH - 已领到的ETH
return (_totalReceived * shares[_account]) / totalShares - _alreadyReleased;
}
/**
* @dev 新增受益人_account以及对应的份额_accountShares。只能在构造器中被调用,不能修改。
*/
function _addPayee(address _account, uint256 _accountShares) private {
// 检查_account不为0地址
require(_account != address(0), "PaymentSplitter: account is the zero address");
// 检查_accountShares不为0
require(_accountShares > 0, "PaymentSplitter: shares are 0");
// 检查_account不重复
require(shares[_account] == 0, "PaymentSplitter: account already has shares");
// 更新payees,shares和totalShares
payees.push(_account);
shares[_account] = _accountShares;
totalShares += _accountShares;
// 释放增加受益人事件
emit PayeeAdded(_account, _accountShares);
}
}
# 编译指令
# npx hardhat compile
测试说明:
const {ethers,getNamedAccounts,deployments} = require("hardhat");
const { assert,expect } = require("chai");
describe("分账合约",function(){
let paymentSplitContract;
let deployer;
let PaymentSplit;//分账合约
let firstAccount//第一个账户
let secondAccount//第二个账户
beforeEach(async function(){
await deployments.fixture(["Paymentsplit"]);
//转账
const { deployer: deployerAddress } = await getNamedAccounts();
deployer = await ethers.provider.getSigner(deployerAddress);
paymentSplitContract = await ethers.getContract("PaymentSplit", deployer);
//获取账户
firstAccount=(await getNamedAccounts()).firstAccount;
secondAccount=(await getNamedAccounts()).secondAccount;
const PaymentsplitDeployment = await deployments.get("PaymentSplit");
PaymentSplit = await ethers.getContractAt("PaymentSplit",PaymentsplitDeployment.address);//已经部署的合约交
});
describe("分账合约测试",function(){
it("分账合约",async function(){
let income="100.0";//合约转的账
const tx = {
to: paymentSplitContract.address,
value: ethers.utils.parseEther(income), // 转账 100 ETH
};
// 发送交易
const txResponse = await deployer.sendTransaction(tx);
console.log("Transaction hash:", txResponse.hash);
// 等待交易确认
await txResponse.wait();
// 检查合约余额
const balance = await ethers.provider.getBalance(paymentSplitContract.address);
console.log("Contract balance:", ethers.utils.formatEther(balance));
//查看受益人地址 参数是说明 账号下标 例如0,1
console.log("查看受益人地址",await PaymentSplit.payees(0))
//查看firstAccount账号应给领取多少代币
let firstAccountBalance=await PaymentSplit.releasable(firstAccount)
console.log("查看firstAccount账号可以领取多少代币",`${ethers.utils.formatEther(firstAccountBalance)} ETH`)
//查看受益人已经领取代币
console.log("受益人已经领取到的代币",await PaymentSplit.released(firstAccount))
//查看受益人的份额 参数是账号地址
console.log("受益人的份额",await PaymentSplit.shares(firstAccount))
//查看合余额总支出
console.log("合余额总支出",await PaymentSplit.totalReleased())
//查看合约总份额
console.log("合约总份额",await PaymentSplit.totalShares())
//领取受益代币方法
await PaymentSplit.release(firstAccount)
let firstAccountreceive=await PaymentSplit.released(firstAccount)
let firstAccountreceiveValue=ethers.utils.formatEther(firstAccountreceive)
console.log("firstAccount已经领取代币",`${firstAccountreceiveValue} ETH`)
let expenditureBalance=await PaymentSplit.totalReleased()
let expenditureBalanceValue=ethers.utils.formatEther(expenditureBalance)
console.log("合余额总支出",`${expenditureBalanceValue} ETH`)
//账号2的测试验证通理
//根据受益人地址_account, 分账合约总收入_totalReceived和该地址已领取的钱_alreadyReleased,计算该受益人现在应分的ETH。
console.log("查看受益账号当下领取多少钱",await PaymentSplit.pendingPayment(firstAccount,Number(income),Number(firstAccountreceiveValue)))
})
})
})
# 测试指令
# npx hardhat test ./test/xxx.js
module.exports = async function ({getNamedAccounts,deployments}) {
const firstAccount= (await getNamedAccounts()).firstAccount;
const secondAccount= (await getNamedAccounts()).secondAccount;
// const [addr1,addr2]=(await ethers.getSigners())
let TokenAddress= [firstAccount,secondAccount];
// console.log(TokenAddress)
const ShareArray=[8,2]
const {deploy,log} = deployments;
const Paymentsplit=await deploy("PaymentSplit",{
from:firstAccount,
args: [TokenAddress,ShareArray],//参数 受益人地址数组,受益人份额数组
log: true,
})
console.log('Paymentsplit合约地址',Paymentsplit.address)
}
module.exports.tags = ["all", "Paymentsplit"];
# 部署指令
# npx hardhat deploy
以上就是分账合约开发、测试、部署全部过程,注意:在测试的中需要通过ethers.getContract的方法对合约进行资金的转入,解决ethers.getContract报错问题需要下载相应的插件(hardhat-deploy-ethers),还用要区分ethers.getContract
和ethers.getContractAt
的区别后者最主要的场景用来进行合约交互。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!