分红派息合约的函数逻辑是怎么实现的?附分红合约代码及教程

fffmCQ.jpg

分红派息合约的函数逻辑是怎么实现的?附分红合约代码及教程

分红派息型智能合约其实很好理解,就是给予持币用户或者LP用户一部分的分红。在区块链的世界里,可以将每个人分红的比例提前写入智能合约,然后由合约自动分配,这样就大大提高分红的公平性和便利性。

具体应该如何创建一个这样的分红合约呢?接下来给大家演示一下。

分红派息合约的函数逻辑是怎么实现的?附分红合约代码及教程

分红合约逻辑

分红合约(PaymentSplit)具有以下几个特点:

  1. 在创建合约时定好分红受益人payees和每人的份额shares。
  2. 份额可以是相等,也可以是其他任意比例。
  3. 在该合约收到的所有ETH中,每个受益人将能够提取与其分配的份额成比例的金额。
  4. 分红合约遵循Pull Payment模式,付款不会自动转入账户,而是保存在此合约中。受益人通过调用release()函数触发实际转账。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/**
 * 分红合约 
 * @dev 这个合约会把收到的ETH按事先定好的份额分给几个账户。收到ETH会存在分红合约中,需要每个受益人调用release()函数来领取。
 */
contract PaymentSplit{

分红合约事件

分红合约中共有3个事件:

  • PayeeAdded:增加受益人事件。
  • PaymentReleased:受益人提款事件。
  • PaymentReceived:分红合约收款事件。
    // 事件
    event PayeeAdded(address account, uint256 shares); // 增加受益人事件
    event PaymentReleased(address to, uint256 amount); // 受益人提款事件
    event PaymentReceived(address from, uint256 amount); // 合约收款事件

分红合约状态变量

分红合约中共有5个状态变量,用来记录受益地址、份额、支付出去的ETH等变量:

  • totalShares:总份额,为shares的和。
  • totalReleased:从分红合约向受益人支付出去的ETH,为released的和。
  • payees:address数组,记录受益人地址
  • shares:address到uint256的映射,记录每个受益人的份额。
  • released:address到uint256的映射,记录分红合约支付给每个受益人的金额。
    uint256 public totalShares; // 总份额
    uint256 public totalReleased; // 总支付

    mapping(address => uint256) public shares; // 每个受益人的份额
    mapping(address => uint256) public released; // 支付给每个受益人的金额
    address[] public payees; // 受益人数组

分红合约函数

分红合约中共有6个函数:

  • 构造函数:始化受益人数组_payees和分红份额数组_shares,其中数组长度不能为0,两个数组长度要相等。_shares中元素要大于0,_payees中地址不能为0地址且不能有重复地址。
  • receive():回调函数,在分红合约收到ETH时释放PaymentReceived事件。
  • release():分红函数,为有效受益人地址_account分配相应的ETH。任何人都可以触发这个函数,但ETH会转给受益人地址account。调用了releasable()函数。
  • releasable():计算一个受益人地址应领取的ETH。调用了pendingPayment()函数。
  • pendingPayment():根据受益人地址_account, 分红合约总收入_totalReceived和该地址已领取的钱_alreadyReleased,计算该受益人现在应分的ETH。
  • _addPayee():新增受益人函数及其份额函数。在合约初始化的时候被调用,之后不能修改。
    /**
     * @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) {
        // 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);
    }

分红合约Remix演示

1. 部署PaymentSplit分红合约,并转入1 ETH

在构造函数中,输入两个受益人地址,份额为1和3。

部署

2. 查看受益人地址、份额、应分到的ETH

查看第一位受益人

查看第二位受益人

3. 函数领取ETH

调用release

4. 查看总支出、受益人余额、应分到的ETH的变化

查看

总结

以上是以太坊及兼容链的分红合约实战演练,相关的代码在文章中也已经给出。学会了以太坊的合约逻辑,那么再开发币安智能链、火币智能链等合约的时候就很方便了。大家对此有疑问,或者想要开发一个这类型的合约,可以联系:微信号:btc6540,或者是电报飞机号:@btc6540

声明:该文观点仅代表作者本人,与炒币网无关。炒币网系信息发布平台,仅提供信息存储空间服务。对所包含内容的准确性、可靠性或者完整性不提供任何明示或暗示的保证,并不对文章观点负责。 提示:投资有风险,入市须谨慎。本资讯仅供参阅,不作为投资理财建议。

发表评论

登录后才能评论