Bitshares研究系列【vesting_policy】
前面文章bitshares基本概念详解【vesting balance】中说过vesting balance的概念,与之相关的还有一个vesting policy,这个决定了什么时候能取出多少币,详细来看看。
linear_vesting_policy(线性授权策略)
中文不知道怎么翻译,这个线性的就类似股份授予一样,一定时间可以兑现一部分。
/**
* @brief Linear vesting balance with cliff
*
* This vesting balance type is used to mimic traditional stock vesting contracts where
* each day a certain amount vests until it is fully matured.
*
* @note New funds may not be added to a linear vesting balance.
*/
struct linear_vesting_policy
{
/// This is the time at which funds begin vesting.
fc::time_point_sec begin_timestamp;
/// No amount may be withdrawn before this many seconds of the vesting period have elapsed.
uint32_t vesting_cliff_seconds = 0;
/// Duration of the vesting period, in seconds. Must be greater than 0 and greater than vesting_cliff_seconds.
uint32_t vesting_duration_seconds = 0;
/// The total amount of asset to vest.
share_type begin_balance;
asset get_allowed_withdraw(const vesting_policy_context& ctx)const;
bool is_deposit_allowed(const vesting_policy_context& ctx)const;
bool is_deposit_vested_allowed(const vesting_policy_context&)const { return false; }
bool is_withdraw_allowed(const vesting_policy_context& ctx)const;
void on_deposit(const vesting_policy_context& ctx);
void on_deposit_vested(const vesting_policy_context&)
{ FC_THROW( "May not deposit vested into a linear vesting balance." ); }
void on_withdraw(const vesting_policy_context& ctx);
};
liner vesting policy有一个初始时间“vesting_cliff_seconds”,只有过了这个时间才能提取资金。
如果时长超过“vesting_duration_seconds”则可以全部提取,如果小于“vesting_duration_seconds”则按时间比率提取相应金额。
具体代码在vesting_balance_object.cpp中,不再列出。
cdd_vesting_policy(币天授权策略)
“币天”这个概念有点意思,仔细来看一下。先了解下“币龄”:
币龄 = 币天 × 币数
如我有100个BTS在帐户上10天了,那这100个BTS的币龄就是100*10=1000币天。而币天销毁就是我把这其中的50个BTS转给其他人了,那这笔交易的币天销毁就是500币天。
币天销毁 = 交易的币数 × 持有这些交易币数的天数
/**
* @brief defines vesting in terms of coin-days accrued which allows for dynamic deposit/withdraw
*
* The economic effect of this vesting policy is to require a certain amount of "interest" to accrue
* before the full balance may be withdrawn. Interest accrues as coindays (balance * length held). If
* some of the balance is withdrawn, the remaining balance must be held longer.
*/
struct cdd_vesting_policy
{
uint32_t vesting_seconds = 0;
fc::uint128_t coin_seconds_earned;
/** while coindays may accrue over time, none may be claimed before first_claim date */
fc::time_point_sec start_claim;
fc::time_point_sec coin_seconds_earned_last_update;
/**
* Compute coin_seconds_earned. Used to
* non-destructively figure out how many coin seconds
* are available.
*/
fc::uint128_t compute_coin_seconds_earned(const vesting_policy_context& ctx)const;
/**
* Update coin_seconds_earned and
* coin_seconds_earned_last_update fields; called by both
* on_deposit() and on_withdraw().
*/
void update_coin_seconds_earned(const vesting_policy_context& ctx);
asset get_allowed_withdraw(const vesting_policy_context& ctx)const;
bool is_deposit_allowed(const vesting_policy_context& ctx)const;
bool is_deposit_vested_allowed(const vesting_policy_context& ctx)const;
bool is_withdraw_allowed(const vesting_policy_context& ctx)const;
void on_deposit(const vesting_policy_context& ctx);
void on_deposit_vested(const vesting_policy_context& ctx);
void on_withdraw(const vesting_policy_context& ctx);
};
再来看看计算币龄的函数(是按秒计的哦):
fc::uint128_t cdd_vesting_policy::compute_coin_seconds_earned(const vesting_policy_context& ctx)const
{
assert(ctx.now >= coin_seconds_earned_last_update);
int64_t delta_seconds = (ctx.now - coin_seconds_earned_last_update).to_seconds();
assert(delta_seconds >= 0);
fc::uint128_t delta_coin_seconds = ctx.balance.amount.value;
delta_coin_seconds *= delta_seconds;
fc::uint128_t coin_seconds_earned_cap = ctx.balance.amount.value;
coin_seconds_earned_cap *= std::max(vesting_seconds, 1u);
return std::min(coin_seconds_earned + delta_coin_seconds, coin_seconds_earned_cap);
}
“coin_seconds_earned_last_update”是上次更新币龄的时间,只要币数量发生变化都应该重新计算并更新一次,实际也是在币存储和提取时会调用update_coin_seconds_earned()函数。
币龄计算刚才也看了公式,只是这里用的是币数乘以秒数,同时保证数量不超过“vesting_seconds”计算出的币龄,否则算币的时候就超出实际的币数量了!
提取资金时根据 cs_earned / std::max(vesting_seconds, 1u) 得到可提取数量,如下:
asset cdd_vesting_policy::get_allowed_withdraw(const vesting_policy_context& ctx)const
{
if(ctx.now <= start_claim)
return asset(0, ctx.balance.asset_id);
fc::uint128_t cs_earned = compute_coin_seconds_earned(ctx);
fc::uint128_t withdraw_available = cs_earned / std::max(vesting_seconds, 1u);
assert(withdraw_available <= ctx.balance.amount.value);
return asset(withdraw_available.to_uint64(), ctx.balance.asset_id);
}
提出vesting balance
在余额提出操作中更新余额数量:
void_result balance_claim_evaluator::do_apply(const balance_claim_operation& op)
{
database& d = db();
if( balance->is_vesting_balance() && op.total_claimed < balance->balance )
d.modify(*balance, [&](balance_object& b) {
b.vesting_policy->on_withdraw({b.balance, d.head_block_time(), op.total_claimed});
b.balance -= op.total_claimed;
b.last_claim_date = d.head_block_time();
});
else
d.remove(*balance);
d.adjust_balance(op.deposit_to_account, op.total_claimed);
return {};
}
on_withdraw()
void cdd_vesting_policy::on_withdraw(const vesting_policy_context& ctx)
{
update_coin_seconds_earned(ctx);
fc::uint128_t coin_seconds_needed = ctx.amount.amount.value;
coin_seconds_needed *= std::max(vesting_seconds, 1u);
// is_withdraw_allowed should forbid any withdrawal that
// would trigger this assert
assert(coin_seconds_needed <= coin_seconds_earned);
coin_seconds_earned -= coin_seconds_needed;
}
而on_withdraw()函数会更新币天数值,剩余的币也需要vesting_seconds指定秒数才能完全提取。
在这些策略函数处理中会用到 vesting_policy_context 对象,这个对象指定了资产余额、当前时间、资产变化(提取)数量。
struct vesting_policy_context
{
vesting_policy_context(
asset _balance,
fc::time_point_sec _now,
asset _amount)
: balance(_balance), now(_now) {}
asset balance;
fc::time_point_sec now;
asset amount;
};
结论
linear_vesting_policy 用在初始币发放,如授予团队币
cdd_vesting_policy 用在见证人打包费用、注册人和引荐人奖励、worker奖励
参考
有兴趣的了解下币天销毁
https://www.jianshu.com/p/a4368696ba1c
@chaimyu, steemit上我觉得只需要静静读你的技术贴就值了~~~
你好吗?欢迎在steemauto里设置跟赞 @cnbuddy 给整个cn区点赞倘若你想让我隐形,请回复“取消”。