一文读懂以太坊代币合约

在以太坊系统中,存在作为基础货币的 Ether(以太),以及同样可以作为货币使用的 Token(代币)。

以太坊与其他加密货币的主要不同在于,以太坊不是单纯的货币,而是一个环境/平台。在这个平台上,任何人都可以利用区块链的技术,通过智能合约来构建自己的项目和DAPPS(去中心化应用)。

如果把以太坊理解成互联网,DAPPS则是在上面运行的网页。DAPPS是去中心化的,意味着它不属于某个人,而是属于一群人。DAPPS发布的方式通常是采用被称为 ICO 的众筹方式。简单来说,你需要用你的以太来购买相应DAPP的一些tokens。

类比到股权,可以把 Usage Tokens 简单理解为普通流通股,可以与真实货币兑换,本身具有价值。而 Work Token,则大致相当于投票权。

不是有以太基础货币了,那为什么还需要 token 呢?可以想下现实生活的真实场景,在游乐场里,我们需要用现金兑换代币,然后用代币支付各种服务。 类比到以太坊,现金就是以太,代币就是 token,用 token 来执行合约中的各项功能。

这个是本文学习的重点,所有遵循 ERC20 标准的函数,都要事先它定义的标准接口。搞懂这些,你也就能很快看懂一些智能合约代币的逻辑。

ERC-20 标准是在2015年11月份推出的,使用这种规则的代币,表现出一种通用的和可预测的方式。任何 ERC-20 代币都能立即兼容以太坊钱包(几乎所有支持以太币的钱包,包括Jaxx、MEW、imToken等),由于交易所已经知道这些代币是如何操作的,它们可以很容易地整合这些代币。这就意味着,在很多情况下,这些代币都是可以立即进行交易的。简单理解就是,ERC20是开发者在自己的tokens中必须采用的一套具体的公式/方法,从而确保不同DAPP的token与ERC20标准兼容。

ERC-20 标准规定了各个代币的基本功能,非常方便第三方使用,在开发人员的编程下,5 分钟就可以发行一个 ERC-20 代币。因为它可以快速发币,而且使用又方便,因此空投币和空气币基本上就是利用 ERC-20 标准开发的。基于 ERC-20 标准开发的同种代币价值都是相同的,它们可以进行互换。ERC-20 代币就类似于人民币,你的 100 元和我的 100 元是没有区别的,价值都是 100 元,并且这两张 100 元可以进行互换。有了这套标准,相当于全世界都使用人民币,而不用去别的国家还要计算汇率换成别的货币。想象下,每个Dapp都有不同格式的币,那对于这些应用的交互简直是种灾难。

talk is cheap show me the code 。前面给的函数说明是简单的概括,大家可能还似懂非懂,下面就将用实例说明。《AMR智能合约漏洞分析》这篇文章用实例讲解了智能合约的一种漏洞,合约代码在,我们就以这个代码做个详细的分析。

这个合约接口的功能是判断和修改该合约的所有者。其中函数 onlyOwner 用到了 modifiers(函数修改器) 关键字。函数修改器可以用来改变一个函数的行为,比如用于在函数执行前检查某种前置条件。如果你了解 python 的装饰器,这个就很容易理解了。还不理解?没关系,我们再详细说明下这个接口。首先你需要理解下这边的几个概念:

2. Ownable() 函数,和合约接口同名,这是个构造函数,只能在创建合约期间运行,不能在事后调用。所以这个owner是创建该合约人的地址,无法被篡改,除非合约创始人授权。

a) 使用账户 A 创建合约,则 owner 则是 A 的地址,切换到用户 B 点击 onlyOwner 函数,看到owner的值是账户 A 的地址。这时候如果点击 transferOwnership 会报错,因为这个函数被 onlyOwner 修饰了,会先判断当前调用合约的是否是合约所有者。当前合约所有者是账户 A,合约调用者账户 B 是没权限转移权限的。

b) 把账户切换到 A,transferOwnership 地址填账户 B,这时候你就可以把合约所有者权限转移给账户 B 了。而再一次执行,发现提示错误了,因为此时合约所有者已经是账户 B,账户 A 没权限。

这边逻辑不复杂,有个概念可能不太好理解,这里详细说明下。allowed 这个变量(类比成二维数组),是用来存取授信的额度,在 approve 函数中定义。

把 allowd 的概念理解了,allowance 函数也就很好理解了,第一个参数 _owner 类比成银行,第二个参数 _spender 类比成用户,这个函数就用来查询用户(_spender)在银行(_owner)剩余的额度(tokens)。通过上述的讲解,可以知道 transfer 和 transferfrom 函数区别如下:

2. transferFrom 则是可以把 ”银行“ 授信额度的钱(tokens)转给自己或者他人,转移的是 “银行” 的 tokens

现在来详细说明下 decimals 这个参数。首先我们来理解下常说的以太(ether)到底是怎么换算的。在以太坊交易中,最小的单位是 wei ,1 ether = 10^18 wei 。单位换算在线地址:

调用合约转发 Token 的时候,传入的值是要转发的 Token 数乘上精度(默认decimals=18),比如转1个Token,传入合约的值是0000 wei

前面把我认为的难点、疑惑点都说完了,想必大家看懂这个合约也没什么难度。看懂合约后,如果看过以太坊智能合约安全漏洞入门之类的文章,应该一看就能看出 multiTransfer 存在溢出漏洞。原理就是 totalTokensToTransfer 没有使用安全函数,可以导致整数上溢出。详情可参考 这篇文章 。下面我们就手动调试下这个漏洞

注意:在 remix 调试时候,传入的数组可以用 [……, ……] 表示,但是地址必须用双引号包裹,传入的数字如果较大也必须用双引号包裹,否则会报错

其实智能合约的代码比平常分析逆向的程序代码都简单多了,只要你掌握 ERC20 的标准几个接口,了解函数修改器的概念以及一些以太坊基本的概念,相信看懂一个 ERC20 标准的合约并不难。也希望大家能把上述分析自己动手实践一下,之前我很多地方也有疑问,通过动手实践很快就明白问题的所在了。如果学习有捷径的话就是多动手,多调试。Solidity 没有打印的函数,有时候会给调试带来不便,下面补个 Solidity 调试的代码,方便大家打印变量值。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注