本文编写了一个简单的EOS智能合约,实现用户管理和资产管理,包括存钱,取钱,转帐的功能,旨在学习如何编写自己的EOS合约功能。

系统:Ubuntu      EOS版本:v1.1.1

  

一.智能合约代码

 #ifndef __AWARD_H__
#define __AWARD_H__ #include <eosiolib/eosio.hpp> namespace eosio { class keephand : public eosio:: contract { private:
/// @abi table userinfo i64
struct st_userinfo {
account_name name;
std::string pubkey; uint64_t get_pubkey() const { return string_to_name(pubkey.data()); }
uint64_t primary_key() const { return name; } EOSLIB_SERIALIZE(st_userinfo, (name)(pubkey))
}; // @abi table
typedef eosio::multi_index<N(userinfo), st_userinfo, indexed_by<N(pubkey), const_mem_fun<st_userinfo, uint64_t, &st_userinfo::get_pubkey>> > user; // @abi table userasset i64
struct st_asset {
account_name name;
double funds; uint64_t primary_key() const { return name; }
//uint64_t get_funds() const { return funds; } EOSLIB_SERIALIZE(st_asset, (name)(funds))
}; // @abi table
typedef eosio::multi_index<N(userasset), st_asset/*, indexed_by<N(funds), const_mem_fun<st_asset, uint64_t, &st_asset::get_funds>>*/ > asset;
private:
static constexpr double fee_rate = 0.01000000; // rate
static constexpr double fee_min = 0.01000000; // the smallest funds of take money once time enum en_fee_type {
EN_TAKE = , // take money
EN_TRANSFER,
}; private:
void create_asset_data_by_account(const account_name name);
void delete_asset_data_by_account(const account_name name); bool is_exist_account(const account_name name);
void funds_option(const account_name& name, const double& funds, bool opt = false); // option: true -- add false--sub
void modify_asset(const account_name& name, const double& funds) const; public:
keephand(account_name self):contract(self) {} // @abi action
void createacnt( const account_name& name, const std::string& pubkey); // @abi action
void deleteacnt(const account_name& name); // @abi action
void modasset(const account_name& name, const double& funds, bool bsaving = false ); // @abi action
void transfer(const account_name& from, const account_name& to, const double& funds, const std::string& str ); }; } EOSIO_ABI(eosio::keephand, (createacnt)(deleteacnt)(modasset) (transfer) ) #endif
 #include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
#include "./keephand.hpp" using namespace eosio; void keephand::createacnt( const account_name& name, const std::string& pubkey) { eosio_assert(name > , "name empty \n");
eosio_assert(pubkey.size() > , "pubkey empty \n"); //check auth
require_auth(_self);
user actns(_self, _self);
auto exist = actns.find(name);
eosio_assert( exist == actns.end(), "name already exists\n"); //modify data
actns.emplace( _self, [&]( auto& n) {
n.name = name;
n.pubkey = pubkey;
}); create_asset_data_by_account(name);
} void keephand::deleteacnt(const account_name& name) { eosio_assert(name > , "name empty \n"); require_auth( _self );
user acnts( _self, _self); auto existing = acnts.find(name);
eosio_assert(existing != acnts.end(), "name not found \n"); acnts.erase(existing);
delete_asset_data_by_account(name);
} void keephand:: create_asset_data_by_account(const account_name name) { asset ass(_self, _self);
ass.emplace(_self, [&](auto& d) {
d.name = name;
d.funds = ;
}); } void keephand::modasset(const account_name& name, const double& funds, bool bsaving ) { eosio_assert( name > , "name empty \n");
eosio_assert( funds > , "funds input error"); user acnts(_self, _self); auto existing_user = acnts.find(name); eosio_assert(existing_user != acnts.end(), "name not foud on userinfo"); //check auth
require_auth(name); asset ass(_self, _self);
auto existing_asset = ass.find(name);
//print("keephand::modasset() find name in asset: ", (existing_asset == ass.end() ? "false" : "true"));
eosio_assert(existing_asset != ass.end(), "name not fund on asset" ); if(existing_asset != ass.end()) { double op_funds = 0.00000000;
if(bsaving) {
op_funds = existing_asset->funds + funds;
} else {
//is enough funds
op_funds = existing_asset->funds - funds - funds * fee_rate;
eosio_assert(op_funds >= , "not enough asset.\n"); auto existing_owner = ass.find(_self);
eosio_assert(existing_owner != ass.end(), " owner user not fund.\n"); ass.modify(*existing_owner, _self , [&]( auto& d ) {
d.name = _self;
d.funds = funds* fee_rate;
});
} ass.modify(*existing_asset, _self , [&]( auto& d ) {
d.name = name;
d.funds = op_funds;
});
}
}
void keephand::delete_asset_data_by_account(const account_name name)
{
asset ass(_self, _self);
auto existing = ass.find(name); if(existing != ass.end()) {
ass.erase(existing);
//print("delete asset name=", name);
}
} void keephand::transfer(const account_name& from, const account_name& to, const double& funds, const std::string& strremark ) {
eosio_assert( from > , "from empty \n");
eosio_assert( to > , "to empty \n");
eosio_assert(funds > , "funds error \n"); require_auth(from); eosio_assert(is_exist_account(to), "fund receiver user failed on userinfo table. \n"); asset ass(_self, _self); auto existing_from = ass.find(from);
eosio_assert(existing_from != ass.end(), "fund sender failed.\n"); double fee = funds * fee_rate;
if(fee < fee_min) {
fee = fee_min;
}
double asset_sender = existing_from->funds - fee - funds;
eosio_assert(asset_sender >= 0.00000000, " sender not enough asset."); funds_option(from, fee + funds, false); auto existing_to = ass.find(to);
eosio_assert(existing_to != ass.end(), "fund receiver failed on asset table\n");
funds_option(to, funds, true ); auto existing_self = ass.find(_self);
eosio_assert(existing_self != ass.end(), "fund self failed on asset table\n");
funds_option(_self, fee, true );
} bool keephand::is_exist_account(const account_name name) {
user acnts(_self, _self);
auto idx = acnts.find(name); return idx != acnts.end();
} void keephand::funds_option(const account_name& name, const double& funds, bool opt) {
asset ass(_self, _self);
auto idx = ass.find(name);
eosio_assert(idx != ass.end(), "fund name failed. \n"); double user_asset = 0.00000000;
if(opt) {
user_asset = idx->funds + funds;
} else {
user_asset = idx->funds - funds;
} eosio_assert(user_asset >= , "asset not enought. \n"); modify_asset(name, user_asset);
} void keephand::modify_asset(const account_name& name, const double& funds) const {
asset ass(_self, _self);
auto idx = ass.find(name);
eosio_assert(idx != ass.end(), "fund name failed on asset table. \n"); ass.modify(*idx, _self , [&]( auto& a ) {
a.name = name;
a.funds = funds;
});
}

