zoukankan      html  css  js  c++  java
  • openzeppelin-solidity/contracts的代码学习——payment

    payment - A collection of smart contracts that can be used to manage payments through escrow arrangements, withdrawals, and claims. Includes support for both single payees and multiple payees.(这个是不是就是token中withdrawl的来源,要好好看看,在博客的the security of smart有写)

    临时账户:其实就是一个映射,在下面例子即deposits_,存储某address应该从合约中取出的钱数

    下面这里的代码是openzepplin中写的有关实现临时账户的标准,值得学习,我们学习类似cryptopunks的代码的时候就发现他们是这么写的

    https://github.com/OpenZeppelin/openzeppelin-solidity/tree/master/contracts/payment

    Escrow.sol

    pragma solidity ^0.4.23;
    
    import "../math/SafeMath.sol";
    import "../ownership/Ownable.sol";
    
    
    /**
     * @title Escrow
     * @dev Base escrow contract, holds funds destinated to a payee until they
     * withdraw them. The contract that uses the escrow as its payment method
     * should be its owner, and provide public methods redirecting to the escrow's
     * deposit and withdraw.
     */
    contract Escrow is Ownable {
      using SafeMath for uint256;
    
      event Deposited(address indexed payee, uint256 weiAmount);
      event Withdrawn(address indexed payee, uint256 weiAmount);
    
      mapping(address => uint256) private deposits_;
      //得到临时账户中的余额
      function depositsOf(address _payee) public view returns (uint256) {
        return deposits_[_payee];
      }
    
      /**
      * @dev Stores the sent amount as credit to be withdrawn.
      * @param _payee The destination address of the funds.
      */
     //往临时账户中存钱,因为声明为payable,所以调用该函数的address通过将msg.value数量的金额传给了合约地址,并同时将数额写到临时账户deposits_上 function deposit(address _payee) public onlyOwner payable { uint256 amount = msg.value;//为什么不直接用msg.value进行add运算,是这样更安全吗?????? deposits_[_payee] = deposits_[_payee].add(amount);//为了安全,不使用+来直接运算,而是使用SafeMath.sol中的函数 emit Deposited(_payee, amount); } /** * @dev Withdraw accumulated balance for a payee. * @param _payee The address whose funds will be withdrawn and transferred to. */

    //从合约地址中取出临时账户上的所有钱,并将临时账户上的数额清零 function withdraw(address _payee) public onlyOwner { uint256 payment = deposits_[_payee]; assert(address(this).balance >= payment);//原本是this.balance来得到当前账户地址上的余额??????,address(this)就是是显示转换成合约地址为address类型 deposits_[_payee] = 0; _payee.transfer(payment); emit Withdrawn(_payee, payment); } }

    疑惑address(this).balance的解决,(这里的this代表的是合约的地址):

    pragma solidity ^0.4.24;  
    contract Get{
    //查询当前的余额 function getBalance() public view returns(uint){ return this.balance; }
      event SendEvent(address to, uint value, bool result);
      //使用send()发送ether,观察会触发fallback函数
      function sendEther() public{
          bool result = this.send(1);
          emit SendEvent(this, 1, result);
    }

    当想要使用this.balance这么写得到账户的余额时,remix编译中会报警告:

    Warning:Using contract member "balance" inherited from the address type is deprecated.Convert the contract to "address" type to access the member,for example use "address(contract).balance" instead.

    除此之外,使用this.send也是会报相似的警告:

    Warning:Using contract member "send" inherited from the address type is deprecated.Convert the contract to "address" type to access the member,for example use "address(contract).send" instead.

    这就是this.balance为什么改为address(this).balance的原因,在这里this.send也要改为address(this).send

    PullPayment.sol

    pragma solidity ^0.4.24;
    
    import "./Escrow.sol";
    
    
    /**
     * @title PullPayment
     * @dev Base contract supporting async send for pull payments. Inherit from this
     * contract and use asyncTransfer instead of send or transfer.
     */
    contract PullPayment {
      Escrow private escrow;
    
      constructor() public {
        escrow = new Escrow();
      }
    
      /**
      * @dev Withdraw accumulated balance, called by payee.
      */
      //取钱
      function withdrawPayments() public {
        address payee = msg.sender;
        escrow.withdraw(payee);
      }
    
      /**
      * @dev Returns the credit owed to an address.
      * @param _dest The creditor's address.
      */
      //查余额
      function payments(address _dest) public view returns (uint256) {
        return escrow.depositsOf(_dest);
      }
    
      /**
      * @dev Called by the payer to store the sent amount as credit to be pulled.
      * @param _dest The destination address of the funds.
      * @param _amount The amount to transfer.
      */
      //向临时账户中存钱
      function asyncTransfer(address _dest, uint256 _amount) internal {
        escrow.deposit.value(_amount)(_dest);//形如someAddress.call.value()() ,因为deposit是payable的,value(_amount)相当于{value:_amount}
    
      }
    }

    contracts/payment/ConditionalEscrow.sol

    就是当某条件允许时才能够将临时账户中的钱取出

    该函数为abstract函数

    pragma solidity ^0.4.23;
    
    import "./Escrow.sol";
    
    
    /**
     * @title ConditionalEscrow
     * @dev Base abstract escrow to only allow withdrawal if a condition is met.
     */
    contract ConditionalEscrow is Escrow {
      /**
      * @dev Returns whether an address is allowed to withdraw their funds. To be
      * implemented by derived contracts.
      * @param _payee The destination address of the funds.
      */
      function withdrawalAllowed(address _payee) public view returns (bool);
    
      function withdraw(address _payee) public {
        require(withdrawalAllowed(_payee));//只有满足情况了才能withdraw,下面即实现例子RefundEscrow.sol
        super.withdraw(_payee);
      }
    }

    contracts/payment/RefundEscrow.sol

    当账户状态为Refunding时,存钱的人能把存的钱取回

    当账户状态为Closed时,受益人才能把账户中的钱取出

    pragma solidity ^0.4.23;
    
    import "./ConditionalEscrow.sol";
    import "../ownership/Ownable.sol";
    
    
    /**
     * @title RefundEscrow
     * @dev Escrow that holds funds for a beneficiary(收益人), deposited from multiple parties.
     * The contract owner may close the deposit period, and allow for either withdrawal
     * by the beneficiary, or refunds to the depositors.
     */
    contract RefundEscrow is Ownable, ConditionalEscrow {
      enum State { Active, Refunding, Closed }
    
      event Closed();
      event RefundsEnabled();
    
      State public state;
      address public beneficiary;
    
      /**
       * @dev Constructor.
       * @param _beneficiary The beneficiary of the deposits.
       */
      constructor(address _beneficiary) public {//声明受益人,此时账户状态为Active
        require(_beneficiary != address(0));
        beneficiary = _beneficiary;
        state = State.Active;
      }
    
      /**
       * @dev Stores funds that may later be refunded.
       * @param _refundee The address funds will be sent to if a refund occurs.
       */
      function deposit(address _refundee) public payable {//往账户存钱
        require(state == State.Active);
        super.deposit(_refundee);//使用的是super,即父合约而不是this本合约
      }
    
      /**
       * @dev Allows for the beneficiary to withdraw their funds, rejecting
       * further deposits.
       */
      function close() public onlyOwner {//当账户状态为Closed,就不能再往里面存钱了,只能受益人取钱
        require(state == State.Active);
        state = State.Closed;
        emit Closed();
      }
    
      /**
       * @dev Allows for refunds to take place, rejecting further deposits.
       */
      function enableRefunds() public onlyOwner {
        require(state == State.Active);
        state = State.Refunding;
        emit RefundsEnabled();
      }
    
      /**
       * @dev Withdraws the beneficiary's funds.
       */
      function beneficiaryWithdraw() public {//受益人取钱
        require(state == State.Closed);
        beneficiary.transfer(address(this).balance);
      }
    
      /**
       * @dev Returns whether refundees can withdraw their deposits (be refunded).
       */
      function withdrawalAllowed(address _payee) public view returns (bool) {//当账户状态为Refunding时,存钱的人能把存的钱取回
        return state == State.Refunding;
      }
    }

    contracts/payment/SplitPayment.sol

    付款人能够根据自己在该合约生成时付的钱生成的股份shares[payee]占总股份的比例来要求合约返还自己的钱

    pragma solidity ^0.4.24;
    
    import "../math/SafeMath.sol";
    
    
    /**
     * @title SplitPayment
     * @dev Base contract that supports multiple payees claiming funds sent to this contract
     * according to the proportion they own.
     */
    contract SplitPayment {
      using SafeMath for uint256;
    
      uint256 public totalShares = 0;
      uint256 public totalReleased = 0;
    
      mapping(address => uint256) public shares;//payee所拥有的股份
      mapping(address => uint256) public released;//合约已经还给payee的钱
      address[] public payees;
    
      /**
       * @dev Constructor
       */
      constructor(address[] _payees, uint256[] _shares) public payable {
        require(_payees.length == _shares.length);
        require(_payees.length > 0);
    
        for (uint256 i = 0; i < _payees.length; i++) {//在该合约创建的时候_payee就都加到该合约中了,比例也是早就算好的
          _addPayee(_payees[i], _shares[i]);
        }
      }
    
      /**
       * @dev payable fallback
       */
      function () external payable {}
    
      /**
       * @dev Claim your share of the balance.
       */
      function claim() public {
        address payee = msg.sender;
    
        require(shares[payee] > 0);
    
        uint256 totalReceived = address(this).balance.add(totalReleased);//就是合约还回去的钱totalReleased+现在合约中有的钱 = 合约总共收到的钱
        uint256 payment = totalReceived.mul( //等价于((totalReceived*(shares[payee]/totalShares))-released[payee]),就是通过比例算出本payee发给该合约的钱-之前还的钱released[payee] = 还需要还的钱payment
          shares[payee]).div(
            totalShares).sub(
              released[payee]
        );
    
        require(payment != 0);
        assert(address(this).balance >= payment);//合约中现在还有的钱要大于payment才能把钱给payee
    
        released[payee] = released[payee].add(payment);
        totalReleased = totalReleased.add(payment);
    
        payee.transfer(payment);
      }
    
      /**
       * @dev Add a new payee to the contract.
       * @param _payee The address of the payee to add.
       * @param _shares The number of shares owned by the payee.
       */
      function _addPayee(address _payee, uint256 _shares) internal {
        require(_payee != address(0));
        require(_shares > 0);
        require(shares[_payee] == 0);
    
        payees.push(_payee);
        shares[_payee] = _shares;
        totalShares = totalShares.add(_shares);
      }
    }

    ⚠️:Add a leading underscore to internal and private functions,要在internal and private函数的名字前加下划线

  • 相关阅读:
    react系列教程
    实现 React Hooks
    实现 call、apply、bind
    Webpack概念
    写一个简单的模板引擎
    闭包和let块级作用域
    react系列(六)Redux Saga
    react系列(五)在React中使用Redux
    java学习12天2020/7/17
    java学习第十一天2020/7/16
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/9593608.html
Copyright © 2011-2022 走看看