BitShares-Core  4.0.0
BitShares blockchain implementation and command-line interface software
vesting_balance_object.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
3  *
4  * The MIT License
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
26 
27 #include <fc/io/raw.hpp>
28 
29 namespace graphene { namespace chain {
30 
31 inline bool sum_below_max_shares(const asset& a, const asset& b)
32 {
34  return (a.amount <= GRAPHENE_MAX_SHARE_SUPPLY)
36  && ((a.amount + b.amount) <= GRAPHENE_MAX_SHARE_SUPPLY);
37 }
38 
40 {
41  share_type allowed_withdraw = 0;
42 
43  if( ctx.now > begin_timestamp )
44  {
45  const auto elapsed_seconds = (ctx.now - begin_timestamp).to_seconds();
46  assert( elapsed_seconds > 0 );
47 
48  if( elapsed_seconds >= vesting_cliff_seconds )
49  {
50  share_type total_vested = 0;
51  if( elapsed_seconds < vesting_duration_seconds )
52  {
53  total_vested = static_cast<uint64_t>(fc::uint128_t( begin_balance.value ) * elapsed_seconds
55  }
56  else
57  {
58  total_vested = begin_balance;
59  }
60  assert( total_vested >= 0 );
61 
62  const share_type withdrawn_already = begin_balance - ctx.balance.amount;
63  assert( withdrawn_already >= 0 );
64 
65  allowed_withdraw = total_vested - withdrawn_already;
66  assert( allowed_withdraw >= 0 );
67  }
68  }
69 
70  return asset( allowed_withdraw, ctx.balance.asset_id );
71 }
72 
74 {
75 }
76 
78 {
79  return (ctx.amount.asset_id == ctx.balance.asset_id)
80  && sum_below_max_shares(ctx.amount, ctx.balance);
81 }
82 
84 {
85 }
86 
88 {
89  return (ctx.amount.asset_id == ctx.balance.asset_id)
90  && (ctx.amount <= get_allowed_withdraw(ctx));
91 }
92 
94 {
95  assert(ctx.now >= coin_seconds_earned_last_update);
96  int64_t delta_seconds = (ctx.now - coin_seconds_earned_last_update).to_seconds();
97  assert(delta_seconds >= 0);
98 
99  fc::uint128_t delta_coin_seconds = ctx.balance.amount.value;
100  delta_coin_seconds *= delta_seconds;
101 
102  fc::uint128_t coin_seconds_earned_cap = ctx.balance.amount.value;
103  coin_seconds_earned_cap *= std::max(vesting_seconds, 1u);
104 
105  return std::min(coin_seconds_earned + delta_coin_seconds, coin_seconds_earned_cap);
106 }
107 
109 {
110  coin_seconds_earned = compute_coin_seconds_earned(ctx);
111  coin_seconds_earned_last_update = ctx.now;
112 }
113 
115 {
116  if(ctx.now <= start_claim)
117  return asset(0, ctx.balance.asset_id);
118  fc::uint128_t cs_earned = compute_coin_seconds_earned(ctx);
119  fc::uint128_t withdraw_available = cs_earned / std::max(vesting_seconds, 1u);
120  assert(withdraw_available <= static_cast<fc::uint128_t>(ctx.balance.amount.value));
121  return asset(static_cast<uint64_t>(withdraw_available), ctx.balance.asset_id);
122 }
123 
125 {
126  update_coin_seconds_earned(ctx);
127 }
128 
130 {
131  on_deposit(ctx);
132  coin_seconds_earned += ctx.amount.amount.value * std::max(vesting_seconds, 1u);
133 }
134 
136 {
137  update_coin_seconds_earned(ctx);
138  fc::uint128_t coin_seconds_needed = ctx.amount.amount.value;
139  coin_seconds_needed *= std::max(vesting_seconds, 1u);
140  // is_withdraw_allowed should forbid any withdrawal that
141  // would trigger this assert
142  assert(coin_seconds_needed <= coin_seconds_earned);
143 
144  coin_seconds_earned -= coin_seconds_needed;
145 }
146 
148 {
149  return (ctx.amount.asset_id == ctx.balance.asset_id)
150  && sum_below_max_shares(ctx.amount, ctx.balance);
151 }
152 
154 {
155  return is_deposit_allowed(ctx);
156 }
157 
159 {
160  return (ctx.amount <= get_allowed_withdraw(ctx));
161 }
162 
164 {
165  return ctx.balance;
166 }
167 
169 {
170 }
171 
173 {
174 
175 }
176 
178 {
179  return (ctx.amount.asset_id == ctx.balance.asset_id)
180  && sum_below_max_shares(ctx.amount, ctx.balance);
181 }
182 
184 {
185 }
186 
188 {
189  return (ctx.amount.asset_id == ctx.balance.asset_id)
190  && (ctx.amount <= get_allowed_withdraw(ctx));
191 }
192 
193 #define VESTING_VISITOR(NAME, MAYBE_CONST) \
194 struct NAME ## _visitor \
195 { \
196  typedef decltype( \
197  std::declval<linear_vesting_policy>().NAME( \
198  std::declval<vesting_policy_context>()) \
199  ) result_type; \
200  \
201  NAME ## _visitor( \
202  const asset& balance, \
203  const time_point_sec& now, \
204  const asset& amount \
205  ) \
206  : ctx(balance, now, amount) {} \
207  \
208  template< typename Policy > \
209  result_type \
210  operator()(MAYBE_CONST Policy& policy) MAYBE_CONST \
211  { \
212  return policy.NAME(ctx); \
213  } \
214  \
215  vesting_policy_context ctx; \
216 }
217 
225 
226 bool vesting_balance_object::is_deposit_allowed(const time_point_sec& now, const asset& amount)const
227 {
228  return policy.visit(is_deposit_allowed_visitor(balance, now, amount));
229 }
230 
231 bool vesting_balance_object::is_withdraw_allowed(const time_point_sec& now, const asset& amount)const
232 {
233  bool result = policy.visit(is_withdraw_allowed_visitor(balance, now, amount));
234  // if some policy allows you to withdraw more than your balance,
235  // there's a programming bug in the policy algorithm
236  assert((amount <= balance) || (!result));
237  return result;
238 }
239 
240 void vesting_balance_object::deposit(const time_point_sec& now, const asset& amount)
241 {
242  on_deposit_visitor vtor(balance, now, amount);
243  policy.visit(vtor);
244  balance += amount;
245 }
246 
247 void vesting_balance_object::deposit_vested(const time_point_sec& now, const asset& amount)
248 {
249  on_deposit_vested_visitor vtor(balance, now, amount);
250  policy.visit(vtor);
251  balance += amount;
252 }
253 
254 bool vesting_balance_object::is_deposit_vested_allowed(const time_point_sec& now, const asset& amount) const
255 {
256  return policy.visit(is_deposit_vested_allowed_visitor(balance, now, amount));
257 }
258 
259 void vesting_balance_object::withdraw(const time_point_sec& now, const asset& amount)
260 {
261  assert(amount <= balance);
262  on_withdraw_visitor vtor(balance, now, amount);
263  policy.visit(vtor);
264  balance -= amount;
265 }
266 
268 {
269  asset amount = asset();
270  return policy.visit(get_allowed_withdraw_visitor(balance, now, amount));
271 }
272 
273 } } // graphene::chain
274 
void on_withdraw(const vesting_policy_context &ctx)
fc::time_point_sec begin_timestamp
This is the time at which funds begin vesting.
uint32_t vesting_duration_seconds
Duration of the vesting period, in seconds. Must be greater than 0 and greater than vesting_cliff_sec...
uint32_t vesting_cliff_seconds
No amount may be withdrawn before this many seconds of the vesting period have elapsed.
bool is_withdraw_allowed(const vesting_policy_context &ctx) const
void on_deposit_vested(const vesting_policy_context &ctx)
bool is_withdraw_allowed(const vesting_policy_context &ctx) const
Definition: api.cpp:56
void update_coin_seconds_earned(const vesting_policy_context &ctx)
asset get_allowed_withdraw(const time_point_sec &now) const
void on_deposit(const vesting_policy_context &ctx)
void deposit(const fc::time_point_sec &now, const asset &amount)
Deposit amount into vesting balance, requiring it to vest before withdrawal.
#define GRAPHENE_MAX_SHARE_SUPPLY
Definition: config.hpp:38
void on_withdraw(const vesting_policy_context &ctx)
void on_deposit_vested(const vesting_policy_context &)
asset get_allowed_withdraw(const vesting_policy_context &ctx) const
void on_deposit(const vesting_policy_context &ctx)
bool is_deposit_allowed(const vesting_policy_context &ctx) const
bool is_deposit_vested_allowed(const fc::time_point_sec &now, const asset &amount) const
share_type begin_balance
The total amount of asset to vest.
asset get_allowed_withdraw(const vesting_policy_context &ctx) const
bool is_deposit_vested_allowed(const vesting_policy_context &) const
void withdraw(const fc::time_point_sec &now, const asset &amount)
#define GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION(type)
Definition: types.hpp:74
bool is_deposit_allowed(const vesting_policy_context &ctx) const
void deposit_vested(const fc::time_point_sec &now, const asset &amount)
Deposit amount into vesting balance, making the new funds vest immediately.
bool sum_below_max_shares(const asset &a, const asset &b)
bool is_withdraw_allowed(const vesting_policy_context &ctx) const
void on_deposit_vested(const vesting_policy_context &)
bool is_deposit_vested_allowed(const vesting_policy_context &ctx) const
bool is_deposit_allowed(const fc::time_point_sec &now, const asset &amount) const
VESTING_VISITOR(on_deposit,)
asset_id_type asset_id
Definition: asset.hpp:39
defines vesting in terms of coin-days accrued which allows for dynamic deposit/withdraw ...
bool is_withdraw_allowed(const fc::time_point_sec &now, const asset &amount) const
asset get_allowed_withdraw(const vesting_policy_context &ctx) const
void on_deposit(const vesting_policy_context &ctx)
void on_withdraw(const vesting_policy_context &ctx)
fc::uint128_t compute_coin_seconds_earned(const vesting_policy_context &ctx) const
Linear vesting balance with cliff.
T value
Definition: safe.hpp:22
bool is_deposit_allowed(const vesting_policy_context &ctx) const