在开始所有之前,先确定已经完成了上两篇文章的内容。
EOS开发入门1 -- 环境搭建
EOS开发入门2 -- 钱包与账户
创建一个新账户
创建账户命令格式为:
cleos create account [OPTIONS] creator name OwnerKey ActiveKey
- cleos create account 命令
- creator 用于创建新帐号的帐号名
- name 新帐号名
- OwnerKey 所有权的key,是这个帐号的最高权限,可以用来设置active权限
- ActiveKey 操作权的key
$ cleos create account eosio eosio.token EOS7ijWCBmoXBi3CgtK7DJxentZZeTkeUnaSDvyro9dq7Sd1C3dC4 EOS7ijWCBmoXBi3CgtK7DJxentZZeTkeUnaSDvyro9dq7Sd1C3dC4
...
我们使用eosio这个系统默认账户创建了eosio.token账户
部署合约
我们准备部署eosio.token这个合约,这个合约名和我们刚创建的账户名相同,这个合约也是eosio源码自带的。位置在eosio源码/build/contracts/eosio.token
部署合约的命令形式为:
cleos set contract [OPTIONS] account contract-dir [wast-file] [abi-file]
- cleos set contract 命令
- acount 用于部署的帐号名称
- contract-dir 合约所在目录
- -p 可选参数,使用指定的账户和权限进行合约部署,默认值为account@active
$ cleos set contract eosio.token build/contracts/eosio.token -p eosio.token
Reading WAST...
Assembling WASM...
Publishing contract...
executed transaction: 528bdbce1181dc5fd72a24e4181e6587dace8ab43b2d7ac9b22b2017992a07ad 8708 bytes 10000 cycles
# eosio <= eosio::setcode {"account":"eosio.token","vmtype":0,"vmversion":0,"code":"0061736d0100000001ce011d60067f7e7f7f7f7f00...
# eosio <= eosio::setabi {"account":"eosio.token","abi":{"types":[],"structs":[{"name":"transfer","base":"","fields":[{"name"...
对照命令参数应该容易理解命令的含义
创建EOS的token
我们先看下eosio.token合约的接口文件:eosio源码下contracts/eosio.token/eosio.token.hpp
void create( account_name issuer,
asset maximum_supply,
uint8_t can_freeze,
uint8_t can_recall,
uint8_t can_whitelist );
void issue( account_name to, asset quantity, string memo );
void transfer( account_name from,
account_name to,
asset quantity,
string memo );
我们看到这里的三个公有方法:
- create用于创建token,参数包括token的发布账户,最大供应量,是否可冻结,是否可召回,是否包含白名单。
- issue用于从当前账户向指定账户发送token,参数包括目标账户,发送数量,备注
- transfer用于从一个账户向另一个账户转移token,除了多一个源账户外,其它参数同issue
调用合约方法的命令
cleos push action [OPTIONS] contract action data
- cleos push action 命令
- contract 合约名
- action 合约的方法名
- data 给方法传参
$ cleos push action eosio.token create '[ "eosio", "1000000000.0000 EOS", 0, 0, 0]' -p eosio.token
executed transaction: 0e49a421f6e75f4c5e09dd738a02d3f51bd18a0cf31894f68d335cd70d9c0e12 260 bytes 1000 cycles
# eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 EOS","can_freeze":0,"can_recall":0,"can_whitelis...
或者使用更明确的命名参数的方式调用方法
$ cleos push action eosio.token create '{"issuer":"eosio", "maximum_supply":"1000000000.0000 EOS", "can_freeze":0, "can_recall":0, "can_whitelist":0}' -p eosio.token
executed transaction: 0e49a421f6e75f4c5e09dd738a02d3f51bd18a0cf31894f68d335cd70d9c0e12 260 bytes 1000 cycles
# eosio.token <= eosio.token::create {"issuer":"eosio","maximum_supply":"1000000000.0000 EOS","can_freeze":0,"can_recall":0,"can_whitelis...
通过这个命令我们创建了一个新的token,名称为EOS,这个token包含4位小数,最大供应量为1000000000.0000 EOS
调用这个命令创建token,我们必须拥有eosio.token合约的所有权,因为它是'EOS'命名空间的拥有者.
因为这个原因,我们必须在命令中加入参数 -p eosio.token 来授权本次调用
将token发放给user账户
现在我们已经创建了token,可以向之前创建的user账户发送token了:
$ cleos push action eosio.token issue '[ "user", "100.0000 EOS", "memo" ]' -p eosio
executed transaction: 822a607a9196112831ecc2dc14ffb1722634f1749f3ac18b73ffacd41160b019 268 bytes 1000 cycles
# eosio.token <= eosio.token::issue {"to":"user","quantity":"100.0000 EOS","memo":"memo"}
>> issue
# eosio.token <= eosio.token::transfer {"from":"eosio","to":"user","quantity":"100.0000 EOS","memo":"memo"}
>> transfer
# eosio <= eosio.token::transfer {"from":"eosio","to":"user","quantity":"100.0000 EOS","memo":"memo"}
# user <= eosio.token::transfer {"from":"eosio","to":"user","quantity":"100.0000 EOS","memo":"memo"}
这次输出包括几个不同的操作:一个发送(issue)和三个转移(transfer),虽然我们仅签名了issue操作。issue执行了一个内联转移(inline transfer),该内联转移通知发送账户和接收账户。命令行的输出显示了所有被调用的操作处理程序,调用的顺序,以及这些操作产生的输出。
从技术上来说,eosio.token合约可以跳过内联转移而直接修改账户余额。但是这里的处理方式是更好的实践方式。即所有账户余额可以通过转移行为来推导出。这里还通知了token的发送账户和收款账户,以便触发其相应的自动操作,处理存款和提款。
我们再次进行相同的操作,但是添加两个参数:
- -d 不在网络中广播交易,仅将其输出到标准输出设备
- -j 以json格式输出结果
$ cleos push action eosio.token issue '["user", "100.0000 EOS", "memo"]' -p eosio -d -j
{
"expiration": "2018-04-01T15:20:44",
"region": 0,
"ref_block_num": 42580,
"ref_block_prefix": 3987474256,
"net_usage_words": 21,
"kcpu_usage": 1000,
"delay_sec": 0,
"context_free_actions": [],
"actions": [{
"account": "eosio.token",
"name": "issue",
"authorization": [{
"actor": "eosio",
"permission": "active"
}
],
"data": "00000000007015d640420f000000000004454f5300000000046d656d6f"
}
],
"signatures": [
"EOSJzPywCKsgBitRh9kxFNeMJc8BeD6QZLagtXzmdS2ib5gKTeELiVxXvcnrdRUiY3ExP9saVkdkzvUNyRZSXj2CLJnj7U42H"
],
"context_free_data": []
}
向tester账户转移token
现在user账户已经拥有了token,我们将user账户的token转移一部分至tester账户。因为这次是对user账户做转出操作,所以需要使用user的账户对操作进行授权。 -p user
$ cleos push action eosio.token transfer '[ "user", "tester", "25.0000 EOS", "m" ]' -p user
executed transaction: 06d0a99652c11637230d08a207520bf38066b8817ef7cafaab2f0344aafd7018 268 bytes 1000 cycles
# eosio.token <= eosio.token::transfer {"from":"user","to":"tester","quantity":"25.0000 EOS","memo":"m"}
>> transfer
# user <= eosio.token::transfer {"from":"user","to":"tester","quantity":"25.0000 EOS","memo":"m"}
# tester <= eosio.token::transfer {"from":"user","to":"tester","quantity":"25.0000 EOS","memo":"m"}
部署Exchange合约
与之前的部署方式相同,我们来部署exchange合约,可以理解为交易所合约。该合约提供了创建和交易token的功能。下面的命令假定当前处于eos源码的根目录:
$ cleos create account eosio exchange EOS7ijWCBmoXBi3CgtK7DJxentZZeTkeUnaSDvyro9dq7Sd1C3dC4 EOS7ijWCBmoXBi3CgtK7DJxentZZeTkeUnaSDvyro9dq7Sd1C3dC4
executed transaction: 4d38de16631a2dc698f1d433f7eb30982d855219e7c7314a888efbbba04e571c 364 bytes 1000 cycles
# eosio <= eosio::newaccount {"creator":"eosio","name":"exchange","owner":{"threshold":1,"keys":[{"key":"EOS7ijWCBmoXBi3CgtK7DJxe...
$ cleos set contract exchange build/contracts/exchange -p exchange
Reading WAST...
Assembling WASM...
Publishing contract...
executed transaction: 5a63b4de8a1da415590778f163c5ed26dc164c960185b20fd834c297cf7fa8f4 35172 bytes 10000 cycles
# eosio <= eosio::setcode {"account":"exchange","vmtype":0,"vmversion":0,"code":"0061736d0100000001f0023460067f7e7f7f7f7f00600...
# eosio <= eosio::setabi {"account":"exchange","abi":{"types":[{"new_type_name":"account_name","type":"name"}],"structs":[{"n...
这里的命令做了两件事情:
- 第一是创建了一个新的账户exchange。
- 第二是用新创建的exchange账户部署了exchange合约。
这个合约是eos源码自带的,位置在build/contracts/exchange。
我觉得这里有些不好的地方,就是账户名和合约名都使用了完全相同的名称,容易弄混淆,但是这是官方教程提供的,我也是照做。
另外需要注意的地方是,生成账户的秘钥是使用的秘钥对中的公钥,不要弄错了。这里的秘钥是官方教程里的,实际上生成的秘钥跟这个不一样,用自己的秘钥替换这里的示例。
部署Eosio.msig合约
eosio.msig合约允许对单个交易进行异步方式的多重签名。EOSIO框架本身也提供了对多重签名(multisig)的支持。但是需要一个同步的侧通道(side channel),对在这个通道中传输的数据进行签名。Eosio.msig合约则是一个对用户更加友好的多重签名方式,可以异步对交易进行多重签名并发布。
以下步骤用来部署eosio.msig合约:
$ cleos create account eosio eosio.msig EOS7ijWCBmoXBi3CgtK7DJxentZZeTkeUnaSDvyro9dq7Sd1C3dC4 EOS7ijWCBmoXBi3CgtK7DJxentZZeTkeUnaSDvyro9dq7Sd1C3dC4
# eosio <= eosio::newaccount {"creator":"eosio","name":"eosio.msig","owner":{"threshold":1,"keys":[{"key":"EOS7ijWCBmoXBi3CgtK7DJ...
$ cleos set contract eosio.msig build/contracts/eosio.msig -p eosio.msig
Reading WAST...
Assembling WASM...
Publishing contract...
executed transaction: a113a7db8c878dfd894671792770b59a04efb3aa8295f5b3d585daf89c314ec9 8964 bytes 10000 cycles
# eosio <= eosio::setcode {"account":"eosio.msig","vmtype":0,"vmversion":0,"code":"0061736d0100000001bd011b60047f7e7e7f0060047...
# eosio <= eosio::setabi {"account":"eosio.msig","abi":{"types":[{"new_type_name":"account_name","type":"name"},{"new_type_na...
这里的部署与前面相同,创建帐号eosio.msig,并部署位于build/contracts/eosio.msig目录下的eosio.msig合约