作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
本ERC20令牌教程的目的是演示如何在尽可能短的时间内创建一个ERC20令牌示例.
让我们从基础开始: ERC20令牌是什么?
近年来,ERC20代币规范已经成为以太坊代币的事实上的标准. 换句话说,目前大多数以太坊合约都符合erc20标准. 本文将详细介绍如何创建自己的以太坊令牌, 但在我们开始之前, 让我们仔细看看ERC20标准.
是什么让ERC20令牌如此有吸引力和成功? 有几个因素在起作用:
就像其他以太坊代币一样, ERC20代币合约以智能合约的形式实现,以去中心化的方式在以太坊虚拟机(EVM)上执行.
以太坊智能合约是用Solidity编写的. 虽然存在其他语言,但几乎没有人将它们用于此目的. Solidity类似于JavaScript, 如果你有一些JavaScript的知识, 甚至Java和其他类c语言, 你应该可以毫不费力地找出Solidity中的一段代码, 甚至在你真正掌握Solidity并使用它之前.
这就是乐趣开始的地方, 因为您应该能够立即开始创建简单的ERC20令牌合约. 这是一项直截了当的任务, 非常简单,本文将演示如何在一小时内编写和部署ERC20令牌.
我们将在本演示中创建的ERC20令牌代码将是一个基本实现, 没有太多的花里胡哨. 然而,我在现实世界中见过许多类似的简单代币,它们往往表现得很好.
简单地说, ERC20标准定义了一组由所有ERC20令牌实现的函数,以便与其他合约集成, wallets, 或市场. 这组函数相当简短和基本.
函数totalSupply()公共视图返回(uint256);
函数balanceOf(地址tokenOwner)公共视图返回(uint);
功能允许(地址tokenOwner,地址sender)
公共视图返回(int);
函数transfer(address to, int tokens) public returns (bool);
函数approve(地址支出者,int令牌)公共返回(bool);
函数transferFrom(地址from,地址to, int tokens)公共返回(bool);
ERC20函数允许外部用户,比如a crypto-wallet app, 查找用户的余额,并在适当授权的情况下将资金从一个用户转移到另一个用户.
ERC20智能合约定义了两个特定的事件:
事件审批(地址索引的tokenOwner,地址索引的支出者,
使用uint令牌);
转移(地址索引从,地址索引到,
使用uint令牌);
这些事件将被调用 emitted 当用户被授予从帐户中提取令牌的权限时, 在代币真正转移之后.
除了标准的ERC20函数, 许多ERC20令牌还具有额外的字段,有些已成为ERC20标准的事实上的一部分, 即使不是书面的,也要付诸实践. 下面是这类字段的几个示例.
字符串公共常量名;
字符串公共常量符号;
公共常数小数;
以下是关于ERC20和solid命名的几点:
public
函数可以在契约本身之外访问view
意思是常数I.e. 合约的内部状态不会被函数改变event
Solidity的方式是允许客户使用吗.g. 您的应用程序前端将在合同中的特定事件得到通知如果你已经掌握了基本的Java/JavaScript技能,那么大多数solid语言结构应该是清晰的.
现在我们已经概述了基础知识,并解释了创建ERC20令牌所需的操作, 是时候开始编写一些逻辑了.
首先,我们需要定义两个映射对象. 这是关联数组或键/值数组的Solidity概念:
mapping(address => uint256) balances;
mapping(address => mapping (address => uint256)) allowed;
表达式 mapping(address => uint256)
定义一个键为类型的关联数组 address
-用于表示帐户地址的数字,其值为type uint256
- 256位整数,通常用于存储令牌余额.
第一个映射对象, balances
,将持有每个所有者账户的代币余额.
第二个映射对象, allowed
, 是否包括所有获准从某一特定帐户提款的帐户,以及每个帐户的提款金额.
如你所见, 允许的映射的值字段本身就是将帐户地址映射到其批准的提款金额的映射.
这些映射与所有其他合约字段将存储在区块链中,并将被 mined 导致更改被传播到所有网络用户节点.
区块链存储是昂贵的,你的合同用户将需要以某种方式付费. 因此,您应该始终尝试最小化存储大小并写入区块链.
现在我们已经准备好了所需的数据结构, 我们可以开始实际地将ERC20逻辑写入相应的函数.
我们如何设置ICO代币的数量? Well, 有许多方法可以设置ICO代币的最大数量,这个问题本身可能值得进行长时间的讨论.
为我们的ECR20教程的需要, 我们将使用最简单的方法:在合约创建时设置代币的总量,并将所有代币初始分配给“合约所有者”i.e. 部署智能合约的账户:
uint256 totalSupply_;
构造函数(uint256 total)
totalSupply_ = total;
余额(味精.发送者]= _totalSupply;
}
构造函数是以太坊在部署合约后自动调用的特殊函数. 它通常用于使用由合约的部署帐户传递的参数初始化令牌的状态.
msg
全局变量是由以太坊自己声明和填充的吗. 它包含了履行合同的重要资料. 我们在这里使用的字段: msg.sender
包含执行当前合约功能的以太坊账户.
只有部署帐户可以进入契约的构造函数. 当合同开始时, 此函数将可用的令牌分配给“合约所有者”帐户.
函数totalSupply()公共视图返回(uint256) {
返回totalSupply_;
}
该函数将返回该合约分配的所有令牌的数量,而不管所有者是谁.
函数balanceOf(地址tokenOwner)公共视图返回(uint) {
返回余额(tokenOwner);
}
balanceOf
是否会返回由其所有者地址标识的帐户的当前令牌余额.
功能转移(地址接收者,
uint numTokens)公共返回(bool) {
require(numTokens <= 余额(味精.发送者);
余额(味精.发送方]=余额[msg ..- numTokens;
余额[接收器]=余额[接收器]+ numTokens;
发射传输(味精.发送方,接收方,numTokens);
返回true;
}
正如它的名字所暗示的那样 transfer
函数用于移动 numTokens
从所有者的余额到另一个用户的余额的令牌数量,或 接收机
. 转让的所有人是 msg.sender
i.e. 执行函数的那个, 这意味着只有代币的所有者才能将其转让给其他人.
坚实性断言谓词的方式是 require
. 在这种情况下,转账账户有足够的余额来执行转账. If a require
语句失败, 交易立即回滚,不向区块链中写入任何更改.
在退出之前,函数会触发ERC20事件 转移
允许注册的侦听器对其完成作出反应.
此功能最常用于令牌市场场景.
函数批准(地址委托)
uint numTokens)公共返回(bool) {
允许(味精.[delegate] = numTokens;
发出批准(味精.sender, delegate, numTokens);
返回true;
}
What approve
是允许业主I吗.e. msg.sender
批准一个代理账户(可能是市场本身)从他的账户中提取代币,并将其转移到其他账户.
如你所见, 此功能用于所有者在市场上提供令牌的场景. 它允许市场在不等待事先批准的情况下完成交易.
在执行结束时,该函数将触发一个 Approval
event.
功能津贴(地址拥有人、
地址委托)公共视图返回(uint) {
返回允许(所有者)(委托);
}
此函数将所有者当前批准的令牌数量返回给特定委托, 正如 approve
function.
The transferFrom
函数的对等体 approve
函数,我们之前讨论过. 它允许批准提款的代表将所有者的资金转移到第三方账户.
函数transferFrom(地址所有者,地址买方,
uint numTokens)公共返回(bool) {
require(numTokens <= balances[owner]);
require(numTokens <= 允许(所有者)[味精.发送者);
余额[所有者]=余额[所有者]- numTokens;
允许(所有者)[味精.发送者]=
允许[的][味精.- numTokens;
余额[买方]=余额[买方]+ numTokens;
转移(owner, buyer, numTokens);
返回true;
}
The two require
函数开始处的语句用于验证事务是否合法.e. 所有者有足够的代币进行转移,并且委托(至少)获得批准。 numTokens
撤回.
除了转移 numTokens
从业主到买方的金额,这个函数也减去 numTokens
从代表津贴中. 这基本上允许一个给定额度的委托将其分成几个单独的提款, 哪种是典型的市场行为.
我们可以停在这里,得到一个有效的ERC20实现. 然而,我们想更进一步,因为我们想要一个工业强度的令牌. 这就要求我们使代码更加安全, 尽管我们仍然能够保持令牌相对简单, 如果不是基本的.
SafeMath Solidity库的目的是处理已知黑客破坏合约的一种方式:整数溢出攻击. 在这样的攻击中, 黑客通过传递接受相关整数的参数来强制合约使用不正确的数值 past 它们的最大值.
SafeMath 通过在执行算术操作之前测试溢出来防止这种情况, 从而消除了溢出攻击的危险. 该库非常小,因此对合同规模的影响很小, 不会产生性能和很少的存储成本损失.
让我们添加 SafeMath 对于我们的代码:
library SafeMath{//只使用相关函数
函数sub(uint256 a, uint256 b)内部纯返回(uint256) {
assert(b <= a);
返回a - b;
}
函数add(uint256 a, uint256 b)内部纯返回(uint256) {
Uint256 c = a + b;
assert(c >= a);
返回c;
}
}
SafeMath uses assert
语句来验证所传递参数的正确性. Should assert
fail, 函数执行将立即停止,所有区块链更改将回滚.
接下来,让我们添加以下语句,将库引入Solidity编译器:
使用SafeMath for uint256;
然后,我们用SafeMath函数替换一开始使用的朴素算法:
余额(味精.发送方]=余额[msg ..sender].子(numTokens);
余额[接收方]=余额[接收方].添加(numTokens);
结余[买方]=结余[买方].添加(numTokens);
余额[所有者]=余额[所有者].子(numTokens);
在Solidity中,智能合约的功能和事件被包装到一个名为a的实体中 contract 您可以将其默默地转换为“区块链类”.下面是我们创建的erc20兼容合约,包括代码要点. 名称和符号字段可以随意更改. 大多数令牌将十进制值保持在18,所以我们也将这样做.
时间到了 将我们的合约部署到区块链上. 部署完成后,我们的合同将被转移到参与网络的所有节点. 对合约所做的任何更改都将传播到所有参与节点.
以太坊开发人员通常使用部署工具,例如 Truffle. 即使是松露对于本文有限的需求来说也是多余的,一个简单的在线工具叫做 Remix 就足够了.
要使用它,您需要安装 MetaMask插件 在您的浏览器和一个Rinkeby(以太坊测试网络)帐户中至少有一些Rinkeby Ether. 这些都是相对简单的步骤,因此我们不会详细讨论.
如果你都没有,请前往 MetaMask and Rinkeby 下载链接,并获得清晰的安装和使用说明.
现在我们已经有了所有的构建块,我们将前往 Remix 并将上面的代码(包括编译行和SafeMath库)粘贴到在线编辑器中.
然后,我们将跳转到右边的第二个选项卡,名为"Run,然后点击"Deploy.“MetaMask将弹出,要求我们确认交易. 当然,我们会批准的.
Gist: http://gist.github.com/giladHaimov/8e81dbde10c9aeff69a1d683ed6870be#file-basicerc20-sol
Congrats! 您刚刚部署了第一个ERC20令牌,就像true一样 Ethereum专业. 正如所承诺的, 令牌简单且轻量级, 但功能齐全, 符合ERC20标准, 并使用MathSafe进行保护. 它可以通过区块链进行购买、支付和转移.
No, 差远了, 因为我们的简短演示仅仅触及了智能合约开发的一个方面.
根据您的业务逻辑,智能合约可能会复杂得多, 您对用户交互的建模, 是否允许代币铸造和燃烧, 您引入契约的生命周期更改, 对管理员级功能的需求,通常伴随着一组管理员授权的功能, 等等......。. 你懂的.
Still, 如果你能复制我们在这里所做的, 这是一个坚实的基础,可以扩展你的知识,并在必要时处理更复杂的合同.
智能合约是在以太坊虚拟机上执行的一段代码. 以太坊智能合约是不可变的,可以发送或接收以太和数据.
简而言之,ERC20令牌是实现ERC20标准的合约. 这些合约处理的操作包括获取代币的总供应量和余额, 以及转移它们的方法.
以太坊的开发目前在Solidity中进行, 受JavaScript启发的一种面向契约的编程语言, Python, and C++.
ERC代表以太坊请求评论. 数字20被分配给这个请求,因此有后缀.
世界级的文章,每周发一次.
世界级的文章,每周发一次.