二.测试流程:

1.创建用户 eoskeephand2  与 eoseosbright
//owner
5JYQB6xwraFX53yaMnhht5bnceZRdS8fFQR2jxdeAFcj5DVjHK9
EOS7er3MePm841zP3VKzCvUhcbqwEy9BRXthZCBZu7ihPfvP4Rtg4
//active
5Jw9zKATACsqtTHJam4ciVYWoh9EBny93L1nswyazQjnEoUa9by
EOS723pRnWd43Lu53LWUq7ciVrmUXvADUoVsjo3ZhDHBi8jDWduYD 创建钱包
cleos --wallet-url http://127.0.0.1:8901 wallet create -n walletkeephand2
PW5JqBoV8GQhVP9GPrJwN7N4oGQ9yrm53LdjST6gYD862eeKM5aWb //导入钱包
cleos --wallet-url http://127.0.0.1:8901 wallet import -n walletkeephand2 --private-key 5JYQB6xwraFX53yaMnhht5bnceZRdS8fFQR2jxdeAFcj5DVjHK9
cleos --wallet-url http://127.0.0.1:8901 wallet import -n walletkeephand2 --private-key 5Jw9zKATACsqtTHJam4ciVYWoh9EBny93L1nswyazQjnEoUa9by //创建eoskeephand2用户
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.141:8888 system newaccount --transfer hml eoskeephand2 EOS7er3MePm841zP3VKzCvUhcbqwEy9BRXthZCBZu7ihPfvP4Rtg4 EOS723pRnWd43Lu53LWUq7ciVrmUXvADUoVsjo3ZhDHBi8jDWduYD --stake-net "200.0000 SYS" --stake-cpu "200.0000 SYS" --buy-ram "200.0000 SYS"
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.141:8888 transfer hml eoskeephand2 "200.0000 SYS" cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.141:8888 system newaccount --transfer hml eoseosbright EOS7er3MePm841zP3VKzCvUhcbqwEy9BRXthZCBZu7ihPfvP4Rtg4 EOS723pRnWd43Lu53LWUq7ciVrmUXvADUoVsjo3ZhDHBi8jDWduYD --stake-net "200.0000 SYS" --stake-cpu "200.0000 SYS" --buy-ram "200.0000 SYS"
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.141:8888 transfer hml eoseosbright "200.0000 SYS" 重复上面步骤自己创建一个用户 eoseosbright 2.编译与加载合约
eosiocpp -o keephand.wast keephand.cpp
eosiocpp -g keephand.abi keephand.cpp //加载合约
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 set contract eoskeephand2 ~/eos/contracts/keephand/ -p eoskeephand2 //查询数据库
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 get table eoskeephand2 eoskeephand2 userinfo
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 get table eoskeephand2 eoskeephand2 userasset 3.增加合约创建者用户
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 createacnt '{"name":"eoskeephand2","pubkey":"EOS723pRnWd43Lu53LWUq7ciVrmUXvADUoVsjo3ZhDHBi8jDWduYD"}' -p eoskeephand2 以后的手率费都会放在这个用户下面 4.创建其它的一些用户usera,userb,userc
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 createacnt '{"name":"eoseosbright","pubkey":"EOS8KjRh1QFLqNECdqg7QXiBnv3F2DhVSQDdSkeFJX2ZLkR13p8Cs"}' -p eoskeephand2
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 createacnt '{"name":"eosxiaomingg","pubkey":"EOS8YHwHXqEdBcNLdNud4Uuste5kbsPyHwSzMuUWCygVHYNr7Gk7r"}' -p eoskeephand2
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 createacnt '{"name":"usera","pubkey":"EOS8Hn8Bbp5oska1LULgHFr2JPP2pGZmkktdYF5e1c1HBPVBakrBY"}' -p eoskeephand2
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 createacnt '{"name":"userb","pubkey":"EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuEz2RMWhXb8LXxEgcR7MC"}' -p eoskeephand2
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 createacnt '{"name":"userc","pubkey":"EOS6XpxPXQz9zxpRoZwcX7qxZBGM5AW9UXmXx5gPj8TQsce2djSkn"}' -p eoskeephand2 5.清除用户数据
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 deleteacnt '{"name":"eoseosbright","pubkey":"EOS8KjRh1QFLqNECdqg7QXiBnv3F2DhVSQDdSkeFJX2ZLkR13p8Cs"}' -p eoskeephand2
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 deleteacnt '{"name":"eosxiaomingg","pubkey":"EOS8YHwHXqEdBcNLdNud4Uuste5kbsPyHwSzMuUWCygVHYNr7Gk7r"}' -p eoskeephand2
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 deleteacnt '{"name":"usera","pubkey":"EOS8Hn8Bbp5oska1LULgHFr2JPP2pGZmkktdYF5e1c1HBPVBakrBY"}' -p eoskeephand2
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 deleteacnt '{"name":"userb","pubkey":"EOS7Ef4kuyTbXbtSPP5Bgethvo6pbitpuEz2RMWhXb8LXxEgcR7MC"}' -p eoskeephand2
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 deleteacnt '{"name":"userc","pubkey":"EOS6XpxPXQz9zxpRoZwcX7qxZBGM5AW9UXmXx5gPj8TQsce2djSkn"}' -p eoskeephand2 cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 deleteacnt '{"name":"eoskeephand2","pubkey":"EOS723pRnWd43Lu53LWUq7ciVrmUXvADUoVsjo3ZhDHBi8jDWduYD"}' -p eoskeephand2
只有合约所有者才有权限清除 6.存款取款
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 modasset '{"name":"eoseosbright","funds":"1000", "bsaving":"1"}' -p eoseosbright
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 modasset '{"name":"eosxiaomingg","funds":"100", "bsaving":"0"}' -p eosxiaomingg 7.转帐
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 transfer '{"from":"eosxiaomingg","to":"eoseosbright","funds":"100.0000","str":"thanks"}' -p eosxiaomingg 8.单用户查询余额
cleos --wallet-url http://127.0.0.1:8901 --url http://10.186.11.223:8888 push action eoskeephand2 queryasset '{"name":"eosxiaomingg"}' -p eosxiaomingg

