Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement BSIP85: Maker order creation fee discount #2145

Merged
merged 3 commits into from
Apr 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 62 additions & 10 deletions libraries/chain/db_market.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,31 +812,83 @@ bool database::fill_limit_order( const limit_order_object& order, const asset& p
assert( pays.asset_id != receives.asset_id );
push_applied_operation( fill_order_operation( order.id, order.seller, pays, receives, issuer_fees, fill_price, is_maker ) );

// BSIP85: Maker order creation fee discount, https://github.com/bitshares/bsips/blob/master/bsip-0085.md
// if the order creation fee was paid in BTS,
// return round_down(deferred_fee * maker_fee_discount_percent) to the owner,
// then process the remaining deferred fee as before;
// if the order creation fee was paid in another asset,
// return round_down(deferred_paid_fee * maker_fee_discount_percent) to the owner,
// return round_down(deferred_fee * maker_fee_discount_percent) to the fee pool of the asset,
// then process the remaining deferred fee and deferred paid fee as before.
const uint16_t maker_discount_percent = get_global_properties().parameters.get_maker_fee_discount_percent();

// Save local copies for calculation
share_type deferred_fee = order.deferred_fee;
share_type deferred_paid_fee = order.deferred_paid_fee.amount;

// conditional because cheap integer comparison may allow us to avoid two expensive modify() and object lookups
if( order.deferred_fee > 0 )
if( order.deferred_paid_fee.amount > 0 ) // implies head_block_time() > HARDFORK_CORE_604_TIME
{
modify( seller.statistics(*this), [&]( account_statistics_object& statistics )
share_type fee_pool_refund = 0;
if( is_maker && maker_discount_percent > 0 )
{
statistics.pay_fee( order.deferred_fee, get_global_properties().parameters.cashback_vesting_threshold );
} );
}
share_type refund = detail::calculate_percent( deferred_paid_fee, maker_discount_percent );
// Note: it's possible that the deferred_paid_fee is very small,
// which can result in a zero refund due to rounding issue,
// in this case, no refund to the fee pool
if( refund > 0 )
{
FC_ASSERT( refund <= deferred_paid_fee, "Internal error" );
adjust_balance( order.seller, asset(refund, order.deferred_paid_fee.asset_id) );
deferred_paid_fee -= refund;

// deferred_fee might be positive too
FC_ASSERT( deferred_fee > 0, "Internal error" );
fee_pool_refund = detail::calculate_percent( deferred_fee, maker_discount_percent );
FC_ASSERT( fee_pool_refund <= deferred_fee, "Internal error" );
deferred_fee -= fee_pool_refund;
}
}

