EOS开发(1.3-1.4)以上版本 智能合约DAPP全栈使用指南

96
cowkeys
0.1 2018.10.27 12:09* 字数 1334

前言

时间 2018-10-26
EOS 1.4.1 github链接
EOS-CDT 1.3.2 github链接
注:
1 本文针对 对EOS稍微有一点基础的以及从ETH转EOS开发的开发者,会在测试网络jungle中进行调试,从创建账号开始一直介绍到部署合约以及合约中转账和权限等问题,本文会同步更新。因为eos项目更新较为频繁,并且eos智能合约的c++语法库最近有变化,因此使用最新的版本来开始做示例。
2 任何疑问可以添加文末的微信以及知识星球,我们是专业的开发讨论组

一、使用工具和前序教程介绍 (部分基础步骤省略)

1 git clone EOS官方库 并按提示编译项目得到 $ cleos 等命令 (该命令用来做参与查询以及部署合约上链的操作)
2 强烈建议 参考官方的【getting start】 因为网上的教程基本都是搬运的这里。
3 git clone EOSCDT-合约工具库 编译项目得到$ eosio-cpp命令 用来编译合约成abi等文件。
4 如果已经有了eos旧版本的合约编写经验,可以参考 新旧版本区别
5 EOS前序教程及笔记

二、创建账号(创建jungle测试节点账号以及如何使用scatter插件)

A 创建一个eos账号

1 进入 JUNGLE测试节点官网地址 (jungle 类似以太坊中的kovan等测试节点)

image.png

2 用cleos 创建秘钥对 (公钥和私钥)

注:eos的账号一般是12个字符(a-z,1-5)组成,可以加小数点. 组成,每一个账号需要两个秘钥对来支持: 一个作为active,一个作为owner,可以理解为一个账号有两个子账号,权限不同而已,当然两个子账号可以使用同样的秘钥对,这样简单但是会有一点风险。每一笔交易都需要指定一个子账号作为发起者 一般用active权限的就够了。我们下面所有的操作都使用以下这一个秘钥对来做介绍。

$ cleos create key --to-console
Private key: 5K9fLKJ6K9ivadLASiXG8oS5qYsUdb2JP8ZNwK7phEi93hFLRTU
Public key: EOS5hSo21o6VXdZ4SM7UXv7u3uiVZ6oeVU7wxfWsxoQ5DFzVNAcRs

3 在jungle界面 选择 创建账号。


image.png

4 输入一个符合要求的账户名(注意 这个以后就是你的eos转账地址了,类似以太坊的钱包地址)
【本文以【abcdefg12345】为例】

5 输入公钥 publickey(两个输入框都填入public key! 私钥后面会用到 仅仅用来导入钱包!) 点击创建账号

6 如无意外 账号已经创建成功,可以点击 account info 查看是否创建成功

7 点击faucet 输入账号 能够获取测试用的100eos。

B 导入scatter

1 scatter下载

使用chrome浏览器,下载scatter插件。初次进入需要输入密码等操作,进入之后可以在设置中将语言调整为中文。


image.png

2 将jungle网络加入scatter

设置-> 网络 -> 新建
在需要填写的空白处填入以下内容 然后保存
域名: jungle.eosio.cr
端口: 443
chainid: 038f4b0fc8ff18a4f0842a8f0564611f6e96e8535901dd45e43ac8691a1c4dca


image.png

3 导入秘钥对

点击 -> 秘钥对 -> 新建
随意输入一个名称jungletest 以及私钥(输入私钥后 公钥会自动出来)

4 导入身份

点击 -> 身份 -> 新建
选择刚刚导入的 jungle 网络 和 秘钥对jungletest
点击导入 会等待几秒后 出现 两个账户名(xxx@active 和 xxx@owner)
选择一个账户之后 保存。
身份已经导入成功。

三、合约编编写 (C++语法以及合约基础架构不知道请事先了解或看前序教程笔记)

1 helloworld 示例
2 语法重点部分 (只介绍部分语法)。

(a). 新版的修改有很多 例如 account_name 类型 symbol类型的变化等等 可以看上面的新旧版本区别
(b). 程序入口 这是一个模板 ,类似路由 可以直接使用

extern "C"
{
    void apply(uint64_t receiver, uint64_t code, uint64_t action)
    {
        print(name{receiver}, name{code}, name{action});
        if (code == receiver)
        {
            switch (action)
            {
                EOSIO_DISPATCH_HELPER(examplecontractname, (func1)(func2))
            }
        }
        else if (code == "eosio.token"_n.value && action == "transfer"_n.value)
        {
            execute_action(name(receiver), name(code), &examplecontractname::transfer);
        }
    }
};

