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

  1. pragma solidity ^0.4.23;
  2.  
  3. import "../math/SafeMath.sol";
  4. import "../ownership/Ownable.sol";
  5.  
  6. /**
  7. * @title Escrow
  8. * @dev Base escrow contract, holds funds destinated to a payee until they
  9. * withdraw them. The contract that uses the escrow as its payment method
  10. * should be its owner, and provide public methods redirecting to the escrow's
  11. * deposit and withdraw.
  12. */
  13. contract Escrow is Ownable {
  14. using SafeMath for uint256;
  15.  
  16. event Deposited(address indexed payee, uint256 weiAmount);
  17. event Withdrawn(address indexed payee, uint256 weiAmount);
  18.  
  19. mapping(address => uint256) private deposits_;
  20. //得到临时账户中的余额
  21. function depositsOf(address _payee) public view returns (uint256) {
  22. return deposits_[_payee];
  23. }
  24.  
  25. /**
  26. * @dev Stores the sent amount as credit to be withdrawn.
  27. * @param _payee The destination address of the funds.
  28. */
     //往临时账户中存钱,因为声明为payable,所以调用该函数的address通过将msg.value数量的金额传给了合约地址,并同时将数额写到临时账户deposits_上
  29. function deposit(address _payee) public onlyOwner payable {
  30. uint256 amount = msg.value;//为什么不直接用msg.value进行add运算,是这样更安全吗??????
  31. deposits_[_payee] = deposits_[_payee].add(amount);//为了安全,不使用+来直接运算,而是使用SafeMath.sol中的函数
  32.  
  33. emit Deposited(_payee, amount);
  34. }
  35.  
  36. /**
  37. * @dev Withdraw accumulated balance for a payee.
  38. * @param _payee The address whose funds will be withdrawn and transferred to.
  39. */
  40.  
  41. //从合约地址中取出临时账户上的所有钱,并将临时账户上的数额清零
  42. function withdraw(address _payee) public onlyOwner {
  43. uint256 payment = deposits_[_payee];
  44. assert(address(this).balance >= payment);//原本是this.balance来得到当前账户地址上的余额??????,address(this)就是是显示转换成合约地址为address类型
  45.  
  46. deposits_[_payee] = 0;
  47.  
  48. _payee.transfer(payment);
  49.  
  50. emit Withdrawn(_payee, payment);
  51. }
  52. }

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

  1. pragma solidity ^0.4.24;
    contract Get{
    //查询当前的余额
  2. function getBalance() public view returns(uint){
  3. return this.balance;
  4. }
      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编译中会报警告:

  1. 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也是会报相似的警告:

  1. 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

  1. pragma solidity ^0.4.;
  2.  
  3. import "./Escrow.sol";
  4.  
  5. /**
  6. * @title PullPayment
  7. * @dev Base contract supporting async send for pull payments. Inherit from this
  8. * contract and use asyncTransfer instead of send or transfer.
  9. */
  10. contract PullPayment {
  11. Escrow private escrow;
  12.  
  13. constructor() public {
  14. escrow = new Escrow();
  15. }
  16.  
  17. /**
  18. * @dev Withdraw accumulated balance, called by payee.
  19. */
  20. //取钱
  21. function withdrawPayments() public {
  22. address payee = msg.sender;
  23. escrow.withdraw(payee);
  24. }
  25.  
  26. /**
  27. * @dev Returns the credit owed to an address.
  28. * @param _dest The creditor's address.
  29. */
  30. //查余额
  31. function payments(address _dest) public view returns (uint256) {
  32. return escrow.depositsOf(_dest);
  33. }
  34.  
  35. /**
  36. * @dev Called by the payer to store the sent amount as credit to be pulled.
  37. * @param _dest The destination address of the funds.
  38. * @param _amount The amount to transfer.
  39. */
  40. //向临时账户中存钱
  41. function asyncTransfer(address _dest, uint256 _amount) internal {
  42. escrow.deposit.value(_amount)(_dest);//形如someAddress.call.value()() ,因为deposit是payable的,value(_amount)相当于{value:_amount}
  43.  
  44. }
  45. }

contracts/payment/ConditionalEscrow.sol

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

该函数为abstract函数

  1. pragma solidity ^0.4.;
  2.  
  3. import "./Escrow.sol";
  4.  
  5. /**
  6. * @title ConditionalEscrow
  7. * @dev Base abstract escrow to only allow withdrawal if a condition is met.
  8. */
  9. contract ConditionalEscrow is Escrow {
  10. /**
  11. * @dev Returns whether an address is allowed to withdraw their funds. To be
  12. * implemented by derived contracts.
  13. * @param _payee The destination address of the funds.
  14. */
  15. function withdrawalAllowed(address _payee) public view returns (bool);
  16.  
  17. function withdraw(address _payee) public {
  18. require(withdrawalAllowed(_payee));//只有满足情况了才能withdraw,下面即实现例子RefundEscrow.sol
  19. super.withdraw(_payee);
  20. }
  21. }

contracts/payment/RefundEscrow.sol

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

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

  1. pragma solidity ^0.4.;
  2.  
  3. import "./ConditionalEscrow.sol";
  4. import "../ownership/Ownable.sol";
  5.  
  6. /**
  7. * @title RefundEscrow
  8. * @dev Escrow that holds funds for a beneficiary(收益人), deposited from multiple parties.
  9. * The contract owner may close the deposit period, and allow for either withdrawal
  10. * by the beneficiary, or refunds to the depositors.
  11. */
  12. contract RefundEscrow is Ownable, ConditionalEscrow {
  13. enum State { Active, Refunding, Closed }
  14.  
  15. event Closed();
  16. event RefundsEnabled();
  17.  
  18. State public state;
  19. address public beneficiary;
  20.  
  21. /**
  22. * @dev Constructor.
  23. * @param _beneficiary The beneficiary of the deposits.
  24. */
  25. constructor(address _beneficiary) public {//声明受益人,此时账户状态为Active
  26. require(_beneficiary != address());
  27. beneficiary = _beneficiary;
  28. state = State.Active;
  29. }
  30.  
  31. /**
  32. * @dev Stores funds that may later be refunded.
  33. * @param _refundee The address funds will be sent to if a refund occurs.
  34. */
  35. function deposit(address _refundee) public payable {//往账户存钱
  36. require(state == State.Active);
  37. super.deposit(_refundee);//使用的是super,即父合约而不是this本合约
  38. }
  39.  
  40. /**
  41. * @dev Allows for the beneficiary to withdraw their funds, rejecting
  42. * further deposits.
  43. */
  44. function close() public onlyOwner {//当账户状态为Closed,就不能再往里面存钱了,只能受益人取钱
  45. require(state == State.Active);
  46. state = State.Closed;
  47. emit Closed();
  48. }
  49.  
  50. /**
  51. * @dev Allows for refunds to take place, rejecting further deposits.
  52. */
  53. function enableRefunds() public onlyOwner {
  54. require(state == State.Active);
  55. state = State.Refunding;
  56. emit RefundsEnabled();
  57. }
  58.  
  59. /**
  60. * @dev Withdraws the beneficiary's funds.
  61. */
  62. function beneficiaryWithdraw() public {//受益人取钱
  63. require(state == State.Closed);
  64. beneficiary.transfer(address(this).balance);
  65. }
  66.  
  67. /**
  68. * @dev Returns whether refundees can withdraw their deposits (be refunded).
  69. */
  70. function withdrawalAllowed(address _payee) public view returns (bool) {//当账户状态为Refunding时,存钱的人能把存的钱取回
  71. return state == State.Refunding;
  72. }
  73. }

contracts/payment/SplitPayment.sol

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

  1. pragma solidity ^0.4.;
  2.  
  3. import "../math/SafeMath.sol";
  4.  
  5. /**
  6. * @title SplitPayment
  7. * @dev Base contract that supports multiple payees claiming funds sent to this contract
  8. * according to the proportion they own.
  9. */
  10. contract SplitPayment {
  11. using SafeMath for uint256;
  12.  
  13. uint256 public totalShares = ;
  14. uint256 public totalReleased = ;
  15.  
  16. mapping(address => uint256) public shares;//payee所拥有的股份
  17. mapping(address => uint256) public released;//合约已经还给payee的钱
  18. address[] public payees;
  19.  
  20. /**
  21. * @dev Constructor
  22. */
  23. constructor(address[] _payees, uint256[] _shares) public payable {
  24. require(_payees.length == _shares.length);
  25. require(_payees.length > );
  26.  
  27. for (uint256 i = ; i < _payees.length; i++) {//在该合约创建的时候_payee就都加到该合约中了,比例也是早就算好的
  28. _addPayee(_payees[i], _shares[i]);
  29. }
  30. }
  31.  
  32. /**
  33. * @dev payable fallback
  34. */
  35. function () external payable {}
  36.  
  37. /**
  38. * @dev Claim your share of the balance.
  39. */
  40. function claim() public {
  41. address payee = msg.sender;
  42.  
  43. require(shares[payee] > );
  44.  
  45. uint256 totalReceived = address(this).balance.add(totalReleased);//就是合约还回去的钱totalReleased+现在合约中有的钱 = 合约总共收到的钱
  46. uint256 payment = totalReceived.mul( //等价于((totalReceived*(shares[payee]/totalShares))-released[payee]),就是通过比例算出本payee发给该合约的钱-之前还的钱released[payee] = 还需要还的钱payment
  47. shares[payee]).div(
  48. totalShares).sub(
  49. released[payee]
  50. );
  51.  
  52. require(payment != );
  53. assert(address(this).balance >= payment);//合约中现在还有的钱要大于payment才能把钱给payee
  54.  
  55. released[payee] = released[payee].add(payment);
  56. totalReleased = totalReleased.add(payment);
  57.  
  58. payee.transfer(payment);
  59. }
  60.  
  61. /**
  62. * @dev Add a new payee to the contract.
  63. * @param _payee The address of the payee to add.
  64. * @param _shares The number of shares owned by the payee.
  65. */
  66. function _addPayee(address _payee, uint256 _shares) internal {
  67. require(_payee != address());
  68. require(_shares > );
  69. require(shares[_payee] == );
  70.  
  71. payees.push(_payee);
  72. shares[_payee] = _shares;
  73. totalShares = totalShares.add(_shares);
  74. }
  75. }

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

openzeppelin-solidity/contracts的代码学习——payment的更多相关文章

  1. openzeppelin-solidity/contracts的代码学习——access

    https://github.com/OpenZeppelin/openzeppelin-solidity/tree/master/contracts/access access - Smart co ...

  2. u-boot代码学习内容

    前言  u-boot代码庞大,不可能全部细读,只能有选择的读部分代码.在读代码之前,根据韦东山教材,关于代码学习内容和深度做以下预先划定. 一.Makefile.mkconfig.config.mk等 ...

  3. Objective-C代码学习大纲(3)

    Objective-C代码学习大纲(3) 2011-05-11 14:06 佚名 otierney 字号:T | T 本文为台湾出版的<Objective-C学习大纲>的翻译文档,系统介绍 ...

  4. ORB-SLAM2 论文&代码学习 ——Tracking 线程

    本文要点: ORB-SLAM2 Tracking 线程 论文内容介绍 ORB-SLAM2 Tracking 线程 代码结构介绍 写在前面 上一篇文章中我们已经对 ORB-SLAM2 系统有了一个概览性 ...

  5. ORB-SLAM2 论文&代码学习 —— 单目初始化

    转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12358458.html 本文要点: ORB-SLAM2 单目初始化 ...

  6. ORB-SLAM2 论文&代码学习 —— LocalMapping 线程

    转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12360913.html 本文要点: ORB-SLAM2 Local ...

  7. Learning Memory-guided Normality代码学习笔记

    Learning Memory-guided Normality代码学习笔记 记忆模块核心 Memory部分的核心在于以下定义Memory类的部分. class Memory(nn.Module): ...

  8. 3.1.5 LTP(Linux Test Project)学习(五)-LTP代码学习

    3.1.5 LTP(Linux Test Project)学习(五)-LTP代码学习 Hello小崔 ​ 华为技术有限公司 Linux内核开发 2 人赞同了该文章 LTP代码学习方法主要介绍两个步骤, ...

  9. Apollo代码学习(七)—MPC与LQR比较

    前言 Apollo中用到了PID.MPC和LQR三种控制器,其中,MPC和LQR控制器在状态方程的形式.状态变量的形式.目标函数的形式等有诸多相似之处,因此结合自己目前了解到的信息,将两者进行一定的比 ...

随机推荐

  1. MQTT再学习 -- MQTT 客户端源码分析

    MQTT 源码分析,搜索了一下发现网络上讲的很少,多是逍遥子的那几篇. 参看:逍遥子_mosquitto源码分析系列 参看:MQTT libmosquitto源码分析 参看:Mosquitto学习笔记 ...

  2. Dynamics CRM 2016/365 窗体中添加按钮

    一.工具下载,及界面介绍 1.下载XrmToolBox工具(XrmToolBox for Microsoft Dynamics CRM/365 CE) 链接:https://www.xrmtoolbo ...

  3. 【Spring】详解spring事务属性

    Spring声明式事务让我们从复杂的事务处理中得到解脱.使得我们再也无需要去处理获得连接.关闭连接.事务提交和回滚等这些操作.再也无需要我们在与事务相关的方法中处理大量的try…catch…final ...

  4. One Person Game(zoj3593+扩展欧几里德)

    One Person Game Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%lld & %llu Submit Status ...

  5. 封装方法公共文件common.js

    /** * Created by Administrator on 2017/3/24. */ /** * 格式化日期 * @param dt 日期对象 * @returns {string} 返回值 ...

  6. sql server: quering roles, schemas, users,logins

    --https://docs.microsoft.com/en-us/sql/relational-databases/security/authentication-access/managing- ...

  7. encodeURIComponent编码时为什么要编码两次

    Why 要对url进行编码? 当使用地址栏提交查询参数时,如果不编码,非英文字符会按照操作系统的字符集进行编码提交到服务器,服务器会按照配置的字符集进行解码,所以如果两者不一致就会导致乱码.   Wh ...

  8. JS中使用document.defaultView.getComputedStyle()、currentStyle()方法获取CSS属性值

    在对网页进行调试的过程中,经常会用到js来获取元素的CSS样式,方法有很多很多,现在仅把我经常用的方法总结如: 1. obj.style:这个方法只能JS只能获取写在html标签中的写在style属性 ...

  9. 本地存储之sessionStorage

    源码可以到GitHub上下载! sessionStorage: 关闭浏览器再打开将不保存数据   复制标签页会连同sessionStorage数据一同复制 复制链接地址打开网页不会复制seession ...

  10. http请求之get和post的区别

    前言:大家现在度娘一下,查得最多的区别,可能就是: “Get把参数写在URL中,Post通过请求体来传参的” “GET没有POST安全,因为Get参数直接显示在URL上” “Get请求在URL中传送的 ...