待字闺中开发了一门区块链方面的课程:《深入浅出ETH原理与智能合约开发》,马良老师讲授。此简书文集记录我的学习笔记。
课程共8节课。其中,前四课讲ETH原理,后四课讲智能合约。
第七课分为三部分:
- Solidity语法之多继承
- ERC20众筹实例之合约分析
- ERC20众筹实例之部署调试
这篇文章是第七课第二部分的学习笔记:ERC20众筹实例之合约分析。(1)
这节课主要讲解了一个众筹合约的代码分析(Open Zeppelin 框架)。这里的众筹,有个高大上的名字叫 ICO 。
ICO(是Initial Coin Offering缩写),首次币发行,源自股票市场的首次公开发行(IPO)概念,是区块链项目首次发行代币,募集比特币、以太坊等通用数字货币的行为。
1、Open Zeppelin Token 分析
这个众筹合约是基于 Open Zeppelin 安全智能合约开发框架来实现的。这个框架下有很多不同的合约,这里主要介绍跟 ERC20 有关的。关于 ERC20 在第五课中有过分析。 ERC20 规范有六个接口组成,在Open Zeppelin 中分解到了 4 个合约来完成。如图。
首先是 ERC20 Basic,这是一个抽象合约,就是它只定义了接口,没实现功能。它是一个最基础的合约,在这个合约中,它定义了三个接口,totalSupply, banlanceOf, transfer。
然后是延伸出 ERC20 合约。它扩展定义了三个新的接口,allowance, transferFrom, approve,依然是没有实现,这是个抽象合约。
再一个是 Basic Token 合约,它继承自 ERC20 Basic,实现了 ERC20 Basic 的三个接口。这里面有一个映射,mapping(address=> uint256),是地址到余额的映射。
Standard Token 继承自 ERC20 ,基本实现了扩展合约中的三个接口。因为它也继承自 Basic Token ,所以它还有 Basic Token 所实现的三个功能。这是一个典型的钻石型多继承关系。这里面的映射相对来说复杂一些,mapping (address => mapping(address => uint256)),允许其它的账户从一个账户取走多少额度。
后面是一个 Mintable Token,类似于一个造币厂的功能,根据有多少人来买,来增加供给量。它还继承自 Ownable 合约,它不但允许在初始时设置合约所有者的所有权,也允许更换所有者。
框架中还用到了 SafeMath Lib,主要是处理一些数学问题,比如防止溢出。
2、Open Zeppelin 代码
在执行了本课第三部分的安装等工作后,可以查看到有关 Open Zeppelin 的代码。接下来分析一下具体的代码。
2.1 ERC20Basic.sol
/node_modules/openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
进入到 /node_modules/openzeppelin-solidity/contracts 目录,执行 vim token/ERC20/ERC20Basic.sol 打开这个文件。
它是一个抽象合约,并没有实现具体的接口,只是定义了这三个接口。如图。第一个是查询总的供给量。第二个是查询特定帐户的余额。第三个是转账。最后还定义了一个事件,记录转账这个事件。
2.2 ERC20.sol
/node_modules/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
这个 ERC20.sol 仍然是一个抽象合约,它继承自 ERC20Basic.sol ,所以在第 3 行引入了 ERC20Basic.sol 的源代码。
它定义了三个接口和一个事件。第一个是 allowance ,意思是 spender 可以从 owner 那里取多少余额。第二个是一个地址到另一个地址的转账操作。第三个是甲方向一个特定的乙方授予一定的额度。最后是记录这个事件,已被应用程度来查询。
2.3 StandardToken.sol
/node_modules/openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol
这个 StandardToken.sol 继承自 ERC20.sol 和 BasicToken.sol,所以在第 3、4 行引入了 这两个合约。
第25、47、59行,分别实现了以下三个接口。
function transferFrom
function approve
function allowance
接下来是两个自定义的接口,不再是 ERC20 中强制规定的接口。
一个是增加余额的额度(第73行),它的实现方式不是直接赋予一个新值,这种方式有漏洞,不安全,在前面的注释中有说明。它是使用原有的值,使用SafeMath增加一个数值,再来更新。避免两次操作(这里不懂)。同时记录下事件。
另一个是相反的操作,减少额度(第89行)。这里有一个例外,就是降低的数值超过了原有的额度,就置为 0 。不例外的情况下,它也是使用 SafeMath 函数,做一个减法,同时记录下事件。
2.4 Ownable.sol
/node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol
这个主要是管理合约的发起人。这种模式很常用,在构造函数中记录合约的发起人,之后一般是增加一个修饰器,专门检查调用这个合约的人是不是合约的发起人。这个合约有个特殊的地方就是,它允许你转发合约所有者的身份。只有合约的所有者才能转让,它会转让一个新的地址,先检查地址是否为空,如果不空,记录这个事件,把所有者设置为新的所有者。
2.5 MintableToken.sol
/node_modules/openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol
这个是造币的合约。它继承自 Ownable.sol 和 StandardToken.sol 合约(第13行),还有两个事件,一个是造币,一个是造币结束。后面是一个布尔值,如果为真,表示造币活动停止(发行结束)。
第 31 行是向一个地址发行代币,这条只有合约的所有者才可以执行。同时还要检查发行活动是否继续。如果都没有问题,先增加总供给量,同时也要对目标地址的余额进行更新,记录下两个事件。
下面 43 的接口也是只能合约的所有者才可以调用。检查是不是正在发行,如果发行活动结束了,就把“结束”设为真,记录下这个事件。
小结,这节课主要讲解了Open Zeppelin 安全智能合约开发框架,并分析了其中的几个代码文件。代码涉及的知识点比较多,平时要注意多积累。
不足之处,请批评指正,谢谢。
课程地址为:深入浅出ETH原理与智能合约开发