// 减资产
// owner 资产的拥有者
// value 资产的减少值
// st 该资产的状态
void token::subbalance(account_name owner,asset value, const currency_states& st){
accounts from_acnts(_self, owner); //初始化
/*accounts 是在eosio.token.hpp 中定义的 资产持有人列表类型 ,这里定义了一个类型为accounts 的变量 from_acnts
*from_acnts 是一个局部变量,他是程序和数据库之间的一个桥梁(沟通的一个对象或者一个工具)。数据在数据库中。
* 这个函数执行完以后,虽然这个from_acnts变量销毁了的,但是数据库的数据还在。
*_self 智能合约的拥有者(智能合约的名字),他拥有读写数据库的权限。
*owner 就是数据库是存在谁名下的,就是发币的或者要减他资产的那个账户(要把资产转进转出的那个人)。
*
*说 明: 数据是存在某人的名下的,但是某人自己不能改动存在自己名下的数据库,必须智能合约来改动这个人的名下的数据库的数据(资产)
*/
const auto& from = from_acnts.get(value.symbol.name());
//接下来需要在from_acnts(是程序和数据库交互的一个工具)数据库中查找某人名下的资产(account 定义资产持有人的资料)
//说明:就是在from_acnts中去get资产value , 这个value是带数字和单位的,value.symbol就是单位(ETH,EOS等)
//from 就是一个迭代器,如果找到了,这个from 就是一个account的实例。
//auto 就是让系统自动定义这个from的类型。
eosio_assert(from.balance.amount>=value.amount,"overdrawn balance");
//检查是不是透支了。如果余额不够,报overdrawn balance的信息。
//下面是要判断某人是不是有权限,我们需要被减资产的人授权,这样才能把他的资产给别人。
//调用api has_auth(owner),这个动作(action)确认是否具有权限。
if(has_auth(owner))
{
eosio_assert(!st.can_freeze||!from.frozen,"account is frozen by issuer");
eosio_assert(!st.can_freeze || st.is_frozen,"all transfers are frozen by issuer");
//!st.can_freeze 该资产不能被冻结
//!from.frozen 某人的资产被冻结
//st.is_frozen 该资产已经被冻结了
//如果上述条件一项不符合就会报错信息:该资产被发行者冻结了
eosio_assert(!st.enforce_whitelist||from.whitelist," account is not white listed");
// !st.enforce_whitelist 某人有没有启用白名单
// from.whitelist 某人是否在白名单上 (某人(账户)有没有出现白名单里)
//如果上述条件一项不符合,就不能进行这笔交易, 报错信息:某人(账户)没有出现白名单里
}else if(has_auth(st.issuer)) //如果这个owner没有授权,那谁可以减某人(账户)的资产呢,只有一种情况,发行者issuer 要回收这个资产并且这个资产是可回收的情况。
{
//如果owner没有授权,那么我们再看看是发行者 issuer 是否授权。
eosio_assert(st.canrecall,"issuer may not recall token");
//st.canrecall 该资产是否可以被回收,不能被回收,系统就会报错。
} else //以上两个条件都不满足,就不能做这个交易动作(减资产的动作)
{
eosio_assert(false, "insufficient authority");
//权限不足
}
//经常上述的判断,下面才是真正的功能,减除资产
from_acnts.modify(from, owner,[&](auto & a){
a.balance.amount -= value.amount; //某人拥有的代币的数目,减去传进来要减的数目。
//a.balance -=value; 这样也可以,更简洁
});
//from_acnts是列表变量。不能用from来改,因为from是from_acnts得到的,修改没有用的,需要用接口modify 来改才行。
//from 是需要改数据(资产持有人的信息)
//owner 就是ram_player(owner : RAM payer) 谁负责支付这笔交易的内存(这笔交易内存是占谁的token)
//eos 中的内存资源是由拥有代币的多少来分配的。转账的人需要拥有一定量的EOS代币才能占有系统内存资源,才能进行转账行为(保障这个动作可以实行)。
//[&](auto & a) 匿名函数类型: 向里面传一个匿名函数来告诉系统他应该怎么办。
}