(c) Multi Index table 结构

struct [[eosio::table]] bet
    {
        uint64_t key;
        uint64_t level;
        name player;
        int result;
        uint64_t primary_key() const { return key; }
        uint64_t by_level() const { return level; }
        EOSLIB_SERIALIZE( bet, (key)(level)(player)(result) )
    };

typedef eosio::multi_index<name("bet"), bet, indexed_by<name("level"), const_mem_fun<cbet, uint64_t, &cbet::by_level>>> betting;
betting _bets;

(d) transfer方法rewrite (这一段是手写, 基本用法应该都在里面)

ACTION transfer(name from, name to, asset quantity, string memo)
    {
        require_auth(from);
        eosio_assert(quantity.is_valid(), "Invalid token transfer...");
        eosio_assert(quantity.symbol == EOS_SYMBOL, "only EOS token is allowed");
        eosio_assert(quantity.amount > 0, "must buy a positive amount");

        print("\n ontransfer from:", from, " to:", to, " quantity:", quantity, " memo:", memo);
        if (to != _self)
            return;

        // 查询 根据第二索引
        auto level_index = _currentbets.get_index<name("level")>();
        uint32_t findindex = quantity.amount;
        auto itr = level_index.find(findindex);
        if (itr != level_index.end())
        {
               // 保存
                _bets.emplace(get_self(), [&](auto &p) {
                    p.key = _bets.available_primary_key();
                    p.level = itr->level;
                    p.player = itr->player;
                    p.result = res;
                });

                // 修改
               level_index.modify(itr, get_self(), [&](auto &p) {
                    p.player1 = iname;
                    p.player2 = iname;
                    p.invest = 0;
          });
         
          // 转账 
          asset reward(amount, quantity.symbol);
          action(
                    permission_level{get_self(), "active"_n},
                    "eosio.token"_n,
                    "transfer"_n,
                    std::make_tuple(get_self(), to, reward, std::string("reward")))
                    .send();
        }
    };
3 当你写好你的逻辑之后 使用编译命令可以得到 abi文件 example.abi
$ eosio-cpp -I include -o example.wasm example.cpp --abigen

四 部署合约 及相关命令

1 先要 为账户购买RAM 以及cpu 和net (命令使用-u 来远程连接jungle节点)

#抵押EOS追加网络和CPU资源
$ cleos system delegatebw <本人账户名> <代币发行账户名>  '0.1 EOS'  '1 EOS'
$ cleos -u http://jungle.cryptolions.io:18888 system delegatebw abcdefg12345 abcdefg12345  '0.1 EOS'  '1 EOS'

#购买内存资源
$ cleos system buyram <本人账户名> <代币发行账户名>  '1 EOS'
$ cleos -u http://jungle.cryptolions.io:18888 system buyram abcdefg12345 abcdefg12345 '1 EOS'

2 部署合约

$ cleos -u http://jungle.cryptolions.io:18888 set contract example /work/dapp/eosproject/example -p abcdefg12345@active

3 发起转账action

注:dapp应用或游戏 很多靠转账的接口transfer 这个接口可以看成是合约固定的接口,可以把逻辑写在transfer接口中,当玩家转账给该合约账户,则会执行相应的游戏逻辑。

# bob是另一个测试账号,用bob这个玩家来对合约进行转账 2 eos (小数点需要写4位)
$ cleos -u http://jungle.cryptolions.io:18888 push action eosio.token transfer '[ "bob", "abcdefg12345", "2.0000 EOS", "备注" ]' -p bob@active;

4 当合约内部写了类似 从合约发送eos奖励给玩家 的逻辑时 需要赋予合约 转账的权限

cleos set account permission abcdefg12345 active '{"threshold": 1,"keys": [{"key":"EOS5hSo21o6VXdZ4SM7UXv7u3uiVZ6oeVU7wxfWsxoQ5DFzVNAcRs", "weight":1}],"accounts": [{"permission":{"actor":"abcdefg12345","permission":"eosio.code"},"weight":1}]}' owner -p abcdefg12345

5 查询账户余额

$ cleos -u http://jungle.cryptolions.io:18888 get currency balance eosio.token abcdefg12345 EOS

6 查询合约内部定义的struct table

$ cleos -u http://jungle.cryptolions.io:18888 get table abcdefg12345 abcdefg12345 table

未完待续... 下篇会讲到如何使用EOS.js 来调用合约

对了 欢迎加入我们分享开发经验

如果qr过期可以留言
知识星球【新】:


知识星球

微信2群:


微信2群
blockchain
Web note ad 1