【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token

简介

本章将深入源码,为大家分析eos的系统合约eosio.token的实现细节。eosio.token是eos的发币合约,这个合约主要实现了EOS代币的创建、发行、转账等功能。

主要合约方法

eosio.token系统合约的源码在eos/contracts/eosio.token中,eos项目方独立开了github,负责eosio.token合约的更新和维护。

eosio.token合约,在eosio.token.hpp头文件中,主要定义了以下三个合约方法:

- create:负责创建资产

- issue:负责发行资产

- transfer:负责资产转账

【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token_第1张图片
eosio.token.hpp头文件中定义的主要方法

下面,将为大家一一介绍各个方法的功能实现细节

create方法

create方法的实现在eosio.token.cpp中,需要传入两个参数完成币种创建:

- issuer:资产发行账户

- maximum_supply:最大发行量

【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token_第2张图片
create方法实现细节

ceate方法调用实例如下,eosio.token合约部署在eosio.token账户,资产发行账户为eosio,最大发行量10亿,币种精度4,币种符号EOS

cleos push action eosio.token create '[ "eosio", "1000000000.0000 EOS"]' -p eosio.token

深入源码来看,create方法通过以下步骤完成了资产的创建:

- 获取eosio.token合约部署账户的授权

- 判断币种符号 (sysmol name) 是否合法,币种符号必须是大写字母,长度小于8位

- 判断发行量是否越界且是否为正数,支持的最大发行量 amount <= 2^62-1

- 查询statstable表,判断代币符号是否存在,eosio.token支持发行多资产

- 建表,将代币符号、发行总量、发行方存入数据库

以上步骤,主要逻辑详见:eos/contracts/eosiolib/symbol.hpp、eos/contracts/eosiolib/asset.hpp、eos/contracts/eosiolib/multi_index.hpp

issue方法

create方法的实现在eosio.token.cpp中,需要传入两个参数完成币种的发行:

- to:发行金额打入的账户

- quantity:发行金额

- memo:交易备注

【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token_第3张图片
issue方法实现细节

issue方法调用实例如下,资产发行账户eosio授权,将10亿EOS打入eosio账户中,备注是test issue

cleos push action eosio.token issue '[ "eosio", "1000000000.0000 EOS", "test issue"]' -p eosio

深入源码来看,issue方法通过以下步骤完成了资产的发行:

- 前置检查:查表判断币种是否存在、memo最大长度不能超过256字节

- 查表获取币种信息:发行账户、最大发行量、币种精度、币种符号

- 获取发行账户的授权

- 前置检查:发行金额为正数且不超过最大发行量、币种精度校验

- 更新表,增加发行资产的余额

- 如果to账户和发行账户不一致,调用内联合约转账

以上步骤,主要逻辑详见:eos/contracts/eosiolib/symbol.hpp、eos/contracts/eosiolib/asset.hpp、eos/contracts/eosiolib/multi_index.hpp、eos/contracts/eosiolib/currency.hpp

这里特别要说明最后一个步骤,内联合约的调用。实现逻辑在eos/contracts/eosiolib/currency.hpp

issue方法最后调用的inline合约方法 - eosio.token的transfer方法

eos智能合约之间,通过action通信,共享数据库存储。一个智能合约,可以异步的读取另一个智能合约的数据库状态。智能合约有两种通信状态:

- Inline 内联合约。指的是在一个已有的交易里调用其他智能合约的方法。如果当前交易失败了,内联合约的执行也不受影响,内联合约执行失败或成功并没有通知,但执行成功会上链

- Deffered 延迟合约。指的是不是立即执行,而是在未来的某个时间计划去执行的合约。当前,可以构造一个交易去发送延迟合约交易,也可以发送一个交易去取消延迟合约。延迟合约也不能保证执行成功,执行失败或者成功并没有通知,但执行成功会上链

在issue方法中,当发现issuer账户和to账户不一致时,会调用lnline合约,触发eosio.token合约的transfer方法,将发行的金额转入to账户。当我们执行issue方法后,会发现除了产生issue的action后,还会有transfer的action:

【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token_第4张图片
inline合约方法调用成功后会上链

transfer方法

transfer方法的实现在eosio.token.cpp中,需要传入四个参数完成币种的转账:

- from:出币账户

- to:入金账户

- quantity:转账金额

- memo:交易备注

【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token_第5张图片
transfer方法的实现细节

深入源码来看,issue方法通过以下步骤完成了资产的转账:

- 前置检查:判断是否转账给自己、判断to账户是否存在

- 获得from账户的授权

- 获取币种信息:发行账户、最大发行量、币种精度、币种符号

- 分别通知from、to账户合约调用结果

- 前置检查:转账金额为正且不超过最大发行量、币种精度正确、memo长度不大于256

- 加减from和to地址账户余额

以上步骤,主要逻辑详见:eos/contracts/eosiolib/symbol.hpp、eos/contracts/eosiolib/asset.hpp、eos/contracts/eosiolib/multi_index.hpp、eos/contracts/eosiolib/currency.hpp

这里特别要说明第四个步骤,通知from、to账户合约调用结果。实现逻辑在eos/contracts/eosiolib/action.hpp、eos/libraries/chain/apply_context.cpp、eos/libraries/chain/transaction_context.cpp

eosio.token的transfer方法调用require_recipient
【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token_第6张图片
将相关账户放入_notified数组中
【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token_第7张图片
封装好trace通知内容,并执行通知
【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token_第8张图片
【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token_第9张图片
trace通知内容封装过程

首先,eosio智能合约的执行结果,会分别通知from、to、eosio.token。我们发送转账交易,会发现有三条actions,通知所有涉及的账户,这是eos系统合约设计的通知机制。大家在执行cleos get actions获取交易结果时,可以通过receiver过滤出发给自己账户的通知。

【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token_第10张图片
transfer方法调用成功后,发送给所有相关账户的通知上链

receipt的通知详情,调用cleos get actions bp1 -j 获取:

【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token_第11张图片

后记

本章为大家介绍了eosio.token合约的实现细节,从源码层面为大家分析了eosio.token如何实现资产的创建、发行、转账的。

目前,基于eos发行资产的项目方,都会参考eosio.token的实现,去实现自己的发币合约。但是,由于eos是一个刚刚完成主网上线的新项目,有许多隐藏的bug有待发现。例如,我们最后讲到的transfer方法的receipt通知机制,由于实现过于复杂,前段时间就被慢雾发现了有严重的安全漏洞,会使交易所的提币账户ram被耗尽,详细issue。

【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token_第12张图片

因此,大家在编写自己的发币合约时,务必要检查好相关逻辑,以免被恶意攻击造成资产的损失。eos社区目前还没有出合约代码的标准规范,但我相信不久的将来,一定会有详细的规范出台。

接下来的文章,将继续从源码层面为大家讲解eos的系统合约实现细节,尽请期待!

你可能感兴趣的:(【eos全家桶系列】eos系统合约介绍 — 发币合约eosio.token)