三.测试功能

运行到测试步骤的第三步后查看用户信息与资产是这样的

运行第四步再查看

现在我们有六个用户了,对应的初始资产为0,下面为存钱的测试

看到eoseosbright的资产增加了,再做取钱的测试:

eoseosbright的资产减少1010,是因为取钱时收取了1%的手率费,手率费存到合约用户创建者用户eoskeephand2上了,再来做做转帐的测试。

转帐也是收了1%的手率费用的,验证OK。

四.智能合约编写注意事项

1.能够让用户使用的函数名称有限制,只能使用数据加字母,不能加下划线,如下所示:

EOSIO_ABI(eosio::keephand, (createacnt)(deleteacnt)(modasset) (transfer) )

2.代码中类似带@的注释是必须的,否则虚拟机无法编译通过,所以不要漏写或者改写及删除

// @abi table userinfo i64

// @abi table

// @abi action

3.智能合约中多索引数据库使用的索引是uint64_t类型,所以如果你使用其它类型当一级索引或者二级索引不匹配的话会无法通过编译,必须自己进行唯一类型转化(保证键的唯一性),不过这里应该可以进行非唯一索引,暂时没有探究;

有问题请联系QQ:289093099,欢迎大家一起交流学习!

EOS 智能合约编写(一)的更多相关文章

  1. 【精解】EOS智能合约演练

    EOS,智能合约,abi,wasm,cleos,eosiocpp,开发调试,钱包,账户,签名权限 热身 本文旨在针对EOS智能合约进行一个完整的实操演练,过程中深入熟悉掌握整个EOS智能合约的流程,过 ...

  2. EOS智能合约存储实例讲解

    EOS智能合约存储实例 智能合约中的基础功能之一是token在某种规则下转移.以EOS提供的token.cpp为例,定义了eos token的数据结构:typedef eos::token<ui ...

  3. EOS智能合约授权限制和数据存储

    EOS智能合约授权限制和数据存储 在EOS合约中,调用合约需要来自账户的授权,同时还要指定需要调用的动作.当然,有的合约并不是所有账户都可以调用的,这就需要用到授权限制.接下来我们就来看看如何限制合约 ...

  4. EOS智能合约开发(四):智能合约部署及调试(附编程示例)

    EOS智能合约开发(一):EOS环境搭建和创建节点 EOS智能合约开发(二):EOS创建和管理钱包 EOS智能合约开发(三):EOS创建和管理账号 部署智能合约的示例代码如下: $ cleos set ...

  5. EOS智能合约开发(三):EOS创建和管理账号

    没有看前面文章的小伙伴可以看一下 EOS智能合约开发(一):EOS环境搭建和启动节点 EOS智能合约开发(二):EOS创建和管理钱包 创建好钱包.密钥之后,接下来你就可以创建账号了,账号是什么?账号保 ...

  6. EOS智能合约开发(二):EOS创建和管理钱包

    上节介绍了EOS智能合约开发之EOS环境搭建及启动节点 那么,节点启动后我们要做的第一件事儿是什么呢?就是我们首先要有账号,但是有账号的前提是什么呢?倒不是先创建账号,而是先要有自己的一组私钥,有了私 ...

  7. eos智能合约与主进程交互

    eos智能合约与主进程交互 1.启动wasm 参考eos智能合约执行流程.md 2.智能合约调用主进程api 如何实现wasm代码与eos宿主交互还需要摸索! 大致:在wasm_interface.c ...

  8. eos智能合约执行流程

    eos智能合约执行 1. 执行流程 controller::push_transaction()  // 事务 -> transaction_context::exec()  // 事务 -&g ...

  9. eos 智能合约开发体验

    eos编译安装 eos 特性 数据存储 eos投票智能合约开发 eos投票智能合约部署测试 注意避坑 eos编译安装 ERROR: Could not find a package configura ...

