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 BSIP 74: Margin Call Fee Ratio #2130

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e9e0e7e
hardfork protection for bsip74
jmjatlanta Mar 30, 2020
00b2ed1
HF for BSIP74 happens on time, not next maint
jmjatlanta Mar 30, 2020
8d5aad6
calculating call order price
jmjatlanta Apr 1, 2020
fee9fe6
test of normal case complete
jmjatlanta Apr 2, 2020
ca6f361
Implement margin call fee
jmjatlanta Apr 4, 2020
fa7d4d5
do not assert if fee is zero
jmjatlanta Apr 10, 2020
a43e18a
update feature branch with hf changes
jmjatlanta Apr 10, 2020
2b120c9
Resolve compiler warning
jmjatlanta Apr 10, 2020
4fd251c
fix/add comments
jmjatlanta Apr 11, 2020
35d797a
Merge hardfork into jmj_bsip74
jmjatlanta Apr 17, 2020
3ea265a
fix misinterpretation of method params
jmjatlanta Apr 17, 2020
4684e51
Fix wrong comment
jmjatlanta Apr 17, 2020
1aee59c
match on calls with price feed/(mssr-mcfr)
jmjatlanta Apr 23, 2020
750c720
rollback db_market changes
jmjatlanta Apr 23, 2020
9ea7962
marge hardfork to bsip74
jmjatlanta Apr 23, 2020
84c3e04
Set up for margin fee in collateral
jmjatlanta Apr 24, 2020
75374de
test cleanup
jmjatlanta Apr 27, 2020
a394deb
Merge cjs-collat-asset-container-pr into jmj_bsip74
jmjatlanta Apr 30, 2020
d11ecbf
MSSR / MCFR Testing
jmjatlanta Apr 30, 2020
fad10a6
Test limit as taker
jmjatlanta May 1, 2020
0fae92f
limit maker case
jmjatlanta May 3, 2020
3531df9
merge in hf changes to jmj_bsip74
jmjatlanta May 3, 2020
96c2d98
handle when limit order is taker
jmjatlanta May 4, 2020
1424257
Merge hardfork into jmj_bsip74
jmjatlanta May 4, 2020
476e3fd
call order with insufficient collateral
jmjatlanta May 4, 2020
efff548
wrap long lines in tests
jmjatlanta May 4, 2020
d062cd2
Add check to proposal/asset_create for bsip 74
jmjatlanta May 4, 2020
eb9a898
move margin_fee to bitasset struct
jmjatlanta May 11, 2020
4c0ac06
tweak code, clean comments
jmjatlanta May 11, 2020
f3f363c
Merge hardfork into jmj_bsip74
jmjatlanta May 11, 2020
7df91b4
comment fix
jmjatlanta May 11, 2020
5c2210b
charge margin fee to call order
jmjatlanta May 12, 2020
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
9 changes: 9 additions & 0 deletions libraries/chain/asset_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ void_result asset_create_evaluator::do_evaluate( const asset_create_operation& o
FC_ASSERT( op.bitasset_opts->feed_lifetime_sec > chain_parameters.block_interval &&
op.bitasset_opts->force_settlement_delay_sec > chain_parameters.block_interval );
}

FC_ASSERT( d.head_block_time() >= HARDFORK_CORE_BSIP74_TIME
|| !op.common_options.extensions.value.margin_call_fee_ratio.valid(),
"A BitAsset's MCFR cannot be set before Hardfork BSIP74" );
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved

if( op.is_prediction_market )
{
FC_ASSERT( op.bitasset_opts );
Expand Down Expand Up @@ -299,6 +304,10 @@ void_result asset_update_evaluator::do_evaluate(const asset_update_operation& o)
"Incorrect issuer for asset! (${o.issuer} != ${a.issuer})",
("o.issuer", o.issuer)("a.issuer", a.issuer) );

FC_ASSERT( d.head_block_time() >= HARDFORK_CORE_BSIP74_TIME
|| !o.new_options.extensions.value.margin_call_fee_ratio.valid(),
"A BitAsset's MCFR cannot be set before Hardfork BSIP74" );
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved

const auto& chain_parameters = d.get_global_properties().parameters;

FC_ASSERT( o.new_options.whitelist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities );
Expand Down
169 changes: 113 additions & 56 deletions libraries/chain/db_market.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -803,9 +803,8 @@ bool database::fill_limit_order( const limit_order_object& order, const asset& p
FC_ASSERT( pays.asset_id != receives.asset_id );

const account_object& seller = order.seller(*this);
const asset_object& recv_asset = receives.asset_id(*this);

auto issuer_fees = pay_market_fees(&seller, recv_asset, receives);
auto issuer_fees = pay_market_fees(&seller, receives.asset_id(*this), receives);

pay_order( seller, receives - issuer_fees, pays );

Expand Down Expand Up @@ -847,9 +846,18 @@ bool database::fill_limit_order( const limit_order_object& order, const asset& p
}
} FC_CAPTURE_AND_RETHROW( (order)(pays)(receives) ) }


/***
* @brief fill a call order in the specified amounts
* @param order the call order
* @param pays What the call order will give to the other party
* @param receives what the call order will receive from the other party
* @param fill_price the price at which the call order will execute
* @param is_maker TRUE if the call order is the maker, FALSE if it is the taker
* @param is_margin_call TRUE if this method was called due to a margin call
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't fully understand what's your definition of "a margin call" nor the logic around this parameter. Looks like it is always equal to !is_maker.

* @returns TRUE if the call order was completely filled
*/
bool database::fill_call_order( const call_order_object& order, const asset& pays, const asset& receives,
const price& fill_price, const bool is_maker )
const price& fill_price, const bool is_maker, bool is_margin_call )
{ try {
FC_ASSERT( order.debt_type() == receives.asset_id );
FC_ASSERT( order.collateral_type() == pays.asset_id );
Expand All @@ -859,38 +867,52 @@ bool database::fill_call_order( const call_order_object& order, const asset& pay
const asset_object& mia = receives.asset_id(*this);
FC_ASSERT( mia.is_market_issued() );

// calculate any margin call fees
asset margin_fee(0, pays.asset_id);
if (is_margin_call)
{
margin_fee = calculate_margin_fee( mia, pays );
FC_ASSERT( margin_fee.asset_id == pays.asset_id ); // margin fee should be paid in the debt asset
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved
// margin fee should never be more than what the call order is receiving (but both could be zero)
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved
FC_ASSERT( margin_fee.amount == 0 || margin_fee.amount < pays.amount );
}

optional<asset> collateral_freed;
modify( order, [&]( call_order_object& o ){
o.debt -= receives.amount;
o.collateral -= pays.amount;
if( o.debt == 0 )
{
collateral_freed = o.get_collateral();
o.collateral = 0;
}
else
// adjust the order
modify( order, [&]( call_order_object& o ) {
o.debt -= receives.amount;
o.collateral -= pays.amount;
if( o.debt == 0 ) // is the whole debt paid?
{
collateral_freed = o.get_collateral();
o.collateral = 0;
}
else // the debt was not completely paid
{
auto maint_time = get_dynamic_global_properties().next_maintenance_time;
// update call_price after core-343 hard fork,
// but don't update call_price after core-1270 hard fork
if( maint_time <= HARDFORK_CORE_1270_TIME && maint_time > HARDFORK_CORE_343_TIME )
{
auto maint_time = get_dynamic_global_properties().next_maintenance_time;
// update call_price after core-343 hard fork,
// but don't update call_price after core-1270 hard fork
if( maint_time <= HARDFORK_CORE_1270_TIME && maint_time > HARDFORK_CORE_343_TIME )
{
o.call_price = price::call_price( o.get_debt(), o.get_collateral(),
mia.bitasset_data(*this).current_feed.maintenance_collateral_ratio );
}
o.call_price = price::call_price( o.get_debt(), o.get_collateral(),
mia.bitasset_data(*this).current_feed.maintenance_collateral_ratio );
}
}
});

// distribute the margin fee
if (margin_fee.amount > 0)
distribute_market_fees( &order.borrower(*this), margin_fee.asset_id(*this), margin_fee );
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved

// update current supply
const asset_dynamic_data_object& mia_ddo = mia.dynamic_asset_data_id(*this);

modify( mia_ddo, [&receives]( asset_dynamic_data_object& ao ){
ao.current_supply -= receives.amount;
});

// Adjust balance
// If the whole debt is paid, adjust borrower's collateral balance
if( collateral_freed.valid() )
adjust_balance( order.borrower, *collateral_freed );
adjust_balance( order.borrower, *collateral_freed - margin_fee );
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved

// Update account statistics. We know that order.collateral_type() == pays.asset_id
if( pays.asset_id == asset_id_type() )
Expand All @@ -902,9 +924,11 @@ bool database::fill_call_order( const call_order_object& order, const asset& pay
});
}

// virtual operation for account history
push_applied_operation( fill_order_operation( order.id, order.borrower, pays, receives,
asset(0, pays.asset_id), fill_price, is_maker ) );
asset(0, pays.asset_id), fill_price, is_maker ) );
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved

// Call order completely filled, remove it
if( collateral_freed.valid() )
remove( order );

Expand Down Expand Up @@ -935,6 +959,7 @@ bool database::fill_settle_order( const force_settlement_object& settle, const a
} else {
filled = true;
}

adjust_balance(settle.owner, receives - issuer_fees);

assert( pays.asset_id != receives.asset_id );
Expand Down Expand Up @@ -1145,7 +1170,7 @@ bool database::check_call_orders( const asset_object& mia, bool enable_black_swa
if( filled_call && before_core_hardfork_343 )
++call_price_itr;
// when for_new_limit_order is true, the call order is maker, otherwise the call order is taker
fill_call_order( call_order, call_pays, call_receives, match_price, for_new_limit_order );
fill_call_order( call_order, call_pays, call_receives, match_price, for_new_limit_order, true );
if( !before_core_hardfork_1270 )
call_collateral_itr = call_collateral_index.lower_bound( call_min );
else if( !before_core_hardfork_343 )
Expand Down Expand Up @@ -1192,34 +1217,57 @@ asset database::calculate_market_fee( const asset_object& trade_asset, const ass
return percent_fee;
}

asset database::pay_market_fees(const account_object* seller, const asset_object& recv_asset, const asset& receives )
/***
* @brief calculate the margin fee
*
* Note that the trade_asset controls the fee percentage, but trade_amount controls the asset the fee is paid in
* @param trade_asset the asset that controls the fee
* @param trade_amount the asset that the fee should be paid in
* @returns the amount to be paid
*/
asset database::calculate_margin_fee( const asset_object& trade_asset, const asset& trade_amount)
{
assert( trade_asset.id != trade_amount.asset_id );
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved

if( !trade_asset.charges_market_fees() )
return asset(0, trade_amount.asset_id);
if( !trade_asset.options.extensions.value.margin_call_fee_ratio.valid()
|| *trade_asset.options.extensions.value.margin_call_fee_ratio == 0 )
return asset(0, trade_amount.asset_id);

auto value = detail::calculate_percent(trade_amount.amount, *trade_asset.options.extensions.value.margin_call_fee_ratio);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems different from the specification.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem I have is clarifying the specifications. I apologize for the lengthy post, but it is how my mind works. The BSIP says:

When a margin call trading happens, the buyer sells smartcoin with quantity X and get collaterals in quantity X*(MSSR-MCFR)/settlement price, the margin call order owner sells collaterals in quantity X*MSSR/settlement price and get smartcoin in quantity X, the delta in paid and received collaterals in quantity X*MCFR/settlement price will be paid to the owner of the smartcoin as margin call fee.

My interpretation (which I will attempt to keep updated within this comment, and probably move to my blog to help me in the future):

Doug the Debtor put up collateral of token C which created token D. Doug was charged an operation fee I think, although I am not sure but it is unimportant. We will assume Doug then sold or transferred D ( also unimportant in this context).

Larry the creator of a Limit order would like to sell the desired quantity of token D and receive the desired quantity of token C. Upon placing the order, Larry was charged a limit order create fee, which is not important in this context.

When the debt position was created, a call order was created for Doug the debtor. Within that call order is the current debt and collateral balances.

When the settlement price of the price feed reaches a certain level, Doug's position will get called. Such a margin call will generate revenue for the asset issuer, if the issuer has set the new margin_call_fee_ratio within that asset's options.

This fee does not affect Larry. He simply placed a limit order on the book of the exchange.

Doug will see the fee if he compares the amount of collateral he received from the transaction with the amount of debt that was paid off by the margin call.

Now the more technical details:

When will these orders be matched? When the settlement price from the price feed pushes the value of Doug's collateral below the allowed threshold for the debt asset (see db_market.cpp#database::check_call_orders).

What will Larry receive? Exactly what he wished in his limit order.

What will Doug receive? Relief from (some or all of) his debt, and some of his collateral back. He will not receive the full value of his collateral, based on the feed's settlement price. Some of the value of the transaction was paid to the issuer of the debt asset as a margin call fee.

Implementation details:

database::check_call_orders (db_market.cpp) knows when to trigger a margin call. When triggered, fill_call_order is called, and then fill_limit_order is called.

Within fill_call_order the fee is taken from the debtor's debt position and given to the asset issuer as a vesting balance. The remaining value of the debt is used to calculate the collateral that the debtor receives. That collateral is then placed in the debtor's available account balance.

Copy link
Contributor Author

@jmjatlanta jmjatlanta Apr 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In looking at the spec, I believe that I need to adjust the "trigger" of the margin call. The spec reads:

Margin call order price = settlement price/(MSSR-MCFR)

And that is part of check_call_orders

Update: No, this only affects the debtor, not when the margin call happens.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may have written something wrong in previous comments. Let's forget them and start here.

With bsip74,

  • condition when a call order is possible to be matched does not change, it's still call_price >= feed_price;
  • condition where (at what price, aka match_price) the call order be matched does change,
    • previously, if a limit order buys at feed_price / mssr, it will match the call order,
    • now, if a limit order buys at feed_price / (mssr - mcfr), it will match the call order,
  • when matched, the limit order gets collateral (be filled) at feed_price / (mssr - mcfr), the call order pays (be filled) at feed_price / mssr, the difference goes to the debt asset owner;
  • the call order can be a maker or a taker, there is a small difference in match_price, iirc maker and taker are handled in different functions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One important thing, the fee is some amount of the collateral asset, so it can not go to the accumulated_fees field of the debt asset, which means we likely can not reuse the code of pay_market_fees. It can not go to the accumulated_fees field of the collateral asset either, since the asset can be owned by someone else.

In addition, a complex scenario is the debt asset can change from one collateral to another, so we need to store the fees in a multi-asset container. Adding new fields into asset_object or another object means we need to add new operations to claim them, that's too much work to implement.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another thing in mind: mssr-mcfr in the specification, and we don't allow something for nonthing, so it's implied that mssr>mcfr. However, mssr is updated by price feed producers and an internal timer, mcfr is updated by asset owner, so likely we can't validate when one of them is updated. So we need to cap the value of mcfr when use it in calculation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@abitmore

I believe I am clear that this change modifies which limit orders qualify to be matched.

To be clear, let me walk through what I am seeing in db_market.cpp::check_call_orders. And just focusing on the price the limit order will transact at...

Prior to this change, the limit order was filled at the price dictated by the order itself:

price match_price = limit_order.sell_price;

Based on what I'm reading in your comment above, after the hardfork, the limit order will transact at a price based on feed price, MSSR and MCFR. That will result in the limit order receiving a price potentially very different than their order.

Or it could be that I am misreading your comment above, and you were only presenting the extreme example of when a limit order just happens to match right at the new calculated price for what qualifies a match, which would mean the order gets exactly what it asked for.

Or I am making assumptions in the code that are incorrect.

Would you clarify please?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep in mind that match price is always price of the maker, see BSIP 32.

  • In check_call_orders, the call order is the taker and the limit order is the maker, so the match price will always be the price of the limit order.
  • In another function where the call order is the maker and the limit order is the taker, the match price will be settlement_price / (mssr-mcfr).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the reference to BSIP 32. There are some inconsistencies in that BSIP that make it difficult to understand, but I believe the gist is as you say, when the limit order is the maker, the maker price is what is used.

So that leads me to believe that BSIP 74 applies only when the call order is the maker. Hence the margin call fee will not apply when the limit order is the maker. Is that correct?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the margin call fee should always apply, although how much to pay is not clearly described in the BSIP when Peter approved the pull request.

In case when the call order is taker, I think it's fine to charge the amount filled_debt * mcfr / feed_price from the call order as fee.

asset percent_fee(value, trade_amount.asset_id);

// TODO: This check should be based on exchange rate
/*
if( percent_fee.amount > trade_asset.options.max_market_fee )
percent_fee.amount = trade_asset.options.max_market_fee;
*/
return percent_fee;
}

void database::distribute_market_fees( const account_object* seller, const asset_object& recv_asset, const asset& market_fees)
{
const auto market_fees = calculate_market_fee( recv_asset, receives );
auto issuer_fees = market_fees;
FC_ASSERT( issuer_fees <= receives, "Market fee shouldn't be greater than receives");
//Don't dirty undo state if not actually collecting any fees
if ( issuer_fees.amount > 0 )
// Share market fees to the network
const uint16_t network_percent = get_global_properties().parameters.get_market_fee_network_percent();
if( network_percent > 0 )
{
// Share market fees to the network
const uint16_t network_percent = get_global_properties().parameters.get_market_fee_network_percent();
if( network_percent > 0 )
const auto network_fees_amt = detail::calculate_percent( issuer_fees.amount, network_percent );
FC_ASSERT( network_fees_amt <= issuer_fees.amount,
"Fee shared to the network shouldn't be greater than total market fee" );
if( network_fees_amt > 0 )
{
const auto network_fees_amt = detail::calculate_percent( issuer_fees.amount, network_percent );
FC_ASSERT( network_fees_amt <= issuer_fees.amount,
"Fee shared to the network shouldn't be greater than total market fee" );
if( network_fees_amt > 0 )
{
const asset network_fees = recv_asset.amount( network_fees_amt );
deposit_market_fee_vesting_balance( GRAPHENE_COMMITTEE_ACCOUNT, network_fees );
issuer_fees -= network_fees;
}
const asset network_fees = recv_asset.amount( network_fees_amt );
deposit_market_fee_vesting_balance( GRAPHENE_COMMITTEE_ACCOUNT, network_fees );
issuer_fees -= network_fees;
}
}

// Process the remaining fees
if ( issuer_fees.amount > 0 )
{
// calculate and pay rewards
// procss the remaining fees
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved
if (issuer_fees.amount > 0)
{
// calculate and pay referral rewards
asset reward = recv_asset.amount(0);

auto is_rewards_allowed = [&recv_asset, seller]() {
Expand Down Expand Up @@ -1262,22 +1310,31 @@ asset database::pay_market_fees(const account_object* seller, const asset_object
deposit_market_fee_vesting_balance(seller->referrer, referrer_reward);
}
}
if( registrar_reward.amount > 0 )
if ( registrar_reward.amount > 0)
deposit_market_fee_vesting_balance(seller->registrar, registrar_reward);
}
}
}

if( issuer_fees.amount > reward.amount )
{
const auto& recv_dyn_data = recv_asset.dynamic_asset_data_id(*this);
modify( recv_dyn_data, [&issuer_fees, &reward]( asset_dynamic_data_object& obj ){
obj.accumulated_fees += issuer_fees.amount - reward.amount;
});
}
const auto& recv_dyn_data = recv_asset.dynamic_asset_data_id(*this);
modify( recv_dyn_data, [&issuer_fees, &reward]( asset_dynamic_data_object& obj ){
obj.accumulated_fees += issuer_fees.amount - reward.amount;
});
}
}

