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

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

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

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());
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.;

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 = ;
uint256 public totalReleased = ; 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 > ); for (uint256 i = ; 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] > ); 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 != );
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());
require(_shares > );
require(shares[_payee] == ); payees.push(_payee);
shares[_payee] = _shares;
totalShares = totalShares.add(_shares);
}
}

⚠️: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. Asp.Net初学小结

    第一章   1.搭建Asp.net开发环境   1).net FrameWork(VS) 2)IIS(xp:5.1,2003:6.0,vista:70,win7:7.5) C:\Windows\Mic ...

  2. Matlab .asv是什么文件

    有时在存放m文件的文件夹中会出现*.asv asv 就是auto save的意思,*.asv文件的内容和相应的*.m文件内容一样,用记事本和matlab都能打开它.它可以作为*.m文件的"备 ...

  3. cordova极光推送插件使用

    首先是在极光官网注册登录账号,然后创建推送应用,创建完应用之后,点击打开应用,设置应用的包名,保存: 然后回到应用主界面,看到AppKey,以及MasterSecret,这时候MasterSecret ...

  4. 洛谷P3721 [AH2017/HNOI2017]单旋(线段树 set spaly)

    题意 题目链接 Sol 这题好毒瘤啊.. 首先要观察到几个性质: 将最小值旋转到根相当于把右子树变为祖先的左子树,然后将原来的根变为当前最小值 上述操作对深度的影响相当于右子树不变,其他的位置-1 然 ...

  5. 【读书笔记】iOS-属性中的内存管理参数

    一,assign 代表设置时候直接赋值,而不是复制或者保留它. 二,retain. 会在赋值的时候把新值保留.此属性只能用于Object-C对象类型. 三,copy 在赋值时,将新值复制一份,复制工作 ...

  6. 接口自动化 基于python+Testlink+Jenkins实现的接口自动化测试框架[V2.0改进版]

    基于python+Testlink+Jenkins实现的接口自动化测试框架[V2.0改进版]   by:授客 QQ:1033553122 由于篇幅问题,,暂且采用网盘分享的形式: 下载地址: [授客] ...

  7. Android项目实战(三十二):圆角对话框Dialog

    前言: 项目中多处用到对话框,用系统对话框太难看,就自己写一个自定义对话框. 对话框包括:1.圆角 2.app图标 , 提示文本,关闭对话框的"确定"按钮 难点:1.对话框边框圆角 ...

  8. Loading加载页面

    一般页面有四种情况 加载中 :就是滚动页面,后台获取加载的数据,每个页面的数据不同所以就让子类来实现,直接抽象abstract了. 加载失败 :一般都需要点击后重新加载 空页面 :也需要点击后重新加载 ...

  9. Kotlin入门(7)循环语句的操作

    上一篇文章介绍了简单分支与多路分支的实现,控制语句除了这两种条件分支之外,还有对循环处理的控制,那么本文接下来继续阐述Kotlin如何对循环语句进行操作. Koltin处理循环语句依旧采纳了for和w ...

  10. 使用sklearn机器学习库实现线性回归

    import numpy as np  # 导入科学技术框架import matplotlib.pyplot as plt  # 导入画图工具from sklearn.linear_model imp ...