随机推荐

  1. JS判断2个时间是否在同一周

    function isSameWeek(old, now) { var oneDayTime = 1000 * 60 * 60 * 24; var old_count = parseInt(+old ...

  2. L99

    You're not obligated to win. You're obligated to keep trying.你不一定要获胜,但你必须不断尝试.He announced an expans ...

  3. ACM学习历程—UESTC 1215 Secrete Master Plan(矩阵旋转)(2015CCPC A)

    题目链接:http://acm.uestc.edu.cn/#/problem/show/1215 题目大意就是问一个2*2的矩阵能否通过旋转得到另一个. 代码: #include <iostre ...

  4. P1607 [USACO09FEB]庙会班车Fair Shuttle

    题目描述 Although Farmer John has no problems walking around the fair to collect prizes or see the shows ...

  5. jraiser小结

    1 合并小结 jrcpl F:\site\js\app --settings package.settings 上面代码的意思,就是说,根据package.settings文件,来对app文件夹下的所 ...

  6. netty中的引导Bootstrap客户端

    一.Bootstrap Bootstrap 是 Netty 提供的一个便利的工厂类, 我们可以通过它来完成 Netty 的客户端或服务器端的 Netty 初始化.下面我以 Netty 源码例子中的 E ...

  7. 人物-IT-雷军:雷军

    ylbtech-人物-IT-雷军:雷军 雷军 (全国工商联副主席,小米科技创始人.董事长) 雷军,1969年12月16日出生于湖北仙桃,毕业于武汉大学,是中国大陆著名天使投资人.  雷军作为中国互联网 ...

  8. 奇异值分解(SVD)详解

    2012-04-10 17:38 45524人阅读 评论(18) 收藏 举报  分类: 数学之美 版权声明:本文为博主原创文章,未经博主允许不得转载. SVD分解 SVD分解是LSA的数学基础,本文是 ...

  9. Java学习路线-知乎

    鼬自来晓 378 人赞同 可以从几方面来看Java:JVM Java JVM:内存结构和相关参数含义 · Issue #24 · pzxwhc/MineKnowContainer · GitHub J ...

  10. overflow: auto;溢出自动显示

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...