本文编写了一个简单的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. [原]NYOJ-房间安排168

    大学生程序代写 /*房间安排 时间限制:3000 ms  |  内存限制:65535 KB 难度:2 描述 2010年上海世界博览会(Expo2010),是第41届世界博览会.于2010年5月1日至1 ...

  2. NO3:步履蹒跚-完成第一章节学习

    第一章小记: 每个C程序都要求有一个main()函数(多于一个main()函数是不合法的(已犯错:在VS 2010一个项目里两个C文件都有main函数,不能编译通过,必须删除一个文件,永记)).mai ...

  3. AngularJS directive简述

    转自:http://segmentfault.com/q/1010000002400734 官方API:http://docs.angularjs.cn/api/ng/service/$compile ...

  4. ACM学习历程—HDU5422 Rikka with Graph(贪心)

    Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...

  5. POJ2689:素数区间筛选

    Prime Distance Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 15820   Accepted: 4202 D ...

  6. 【转】 Pro Android学习笔记(七九):服务(4):远程服务的实现

    目录(?)[-] 远程服务的实现小例子 对外开放远程服务的接口 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flow ...

  7. sql server 表索引碎片处理

    DBCC SHOWCONTIG (Transact-SQL) SQL Server 2005 其他版本 更新日期: 2007 年 9 月 15 日 显示指定的表或视图的数据和索引的碎片信息. 重要提示 ...

  8. 问题:C# List;结果:C#中数组、ArrayList和List三者的区别

    C#中数组.ArrayList和List三者的区别 分类: [C#那些事] 2013-03-11 00:03 36533人阅读 评论(23) 收藏 举报 目录(?)[+] 在C#中数组,ArrayLi ...

  9. linux命令-tar打包和压缩并用

    tar在打包的时候进行压缩 支持 gzip bzip2 xz 格式 -z  gzip格式 -j  bzip2格式 -J  xz格式 压缩打包 [root@wangshaojun ~]# tar -zc ...

  10. 洛谷-铺地毯-NOIP2011提高组复赛

    题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n 张地毯,编号从 1 到n .现在将这些地毯按照编号从小到大的顺序平行于 ...