EOS [从零开始 DAPP 开发] 09 - DAPP 业务逻辑合约开发:提现和充值

pendingauth · 2019年07月09日 · 15 次阅读

本文转载自币乎,作者松果,原文链接: https://bihu.com/article/1853308548

这篇文章介绍DAPP中经常会使用到的业务场景:提现(withdraw)和 充值(deposit)。

对于DAPP来说,代币(通证)是不可缺少的组成部分,大量业务逻辑都会涉及到代币的交易,如果每笔代币交易都调用通证合约,不但会消耗资源,还存在安全问题(因为DAPP需要拿到用户的授权才可以发起转账,这就相当于DAPP控制了EOS账户);

因此DAPP内部一般使用专用账户管理用户的代币,并在数据表中记录用户的代币余额,用户通过提现操作来转移这些代币。

提现(withdraw)

提现功能可以写成一个Action,代码如下:

ACTION withdraw(name account, asset quantity) {
  require_auth(account);

  user_t users(_self, _self.value);    
  auto itr = users.find(account.value);

  check(quantity.amount > 0, "withdraw amount must be positive");
  check(itr->balance >= quantity, "overdrawn balance");

  transfer_token(account, quantity);
  users.modify(itr, account, [&](auto& user){
    user.balance -= quantity;
  });
}

内部调用了transfer_token函数,从weiwendappss账户向用户转账,定义如下:

void transfer_token(name to, asset quantity){
  action(
    permission_level{get_self(),"active"_n},
    "weiwentokens"_n,
    "transfer"_n,
    std::make_tuple(get_self(), to, quantity, std::string("transfer token"))
  ).send();
}

上一篇文章中定义的issue_token函数类似,transfer_token也构造了内联Action,调用weiwentokens合约的transfer Action。

内联Action的执行模式类似于数据库事务,具有原子性,即weiwendappss::withdraw和weiwentokens::transfer这两个Action,要么一起执行成功,要么一起失败,确保了用户的代币余额和multi_index表中的数据是一致的。

调用weiwendappss::withdraw:

可以看到,第一次调用成功提现1000WEI,代码中做了条件检测,第二次调用因为提现数额超过了用户的余额,提现失败并返回错误。

验证账户中的代币余额,提现前:

提现后:

usertable表中alice的WEI余额也减少了1000:

充值(deposit)

和提现不同,因为安全问题,充值不应该使用Action来实现。

原因在于,如果把充值做成Action,用户调用weiwendappss::deposit这个Action时,会内联调用weiwentokens::transfer来转账;

而调用外部合约的Action,DAPP需要拿到用户的授权才能执行,即给用户的active权限组加上一个weiwendappss@eosio.code权限;

这样做是非常危险的,相当于把自己EOS账户的控制权交给了智能合约,这样项目方账户就可以随意转账属于你的代币!

那要怎么做呢?

可以使用之前的文章介绍过的on_notify,它可以监听传入的Action调用,用户自己使用钱包把代币转账到合约账户,合约使用on_notify监听这笔转账;

on_notify是eosio.cdt v1.6.0版本新提供的通知/监听机制,如果你使用的是较老版本的eosio.cdt,则需要修改apply入口函数,通过判断receiver和code参数是否相等来编写代码。

weiwentokens::transfer内部调用了:

require_recipient( from );
require_recipient( to );

通过调用require_recipient函数,weiwentokens向交易双发都发送了通知,使用on_notify可以监听到这个通知,下面就通过on_notify来实现充值功能,代码如下:

[[eosio::on_notify("weiwentokens::transfer")]] 
void deposit(name from, name to, asset quantity, std::string memo) {
  if(to != _self) return;

  if(quantity.symbol == TOKEN_SYMBOL){
    user_t users(_self, _self.value);    
    auto itr = users.find(from.value);    

    if(itr != users.end()){
      users.modify(itr, _self, [&](auto& user){
        user.balance += quantity;
      });
    }    
  }
}

on_notify是一个EOS自定义属性,可以通过参数监听指定的合约和Action,这里指定监听weiwentokens::transfer。

下面使用alice账户转移55个WEI到weiwendappss和合约账户:

查询usertable表:

可以看到,alice的WEI余额变成了41176个,比之前增加了55个,说明成功监听到了weiwentokens::transfer,并根据转账金额修改了multi_index表。

Tips

项目代码在Github同步更新:https://github.com/songguo6/weiwen-dapp

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册