eos源码赏析(十八):EOS智能合约之合约内ram购买及资源抵押

昨天群内有朋友问,智能合约内是否可以实现帮用户购买ram或者帮用户抵押资源(cpu及net),以及如何来实现这个功能。今天我们一起来看下这个问题。文章的内容分为以下两个部分:

  • buyram及delegatebw的实现

  • 合约内实现替用户购买ram及抵押资源

1、buyram及delegatebw的实现

我们知道在执行buyram的时候是分为两种情况的:

  1. 以eos的单位来购买ram

  2. 以ram的单位来购买ram

那么buyram这个功能在哪里实现的呢,我们通过cleos中的main.cpp很容易查找到这两个操作都是在系统合约eosio.system中实现的,以buyram为例,其分为了两种,代码如下:

可以看出,buyrambytes最终还是调用了buyram,当购买ram的时候,支付的用户会将eos交易至系统合约账户,而接收ram的用户可以通过sellram这个action换回token,接收方支付这次action执行所需内存。我们大多已经知道ram的价格是动态变化的,因为其使用了bancor算法,就像现在大热的fibos一样,使用bancor算法可以更自主的给ram【定价】,本篇重点不在此,笔者正在尝试使用该算法进行测试,以后的文章中会逐步提及。同样的,delegatebw的操作也是类似的,我们不再进行代码的粘贴,感兴趣的朋友可以自行测试。

2、合约内实现替用户购买ram及抵押资源

为用户抵押资源是可以解除质押,最终是不消耗我们的token的,但是为用户购买ram却是消耗合约开发者自己的token的,我们假设一种情况如下,用户支付我们10 EOS,我们便为其购买100kbytes的ram,而为其抵押10 EOS的资源,代码如下:

1   //这个action将会以市场价格且单位bytes的形式购买ram
 2   void system_contract::buyrambytes( account_name payer, account_name receiver, uint32_t bytes ) {
 3      auto itr = _rammarket.find(S(4,RAMCORE));
 4      auto tmp = *itr;
 5      auto eosout = tmp.convert( asset(bytes,S(0,RAM)), CORE_SYMBOL );
 6
 7      buyram( payer, receiver, eosout );
 8   }
 9   //当购买ram的时候,支付的用户会将eos交易至系统合约账户,而接收ram的用户可以通过sellram这个action换回token,接收方支付这次action执行所需内存。
10   void system_contract::buyram( account_name payer, account_name receiver, asset quant )
11   {
12      require_auth( payer );
13      eosio_assert( quant.amount > 0"must purchase a positive amount" );
14      auto fee = quant;
15      fee.amount = ( fee.amount + 199 ) / 200/// .5% fee (round up)
16      auto quant_after_fee = quant;
17      quant_after_fee.amount -= fee.amount;
18      INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {payer,N(active)},
19         { payer, N(eosio.ram), quant_after_fee, std::string("buy ram") } );
20      if( fee.amount > 0 ) {
21         INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {payer,N(active)},
22                                                       { payer, N(eosio.ramfee), fee, std::string("ram fee") } );
23      }
24
25      int64_t bytes_out;
26
27      const auto& market = _rammarket.get(S(4,RAMCORE), "ram market does not exist");
28      _rammarket.modify( market, 0, [&]( auto& es ) {
29          bytes_out = es.convert( quant_after_fee,  S(0,RAM) ).amount;
30      });
31
32      eosio_assert( bytes_out > 0"must reserve a positive amount" );
33
34      _gstate.total_ram_bytes_reserved += uint64_t(bytes_out);
35      _gstate.total_ram_stake          += quant_after_fee.amount;
36
37      user_resources_table  userres( _self, receiver );
38      auto res_itr = userres.find( receiver );
39      if( res_itr ==  userres.end() ) {
40         res_itr = userres.emplace( receiver, [&]( auto& res ) {
41               res.owner = receiver;
42               res.ram_bytes = bytes_out;
43            });
44      } else {
45         userres.modify( res_itr, receiver, [&]( auto& res ) {
46               res.ram_bytes += bytes_out;
47            });
48      }
49      set_resource_limits( res_itr->owner, res_itr->ram_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount );
50   }

可以看出,buyrambytes最终还是调用了buyram,当购买ram的时候,支付的用户会将eos交易至系统合约账户,而接收ram的用户可以通过sellram这个action换回token,接收方支付这次action执行所需内存。我们大多已经知道ram的价格是动态变化的,因为其使用了bancor算法,就像现在大热的fibos一样,使用bancor算法可以更自主的给ram【定价】,本篇重点不在此,笔者正在尝试使用该算法进行测试,以后的文章中会逐步提及。同样的,delegatebw的操作也是类似的,我们不再进行代码的粘贴,感兴趣的朋友可以自行测试。

2、合约内实现替用户购买ram及抵押资源

为用户抵押资源是可以解除质押,最终是不消耗我们的token的,但是为用户购买ram却是消耗合约开发者自己的token的,我们假设一种情况如下,用户支付我们10 EOS,我们便为其购买100kbytes的ram,而为其抵押10 EOS的资源,代码如下:

1void tianlongbabu::buysilver(account_name user,asset quanitity,string memo)
 2{
 3    if (user != _this_contract && quanitity.symbol == S(4,EOS))
 4    {
 5            //购买ram
 6        action(
 7              {permission_level{_this_contract,N(active)}}, 
 8              N(eosio), N(buyrambytes),
 9              std::make_tuple(_this_contract,user,quanitity.amount * 10)
10              ).send(); 
11            //抵押资源
12
13        asset delquan = quanitity;
14        delquan.amount /= 10;
15        action(
16              {permission_level{_this_contract,N(active)}}, 
17              N(eosio), N(delegatebw),
18              std::make_tuple(_this_contract,user,delquan,delquan,true)
19              ).send();
20    }
21}

通过上面的代码我们可以看到,本合约调用了系统合约eosio.system,在代码中的体现就是N(eosio),以及其对应的action–buyrambytes以及delegatebw,inline action执行之后,通过合约内部为用户购买ram以及质押资源便可实现了。当然购买和质押实现之后,我们也可以实现卖出ram以及解除质押资源,感兴趣的话可以去尝试下。

在合约部署成功之后,我们可以通过命令行简单的测试下该合约是否生效:

cleos  push action mycontract buysilver '["user","10.0000 EOS","test"]' -p user@active

本文从群内朋友问题出发,首先查看了eos中buyram的逻辑,然后以合约内部调用调用系统合约eosio.system中的buyram及delegatebw来实现替用户购买ram以及质押资源,关于buyram中的bancor算法笔者会在后续的文章中继续进行说明及测试。

如果你觉得我的文章对你有一定的帮助,请点击文章末尾的喜欢该作者。

如果你对eos开发感兴趣,欢迎关注本公众号,一起学习eos开发。

这里写图片描述
微信公众号

     有任何疑问或者指教请添加本人个人微信,当然有对eos开发感兴趣或者金庸粉的也可以添加一起交流,备注eos开发或金庸。

这里写图片描述

个人微信号

猜你喜欢

转载自blog.csdn.net/zhuxiangzhidi/article/details/82597790