Progress #31: Implement threshold for vesting fees
This commit is contained in:
parent
c6a7cdf5a3
commit
a185f864fc
10 changed files with 234 additions and 201 deletions
|
|
@ -36,4 +36,24 @@ void account_balance_object::adjust_balance(const asset& delta)
|
||||||
balance += delta.amount;
|
balance += delta.amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t account_statistics_object::calculate_bulk_discount_percent(const chain_parameters& params) const
|
||||||
|
{
|
||||||
|
uint64_t bulk_discount_percent = 0;
|
||||||
|
if( lifetime_fees_paid >= params.bulk_discount_threshold_max )
|
||||||
|
bulk_discount_percent = params.max_bulk_discount_percent_of_fee;
|
||||||
|
else if(params.bulk_discount_threshold_max.value !=
|
||||||
|
params.bulk_discount_threshold_min.value)
|
||||||
|
{
|
||||||
|
bulk_discount_percent =
|
||||||
|
(params.max_bulk_discount_percent_of_fee *
|
||||||
|
(lifetime_fees_paid.value -
|
||||||
|
params.bulk_discount_threshold_min.value)) /
|
||||||
|
(params.bulk_discount_threshold_max.value -
|
||||||
|
params.bulk_discount_threshold_min.value);
|
||||||
|
}
|
||||||
|
assert( bulk_discount_percent <= GRAPHENE_100_PERCENT );
|
||||||
|
|
||||||
|
return bulk_discount_percent;
|
||||||
|
}
|
||||||
|
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2015, Cryptonomex, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This source code is provided for evaluation in private test networks only, until September 8, 2015. After this date, this license expires and
|
|
||||||
* the code may not be used, modified or distributed for any purpose. Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted until September 8, 2015, provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. The code and/or derivative works are used only for private test networks consisting of no more than 10 P2P nodes.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
||||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
#include <graphene/chain/asset_operations.hpp>
|
|
||||||
#include <graphene/chain/database.hpp>
|
|
||||||
#include <graphene/chain/account_object.hpp>
|
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
|
||||||
} }
|
|
||||||
|
|
@ -89,7 +89,7 @@ void database::adjust_core_in_orders( const account_object& acnt, asset delta )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void database::deposit_cashback( const account_object& acct, share_type amount )
|
void database::deposit_cashback(const account_object& acct, share_type amount, bool require_vesting)
|
||||||
{
|
{
|
||||||
// If we don't have a VBO, or if it has the wrong maturity
|
// If we don't have a VBO, or if it has the wrong maturity
|
||||||
// due to a policy change, cut it loose.
|
// due to a policy change, cut it loose.
|
||||||
|
|
@ -112,7 +112,10 @@ void database::deposit_cashback( const account_object& acct, share_type amount )
|
||||||
|
|
||||||
modify( cashback_vb, [&]( vesting_balance_object& obj )
|
modify( cashback_vb, [&]( vesting_balance_object& obj )
|
||||||
{
|
{
|
||||||
|
if( require_vesting )
|
||||||
obj.deposit(now, amount);
|
obj.deposit(now, amount);
|
||||||
|
else
|
||||||
|
obj.deposit_vested(now, amount);
|
||||||
} );
|
} );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +127,7 @@ void database::deposit_cashback( const account_object& acct, share_type amount )
|
||||||
|
|
||||||
cdd_vesting_policy policy;
|
cdd_vesting_policy policy;
|
||||||
policy.vesting_seconds = global_vesting_seconds;
|
policy.vesting_seconds = global_vesting_seconds;
|
||||||
policy.coin_seconds_earned = 0;
|
policy.coin_seconds_earned = require_vesting? 0 : amount.value * policy.vesting_seconds;
|
||||||
policy.coin_seconds_earned_last_update = now;
|
policy.coin_seconds_earned_last_update = now;
|
||||||
|
|
||||||
obj.policy = policy;
|
obj.policy = policy;
|
||||||
|
|
|
||||||
|
|
@ -357,10 +357,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
|
||||||
process_fees_helper(database& d, const global_property_object& gpo)
|
process_fees_helper(database& d, const global_property_object& gpo)
|
||||||
: d(d), props(gpo) {}
|
: d(d), props(gpo) {}
|
||||||
|
|
||||||
void operator()(const account_object& a) {
|
share_type cut_fee(share_type a, uint16_t p)const
|
||||||
const account_statistics_object& stats = a.statistics(d);
|
|
||||||
|
|
||||||
auto cut_fee = [](share_type a, uint16_t p) -> share_type
|
|
||||||
{
|
{
|
||||||
if( a == 0 || p == 0 )
|
if( a == 0 || p == 0 )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -371,72 +368,70 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
|
||||||
r *= p;
|
r *= p;
|
||||||
r /= GRAPHENE_100_PERCENT;
|
r /= GRAPHENE_100_PERCENT;
|
||||||
return r.to_uint64();
|
return r.to_uint64();
|
||||||
};
|
|
||||||
|
|
||||||
if( stats.pending_fees > 0 )
|
|
||||||
{
|
|
||||||
share_type core_fee_subtotal(stats.pending_fees);
|
|
||||||
share_type bulk_cashback = share_type(0);
|
|
||||||
if( stats.lifetime_fees_paid > props.parameters.bulk_discount_threshold_min &&
|
|
||||||
a.is_member(d.head_block_time()) )
|
|
||||||
{
|
|
||||||
uint64_t bulk_discount_percent = 0;
|
|
||||||
if( stats.lifetime_fees_paid >= props.parameters.bulk_discount_threshold_max )
|
|
||||||
bulk_discount_percent = props.parameters.max_bulk_discount_percent_of_fee;
|
|
||||||
else if(props.parameters.bulk_discount_threshold_max.value !=
|
|
||||||
props.parameters.bulk_discount_threshold_min.value)
|
|
||||||
{
|
|
||||||
bulk_discount_percent =
|
|
||||||
(props.parameters.max_bulk_discount_percent_of_fee *
|
|
||||||
(stats.lifetime_fees_paid.value -
|
|
||||||
props.parameters.bulk_discount_threshold_min.value)) /
|
|
||||||
(props.parameters.bulk_discount_threshold_max.value -
|
|
||||||
props.parameters.bulk_discount_threshold_min.value);
|
|
||||||
}
|
|
||||||
assert( bulk_discount_percent <= GRAPHENE_100_PERCENT );
|
|
||||||
assert( bulk_discount_percent >= 0 );
|
|
||||||
|
|
||||||
bulk_cashback = cut_fee(core_fee_subtotal, bulk_discount_percent);
|
|
||||||
assert( bulk_cashback <= core_fee_subtotal );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
share_type core_fee_total = core_fee_subtotal - bulk_cashback;
|
void pay_out_fees(const account_object& account, share_type core_fee_total, bool require_vesting)
|
||||||
share_type network_cut = cut_fee(core_fee_total, a.network_fee_percentage);
|
{
|
||||||
|
share_type network_cut = cut_fee(core_fee_total, account.network_fee_percentage);
|
||||||
assert( network_cut <= core_fee_total );
|
assert( network_cut <= core_fee_total );
|
||||||
share_type burned = cut_fee(network_cut, props.parameters.burn_percent_of_fee);
|
share_type burned = cut_fee(network_cut, props.parameters.burn_percent_of_fee);
|
||||||
share_type accumulated = network_cut - burned;
|
share_type accumulated = network_cut - burned;
|
||||||
assert( accumulated + burned == network_cut );
|
assert( accumulated + burned == network_cut );
|
||||||
share_type lifetime_cut = cut_fee(core_fee_total, a.lifetime_referrer_fee_percentage);
|
share_type lifetime_cut = cut_fee(core_fee_total, account.lifetime_referrer_fee_percentage);
|
||||||
share_type referral = core_fee_total - network_cut - lifetime_cut;
|
share_type referral = core_fee_total - network_cut - lifetime_cut;
|
||||||
|
|
||||||
d.modify(dynamic_asset_data_id_type()(d), [network_cut](asset_dynamic_data_object& d) {
|
d.modify(dynamic_asset_data_id_type()(d), [network_cut](asset_dynamic_data_object& d) {
|
||||||
d.accumulated_fees += network_cut;
|
d.accumulated_fees += network_cut;
|
||||||
});
|
});
|
||||||
|
|
||||||
d.modify(a.statistics(d), [core_fee_total](account_statistics_object& s) {
|
|
||||||
s.lifetime_fees_paid += core_fee_total;
|
|
||||||
s.pending_fees = 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
d.deposit_cashback( a, bulk_cashback );
|
|
||||||
|
|
||||||
// Potential optimization: Skip some of this math and object lookups by special casing on the account type.
|
// Potential optimization: Skip some of this math and object lookups by special casing on the account type.
|
||||||
// For example, if the account is a lifetime member, we can skip all this and just deposit the referral to
|
// For example, if the account is a lifetime member, we can skip all this and just deposit the referral to
|
||||||
// it directly.
|
// it directly.
|
||||||
share_type referrer_cut = cut_fee(referral, a.referrer_rewards_percentage);
|
share_type referrer_cut = cut_fee(referral, account.referrer_rewards_percentage);
|
||||||
share_type registrar_cut = referral - referrer_cut;
|
share_type registrar_cut = referral - referrer_cut;
|
||||||
|
|
||||||
d.deposit_cashback(d.get(a.lifetime_referrer), lifetime_cut);
|
d.deposit_cashback(d.get(account.lifetime_referrer), lifetime_cut, require_vesting);
|
||||||
d.deposit_cashback(d.get(a.referrer), referrer_cut);
|
d.deposit_cashback(d.get(account.referrer), referrer_cut, require_vesting);
|
||||||
d.deposit_cashback(d.get(a.registrar), registrar_cut);
|
d.deposit_cashback(d.get(account.registrar), registrar_cut, require_vesting);
|
||||||
|
|
||||||
idump((referrer_cut)(registrar_cut)(bulk_cashback)(accumulated)(burned)(lifetime_cut)(core_fee_subtotal));
|
assert( referrer_cut + registrar_cut + accumulated + burned + lifetime_cut == core_fee_total );
|
||||||
assert( referrer_cut + registrar_cut + bulk_cashback + accumulated + burned + lifetime_cut == core_fee_subtotal );
|
}
|
||||||
|
|
||||||
|
void operator()(const account_object& a) {
|
||||||
|
const account_statistics_object& stats = a.statistics(d);
|
||||||
|
|
||||||
|
if( stats.pending_fees > 0 )
|
||||||
|
{
|
||||||
|
share_type vesting_fee_subtotal(stats.pending_fees);
|
||||||
|
share_type vested_fee_subtotal(stats.pending_vested_fees);
|
||||||
|
share_type vesting_cashback, vested_cashback;
|
||||||
|
|
||||||
|
if( stats.lifetime_fees_paid > props.parameters.bulk_discount_threshold_min &&
|
||||||
|
a.is_member(d.head_block_time()) )
|
||||||
|
{
|
||||||
|
auto bulk_discount_rate = stats.calculate_bulk_discount_percent(props.parameters);
|
||||||
|
vesting_cashback = cut_fee(vesting_fee_subtotal, bulk_discount_rate);
|
||||||
|
vesting_fee_subtotal -= vesting_cashback;
|
||||||
|
|
||||||
|
vested_cashback = cut_fee(vested_fee_subtotal, bulk_discount_rate);
|
||||||
|
vested_fee_subtotal -= vested_cashback;
|
||||||
|
}
|
||||||
|
|
||||||
|
pay_out_fees(a, vesting_fee_subtotal, true);
|
||||||
|
d.deposit_cashback(a, vesting_cashback, true);
|
||||||
|
pay_out_fees(a, vested_fee_subtotal, false);
|
||||||
|
d.deposit_cashback(a, vested_cashback, false);
|
||||||
|
|
||||||
|
d.modify(stats, [vested_fee_subtotal, vesting_fee_subtotal](account_statistics_object& s) {
|
||||||
|
s.lifetime_fees_paid += vested_fee_subtotal + vesting_fee_subtotal;
|
||||||
|
s.pending_fees = 0;
|
||||||
|
s.pending_vested_fees = 0;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} fees_helper(*this, gpo);
|
} fee_helper(*this, gpo);
|
||||||
|
|
||||||
perform_account_maintenance(std::tie(tally_helper, fees_helper));
|
perform_account_maintenance(std::tie(tally_helper, fee_helper));
|
||||||
|
|
||||||
struct clear_canary {
|
struct clear_canary {
|
||||||
clear_canary(vector<uint64_t>& target): target(target){}
|
clear_canary(vector<uint64_t>& target): target(target){}
|
||||||
|
|
@ -451,9 +446,8 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
|
||||||
update_active_witnesses();
|
update_active_witnesses();
|
||||||
update_active_delegates();
|
update_active_delegates();
|
||||||
|
|
||||||
const global_property_object& global_properties = get_global_properties();
|
if( gpo.pending_parameters )
|
||||||
if( global_properties.pending_parameters )
|
modify(gpo, [](global_property_object& p) {
|
||||||
modify(get_global_properties(), [](global_property_object& p) {
|
|
||||||
p.parameters = std::move(*p.pending_parameters);
|
p.parameters = std::move(*p.pending_parameters);
|
||||||
p.pending_parameters.reset();
|
p.pending_parameters.reset();
|
||||||
});
|
});
|
||||||
|
|
@ -472,7 +466,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
|
||||||
}
|
}
|
||||||
|
|
||||||
auto next_maintenance_time = get<dynamic_global_property_object>(dynamic_global_property_id_type()).next_maintenance_time;
|
auto next_maintenance_time = get<dynamic_global_property_object>(dynamic_global_property_id_type()).next_maintenance_time;
|
||||||
auto maintenance_interval = get_global_properties().parameters.maintenance_interval;
|
auto maintenance_interval = gpo.parameters.maintenance_interval;
|
||||||
|
|
||||||
if( next_maintenance_time <= next_block.timestamp )
|
if( next_maintenance_time <= next_block.timestamp )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,10 @@ namespace graphene { namespace chain {
|
||||||
d.fee_pool -= core_fee_paid;
|
d.fee_pool -= core_fee_paid;
|
||||||
});
|
});
|
||||||
db().modify(*fee_paying_account_statistics, [&](account_statistics_object& s) {
|
db().modify(*fee_paying_account_statistics, [&](account_statistics_object& s) {
|
||||||
|
if( core_fee_paid > db().get_global_properties().parameters.cashback_vesting_threshold )
|
||||||
s.pending_fees += core_fee_paid;
|
s.pending_fees += core_fee_paid;
|
||||||
|
else
|
||||||
|
s.pending_vested_fees += core_fee_paid;
|
||||||
});
|
});
|
||||||
} FC_CAPTURE_AND_RETHROW() }
|
} FC_CAPTURE_AND_RETHROW() }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,11 +62,20 @@ namespace graphene { namespace chain {
|
||||||
/**
|
/**
|
||||||
* Tracks the fees paid by this account which have not been disseminated to the various parties that receive
|
* Tracks the fees paid by this account which have not been disseminated to the various parties that receive
|
||||||
* them yet (registrar, referrer, lifetime referrer, network, etc). This is used as an optimization to avoid
|
* them yet (registrar, referrer, lifetime referrer, network, etc). This is used as an optimization to avoid
|
||||||
* doing massive amounts of uint128 math on each and every operation.
|
* doing massive amounts of uint128 arithmetic on each and every operation.
|
||||||
*
|
*
|
||||||
* These fees will be paid out and this counter will reset during the maintenance interval.
|
*These fees will be paid out as vesting cash-back, and this counter will reset during the maintenance
|
||||||
|
*interval.
|
||||||
*/
|
*/
|
||||||
share_type pending_fees;
|
share_type pending_fees;
|
||||||
|
/**
|
||||||
|
* Same as @ref pending_fees, except these fees will be paid out as pre-vested cash-back (immediately
|
||||||
|
* available for withdrawal) rather than requiring the normal vesting period.
|
||||||
|
*/
|
||||||
|
share_type pending_vested_fees;
|
||||||
|
|
||||||
|
/// @brief Calculate the percentage discount this user receives on his fees
|
||||||
|
uint16_t calculate_bulk_discount_percent(const chain_parameters& params)const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -290,5 +299,6 @@ FC_REFLECT_DERIVED( graphene::chain::account_statistics_object, (graphene::chain
|
||||||
(most_recent_op)
|
(most_recent_op)
|
||||||
(total_core_in_orders)
|
(total_core_in_orders)
|
||||||
(lifetime_fees_paid)
|
(lifetime_fees_paid)
|
||||||
|
(pending_fees)(pending_vested_fees)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ namespace graphene { namespace chain {
|
||||||
void adjust_core_in_orders( const account_object& acnt, asset delta );
|
void adjust_core_in_orders( const account_object& acnt, asset delta );
|
||||||
|
|
||||||
// helper to handle cashback rewards
|
// helper to handle cashback rewards
|
||||||
void deposit_cashback( const account_object& acct, share_type amount );
|
void deposit_cashback(const account_object& acct, share_type amount, bool require_vesting = true);
|
||||||
|
|
||||||
//////////////////// db_debug.cpp ////////////////////
|
//////////////////// db_debug.cpp ////////////////////
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,11 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
asset get_allowed_withdraw(const vesting_policy_context& ctx)const;
|
asset get_allowed_withdraw(const vesting_policy_context& ctx)const;
|
||||||
bool is_deposit_allowed(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;
|
bool is_withdraw_allowed(const vesting_policy_context& ctx)const;
|
||||||
void on_deposit(const vesting_policy_context& ctx);
|
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);
|
void on_withdraw(const vesting_policy_context& ctx);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -82,8 +85,10 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
asset get_allowed_withdraw(const vesting_policy_context& ctx)const;
|
asset get_allowed_withdraw(const vesting_policy_context& ctx)const;
|
||||||
bool is_deposit_allowed(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;
|
bool is_withdraw_allowed(const vesting_policy_context& ctx)const;
|
||||||
void on_deposit(const vesting_policy_context& ctx);
|
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);
|
void on_withdraw(const vesting_policy_context& ctx);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -114,6 +119,10 @@ namespace graphene { namespace chain {
|
||||||
void deposit(const fc::time_point_sec& now, const asset& amount);
|
void deposit(const fc::time_point_sec& now, const asset& amount);
|
||||||
bool is_deposit_allowed(const fc::time_point_sec& now, const asset& amount)const;
|
bool is_deposit_allowed(const fc::time_point_sec& now, const asset& amount)const;
|
||||||
|
|
||||||
|
/// @brief Deposit amount into vesting balance, making the new funds vest immediately
|
||||||
|
void deposit_vested(const fc::time_point_sec& now, const asset& amount);
|
||||||
|
bool is_deposit_vested_allowed(const fc::time_point_sec& now, const asset& amount)const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to remove a vesting balance from the VBO. As well
|
* Used to remove a vesting balance from the VBO. As well
|
||||||
* as the balance field, coin_seconds_earned and
|
* as the balance field, coin_seconds_earned and
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,6 @@ asset linear_vesting_policy::get_allowed_withdraw( const vesting_policy_context&
|
||||||
|
|
||||||
void linear_vesting_policy::on_deposit(const vesting_policy_context& ctx)
|
void linear_vesting_policy::on_deposit(const vesting_policy_context& ctx)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool linear_vesting_policy::is_deposit_allowed(const vesting_policy_context& ctx)const
|
bool linear_vesting_policy::is_deposit_allowed(const vesting_policy_context& ctx)const
|
||||||
|
|
@ -67,7 +66,6 @@ bool linear_vesting_policy::is_deposit_allowed( const vesting_policy_context& ct
|
||||||
void linear_vesting_policy::on_withdraw(const vesting_policy_context& ctx)
|
void linear_vesting_policy::on_withdraw(const vesting_policy_context& ctx)
|
||||||
{
|
{
|
||||||
total_withdrawn += ctx.amount.amount;
|
total_withdrawn += ctx.amount.amount;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool linear_vesting_policy::is_withdraw_allowed(const vesting_policy_context& ctx)const
|
bool linear_vesting_policy::is_withdraw_allowed(const vesting_policy_context& ctx)const
|
||||||
|
|
@ -87,17 +85,13 @@ fc::uint128_t cdd_vesting_policy::compute_coin_seconds_earned( const vesting_pol
|
||||||
fc::uint128_t coin_seconds_earned_cap = ctx.balance.amount.value;
|
fc::uint128_t coin_seconds_earned_cap = ctx.balance.amount.value;
|
||||||
coin_seconds_earned_cap *= vesting_seconds;
|
coin_seconds_earned_cap *= vesting_seconds;
|
||||||
|
|
||||||
return std::min(
|
return std::min(coin_seconds_earned + delta_coin_seconds, coin_seconds_earned_cap);
|
||||||
coin_seconds_earned + delta_coin_seconds,
|
|
||||||
coin_seconds_earned_cap
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cdd_vesting_policy::update_coin_seconds_earned(const vesting_policy_context& ctx)
|
void cdd_vesting_policy::update_coin_seconds_earned(const vesting_policy_context& ctx)
|
||||||
{
|
{
|
||||||
coin_seconds_earned = compute_coin_seconds_earned(ctx);
|
coin_seconds_earned = compute_coin_seconds_earned(ctx);
|
||||||
coin_seconds_earned_last_update = ctx.now;
|
coin_seconds_earned_last_update = ctx.now;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asset cdd_vesting_policy::get_allowed_withdraw(const vesting_policy_context& ctx)const
|
asset cdd_vesting_policy::get_allowed_withdraw(const vesting_policy_context& ctx)const
|
||||||
|
|
@ -111,7 +105,12 @@ asset cdd_vesting_policy::get_allowed_withdraw( const vesting_policy_context& ct
|
||||||
void cdd_vesting_policy::on_deposit(const vesting_policy_context& ctx)
|
void cdd_vesting_policy::on_deposit(const vesting_policy_context& ctx)
|
||||||
{
|
{
|
||||||
update_coin_seconds_earned(ctx);
|
update_coin_seconds_earned(ctx);
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
void cdd_vesting_policy::on_deposit_vested(const vesting_policy_context& ctx)
|
||||||
|
{
|
||||||
|
on_deposit(ctx);
|
||||||
|
coin_seconds_earned += ctx.amount.amount.value * vesting_seconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cdd_vesting_policy::on_withdraw(const vesting_policy_context& ctx)
|
void cdd_vesting_policy::on_withdraw(const vesting_policy_context& ctx)
|
||||||
|
|
@ -124,7 +123,6 @@ void cdd_vesting_policy::on_withdraw( const vesting_policy_context& ctx )
|
||||||
assert(coin_seconds_needed <= coin_seconds_earned);
|
assert(coin_seconds_needed <= coin_seconds_earned);
|
||||||
|
|
||||||
coin_seconds_earned -= coin_seconds_needed;
|
coin_seconds_earned -= coin_seconds_needed;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cdd_vesting_policy::is_deposit_allowed(const vesting_policy_context& ctx)const
|
bool cdd_vesting_policy::is_deposit_allowed(const vesting_policy_context& ctx)const
|
||||||
|
|
@ -133,6 +131,11 @@ bool cdd_vesting_policy::is_deposit_allowed( const vesting_policy_context& ctx )
|
||||||
&& sum_below_max_shares(ctx.amount, ctx.balance);
|
&& sum_below_max_shares(ctx.amount, ctx.balance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cdd_vesting_policy::is_deposit_vested_allowed(const vesting_policy_context& ctx) const
|
||||||
|
{
|
||||||
|
return is_deposit_allowed(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
bool cdd_vesting_policy::is_withdraw_allowed(const vesting_policy_context& ctx)const
|
bool cdd_vesting_policy::is_withdraw_allowed(const vesting_policy_context& ctx)const
|
||||||
{
|
{
|
||||||
return (ctx.amount <= get_allowed_withdraw(ctx));
|
return (ctx.amount <= get_allowed_withdraw(ctx));
|
||||||
|
|
@ -164,8 +167,10 @@ struct NAME ## _visitor \
|
||||||
}
|
}
|
||||||
|
|
||||||
VESTING_VISITOR(on_deposit,);
|
VESTING_VISITOR(on_deposit,);
|
||||||
|
VESTING_VISITOR(on_deposit_vested,);
|
||||||
VESTING_VISITOR(on_withdraw,);
|
VESTING_VISITOR(on_withdraw,);
|
||||||
VESTING_VISITOR(is_deposit_allowed, const);
|
VESTING_VISITOR(is_deposit_allowed, const);
|
||||||
|
VESTING_VISITOR(is_deposit_vested_allowed, const);
|
||||||
VESTING_VISITOR(is_withdraw_allowed, const);
|
VESTING_VISITOR(is_withdraw_allowed, const);
|
||||||
|
|
||||||
bool vesting_balance_object::is_deposit_allowed(const time_point_sec& now, const asset& amount)const
|
bool vesting_balance_object::is_deposit_allowed(const time_point_sec& now, const asset& amount)const
|
||||||
|
|
@ -189,6 +194,18 @@ void vesting_balance_object::deposit(const time_point_sec& now, const asset& amo
|
||||||
balance += amount;
|
balance += amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vesting_balance_object::deposit_vested(const time_point_sec& now, const asset& amount)
|
||||||
|
{
|
||||||
|
on_deposit_vested_visitor vtor(balance, now, amount);
|
||||||
|
policy.visit(vtor);
|
||||||
|
balance += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vesting_balance_object::is_deposit_vested_allowed(const time_point_sec& now, const asset& amount) const
|
||||||
|
{
|
||||||
|
return policy.visit(is_deposit_vested_allowed_visitor(balance, now, amount));
|
||||||
|
}
|
||||||
|
|
||||||
void vesting_balance_object::withdraw(const time_point_sec& now, const asset& amount)
|
void vesting_balance_object::withdraw(const time_point_sec& now, const asset& amount)
|
||||||
{
|
{
|
||||||
assert(amount <= balance);
|
assert(amount <= balance);
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ void database_fixture::verify_asset_supplies( )const
|
||||||
for( const account_statistics_object& a : statistics_index )
|
for( const account_statistics_object& a : statistics_index )
|
||||||
{
|
{
|
||||||
reported_core_in_orders += a.total_core_in_orders;
|
reported_core_in_orders += a.total_core_in_orders;
|
||||||
total_balances[asset_id_type()] += a.pending_fees;
|
total_balances[asset_id_type()] += a.pending_fees + a.pending_vested_fees;
|
||||||
}
|
}
|
||||||
for( const limit_order_object& o : db.get_index_type<limit_order_index>().indices() )
|
for( const limit_order_object& o : db.get_index_type<limit_order_index>().indices() )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue