-
Notifications
You must be signed in to change notification settings - Fork 647
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
BSIP38 add target_cr option to call order #838
Changes from 17 commits
82c8d31
51a2aff
7c84535
a60573e
96b85ad
ec00b2a
7d5db49
49e5a59
087e564
2c61ad9
b4b18e2
ddb6baa
dd8d7f6
15b2b16
58542b8
464fd38
e68df58
a1e9d89
e7f4af8
baaf170
d1c3448
e2f33f5
516228b
6a43799
182e6ec
610dbf5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
// bitshares-core issue #834 "BSIP38: add target CR option to short positions" | ||
#ifndef HARDFORK_CORE_834_TIME | ||
#define HARDFORK_CORE_834_TIME (fc::time_point_sec( 1600000000 )) | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,7 @@ | |
*/ | ||
#pragma once | ||
#include <graphene/chain/protocol/base.hpp> | ||
#include <graphene/chain/protocol/ext.hpp> | ||
|
||
namespace graphene { namespace chain { | ||
|
||
|
@@ -94,8 +95,6 @@ namespace graphene { namespace chain { | |
void validate()const; | ||
}; | ||
|
||
|
||
|
||
/** | ||
* @ingroup operations | ||
* | ||
|
@@ -110,14 +109,26 @@ namespace graphene { namespace chain { | |
*/ | ||
struct call_order_update_operation : public base_operation | ||
{ | ||
/** | ||
* Options to be used in @ref call_order_update_operation. | ||
* | ||
* @note this struct can be expanded by adding more options in the end. | ||
*/ | ||
struct options_type | ||
{ | ||
optional<uint16_t> target_collateral_ratio; ///< maximum CR to maintain when selling collateral on margin call | ||
}; | ||
|
||
/** this is slightly more expensive than limit orders, this pricing impacts prediction markets */ | ||
struct fee_parameters_type { uint64_t fee = 20 * GRAPHENE_BLOCKCHAIN_PRECISION; }; | ||
|
||
asset fee; | ||
account_id_type funding_account; ///< pays fee, collateral, and cover | ||
asset delta_collateral; ///< the amount of collateral to add to the margin position | ||
asset delta_debt; ///< the amount of the debt to be paid off, may be negative to issue new debt | ||
extensions_type extensions; | ||
|
||
typedef vector<extension<options_type>> extension_type; // use a vector here to be compatible with old JSON | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrapping the extension in a 1-element-vector is ugly. Is it really worth it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sacrificing JSON compatibility means all UI / bot / client software need to update before any API node is updated (before and after hard fork), and need to use different JSON format for different version of nodes (before hardfork). It affects not only reading from the blockchain, but also broadcasting new transactions. Giving that we have many different clients now, I don't think it's a good idea to break the compatibility. (I personally is using a 2016 build of bitshares-ui and don't want to upgrade :P) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually for clients that submit extensions, an empty array is treated like an empty object: https://github.com/bitshares/bitshares-core/blob/master/libraries/chain/include/graphene/chain/protocol/ext.hpp#L169 So we're breaking compatibility only when reading from the chain, and even there it won't matter in client languages that treat objects and arrays mostly the same (like JavaScript). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So old clients can still broad transactions with new nodes even without the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed |
||
extension_type extensions; | ||
|
||
account_id_type fee_payer()const { return funding_account; } | ||
void validate()const; | ||
|
@@ -214,6 +225,10 @@ FC_REFLECT( graphene::chain::bid_collateral_operation::fee_parameters_type, (fee | |
FC_REFLECT( graphene::chain::fill_order_operation::fee_parameters_type, ) // VIRTUAL | ||
FC_REFLECT( graphene::chain::execute_bid_operation::fee_parameters_type, ) // VIRTUAL | ||
|
||
FC_REFLECT( graphene::chain::call_order_update_operation::options_type, (target_collateral_ratio) ) | ||
|
||
FC_REFLECT_TYPENAME( graphene::chain::call_order_update_operation::extension_type ) | ||
|
||
FC_REFLECT( graphene::chain::limit_order_create_operation,(fee)(seller)(amount_to_sell)(min_to_receive)(expiration)(fill_or_kill)(extensions)) | ||
FC_REFLECT( graphene::chain::limit_order_cancel_operation,(fee)(fee_paying_account)(order)(extensions) ) | ||
FC_REFLECT( graphene::chain::call_order_update_operation, (fee)(funding_account)(delta_collateral)(delta_debt)(extensions) ) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -157,6 +157,11 @@ void_result call_order_update_evaluator::do_evaluate(const call_order_update_ope | |
{ try { | ||
database& d = db(); | ||
|
||
// TODO: remove this check and the assertion after hf_834 | ||
if( d.get_dynamic_global_properties().next_maintenance_time <= HARDFORK_CORE_834_TIME ) | ||
FC_ASSERT( o.extensions.empty(), | ||
"Can not specify non-empty extensions in call_order_update_operation before hardfork 834." ); | ||
|
||
_paying_account = &o.funding_account(d); | ||
_debt_asset = &o.delta_debt.asset_id(d); | ||
FC_ASSERT( _debt_asset->is_market_issued(), "Unable to cover ${sym} as it is not a collateralized asset.", | ||
|
@@ -221,6 +226,10 @@ void_result call_order_update_evaluator::do_apply(const call_order_update_operat | |
|
||
optional<price> old_collateralization; | ||
|
||
optional<uint16_t> new_target_cr; // new target collateral ratio | ||
if( o.extensions.size() > 0 ) | ||
new_target_cr = o.extensions.front().value.target_collateral_ratio; | ||
|
||
if( itr == call_idx.end() ) | ||
{ | ||
FC_ASSERT( o.delta_collateral.amount > 0 ); | ||
|
@@ -232,7 +241,7 @@ void_result call_order_update_evaluator::do_apply(const call_order_update_operat | |
call.debt = o.delta_debt.amount; | ||
call.call_price = price::call_price(o.delta_debt, o.delta_collateral, | ||
_bitasset_data->current_feed.maintenance_collateral_ratio); | ||
|
||
call.target_collateral_ratio = new_target_cr; | ||
}); | ||
} | ||
else | ||
|
@@ -241,13 +250,14 @@ void_result call_order_update_evaluator::do_apply(const call_order_update_operat | |
old_collateralization = call_obj->collateralization(); | ||
|
||
d.modify( *call_obj, [&]( call_order_object& call ){ | ||
call.collateral += o.delta_collateral.amount; | ||
call.debt += o.delta_debt.amount; | ||
if( call.debt > 0 ) | ||
{ | ||
call.call_price = price::call_price(call.get_debt(), call.get_collateral(), | ||
_bitasset_data->current_feed.maintenance_collateral_ratio); | ||
} | ||
call.collateral += o.delta_collateral.amount; | ||
call.debt += o.delta_debt.amount; | ||
if( call.debt > 0 ) | ||
{ | ||
call.call_price = price::call_price(call.get_debt(), call.get_collateral(), | ||
_bitasset_data->current_feed.maintenance_collateral_ratio); | ||
} | ||
call.target_collateral_ratio = new_target_cr; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The usual semantics of *_update operations is "if absent leave untouched", while here it is "if absent delete". This is confusing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think Since type of that field is Another approach is to use 2 fields, one for existence and the other for the real value. But I think it's too complicated since the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd still prefer to keep the "if absent leave untouched" semantic. I suppose the option will not be available in the UI (all UI's) very soon, so someone who is used to trade via UI might want to set the tcr once via cli_wallet and continue normal operation using the UI. Since tcr < 1000 doesn't make sense anyway, you could treat and invalid value (i. e. < 1000) as a deliberate delete request. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still think it's clearer to just update as is (which is written in BSIP). Compare the two approaches:
IMHO the 2nd one will lead to more confusion. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another thing related is that If the option is in "if absent leave untouched" semantic, the user may expect that the system will "remember" the option when a position is closed (either intendedly or unintendedly), also sometimes may forget to set when recreating a new position, both may lead to unintended behavior. Compare the two approaches (I think the 1st one is better):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, seems we have to agree to disagree (again ;-) ). BSIP is authoritative though, so I'm OK with leaving it as it is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps propose a BSIP change? E.G. drop |
||
}); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why return both? You only ever use the second member of the return value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, in the beginning, I only returned the first member; while coding I noticed that the second is needed, so changed it to return a pair; at last I found the first is not being used in main code, but is heavily used in test cases, in addition I'm not sure whether it will be useful for potential new APIs, so decided to leave it there.
Do you think it's necessary to change it to only return the second?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not strictly necessary, but a significant simplification IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
pair
.