Bitshares研究系列【vesting_policy】

in #bitshares6 years ago

前面文章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

Sort:  

@chaimyu, steemit上我觉得只需要静静读你的技术贴就值了~~~ img

你好吗?欢迎在steemauto里设置跟赞 @cnbuddy 给整个cn区点赞倘若你想让我隐形,请回复“取消”。

Coin Marketplace

STEEM 0.30
TRX 0.12
JST 0.034
BTC 63799.64
ETH 3130.40
USDT 1.00
SBD 3.97