if( order.deferred_paid_fee.amount > 0 ) // implies head_block_time() > HARDFORK_CORE_604_TIME
{
const auto& fee_asset_dyn_data = order.deferred_paid_fee.asset_id(*this).dynamic_asset_data_id(*this);
modify( fee_asset_dyn_data, [&](asset_dynamic_data_object& addo) {
addo.accumulated_fees += order.deferred_paid_fee.amount;
modify( fee_asset_dyn_data, [deferred_paid_fee,fee_pool_refund](asset_dynamic_data_object& addo) {
addo.accumulated_fees += deferred_paid_fee;
addo.fee_pool += fee_pool_refund;
});
}

if( order.deferred_fee > 0 )
{
if( order.deferred_paid_fee.amount <= 0 // paid in CORE, or before HF 604
&& is_maker && maker_discount_percent > 0 )
{
share_type refund = detail::calculate_percent( deferred_fee, maker_discount_percent );
if( refund > 0 )
{
FC_ASSERT( refund <= deferred_fee, "Internal error" );
adjust_balance( order.seller, asset(refund, asset_id_type()) );
deferred_fee -= refund;
}
}
// else do nothing here, because we have already processed it above, or no need to process

if( deferred_fee > 0 )
{
modify( seller.statistics(*this), [deferred_fee,this]( account_statistics_object& statistics )
{
statistics.pay_fee( deferred_fee, get_global_properties().parameters.cashback_vesting_threshold );
} );
}
}

if( pays == order.amount_for_sale() )
{
remove( order );
return true;
}
else
{
modify( order, [&]( limit_order_object& b ) {
modify( order, [&pays]( limit_order_object& b ) {
b.for_sale -= pays.amount;
b.deferred_fee = 0;
b.deferred_paid_fee.amount = 0;
Expand Down
6 changes: 6 additions & 0 deletions libraries/chain/hardfork.d/BSIP_85.hf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// BSIP 85 (Maker order creation fee discount) hardfork check
#ifndef HARDFORK_BSIP_85_TIME
// Jan 1 2030, midnight; this is a dummy date until a hardfork date is scheduled
#define HARDFORK_BSIP_85_TIME (fc::time_point_sec( 1893456000 ))
#define HARDFORK_BSIP_85_PASSED(now) (now >= HARDFORK_BSIP_85_TIME)
#endif
4 changes: 4 additions & 0 deletions libraries/chain/proposal_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ struct proposal_operation_hardfork_visitor
FC_ASSERT(!op.new_parameters.current_fees->exists<custom_authority_delete_operation>(),
"Unable to define fees for custom authority operations prior to hardfork BSIP 40");
}
if (!HARDFORK_BSIP_85_PASSED(block_time)) {
FC_ASSERT(!op.new_parameters.extensions.value.maker_fee_discount_percent.valid(),
"Unable to set maker_fee_discount_percent before hardfork BSIP 85");
}
if (!HARDFORK_BSIP_86_PASSED(block_time)) {
FC_ASSERT(!op.new_parameters.extensions.value.market_fee_network_percent.valid(),
"Unable to set market_fee_network_percent before hardfork BSIP 86");
Expand Down
11 changes: 11 additions & 0 deletions libraries/protocol/chain_parameters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ namespace graphene { namespace protocol {
FC_ASSERT( *extensions.value.market_fee_network_percent <= GRAPHENE_100_PERCENT,
"The market_fee_network_percent parameter can not exceed 100%" );
}
if( extensions.value.maker_fee_discount_percent.valid() )
{
FC_ASSERT( *extensions.value.maker_fee_discount_percent <= GRAPHENE_100_PERCENT,
"The maker_fee_discount_percent parameter can not exceed 100%" );
}
}

uint16_t chain_parameters::get_market_fee_network_percent() const
Expand All @@ -114,6 +119,12 @@ namespace graphene { namespace protocol {
*extensions.value.market_fee_network_percent : 0;
}

uint16_t chain_parameters::get_maker_fee_discount_percent() const
{
return extensions.value.maker_fee_discount_percent.valid() ?
*extensions.value.maker_fee_discount_percent : 0;
}

}}

GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION( graphene::protocol::chain_parameters )
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ namespace graphene { namespace protocol {
optional< htlc_options > updatable_htlc_options;
optional< custom_authority_options_type > custom_authority_options;
optional< uint16_t > market_fee_network_percent;
optional< uint16_t > maker_fee_discount_percent;
};

extension<ext> extensions;
Expand All @@ -99,6 +100,9 @@ namespace graphene { namespace protocol {
/// If @ref market_fee_network_percent is valid, return the value it contains, otherwise return 0
uint16_t get_market_fee_network_percent() const;

/// If @ref maker_fee_discount_percent is valid, return the value it contains, otherwise return 0
uint16_t get_maker_fee_discount_percent() const;

private:
static void safe_copy(chain_parameters& to, const chain_parameters& from);
};
Expand All @@ -121,6 +125,7 @@ FC_REFLECT( graphene::protocol::chain_parameters::ext,
(updatable_htlc_options)
(custom_authority_options)
(market_fee_network_percent)
(maker_fee_discount_percent)
)

FC_REFLECT( graphene::protocol::chain_parameters,
Expand Down
Loading