asset database::pay_market_fees(const account_object* seller, const asset_object& recv_asset, const asset& receives )
{
// market fee calculation
const auto issuer_fees = calculate_market_fee( recv_asset, receives );
FC_ASSERT( issuer_fees <= receives, "Market fee shouldn't be greater than receives");
//Don't dirty undo state if not actually collecting any fees
if ( issuer_fees.amount > 0 )
{
distribute_market_fees(seller, recv_asset, issuer_fees);
}

return market_fees;
return issuer_fees;
}

} }
4 changes: 4 additions & 0 deletions libraries/chain/hardfork.d/CORE_BSIP74.hf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// bitshares-core BSIP 74 add margin call fee
#ifndef HARDFORK_CORE_BSIP74_TIME
#define HARDFORK_CORE_BSIP74_TIME (fc::time_point_sec( 1679955066 ) ) // Temporary date until actual hardfork date is set
#endif
30 changes: 29 additions & 1 deletion libraries/chain/include/graphene/chain/database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,16 @@ namespace graphene { namespace chain {
*/
///@{
int match( const limit_order_object& taker, const limit_order_object& maker, const price& trade_price );
/***
* @brief Match the two orders
* @param taker the taker
jmjatlanta marked this conversation as resolved.
Show resolved Hide resolved
* @param maker the maker
* @param trade_price the price the trade should execute at
* @param feed_price the price of the current feed
* @param maintenance_collateral_ratio the maintenance collateral ratio
* @param maintenance_collateralization the maintenance collateralization
* @returns 0 if no orders were matched, 1 if taker was filled, 2 if maker was filled, 3 if both were filled
*/
int match( const limit_order_object& taker, const call_order_object& maker, const price& trade_price,
const price& feed_price, const uint16_t maintenance_collateral_ratio,
const optional<price>& maintenance_collateralization );
Expand All @@ -428,8 +438,17 @@ namespace graphene { namespace chain {
*/
bool fill_limit_order( const limit_order_object& order, const asset& pays, const asset& receives, bool cull_if_small,
const price& fill_price, const bool is_maker );
/***
* @brief attempt to fill a call order
* @param order the order
* @param pays what the buyer pays for the collateral
* @param receives the collateral received by the buyer
* @param fill_price the price the transaction executed at
* @param is_maker TRUE if the buyer is the maker, FALSE if the buyer is the taker
* @returns TRUE if the order was completely filled
*/
bool fill_call_order( const call_order_object& order, const asset& pays, const asset& receives,
const price& fill_price, const bool is_maker );
const price& fill_price, const bool is_maker, bool is_margin_call = false );
bool fill_settle_order( const force_settlement_object& settle, const asset& pays, const asset& receives,
const price& fill_price, const bool is_maker );

Expand All @@ -439,8 +458,17 @@ namespace graphene { namespace chain {
// helpers to fill_order
void pay_order( const account_object& receiver, const asset& receives, const asset& pays );

/**
* Calculate the market fee that is to be taken
* @param recv_asset the asset that is to be given
* @param trade_amount the quantity
* @param is_margin_trading TRUE if this is a limit order going against a call order
*/
asset calculate_market_fee(const asset_object& recv_asset, const asset& trade_amount);
asset calculate_margin_fee(const asset_object& pays_asset, const asset& trade_amount);
asset pay_market_fees(const account_object* seller, const asset_object& recv_asset, const asset& receives );
void distribute_market_fees( const account_object* seller, const asset_object& recv_asset, const asset& issuer_fees);

///@}


Expand Down
2 changes: 0 additions & 2 deletions libraries/chain/include/graphene/chain/market_evaluator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ namespace graphene { namespace chain {
void_result do_evaluate( const limit_order_create_operation& o );
object_id_type do_apply( const limit_order_create_operation& o );

asset calculate_market_fee( const asset_object* aobj, const asset& trade_amount );

/** override the default behavior defined by generic_evalautor
*/
virtual void convert_fee() override;
Expand Down
5 changes: 4 additions & 1 deletion libraries/protocol/include/graphene/protocol/asset_ops.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ namespace graphene { namespace protocol {
{
fc::optional<uint16_t> reward_percent;
fc::optional<flat_set<account_id_type>> whitelist_market_fee_sharing;
fc::optional<uint16_t> margin_call_fee_ratio; // fee to asset issuer for margin call trading
};

typedef extension<additional_asset_options> additional_asset_options_t;

bool is_valid_symbol( const string& symbol );
Expand Down Expand Up @@ -113,6 +115,7 @@ namespace graphene { namespace protocol {
/// This speicifies which asset type is used to collateralize short sales
/// This field may only be updated if the current supply of the asset is zero.
asset_id_type short_backing_asset;

extensions_type extensions;

/// Perform internal consistency checks.
Expand Down Expand Up @@ -544,7 +547,7 @@ FC_REFLECT( graphene::protocol::bitasset_options,
(extensions)
)

FC_REFLECT( graphene::protocol::additional_asset_options, (reward_percent)(whitelist_market_fee_sharing) )
FC_REFLECT( graphene::protocol::additional_asset_options, (reward_percent)(whitelist_market_fee_sharing) (margin_call_fee_ratio) )
FC_REFLECT( graphene::protocol::asset_create_operation::fee_parameters_type, (symbol3)(symbol4)(long_symbol)(price_per_kbyte) )
FC_REFLECT( graphene::protocol::asset_global_settle_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::protocol::asset_settle_operation::fee_parameters_type, (fee) )
Expand Down
2 changes: 1 addition & 1 deletion programs/size_checker/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ int main( int argc, char** argv )

idump( (witnesses) );

for( int32_t i = 0; i < op.count(); ++i )
for( size_t i = 0; i < op.count(); ++i )
{
op.set_which(i);
op.visit( size_check_type_visitor(i) );
Expand Down
Loading