merge from master, clean up test output
This commit is contained in:
commit
a14500a364
41 changed files with 603 additions and 1948 deletions
|
|
@ -215,22 +215,6 @@ namespace graphene { namespace app {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<short_order_object> database_api::get_short_orders(asset_id_type a, uint32_t limit)const
|
|
||||||
{
|
|
||||||
const auto& short_order_idx = _db.get_index_type<short_order_index>();
|
|
||||||
const auto& sell_price_idx = short_order_idx.indices().get<by_price>();
|
|
||||||
const asset_object& mia = _db.get(a);
|
|
||||||
|
|
||||||
FC_ASSERT( mia.is_market_issued(), "must be a market issued asset" );
|
|
||||||
|
|
||||||
price index_price = price::min(mia.get_id(), mia.bitasset_data(_db).options.short_backing_asset);
|
|
||||||
|
|
||||||
auto short_itr = sell_price_idx.lower_bound(index_price.max());
|
|
||||||
auto short_end = sell_price_idx.upper_bound(index_price.min());
|
|
||||||
|
|
||||||
return vector<short_order_object>(short_itr, short_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<call_order_object> database_api::get_call_orders(asset_id_type a, uint32_t limit)const
|
vector<call_order_object> database_api::get_call_orders(asset_id_type a, uint32_t limit)const
|
||||||
{
|
{
|
||||||
const auto& call_index = _db.get_index_type<call_order_index>().indices().get<by_price>();
|
const auto& call_index = _db.get_index_type<call_order_index>().indices().get<by_price>();
|
||||||
|
|
@ -358,15 +342,11 @@ namespace graphene { namespace app {
|
||||||
case operation::tag<limit_order_create_operation>::value:
|
case operation::tag<limit_order_create_operation>::value:
|
||||||
market = op.op.get<limit_order_create_operation>().get_market();
|
market = op.op.get<limit_order_create_operation>().get_market();
|
||||||
break;
|
break;
|
||||||
case operation::tag<short_order_create_operation>::value:
|
|
||||||
market = op.op.get<limit_order_create_operation>().get_market();
|
|
||||||
break;
|
|
||||||
case operation::tag<fill_order_operation>::value:
|
case operation::tag<fill_order_operation>::value:
|
||||||
market = op.op.get<fill_order_operation>().get_market();
|
market = op.op.get<fill_order_operation>().get_market();
|
||||||
break;
|
break;
|
||||||
/*
|
/*
|
||||||
case operation::tag<limit_order_cancel_operation>::value:
|
case operation::tag<limit_order_cancel_operation>::value:
|
||||||
case operation::tag<short_order_cancel_operation>::value:
|
|
||||||
*/
|
*/
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -400,13 +400,13 @@ application::~application()
|
||||||
{
|
{
|
||||||
if( my->_p2p_network )
|
if( my->_p2p_network )
|
||||||
{
|
{
|
||||||
ilog("Closing p2p node");
|
//ilog("Closing p2p node");
|
||||||
my->_p2p_network->close();
|
my->_p2p_network->close();
|
||||||
my->_p2p_network.reset();
|
my->_p2p_network.reset();
|
||||||
}
|
}
|
||||||
if( my->_chain_db )
|
if( my->_chain_db )
|
||||||
{
|
{
|
||||||
ilog("Closing chain database");
|
//ilog("Closing chain database");
|
||||||
my->_chain_db->close();
|
my->_chain_db->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
#include <graphene/chain/operation_history_object.hpp>
|
#include <graphene/chain/operation_history_object.hpp>
|
||||||
#include <graphene/chain/asset_object.hpp>
|
#include <graphene/chain/asset_object.hpp>
|
||||||
#include <graphene/chain/limit_order_object.hpp>
|
#include <graphene/chain/limit_order_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
#include <graphene/chain/key_object.hpp>
|
#include <graphene/chain/key_object.hpp>
|
||||||
#include <graphene/net/node.hpp>
|
#include <graphene/net/node.hpp>
|
||||||
#include <fc/api.hpp>
|
#include <fc/api.hpp>
|
||||||
|
|
@ -142,13 +142,6 @@ namespace graphene { namespace app {
|
||||||
* @return The limit orders, ordered from least price to greatest
|
* @return The limit orders, ordered from least price to greatest
|
||||||
*/
|
*/
|
||||||
vector<limit_order_object> get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const;
|
vector<limit_order_object> get_limit_orders(asset_id_type a, asset_id_type b, uint32_t limit)const;
|
||||||
/**
|
|
||||||
* @brief Get short orders in a given asset
|
|
||||||
* @param a ID of asset being sold
|
|
||||||
* @param limit Maximum number of orders to retrieve
|
|
||||||
* @return The short orders, ordered from least price to greatest
|
|
||||||
*/
|
|
||||||
vector<short_order_object> get_short_orders(asset_id_type a, uint32_t limit)const;
|
|
||||||
/**
|
/**
|
||||||
* @brief Get call orders in a given asset
|
* @brief Get call orders in a given asset
|
||||||
* @param a ID of asset being called
|
* @param a ID of asset being called
|
||||||
|
|
@ -342,7 +335,6 @@ FC_API(graphene::app::database_api,
|
||||||
(get_named_account_balances)
|
(get_named_account_balances)
|
||||||
(lookup_asset_symbols)
|
(lookup_asset_symbols)
|
||||||
(get_limit_orders)
|
(get_limit_orders)
|
||||||
(get_short_orders)
|
|
||||||
(get_call_orders)
|
(get_call_orders)
|
||||||
(get_settle_orders)
|
(get_settle_orders)
|
||||||
(list_assets)
|
(list_assets)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ add_library( graphene_chain
|
||||||
asset_evaluator.cpp
|
asset_evaluator.cpp
|
||||||
transfer_evaluator.cpp
|
transfer_evaluator.cpp
|
||||||
proposal_evaluator.cpp
|
proposal_evaluator.cpp
|
||||||
short_order_evaluator.cpp
|
call_order_evaluator.cpp
|
||||||
limit_order_evaluator.cpp
|
limit_order_evaluator.cpp
|
||||||
vesting_balance_evaluator.cpp
|
vesting_balance_evaluator.cpp
|
||||||
withdraw_permission_evaluator.cpp
|
withdraw_permission_evaluator.cpp
|
||||||
|
|
|
||||||
|
|
@ -101,13 +101,13 @@ namespace graphene { namespace chain {
|
||||||
price price::min( asset_id_type base, asset_id_type quote ) { return asset( 1, base ) / asset( GRAPHENE_MAX_SHARE_SUPPLY, quote); }
|
price price::min( asset_id_type base, asset_id_type quote ) { return asset( 1, base ) / asset( GRAPHENE_MAX_SHARE_SUPPLY, quote); }
|
||||||
|
|
||||||
price price::call_price(const asset& debt, const asset& collateral, uint16_t collateral_ratio)
|
price price::call_price(const asset& debt, const asset& collateral, uint16_t collateral_ratio)
|
||||||
{
|
{ try {
|
||||||
fc::uint128 tmp( collateral.amount.value );
|
fc::uint128 tmp( collateral.amount.value );
|
||||||
tmp *= collateral_ratio - 1000;
|
tmp *= collateral_ratio - 1000;
|
||||||
tmp /= 1000;
|
tmp /= 1000;
|
||||||
FC_ASSERT( tmp <= GRAPHENE_MAX_SHARE_SUPPLY );
|
FC_ASSERT( tmp <= GRAPHENE_MAX_SHARE_SUPPLY );
|
||||||
return asset( tmp.to_uint64(), collateral.asset_id) / debt;
|
return asset( tmp.to_uint64(), collateral.asset_id) / debt;
|
||||||
}
|
} FC_CAPTURE_AND_RETHROW( (debt)(collateral)(collateral_ratio) ) }
|
||||||
|
|
||||||
bool price::is_null() const { return *this == price(); }
|
bool price::is_null() const { return *this == price(); }
|
||||||
|
|
||||||
|
|
@ -120,20 +120,10 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
void price_feed::validate() const
|
void price_feed::validate() const
|
||||||
{ try {
|
{ try {
|
||||||
if( !call_limit.is_null() )
|
|
||||||
call_limit.validate();
|
|
||||||
if( !short_limit.is_null() )
|
|
||||||
short_limit.validate();
|
|
||||||
if( !settlement_price.is_null() )
|
if( !settlement_price.is_null() )
|
||||||
settlement_price.validate();
|
settlement_price.validate();
|
||||||
FC_ASSERT( call_limit.is_null() == short_limit.is_null() );
|
FC_ASSERT( maximum_short_squeeze_ratio >= 1000 );
|
||||||
FC_ASSERT( call_limit.base.asset_id == short_limit.quote.asset_id );
|
FC_ASSERT( maintenance_collateral_ratio >= maximum_short_squeeze_ratio );
|
||||||
FC_ASSERT( call_limit.quote.asset_id == short_limit.base.asset_id );
|
} FC_CAPTURE_AND_RETHROW( (*this) ) }
|
||||||
FC_ASSERT( max_margin_period_sec > 0 );
|
|
||||||
FC_ASSERT( required_maintenance_collateral < required_initial_collateral );
|
|
||||||
FC_ASSERT( required_maintenance_collateral >= 1000 );
|
|
||||||
FC_ASSERT( call_limit.is_null() || call_limit < ~short_limit );
|
|
||||||
} FC_CAPTURE_AND_RETHROW( (call_limit.is_null())(short_limit.is_null())(call_limit)(short_limit)
|
|
||||||
(max_margin_period_sec)(required_maintenance_collateral)(required_initial_collateral) ) }
|
|
||||||
|
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
#include <graphene/chain/asset_evaluator.hpp>
|
#include <graphene/chain/asset_evaluator.hpp>
|
||||||
#include <graphene/chain/asset_object.hpp>
|
#include <graphene/chain/asset_object.hpp>
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
#include <graphene/chain/database.hpp>
|
#include <graphene/chain/database.hpp>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
@ -365,16 +365,17 @@ void_result asset_publish_feeds_evaluator::do_evaluate(const asset_publish_feed_
|
||||||
{ try {
|
{ try {
|
||||||
database& d = db();
|
database& d = db();
|
||||||
|
|
||||||
const asset_object& quote = o.asset_id(d);
|
const asset_object& base = o.asset_id(d);
|
||||||
//Verify that this feed is for a market-issued asset and that asset is backed by the base
|
//Verify that this feed is for a market-issued asset and that asset is backed by the base
|
||||||
FC_ASSERT(quote.is_market_issued());
|
FC_ASSERT(base.is_market_issued());
|
||||||
|
|
||||||
const asset_bitasset_data_object& bitasset = quote.bitasset_data(d);
|
const asset_bitasset_data_object& bitasset = base.bitasset_data(d);
|
||||||
FC_ASSERT(bitasset.options.short_backing_asset == o.feed.call_limit.base.asset_id);
|
FC_ASSERT(bitasset.options.short_backing_asset == o.feed.settlement_price.quote.asset_id);
|
||||||
//Verify that the publisher is authoritative to publish a feed
|
//Verify that the publisher is authoritative to publish a feed
|
||||||
if( quote.issuer == account_id_type() )
|
if( base.issuer == account_id_type() )
|
||||||
{
|
{
|
||||||
//It's a delegate-fed asset. Verify that publisher is an active delegate or witness.
|
//It's a delegate-fed asset. Verify that publisher is an active delegate or witness.
|
||||||
|
// TODO: replace account_id_type with global variable for delegates account id
|
||||||
FC_ASSERT(d.get(account_id_type()).active.auths.count(o.publisher) ||
|
FC_ASSERT(d.get(account_id_type()).active.auths.count(o.publisher) ||
|
||||||
d.get_global_properties().witness_accounts.count(o.publisher));
|
d.get_global_properties().witness_accounts.count(o.publisher));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -388,9 +389,9 @@ void_result asset_publish_feeds_evaluator::do_apply(const asset_publish_feed_ope
|
||||||
{ try {
|
{ try {
|
||||||
database& d = db();
|
database& d = db();
|
||||||
|
|
||||||
const asset_object& quote = o.asset_id(d);
|
const asset_object& base = o.asset_id(d);
|
||||||
// Store medians for this asset
|
// Store medians for this asset
|
||||||
d.modify(quote.bitasset_data(d), [&o,&d](asset_bitasset_data_object& a) {
|
d.modify(base.bitasset_data(d), [&o,&d](asset_bitasset_data_object& a) {
|
||||||
a.feeds[o.publisher] = make_pair(d.head_block_time(), o.feed);
|
a.feeds[o.publisher] = make_pair(d.head_block_time(), o.feed);
|
||||||
a.update_median_feeds(d.head_block_time());
|
a.update_median_feeds(d.head_block_time());
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
void block_database::open( const fc::path& dbdir )
|
void block_database::open( const fc::path& dbdir )
|
||||||
{ try {
|
{ try {
|
||||||
idump((sizeof(index_entry)) );
|
|
||||||
fc::create_directories(dbdir);
|
fc::create_directories(dbdir);
|
||||||
_block_num_to_pos.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
_block_num_to_pos.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||||
_blocks.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
_blocks.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||||
|
|
|
||||||
156
libraries/chain/call_order_evaluator.cpp
Normal file
156
libraries/chain/call_order_evaluator.cpp
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* 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/database.hpp>
|
||||||
|
#include <graphene/chain/call_order_evaluator.hpp>
|
||||||
|
#include <graphene/chain/account_object.hpp>
|
||||||
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
|
#include <graphene/chain/limit_order_object.hpp>
|
||||||
|
#include <fc/uint128.hpp>
|
||||||
|
|
||||||
|
namespace graphene { namespace chain {
|
||||||
|
|
||||||
|
void_result call_order_update_evaluator::do_evaluate(const call_order_update_operation& o)
|
||||||
|
{ try {
|
||||||
|
database& d = db();
|
||||||
|
|
||||||
|
_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.",
|
||||||
|
("sym", _debt_asset->symbol) );
|
||||||
|
|
||||||
|
_bitasset_data = &_debt_asset->bitasset_data(d);
|
||||||
|
|
||||||
|
FC_ASSERT( o.delta_collateral.asset_id == _bitasset_data->options.short_backing_asset );
|
||||||
|
|
||||||
|
if( _bitasset_data->is_prediction_market )
|
||||||
|
FC_ASSERT( o.delta_collateral.amount == o.delta_debt.amount );
|
||||||
|
else
|
||||||
|
FC_ASSERT( !_bitasset_data->current_feed.settlement_price.is_null() );
|
||||||
|
|
||||||
|
if( o.delta_debt.amount < 0 )
|
||||||
|
{
|
||||||
|
FC_ASSERT( d.get_balance(*_paying_account, *_debt_asset) >= o.delta_debt,
|
||||||
|
"Cannot cover by ${c} when payer only has ${b}",
|
||||||
|
("c", o.delta_debt.amount)("b", d.get_balance(*_paying_account, *_debt_asset).amount) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( o.delta_collateral.amount > 0 )
|
||||||
|
{
|
||||||
|
FC_ASSERT( d.get_balance(*_paying_account, _bitasset_data->options.short_backing_asset(d)) >= o.delta_collateral,
|
||||||
|
"Cannot increase collateral by ${c} when payer only has ${b}", ("c", o.delta_collateral.amount)
|
||||||
|
("b", d.get_balance(*_paying_account, o.delta_collateral.asset_id(d)).amount) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return void_result();
|
||||||
|
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
||||||
|
|
||||||
|
|
||||||
|
void_result call_order_update_evaluator::do_apply(const call_order_update_operation& o)
|
||||||
|
{
|
||||||
|
database& d = db();
|
||||||
|
//wdump( (_bitasset_data->current_feed) );
|
||||||
|
|
||||||
|
if( o.delta_debt.amount != 0 )
|
||||||
|
{
|
||||||
|
d.adjust_balance( o.funding_account, o.delta_debt );
|
||||||
|
|
||||||
|
// Deduct the debt paid from the total supply of the debt asset.
|
||||||
|
d.modify(_debt_asset->dynamic_asset_data_id(d), [&](asset_dynamic_data_object& dynamic_asset) {
|
||||||
|
dynamic_asset.current_supply += o.delta_debt.amount;
|
||||||
|
assert(dynamic_asset.current_supply >= 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if( o.delta_collateral.amount != 0 )
|
||||||
|
{
|
||||||
|
d.adjust_balance( o.funding_account, -o.delta_collateral );
|
||||||
|
|
||||||
|
// Adjust the total core in orders accodingly
|
||||||
|
if( o.delta_collateral.asset_id == asset_id_type() )
|
||||||
|
{
|
||||||
|
d.modify(_paying_account->statistics(d), [&](account_statistics_object& stats) {
|
||||||
|
stats.total_core_in_orders += o.delta_collateral.amount;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto& call_idx = d.get_index_type<call_order_index>().indices().get<by_account>();
|
||||||
|
auto itr = call_idx.find( boost::make_tuple(o.funding_account, o.delta_debt.asset_id) );
|
||||||
|
const call_order_object* call_obj = nullptr;
|
||||||
|
if( itr == call_idx.end() )
|
||||||
|
{
|
||||||
|
FC_ASSERT( o.delta_collateral.amount > 0 );
|
||||||
|
FC_ASSERT( o.delta_debt.amount > 0 );
|
||||||
|
|
||||||
|
call_obj = &d.create<call_order_object>( [&](call_order_object& call ){
|
||||||
|
call.borrower = o.funding_account;
|
||||||
|
call.collateral = o.delta_collateral.amount;
|
||||||
|
call.debt = o.delta_debt.amount;
|
||||||
|
call.call_price = ~o.call_price;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
call_obj = &*itr;
|
||||||
|
|
||||||
|
d.modify( *call_obj, [&]( call_order_object& call ){
|
||||||
|
call.collateral += o.delta_collateral.amount;
|
||||||
|
call.debt += o.delta_debt.amount;
|
||||||
|
call.call_price = ~o.call_price;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto debt = call_obj->get_debt();
|
||||||
|
if( debt.amount == 0 )
|
||||||
|
{
|
||||||
|
FC_ASSERT( call_obj->collateral == 0 );
|
||||||
|
d.remove( *call_obj );
|
||||||
|
return void_result();
|
||||||
|
}
|
||||||
|
auto collateral = call_obj->get_collateral();
|
||||||
|
|
||||||
|
auto mp = _bitasset_data->current_feed.maintenance_price();
|
||||||
|
|
||||||
|
// edump((debt)(collateral)((debt/collateral).to_real())(mp.to_real()) );
|
||||||
|
// edump((debt*mp));
|
||||||
|
/// paying off the debt at the user specified call price should require
|
||||||
|
/// less collateral than paying off the debt at the maitenance price
|
||||||
|
auto col_at_call_price = debt * o.call_price;
|
||||||
|
auto col_at_min_callprice = debt * mp;
|
||||||
|
FC_ASSERT( col_at_call_price <= col_at_min_callprice, "", ("debt*o.callprice",debt*o.call_price)("debt*mp",debt*mp) );
|
||||||
|
FC_ASSERT( col_at_call_price <= collateral );
|
||||||
|
|
||||||
|
//wdump( (o.call_price)(mp)(call_obj->call_price.to_real())(mp.to_real()) );
|
||||||
|
//FC_ASSERT( call_obj->call_price <= mp );
|
||||||
|
|
||||||
|
auto call_order_id = call_obj->id;
|
||||||
|
|
||||||
|
//ilog( "checking call orders" );
|
||||||
|
|
||||||
|
// check to see if the order needs to be margin called now, but don't allow black swans and require there to be
|
||||||
|
// limit orders available that could be used to fill the order.
|
||||||
|
if( d.check_call_orders( *_debt_asset, false ) )
|
||||||
|
{
|
||||||
|
FC_ASSERT( !d.find_object( call_order_id ), "If updating the call order triggers a margin call, then it must completely cover the order" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return void_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
} } // graphene::chain
|
||||||
|
|
@ -99,7 +99,7 @@ bool database::_push_block( const signed_block& new_block )
|
||||||
//If the head block from the longest chain does not build off of the current head, we need to switch forks.
|
//If the head block from the longest chain does not build off of the current head, we need to switch forks.
|
||||||
if( new_head->data.previous != head_block_id() )
|
if( new_head->data.previous != head_block_id() )
|
||||||
{
|
{
|
||||||
edump((new_head->data.previous));
|
//edump((new_head->data.previous));
|
||||||
//If the newly pushed block is the same height as head, we get head back in new_head
|
//If the newly pushed block is the same height as head, we get head back in new_head
|
||||||
//Only switch forks if new_head is actually higher than head
|
//Only switch forks if new_head is actually higher than head
|
||||||
if( new_head->data.block_num() > head_block_num() )
|
if( new_head->data.block_num() > head_block_num() )
|
||||||
|
|
@ -107,11 +107,11 @@ bool database::_push_block( const signed_block& new_block )
|
||||||
auto branches = _fork_db.fetch_branch_from( new_head->data.id(), _pending_block.previous );
|
auto branches = _fork_db.fetch_branch_from( new_head->data.id(), _pending_block.previous );
|
||||||
for( auto item : branches.first )
|
for( auto item : branches.first )
|
||||||
{
|
{
|
||||||
wdump( ("new")(item->id)(item->data.previous) );
|
// wdump( ("new")(item->id)(item->data.previous) );
|
||||||
}
|
}
|
||||||
for( auto item : branches.second )
|
for( auto item : branches.second )
|
||||||
{
|
{
|
||||||
wdump( ("old")(item->id)(item->data.previous) );
|
// wdump( ("old")(item->id)(item->data.previous) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// pop blocks until we hit the forked block
|
// pop blocks until we hit the forked block
|
||||||
|
|
@ -131,9 +131,9 @@ bool database::_push_block( const signed_block& new_block )
|
||||||
catch ( const fc::exception& e ) { except = e; }
|
catch ( const fc::exception& e ) { except = e; }
|
||||||
if( except )
|
if( except )
|
||||||
{
|
{
|
||||||
wdump((except->to_detail_string()));
|
//wdump((except->to_detail_string()));
|
||||||
elog( "Encountered error when switching to a longer fork at id ${id}. Going back.",
|
// elog( "Encountered error when switching to a longer fork at id ${id}. Going back.",
|
||||||
("id", (*ritr)->id) );
|
// ("id", (*ritr)->id) );
|
||||||
// remove the rest of branches.first from the fork_db, those blocks are invalid
|
// remove the rest of branches.first from the fork_db, those blocks are invalid
|
||||||
while( ritr != branches.first.rend() )
|
while( ritr != branches.first.rend() )
|
||||||
{
|
{
|
||||||
|
|
@ -239,8 +239,8 @@ processed_transaction database::push_proposal(const proposal_object& proposal)
|
||||||
return std::make_pair(id, authority::owner);
|
return std::make_pair(id, authority::owner);
|
||||||
});
|
});
|
||||||
|
|
||||||
ilog("Attempting to push proposal ${prop}", ("prop", proposal));
|
//ilog("Attempting to push proposal ${prop}", ("prop", proposal));
|
||||||
idump((eval_state.approved_by));
|
//idump((eval_state.approved_by));
|
||||||
|
|
||||||
eval_state.operation_results.reserve(proposal.proposed_transaction.operations.size());
|
eval_state.operation_results.reserve(proposal.proposed_transaction.operations.size());
|
||||||
processed_transaction ptrx(proposal.proposed_transaction);
|
processed_transaction ptrx(proposal.proposed_transaction);
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
#include <graphene/chain/asset_object.hpp>
|
#include <graphene/chain/asset_object.hpp>
|
||||||
#include <graphene/chain/limit_order_object.hpp>
|
#include <graphene/chain/limit_order_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
#include <graphene/chain/vesting_balance_object.hpp>
|
#include <graphene/chain/vesting_balance_object.hpp>
|
||||||
#include <graphene/chain/witness_object.hpp>
|
#include <graphene/chain/witness_object.hpp>
|
||||||
|
|
||||||
|
|
@ -60,13 +60,6 @@ void database::debug_dump()
|
||||||
if( for_sale.asset_id == asset_id_type() ) core_in_orders += for_sale.amount;
|
if( for_sale.asset_id == asset_id_type() ) core_in_orders += for_sale.amount;
|
||||||
total_balances[for_sale.asset_id] += for_sale.amount;
|
total_balances[for_sale.asset_id] += for_sale.amount;
|
||||||
}
|
}
|
||||||
for( const short_order_object& o : db.get_index_type<short_order_index>().indices() )
|
|
||||||
{
|
|
||||||
idump(("short_order")(o));
|
|
||||||
auto col = o.get_collateral();
|
|
||||||
if( col.asset_id == asset_id_type() ) core_in_orders += col.amount;
|
|
||||||
total_balances[col.asset_id] += col.amount;
|
|
||||||
}
|
|
||||||
for( const call_order_object& o : db.get_index_type<call_order_index>().indices() )
|
for( const call_order_object& o : db.get_index_type<call_order_index>().indices() )
|
||||||
{
|
{
|
||||||
idump(("call_order")(o));
|
idump(("call_order")(o));
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
#include <graphene/chain/key_object.hpp>
|
#include <graphene/chain/key_object.hpp>
|
||||||
#include <graphene/chain/limit_order_object.hpp>
|
#include <graphene/chain/limit_order_object.hpp>
|
||||||
#include <graphene/chain/proposal_object.hpp>
|
#include <graphene/chain/proposal_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
#include <graphene/chain/transaction_object.hpp>
|
#include <graphene/chain/transaction_object.hpp>
|
||||||
#include <graphene/chain/vesting_balance_object.hpp>
|
#include <graphene/chain/vesting_balance_object.hpp>
|
||||||
#include <graphene/chain/withdraw_permission_object.hpp>
|
#include <graphene/chain/withdraw_permission_object.hpp>
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
#include <graphene/chain/key_evaluator.hpp>
|
#include <graphene/chain/key_evaluator.hpp>
|
||||||
#include <graphene/chain/limit_order_evaluator.hpp>
|
#include <graphene/chain/limit_order_evaluator.hpp>
|
||||||
#include <graphene/chain/proposal_evaluator.hpp>
|
#include <graphene/chain/proposal_evaluator.hpp>
|
||||||
#include <graphene/chain/short_order_evaluator.hpp>
|
#include <graphene/chain/call_order_evaluator.hpp>
|
||||||
#include <graphene/chain/transfer_evaluator.hpp>
|
#include <graphene/chain/transfer_evaluator.hpp>
|
||||||
#include <graphene/chain/vesting_balance_evaluator.hpp>
|
#include <graphene/chain/vesting_balance_evaluator.hpp>
|
||||||
#include <graphene/chain/withdraw_permission_evaluator.hpp>
|
#include <graphene/chain/withdraw_permission_evaluator.hpp>
|
||||||
|
|
@ -75,8 +75,6 @@ void database::initialize_evaluators()
|
||||||
register_evaluator<asset_global_settle_evaluator>();
|
register_evaluator<asset_global_settle_evaluator>();
|
||||||
register_evaluator<limit_order_create_evaluator>();
|
register_evaluator<limit_order_create_evaluator>();
|
||||||
register_evaluator<limit_order_cancel_evaluator>();
|
register_evaluator<limit_order_cancel_evaluator>();
|
||||||
register_evaluator<short_order_create_evaluator>();
|
|
||||||
register_evaluator<short_order_cancel_evaluator>();
|
|
||||||
register_evaluator<call_order_update_evaluator>();
|
register_evaluator<call_order_update_evaluator>();
|
||||||
register_evaluator<transfer_evaluator>();
|
register_evaluator<transfer_evaluator>();
|
||||||
register_evaluator<asset_fund_fee_pool_evaluator>();
|
register_evaluator<asset_fund_fee_pool_evaluator>();
|
||||||
|
|
@ -108,7 +106,6 @@ void database::initialize_indexes()
|
||||||
add_index< primary_index<simple_index<delegate_object>> >();
|
add_index< primary_index<simple_index<delegate_object>> >();
|
||||||
add_index< primary_index<simple_index<witness_object>> >();
|
add_index< primary_index<simple_index<witness_object>> >();
|
||||||
add_index< primary_index<limit_order_index > >();
|
add_index< primary_index<limit_order_index > >();
|
||||||
add_index< primary_index<short_order_index > >();
|
|
||||||
add_index< primary_index<call_order_index > >();
|
add_index< primary_index<call_order_index > >();
|
||||||
add_index< primary_index<proposal_index > >();
|
add_index< primary_index<proposal_index > >();
|
||||||
add_index< primary_index<withdraw_permission_index > >();
|
add_index< primary_index<withdraw_permission_index > >();
|
||||||
|
|
@ -295,9 +292,9 @@ void database::init_genesis(const genesis_state_type& genesis_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fc::microseconds duration = fc::time_point::now() - start_time;
|
// fc::microseconds duration = fc::time_point::now() - start_time;
|
||||||
ilog("Finished allocating to ${n} accounts in ${t} milliseconds.",
|
// ilog("Finished allocating to ${n} accounts in ${t} milliseconds.",
|
||||||
("n", genesis_state.allocation_targets.size())("t", duration.count() / 1000));
|
// ("n", genesis_state.allocation_targets.size())("t", duration.count() / 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
flat_set<delegate_id_type> init_delegates;
|
flat_set<delegate_id_type> init_delegates;
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ vector<std::reference_wrapper<const ObjectType>> database::sort_votable_objects(
|
||||||
|
|
||||||
void database::pay_workers( share_type& budget )
|
void database::pay_workers( share_type& budget )
|
||||||
{
|
{
|
||||||
ilog("Processing payroll! Available budget is ${b}", ("b", budget));
|
// ilog("Processing payroll! Available budget is ${b}", ("b", budget));
|
||||||
vector<std::reference_wrapper<const worker_object>> active_workers;
|
vector<std::reference_wrapper<const worker_object>> active_workers;
|
||||||
get_index_type<worker_index>().inspect_all_objects([this, &active_workers](const object& o) {
|
get_index_type<worker_index>().inspect_all_objects([this, &active_workers](const object& o) {
|
||||||
const worker_object& w = static_cast<const worker_object&>(o);
|
const worker_object& w = static_cast<const worker_object&>(o);
|
||||||
|
|
@ -78,7 +78,7 @@ void database::pay_workers( share_type& budget )
|
||||||
}
|
}
|
||||||
|
|
||||||
share_type actual_pay = std::min(budget, requested_pay);
|
share_type actual_pay = std::min(budget, requested_pay);
|
||||||
ilog(" ==> Paying ${a} to worker ${w}", ("w", active_worker.id)("a", actual_pay));
|
//ilog(" ==> Paying ${a} to worker ${w}", ("w", active_worker.id)("a", actual_pay));
|
||||||
modify(active_worker, [&](worker_object& w) {
|
modify(active_worker, [&](worker_object& w) {
|
||||||
w.worker.visit(worker_pay_visitor(actual_pay, *this));
|
w.worker.visit(worker_pay_visitor(actual_pay, *this));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -35,14 +35,13 @@ database::~database(){
|
||||||
|
|
||||||
void database::open( const fc::path& data_dir, const genesis_state_type& initial_allocation )
|
void database::open( const fc::path& data_dir, const genesis_state_type& initial_allocation )
|
||||||
{ try {
|
{ try {
|
||||||
ilog("Open database in ${d}", ("d", data_dir));
|
|
||||||
object_database::open( data_dir );
|
object_database::open( data_dir );
|
||||||
|
|
||||||
_block_id_to_block.open(data_dir / "database" / "block_num_to_block");
|
_block_id_to_block.open(data_dir / "database" / "block_num_to_block");
|
||||||
|
|
||||||
if( !find(global_property_id_type()) )
|
if( !find(global_property_id_type()) )
|
||||||
{
|
{
|
||||||
ilog( "Init Genesis State" );
|
// ilog( "Init Genesis State" );
|
||||||
init_genesis(initial_allocation);
|
init_genesis(initial_allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
#include <graphene/chain/asset_object.hpp>
|
#include <graphene/chain/asset_object.hpp>
|
||||||
#include <graphene/chain/limit_order_object.hpp>
|
#include <graphene/chain/limit_order_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
|
|
||||||
#include <fc/uint128.hpp>
|
#include <fc/uint128.hpp>
|
||||||
|
|
||||||
|
|
@ -69,9 +69,10 @@ void database::globally_settle_asset( const asset_object& mia, const price& sett
|
||||||
const limit_order_index& limit_index = get_index_type<limit_order_index>();
|
const limit_order_index& limit_index = get_index_type<limit_order_index>();
|
||||||
const auto& limit_price_index = limit_index.indices().get<by_price>();
|
const auto& limit_price_index = limit_index.indices().get<by_price>();
|
||||||
|
|
||||||
|
auto max_short_squeeze = bitasset.current_feed.max_short_squeeze_price();
|
||||||
// cancel all orders selling the market issued asset
|
// cancel all orders selling the market issued asset
|
||||||
auto limit_itr = limit_price_index.lower_bound(price::max(mia.id, bitasset.options.short_backing_asset));
|
auto limit_itr = limit_price_index.lower_bound(price::max(mia.id, bitasset.options.short_backing_asset));
|
||||||
auto limit_end = limit_price_index.upper_bound(~bitasset.current_feed.call_limit);
|
auto limit_end = limit_price_index.upper_bound(~max_short_squeeze);
|
||||||
while( limit_itr != limit_end )
|
while( limit_itr != limit_end )
|
||||||
{
|
{
|
||||||
const auto& order = *limit_itr;
|
const auto& order = *limit_itr;
|
||||||
|
|
@ -225,10 +226,6 @@ int database::match( const limit_order_object& bid, const limit_order_object& as
|
||||||
return match<limit_order_object>( bid, ask, match_price );
|
return match<limit_order_object>( bid, ask, match_price );
|
||||||
}
|
}
|
||||||
|
|
||||||
int database::match( const limit_order_object& bid, const short_order_object& ask, const price& match_price )
|
|
||||||
{
|
|
||||||
return match<short_order_object>( bid, ask, match_price );
|
|
||||||
}
|
|
||||||
|
|
||||||
asset database::match( const call_order_object& call, const force_settlement_object& settle, const price& match_price,
|
asset database::match( const call_order_object& call, const force_settlement_object& settle, const price& match_price,
|
||||||
asset max_settlement )
|
asset max_settlement )
|
||||||
|
|
@ -290,107 +287,6 @@ bool database::fill_order( const limit_order_object& order, const asset& pays, c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool database::fill_order( const short_order_object& order, const asset& pays, const asset& receives )
|
|
||||||
{ try {
|
|
||||||
assert( order.amount_for_sale().asset_id == pays.asset_id );
|
|
||||||
assert( pays.asset_id != receives.asset_id );
|
|
||||||
|
|
||||||
const call_order_index& call_index = get_index_type<call_order_index>();
|
|
||||||
|
|
||||||
const account_object& seller = order.seller(*this);
|
|
||||||
const asset_object& recv_asset = receives.asset_id(*this);
|
|
||||||
const asset_object& pays_asset = pays.asset_id(*this);
|
|
||||||
assert( pays_asset.is_market_issued() );
|
|
||||||
|
|
||||||
auto issuer_fees = pay_market_fees( recv_asset, receives );
|
|
||||||
|
|
||||||
bool filled = pays == order.amount_for_sale();
|
|
||||||
asset seller_to_collateral;
|
|
||||||
if( (*pays_asset.bitasset_data_id)(*this).is_prediction_market )
|
|
||||||
{
|
|
||||||
assert( pays.amount >= receives.amount );
|
|
||||||
seller_to_collateral = pays.amount - receives.amount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
seller_to_collateral = filled ? order.get_collateral() : pays * order.sell_price;
|
|
||||||
}
|
|
||||||
auto buyer_to_collateral = receives - issuer_fees;
|
|
||||||
|
|
||||||
if( receives.asset_id == asset_id_type() )
|
|
||||||
{
|
|
||||||
const auto& statistics = seller.statistics(*this);
|
|
||||||
modify( statistics, [&]( account_statistics_object& b ){
|
|
||||||
b.total_core_in_orders += buyer_to_collateral.amount;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
modify( pays_asset.dynamic_asset_data_id(*this), [&]( asset_dynamic_data_object& obj ){
|
|
||||||
obj.current_supply += pays.amount;
|
|
||||||
});
|
|
||||||
|
|
||||||
const auto& call_account_index = call_index.indices().get<by_account>();
|
|
||||||
auto call_itr = call_account_index.find( boost::make_tuple(order.seller, pays.asset_id) );
|
|
||||||
if( call_itr == call_account_index.end() )
|
|
||||||
{
|
|
||||||
create<call_order_object>( [&]( call_order_object& c ){
|
|
||||||
c.borrower = seller.id;
|
|
||||||
c.collateral = seller_to_collateral.amount + buyer_to_collateral.amount;
|
|
||||||
c.debt = pays.amount;
|
|
||||||
c.maintenance_collateral_ratio = order.maintenance_collateral_ratio;
|
|
||||||
c.call_price = price::max(seller_to_collateral.asset_id, pays.asset_id);
|
|
||||||
c.update_call_price();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
modify( *call_itr, [&]( call_order_object& c ){
|
|
||||||
c.debt += pays.amount;
|
|
||||||
c.collateral += seller_to_collateral.amount + buyer_to_collateral.amount;
|
|
||||||
c.maintenance_collateral_ratio = order.maintenance_collateral_ratio;
|
|
||||||
c.update_call_price();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if( filled )
|
|
||||||
{
|
|
||||||
remove( order );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
modify( order, [&]( short_order_object& b ) {
|
|
||||||
b.for_sale -= pays.amount;
|
|
||||||
b.available_collateral -= seller_to_collateral.amount;
|
|
||||||
assert( b.available_collateral > 0 );
|
|
||||||
assert( b.for_sale > 0 );
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* There are times when the AMOUNT_FOR_SALE * SALE_PRICE == 0 which means that we
|
|
||||||
* have hit the limit where the seller is asking for nothing in return. When this
|
|
||||||
* happens we must refund any balance back to the seller, it is too small to be
|
|
||||||
* sold at the sale price.
|
|
||||||
*/
|
|
||||||
if( order.amount_to_receive().amount == 0 )
|
|
||||||
{
|
|
||||||
adjust_balance(seller.get_id(), order.get_collateral());
|
|
||||||
if( order.get_collateral().asset_id == asset_id_type() )
|
|
||||||
{
|
|
||||||
const auto& statistics = seller.statistics(*this);
|
|
||||||
modify( statistics, [&]( account_statistics_object& b ){
|
|
||||||
b.total_core_in_orders -= order.available_collateral;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
remove( order );
|
|
||||||
filled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
push_applied_operation( fill_order_operation{ order.id, order.seller, pays, receives, issuer_fees } );
|
|
||||||
|
|
||||||
return filled;
|
|
||||||
} FC_CAPTURE_AND_RETHROW( (order)(pays)(receives) ) }
|
|
||||||
|
|
||||||
bool database::fill_order( const call_order_object& order, const asset& pays, const asset& receives )
|
bool database::fill_order( const call_order_object& order, const asset& pays, const asset& receives )
|
||||||
{ try {
|
{ try {
|
||||||
|
|
@ -468,13 +364,22 @@ bool database::fill_order(const force_settlement_object& settle, const asset& pa
|
||||||
} FC_CAPTURE_AND_RETHROW( (settle)(pays)(receives) ) }
|
} FC_CAPTURE_AND_RETHROW( (settle)(pays)(receives) ) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Starting with the least collateralized orders, fill them if their
|
||||||
|
* call price is above the max(lowest bid,call_limit).
|
||||||
*
|
*
|
||||||
|
* This method will return true if it filled a short or limit
|
||||||
|
*
|
||||||
|
* @param mia - the market issued asset that should be called.
|
||||||
|
* @param enable_black_swan - when adjusting collateral, triggering a black swan is invalid and will throw
|
||||||
|
* if enable_black_swan is not set to true.
|
||||||
|
*
|
||||||
|
* @return true if a margin call was executed.
|
||||||
*/
|
*/
|
||||||
bool database::check_call_orders( const asset_object& mia )
|
bool database::check_call_orders( const asset_object& mia, bool enable_black_swan )
|
||||||
{ try {
|
{ try {
|
||||||
if( !mia.is_market_issued() ) return false;
|
if( !mia.is_market_issued() ) return false;
|
||||||
const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this);
|
const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this);
|
||||||
if( bitasset.current_feed.call_limit.is_null() ) return false;
|
if( bitasset.current_feed.settlement_price.is_null() ) return false;
|
||||||
if( bitasset.is_prediction_market ) return false;
|
if( bitasset.is_prediction_market ) return false;
|
||||||
|
|
||||||
const call_order_index& call_index = get_index_type<call_order_index>();
|
const call_order_index& call_index = get_index_type<call_order_index>();
|
||||||
|
|
@ -483,14 +388,42 @@ bool database::check_call_orders( const asset_object& mia )
|
||||||
const limit_order_index& limit_index = get_index_type<limit_order_index>();
|
const limit_order_index& limit_index = get_index_type<limit_order_index>();
|
||||||
const auto& limit_price_index = limit_index.indices().get<by_price>();
|
const auto& limit_price_index = limit_index.indices().get<by_price>();
|
||||||
|
|
||||||
const short_order_index& short_index = get_index_type<short_order_index>();
|
auto max_price = price::max( mia.id, bitasset.options.short_backing_asset );
|
||||||
const auto& short_price_index = short_index.indices().get<by_price>();
|
auto min_price = bitasset.current_feed.max_short_squeeze_price();
|
||||||
|
/*
|
||||||
|
if( require_orders )
|
||||||
|
{
|
||||||
|
for( const auto& order : limit_price_index )
|
||||||
|
wdump((order)(order.sell_price.to_real()));
|
||||||
|
|
||||||
auto short_itr = short_price_index.lower_bound( price::max( mia.id, bitasset.options.short_backing_asset ) );
|
for( const auto& call : call_price_index )
|
||||||
auto short_end = short_price_index.upper_bound( ~bitasset.current_feed.call_limit );
|
idump((call)(call.call_price.to_real()));
|
||||||
|
|
||||||
auto limit_itr = limit_price_index.lower_bound( price::max( mia.id, bitasset.options.short_backing_asset ) );
|
// limit pirce index is sorted from highest price to lowest price.
|
||||||
auto limit_end = limit_price_index.upper_bound( ~bitasset.current_feed.call_limit );
|
//auto limit_itr = limit_price_index.lower_bound( price::max( mia.id, bitasset.options.short_backing_asset ) );
|
||||||
|
wdump((max_price)(max_price.to_real()));
|
||||||
|
wdump((min_price)(min_price.to_real()));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
FC_ASSERT( max_price.base.asset_id == min_price.base.asset_id );
|
||||||
|
// wlog( "from ${a} Debt/Col to ${b} Debt/Col ", ("a", max_price.to_real())("b",min_price.to_real()) );
|
||||||
|
// NOTE limit_price_index is sorted from greatest to least
|
||||||
|
auto limit_itr = limit_price_index.lower_bound( max_price );
|
||||||
|
auto limit_end = limit_price_index.upper_bound( min_price );
|
||||||
|
|
||||||
|
/*
|
||||||
|
if( limit_itr != limit_price_index.end() )
|
||||||
|
wdump((*limit_itr)(limit_itr->sell_price.to_real()));
|
||||||
|
if( limit_end != limit_price_index.end() )
|
||||||
|
wdump((*limit_end)(limit_end->sell_price.to_real()));
|
||||||
|
*/
|
||||||
|
|
||||||
|
if( limit_itr == limit_end )
|
||||||
|
{
|
||||||
|
//wlog( "no orders available to fill margin calls" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto call_itr = call_price_index.lower_bound( price::min( bitasset.options.short_backing_asset, mia.id ) );
|
auto call_itr = call_price_index.lower_bound( price::min( bitasset.options.short_backing_asset, mia.id ) );
|
||||||
auto call_end = call_price_index.upper_bound( price::max( bitasset.options.short_backing_asset, mia.id ) );
|
auto call_end = call_price_index.upper_bound( price::max( bitasset.options.short_backing_asset, mia.id ) );
|
||||||
|
|
@ -499,34 +432,15 @@ bool database::check_call_orders( const asset_object& mia )
|
||||||
|
|
||||||
while( call_itr != call_end )
|
while( call_itr != call_end )
|
||||||
{
|
{
|
||||||
bool current_is_limit = true;
|
|
||||||
bool filled_call = false;
|
bool filled_call = false;
|
||||||
price match_price;
|
price match_price;
|
||||||
asset usd_for_sale;
|
asset usd_for_sale;
|
||||||
if( limit_itr != limit_end )
|
if( limit_itr != limit_end )
|
||||||
{
|
{
|
||||||
assert( limit_itr != limit_price_index.end() );
|
assert( limit_itr != limit_price_index.end() );
|
||||||
if( short_itr != short_end && limit_itr->sell_price < short_itr->sell_price )
|
|
||||||
{
|
|
||||||
assert( short_itr != short_price_index.end() );
|
|
||||||
current_is_limit = false;
|
|
||||||
match_price = short_itr->sell_price;
|
|
||||||
usd_for_sale = short_itr->amount_for_sale();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
current_is_limit = true;
|
|
||||||
match_price = limit_itr->sell_price;
|
match_price = limit_itr->sell_price;
|
||||||
usd_for_sale = limit_itr->amount_for_sale();
|
usd_for_sale = limit_itr->amount_for_sale();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if( short_itr != short_end )
|
|
||||||
{
|
|
||||||
assert( short_itr != short_price_index.end() );
|
|
||||||
current_is_limit = false;
|
|
||||||
match_price = short_itr->sell_price;
|
|
||||||
usd_for_sale = short_itr->amount_for_sale();
|
|
||||||
}
|
|
||||||
else return filled_short_or_limit;
|
else return filled_short_or_limit;
|
||||||
|
|
||||||
match_price.validate();
|
match_price.validate();
|
||||||
|
|
@ -540,6 +454,7 @@ bool database::check_call_orders( const asset_object& mia )
|
||||||
|
|
||||||
if( usd_to_buy * match_price > call_itr->get_collateral() )
|
if( usd_to_buy * match_price > call_itr->get_collateral() )
|
||||||
{
|
{
|
||||||
|
FC_ASSERT( enable_black_swan );
|
||||||
elog( "black swan, we do not have enough collateral to cover at this price" );
|
elog( "black swan, we do not have enough collateral to cover at this price" );
|
||||||
globally_settle_asset( mia, call_itr->get_debt() / call_itr->get_collateral() );
|
globally_settle_asset( mia, call_itr->get_debt() / call_itr->get_collateral() );
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -569,16 +484,9 @@ bool database::check_call_orders( const asset_object& mia )
|
||||||
auto old_call_itr = call_itr;
|
auto old_call_itr = call_itr;
|
||||||
if( filled_call ) ++call_itr;
|
if( filled_call ) ++call_itr;
|
||||||
fill_order( *old_call_itr, call_pays, call_receives );
|
fill_order( *old_call_itr, call_pays, call_receives );
|
||||||
if( current_is_limit )
|
|
||||||
{
|
|
||||||
auto old_limit_itr = !filled_call ? limit_itr++ : limit_itr;
|
auto old_limit_itr = !filled_call ? limit_itr++ : limit_itr;
|
||||||
fill_order( *old_limit_itr, order_pays, order_receives );
|
fill_order( *old_limit_itr, order_pays, order_receives );
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto old_short_itr = !filled_call ? short_itr++ : short_itr;
|
|
||||||
fill_order( *old_short_itr, order_pays, order_receives );
|
|
||||||
}
|
|
||||||
} // whlie call_itr != call_end
|
} // whlie call_itr != call_end
|
||||||
|
|
||||||
return filled_short_or_limit;
|
return filled_short_or_limit;
|
||||||
|
|
@ -636,7 +544,7 @@ asset database::pay_market_fees( const asset_object& recv_asset, const asset& re
|
||||||
{
|
{
|
||||||
const auto& recv_dyn_data = recv_asset.dynamic_asset_data_id(*this);
|
const auto& recv_dyn_data = recv_asset.dynamic_asset_data_id(*this);
|
||||||
modify( recv_dyn_data, [&]( asset_dynamic_data_object& obj ){
|
modify( recv_dyn_data, [&]( asset_dynamic_data_object& obj ){
|
||||||
idump((issuer_fees));
|
//idump((issuer_fees));
|
||||||
obj.accumulated_fees += issuer_fees.amount;
|
obj.accumulated_fees += issuer_fees.amount;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
#include <graphene/chain/global_property_object.hpp>
|
#include <graphene/chain/global_property_object.hpp>
|
||||||
#include <graphene/chain/limit_order_object.hpp>
|
#include <graphene/chain/limit_order_object.hpp>
|
||||||
#include <graphene/chain/proposal_object.hpp>
|
#include <graphene/chain/proposal_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
#include <graphene/chain/transaction_object.hpp>
|
#include <graphene/chain/transaction_object.hpp>
|
||||||
#include <graphene/chain/withdraw_permission_object.hpp>
|
#include <graphene/chain/withdraw_permission_object.hpp>
|
||||||
#include <graphene/chain/witness_object.hpp>
|
#include <graphene/chain/witness_object.hpp>
|
||||||
|
|
@ -119,8 +119,7 @@ void database::clear_expired_proposals()
|
||||||
void database::clear_expired_orders()
|
void database::clear_expired_orders()
|
||||||
{
|
{
|
||||||
with_skip_flags(
|
with_skip_flags(
|
||||||
get_node_properties().skip_flags | skip_authority_check, [&]()
|
get_node_properties().skip_flags | skip_authority_check, [&](){
|
||||||
{
|
|
||||||
transaction_evaluation_state cancel_context(this);
|
transaction_evaluation_state cancel_context(this);
|
||||||
|
|
||||||
//Cancel expired limit orders
|
//Cancel expired limit orders
|
||||||
|
|
@ -133,19 +132,9 @@ void database::clear_expired_orders()
|
||||||
canceler.order = order.id;
|
canceler.order = order.id;
|
||||||
apply_operation(cancel_context, canceler);
|
apply_operation(cancel_context, canceler);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Cancel expired short orders
|
|
||||||
auto& short_index = get_index_type<short_order_index>().indices().get<by_expiration>();
|
|
||||||
while( !short_index.empty() && short_index.begin()->expiration <= head_block_time() )
|
|
||||||
{
|
|
||||||
const short_order_object& order = *short_index.begin();
|
|
||||||
short_order_cancel_operation canceler;
|
|
||||||
canceler.fee_paying_account = order.seller;
|
|
||||||
canceler.order = order.id;
|
|
||||||
apply_operation(cancel_context, canceler);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
//Process expired force settlement orders
|
//Process expired force settlement orders
|
||||||
auto& settlement_index = get_index_type<force_settlement_index>().indices().get<by_expiration>();
|
auto& settlement_index = get_index_type<force_settlement_index>().indices().get<by_expiration>();
|
||||||
if( !settlement_index.empty() )
|
if( !settlement_index.empty() )
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
#include <graphene/chain/delegate_object.hpp>
|
#include <graphene/chain/delegate_object.hpp>
|
||||||
#include <graphene/chain/limit_order_object.hpp>
|
#include <graphene/chain/limit_order_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
|
|
||||||
#include <fc/uint128.hpp>
|
#include <fc/uint128.hpp>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,43 +121,10 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class price_feed
|
* @class price_feed
|
||||||
* @brief defines market parameters for shorts and margin positions
|
* @brief defines market parameters for margin positions
|
||||||
*/
|
*/
|
||||||
struct price_feed
|
struct price_feed
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* This is the lowest price at which margin positions will be forced to sell their collateral. This does not
|
|
||||||
* directly affect the price at which margin positions will be called; it is only a safety to prevent calls at
|
|
||||||
* unreasonable prices.
|
|
||||||
*/
|
|
||||||
price call_limit;
|
|
||||||
/**
|
|
||||||
* Short orders will only be matched against bids above this price.
|
|
||||||
*/
|
|
||||||
price short_limit;
|
|
||||||
/**
|
|
||||||
* Forced settlements will evaluate using this price.
|
|
||||||
*/
|
|
||||||
price settlement_price;
|
|
||||||
/**
|
|
||||||
* Maximum number of seconds margin positions should be able to remain open.
|
|
||||||
*/
|
|
||||||
uint32_t max_margin_period_sec = GRAPHENE_DEFAULT_MARGIN_PERIOD_SEC;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Required maintenance collateral is defined
|
|
||||||
* as a fixed point number with a maximum value of 10.000
|
|
||||||
* and a minimum value of 1.000.
|
|
||||||
*
|
|
||||||
* This value must be greater than required_maintenance_collateral or
|
|
||||||
* a margin call would be triggered immediately.
|
|
||||||
*
|
|
||||||
* Default requirement is $2 of collateral per $1 of debt based
|
|
||||||
* upon the premise that both parties to every trade should bring
|
|
||||||
* equal value to the table.
|
|
||||||
*/
|
|
||||||
uint16_t required_initial_collateral = GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required maintenance collateral is defined
|
* Required maintenance collateral is defined
|
||||||
* as a fixed point number with a maximum value of 10.000
|
* as a fixed point number with a maximum value of 10.000
|
||||||
|
|
@ -169,19 +136,49 @@ namespace graphene { namespace chain {
|
||||||
* equals value_of_collateral using rate.
|
* equals value_of_collateral using rate.
|
||||||
*
|
*
|
||||||
* Default requirement is $1.75 of collateral per $1 of debt
|
* Default requirement is $1.75 of collateral per $1 of debt
|
||||||
|
*
|
||||||
|
* BlackSwan ---> SQR ---> MCR ----> SP
|
||||||
*/
|
*/
|
||||||
uint16_t required_maintenance_collateral = GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO;
|
///@{
|
||||||
|
/**
|
||||||
|
* Forced settlements will evaluate using this price, defined as BITASSET / COLLATERAL
|
||||||
|
*/
|
||||||
|
price settlement_price;
|
||||||
|
|
||||||
friend bool operator < ( const price_feed& a, const price_feed& b )
|
/** Fixed point between 1.000 and 10.000 */
|
||||||
|
uint16_t maintenance_collateral_ratio = GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO;
|
||||||
|
|
||||||
|
/** Fixed point between 1.000 and 10.000 */
|
||||||
|
uint16_t maximum_short_squeeze_ratio = GRAPHENE_DEFAULT_MAX_SHORT_SQUEEZE_RATIO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When updating a call order the following condition must be maintained:
|
||||||
|
*
|
||||||
|
* debt * maintenance_price() < collateral
|
||||||
|
* debt * settlement_price < debt * maintenance
|
||||||
|
* debt * maintenance_price() < debt * max_short_squeeze_price()
|
||||||
|
*/
|
||||||
|
price maintenance_price()const
|
||||||
{
|
{
|
||||||
return std::tie( a.call_limit.base.asset_id, a.call_limit.quote.asset_id ) <
|
return ~price::call_price( settlement_price.base, settlement_price.quote, maintenance_collateral_ratio );
|
||||||
std::tie( b.call_limit.base.asset_id, b.call_limit.quote.asset_id );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** When selling collateral to pay off debt, the least amount of debt to receive should be
|
||||||
|
* min_usd = max_short_squeeze_price() * collateral
|
||||||
|
*
|
||||||
|
* This is provided to ensure that a black swan cannot be trigged due to poor liquidity alone, it
|
||||||
|
* must be confirmed by having the max_short_squeeze_price() move below the black swan price.
|
||||||
|
*/
|
||||||
|
price max_short_squeeze_price()const
|
||||||
|
{
|
||||||
|
return ~price::call_price( settlement_price.base, settlement_price.quote, maximum_short_squeeze_ratio );
|
||||||
|
}
|
||||||
|
///@}
|
||||||
|
|
||||||
friend bool operator == ( const price_feed& a, const price_feed& b )
|
friend bool operator == ( const price_feed& a, const price_feed& b )
|
||||||
{
|
{
|
||||||
return std::tie( a.call_limit.base.asset_id, a.call_limit.quote.asset_id ) ==
|
return std::tie( a.settlement_price, a.maintenance_collateral_ratio, a.maximum_short_squeeze_ratio ) ==
|
||||||
std::tie( b.call_limit.base.asset_id, b.call_limit.quote.asset_id );
|
std::tie( b.settlement_price, b.maintenance_collateral_ratio, b.maximum_short_squeeze_ratio );
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate() const;
|
void validate() const;
|
||||||
|
|
@ -191,6 +188,8 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
FC_REFLECT( graphene::chain::asset, (amount)(asset_id) )
|
FC_REFLECT( graphene::chain::asset, (amount)(asset_id) )
|
||||||
FC_REFLECT( graphene::chain::price, (base)(quote) )
|
FC_REFLECT( graphene::chain::price, (base)(quote) )
|
||||||
#define GRAPHENE_PRICE_FEED_FIELDS (call_limit)(short_limit)(settlement_price)(max_margin_period_sec)\
|
|
||||||
(required_initial_collateral)(required_maintenance_collateral)
|
#define GRAPHENE_PRICE_FEED_FIELDS (settlement_price)(maintenance_collateral_ratio)(maximum_short_squeeze_ratio)
|
||||||
|
|
||||||
FC_REFLECT( graphene::chain::price_feed, GRAPHENE_PRICE_FEED_FIELDS )
|
FC_REFLECT( graphene::chain::price_feed, GRAPHENE_PRICE_FEED_FIELDS )
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,44 +22,19 @@
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
||||||
class short_order_create_evaluator : public evaluator<short_order_create_evaluator>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef short_order_create_operation operation_type;
|
|
||||||
|
|
||||||
object_id_type do_evaluate( const short_order_create_operation& o );
|
|
||||||
object_id_type do_apply( const short_order_create_operation& o );
|
|
||||||
|
|
||||||
const short_order_create_operation* _op = nullptr;
|
|
||||||
const account_object* _seller = nullptr;
|
|
||||||
const asset_object* _sell_asset = nullptr;
|
|
||||||
const asset_object* _receive_asset = nullptr;
|
|
||||||
share_type _priority_fee = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class short_order_cancel_evaluator : public evaluator<short_order_cancel_evaluator>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef short_order_cancel_operation operation_type;
|
|
||||||
|
|
||||||
asset do_evaluate( const short_order_cancel_operation& o );
|
|
||||||
asset do_apply( const short_order_cancel_operation& o );
|
|
||||||
|
|
||||||
const short_order_object* _order;
|
|
||||||
};
|
|
||||||
|
|
||||||
class call_order_update_evaluator : public evaluator<call_order_update_evaluator>
|
class call_order_update_evaluator : public evaluator<call_order_update_evaluator>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef call_order_update_operation operation_type;
|
typedef call_order_update_operation operation_type;
|
||||||
|
|
||||||
asset do_evaluate( const call_order_update_operation& o );
|
void_result do_evaluate( const call_order_update_operation& o );
|
||||||
asset do_apply( const call_order_update_operation& o );
|
void_result do_apply( const call_order_update_operation& o );
|
||||||
|
|
||||||
bool _closing_order = false;
|
bool _closing_order = false;
|
||||||
const asset_object* _debt_asset = nullptr;
|
const asset_object* _debt_asset = nullptr;
|
||||||
const account_object* _paying_account = nullptr;
|
const account_object* _paying_account = nullptr;
|
||||||
const call_order_object* _order = nullptr;
|
const call_order_object* _order = nullptr;
|
||||||
|
const asset_bitasset_data_object* _bitasset_data = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
@ -26,47 +26,6 @@
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
using namespace graphene::db;
|
using namespace graphene::db;
|
||||||
|
|
||||||
/**
|
|
||||||
* @class short_order_object
|
|
||||||
* @brief maintains state about requests to short an asset
|
|
||||||
*
|
|
||||||
* Short orders are only valid if their sell price is above the
|
|
||||||
* fair market value of the asset at the feed price. Users can
|
|
||||||
* place shorts at any price but their order will be ignored
|
|
||||||
* beyond the feed.
|
|
||||||
*
|
|
||||||
* All shorts have a minimial initial collateral ratio requirement that is
|
|
||||||
* defined by the network, but individuals may choose to have a higher
|
|
||||||
* initial collateral to avoid the risk of being margin called.
|
|
||||||
*
|
|
||||||
* All shorts have a maintenance collateral ratio that must be kept or
|
|
||||||
* the network will automatically cover the short order. Users can
|
|
||||||
* specify a higher maintenance collateral ratio as a form of "stop loss"
|
|
||||||
* and to potentially get ahead of a short squeeze.
|
|
||||||
*/
|
|
||||||
class short_order_object : public abstract_object<short_order_object>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const uint8_t space_id = protocol_ids;
|
|
||||||
static const uint8_t type_id = short_order_object_type;
|
|
||||||
|
|
||||||
time_point_sec expiration;
|
|
||||||
account_id_type seller;
|
|
||||||
share_type for_sale;
|
|
||||||
share_type available_collateral; ///< asset_id == sell_price.quote.asset_id
|
|
||||||
price sell_price; ///< the price the short is currently at = min(limit_price,feed)
|
|
||||||
price call_price; ///< the price that will be used to trigger margin calls after match, must be 1:1 if prediction market
|
|
||||||
uint16_t initial_collateral_ratio = 0; ///< may be higher than the network requires
|
|
||||||
uint16_t maintenance_collateral_ratio = 0; ///< may optionally be higher than the network requires
|
|
||||||
|
|
||||||
asset get_collateral()const { return asset( available_collateral, sell_price.quote.asset_id ); }
|
|
||||||
/** if the initial_collateral_ratio is 0, then this is a prediction market order which means the
|
|
||||||
* amount for sale depends upon price and available collateral.
|
|
||||||
*/
|
|
||||||
asset amount_for_sale()const { return asset( for_sale, sell_price.base.asset_id ); }
|
|
||||||
asset amount_to_receive()const { return amount_for_sale() * sell_price; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class call_order_object
|
* @class call_order_object
|
||||||
* @brief tracks debt and call price information
|
* @brief tracks debt and call price information
|
||||||
|
|
@ -86,13 +45,10 @@ namespace graphene { namespace chain {
|
||||||
asset_id_type debt_type()const { return call_price.quote.asset_id; }
|
asset_id_type debt_type()const { return call_price.quote.asset_id; }
|
||||||
price collateralization()const { return get_collateral() / get_debt(); }
|
price collateralization()const { return get_collateral() / get_debt(); }
|
||||||
|
|
||||||
void update_call_price() { call_price = price::call_price(get_debt(), get_collateral(), maintenance_collateral_ratio); }
|
|
||||||
|
|
||||||
account_id_type borrower;
|
account_id_type borrower;
|
||||||
share_type collateral; ///< call_price.base.asset_id, access via get_collateral
|
share_type collateral; ///< call_price.base.asset_id, access via get_collateral
|
||||||
share_type debt; ///< call_price.quote.asset_id, access via get_collateral
|
share_type debt; ///< call_price.quote.asset_id, access via get_collateral
|
||||||
price call_price;
|
price call_price;
|
||||||
uint16_t maintenance_collateral_ratio;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -115,27 +71,9 @@ namespace graphene { namespace chain {
|
||||||
{ return balance.asset_id; }
|
{ return balance.asset_id; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct by_id;
|
|
||||||
struct by_price;
|
|
||||||
struct by_account;
|
|
||||||
struct by_expiration;
|
|
||||||
struct by_collateral;
|
struct by_collateral;
|
||||||
typedef multi_index_container<
|
struct by_account;
|
||||||
short_order_object,
|
struct by_price;
|
||||||
indexed_by<
|
|
||||||
hashed_unique< tag<by_id>,
|
|
||||||
member< object, object_id_type, &object::id > >,
|
|
||||||
ordered_non_unique< tag<by_expiration>, member< short_order_object, time_point_sec, &short_order_object::expiration> >,
|
|
||||||
ordered_unique< tag<by_price>,
|
|
||||||
composite_key< short_order_object,
|
|
||||||
member< short_order_object, price, &short_order_object::sell_price>,
|
|
||||||
member< object, object_id_type, &object::id>
|
|
||||||
>,
|
|
||||||
composite_key_compare< std::greater<price>, std::less<object_id_type> >
|
|
||||||
>
|
|
||||||
>
|
|
||||||
> short_order_multi_index_type;
|
|
||||||
|
|
||||||
typedef multi_index_container<
|
typedef multi_index_container<
|
||||||
call_order_object,
|
call_order_object,
|
||||||
indexed_by<
|
indexed_by<
|
||||||
|
|
@ -163,7 +101,6 @@ namespace graphene { namespace chain {
|
||||||
>
|
>
|
||||||
> call_order_multi_index_type;
|
> call_order_multi_index_type;
|
||||||
|
|
||||||
struct by_account;
|
|
||||||
struct by_expiration;
|
struct by_expiration;
|
||||||
typedef multi_index_container<
|
typedef multi_index_container<
|
||||||
force_settlement_object,
|
force_settlement_object,
|
||||||
|
|
@ -182,17 +119,12 @@ namespace graphene { namespace chain {
|
||||||
> force_settlement_object_multi_index_type;
|
> force_settlement_object_multi_index_type;
|
||||||
|
|
||||||
|
|
||||||
typedef generic_index<short_order_object, short_order_multi_index_type> short_order_index;
|
|
||||||
typedef generic_index<call_order_object, call_order_multi_index_type> call_order_index;
|
typedef generic_index<call_order_object, call_order_multi_index_type> call_order_index;
|
||||||
typedef generic_index<force_settlement_object, force_settlement_object_multi_index_type> force_settlement_index;
|
typedef generic_index<force_settlement_object, force_settlement_object_multi_index_type> force_settlement_index;
|
||||||
} } // graphene::chain
|
} } // graphene::chain
|
||||||
|
|
||||||
FC_REFLECT_DERIVED( graphene::chain::short_order_object, (graphene::db::object),
|
|
||||||
(expiration)(seller)(for_sale)(available_collateral)(sell_price)
|
|
||||||
(call_price)(initial_collateral_ratio)(maintenance_collateral_ratio)
|
|
||||||
)
|
|
||||||
|
|
||||||
FC_REFLECT_DERIVED( graphene::chain::call_order_object, (graphene::db::object),
|
FC_REFLECT_DERIVED( graphene::chain::call_order_object, (graphene::db::object),
|
||||||
(borrower)(collateral)(debt)(call_price)(maintenance_collateral_ratio) )
|
(borrower)(collateral)(debt)(call_price) )
|
||||||
|
|
||||||
FC_REFLECT( graphene::chain::force_settlement_object, (owner)(balance)(settlement_date) )
|
FC_REFLECT( graphene::chain::force_settlement_object, (owner)(balance)(settlement_date) )
|
||||||
|
|
@ -65,6 +65,7 @@
|
||||||
#define GRAPHENE_MAX_COLLATERAL_RATIO 32000 // higher than this is unnecessary and may exceed int16 storage
|
#define GRAPHENE_MAX_COLLATERAL_RATIO 32000 // higher than this is unnecessary and may exceed int16 storage
|
||||||
#define GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO 2000
|
#define GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO 2000
|
||||||
#define GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO 1750
|
#define GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO 1750
|
||||||
|
#define GRAPHENE_DEFAULT_MAX_SHORT_SQUEEZE_RATIO 1500
|
||||||
#define GRAPHENE_DEFAULT_MARGIN_PERIOD_SEC (30*60*60*24)
|
#define GRAPHENE_DEFAULT_MARGIN_PERIOD_SEC (30*60*60*24)
|
||||||
|
|
||||||
#define GRAPHENE_DEFAULT_NUM_WITNESSES (101)
|
#define GRAPHENE_DEFAULT_NUM_WITNESSES (101)
|
||||||
|
|
|
||||||
|
|
@ -361,7 +361,6 @@ namespace graphene { namespace chain {
|
||||||
template<typename OrderType>
|
template<typename OrderType>
|
||||||
int match( const limit_order_object& bid, const OrderType& ask, const price& match_price );
|
int match( const limit_order_object& bid, const OrderType& ask, const price& match_price );
|
||||||
int match( const limit_order_object& bid, const limit_order_object& ask, const price& trade_price );
|
int match( const limit_order_object& bid, const limit_order_object& ask, const price& trade_price );
|
||||||
int match( const limit_order_object& bid, const short_order_object& ask, const price& trade_price );
|
|
||||||
/// @return the amount of asset settled
|
/// @return the amount of asset settled
|
||||||
asset match(const call_order_object& call,
|
asset match(const call_order_object& call,
|
||||||
const force_settlement_object& settle,
|
const force_settlement_object& settle,
|
||||||
|
|
@ -373,11 +372,10 @@ namespace graphene { namespace chain {
|
||||||
* @return true if the order was completely filled and thus freed.
|
* @return true if the order was completely filled and thus freed.
|
||||||
*/
|
*/
|
||||||
bool fill_order( const limit_order_object& order, const asset& pays, const asset& receives );
|
bool fill_order( const limit_order_object& order, const asset& pays, const asset& receives );
|
||||||
bool fill_order( const short_order_object& order, const asset& pays, const asset& receives );
|
|
||||||
bool fill_order( const call_order_object& order, const asset& pays, const asset& receives );
|
bool fill_order( const call_order_object& order, const asset& pays, const asset& receives );
|
||||||
bool fill_order( const force_settlement_object& settle, const asset& pays, const asset& receives );
|
bool fill_order( const force_settlement_object& settle, const asset& pays, const asset& receives );
|
||||||
|
|
||||||
bool check_call_orders( const asset_object& mia );
|
bool check_call_orders( const asset_object& mia, bool enable_black_swan = true );
|
||||||
|
|
||||||
// helpers to fill_order
|
// helpers to fill_order
|
||||||
void pay_order( const account_object& receiver, const asset& receives, const asset& pays );
|
void pay_order( const account_object& receiver, const asset& receives, const asset& pays );
|
||||||
|
|
|
||||||
|
|
@ -809,10 +809,10 @@ namespace graphene { namespace chain {
|
||||||
*/
|
*/
|
||||||
struct limit_order_cancel_operation
|
struct limit_order_cancel_operation
|
||||||
{
|
{
|
||||||
|
asset fee;
|
||||||
limit_order_id_type order;
|
limit_order_id_type order;
|
||||||
/** must be order->seller */
|
/** must be order->seller */
|
||||||
account_id_type fee_paying_account;
|
account_id_type fee_paying_account;
|
||||||
asset fee;
|
|
||||||
|
|
||||||
account_id_type fee_payer()const { return fee_paying_account; }
|
account_id_type fee_payer()const { return fee_paying_account; }
|
||||||
void get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&)const;
|
void get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&)const;
|
||||||
|
|
@ -826,111 +826,26 @@ namespace graphene { namespace chain {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @ingroup operations
|
|
||||||
*
|
|
||||||
* Define a new short order, if it is filled it will
|
|
||||||
* be merged with existing call orders for the same
|
|
||||||
* account. If maintenance_collateral_ratio is set
|
|
||||||
* it will update any existing open call orders to
|
|
||||||
* use the new maintenance level.
|
|
||||||
*
|
|
||||||
* When shorting you specify the total amount to sell
|
|
||||||
* and the amount of collateral along with the initial
|
|
||||||
* ratio. The price it will sell at is (amount_to_sell/(collateral*initial_collateral_ratio/2000))
|
|
||||||
*/
|
|
||||||
struct short_order_create_operation
|
|
||||||
{
|
|
||||||
/// The account placing a short order (this account must sign the transaction)
|
|
||||||
account_id_type seller;
|
|
||||||
/// The amount of market-issued asset to short sell
|
|
||||||
asset amount_to_sell;
|
|
||||||
/// The fee paid by seller
|
|
||||||
asset fee;
|
|
||||||
/// The amount of collateral to withdraw from the seller
|
|
||||||
asset collateral;
|
|
||||||
/// Fixed point representation of initial collateral ratio, with three digits of precision
|
|
||||||
/// Must be greater than or equal to the minimum specified by price feed
|
|
||||||
uint16_t initial_collateral_ratio = GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO;
|
|
||||||
/// Fixed point representation of maintenance collateral ratio, with three digits of precision
|
|
||||||
/// Must be greater than or equal to the minimum specified by price feed
|
|
||||||
uint16_t maintenance_collateral_ratio = GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO;
|
|
||||||
/// Expiration time for this order. Any unfilled portion of this order which is on the books at or past this time
|
|
||||||
/// will automatically be canceled.
|
|
||||||
time_point_sec expiration = time_point_sec::maximum();
|
|
||||||
|
|
||||||
account_id_type fee_payer()const { return seller; }
|
|
||||||
void get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&)const;
|
|
||||||
void validate()const;
|
|
||||||
share_type calculate_fee( const fee_schedule_type& k )const;
|
|
||||||
|
|
||||||
pair<asset_id_type,asset_id_type> get_market()const
|
|
||||||
{
|
|
||||||
return amount_to_sell.asset_id < collateral.asset_id ?
|
|
||||||
std::make_pair( amount_to_sell.asset_id, collateral.asset_id ) :
|
|
||||||
std::make_pair( collateral.asset_id, amount_to_sell.asset_id );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** convention: amount_to_sell / amount_to_receive */
|
|
||||||
price sell_price()const { return ~price::call_price(amount_to_sell, collateral, initial_collateral_ratio); }
|
|
||||||
|
|
||||||
/** convention: amount_to_sell / amount_to_receive means we are
|
|
||||||
* selling collateral to receive debt
|
|
||||||
**/
|
|
||||||
price call_price() const { return price::call_price(amount_to_sell, collateral, maintenance_collateral_ratio); }
|
|
||||||
|
|
||||||
void get_balance_delta( balance_accumulator& acc, const operation_result& result = asset())const
|
|
||||||
{
|
|
||||||
acc.adjust( fee_payer(), -fee );
|
|
||||||
acc.adjust( seller, -collateral );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ingroup operations
|
|
||||||
* Cancel the short order and return the balance to the
|
|
||||||
* order->seller account.
|
|
||||||
*/
|
|
||||||
struct short_order_cancel_operation
|
|
||||||
{
|
|
||||||
short_order_id_type order;
|
|
||||||
account_id_type fee_paying_account; ///< Must be order->seller
|
|
||||||
asset fee; ///< paid by order->seller
|
|
||||||
|
|
||||||
account_id_type fee_payer()const { return fee_paying_account; }
|
|
||||||
void get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&)const;
|
|
||||||
void validate()const;
|
|
||||||
share_type calculate_fee( const fee_schedule_type& k )const;
|
|
||||||
|
|
||||||
void get_balance_delta( balance_accumulator& acc, const operation_result& result )const
|
|
||||||
{
|
|
||||||
acc.adjust( fee_payer(), -fee );
|
|
||||||
acc.adjust( fee_payer(), result.get<asset>() );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup operations
|
* @ingroup operations
|
||||||
*
|
*
|
||||||
* This operation can be used to add collateral, cover, and adjust the margin call price with a new maintenance
|
* This operation can be used to add collateral, cover, and adjust the margin call price for a particular user.
|
||||||
* collateral ratio.
|
|
||||||
*
|
*
|
||||||
* The only way to "cancel" a call order is to pay off the balance due. The order is invalid if the payoff amount
|
* For prediction markets the collateral and debt must always be equal.
|
||||||
* is greater than the amount due.
|
|
||||||
*
|
*
|
||||||
* @note the call_order_id is implied by the funding_account and assets involved. This implies that the assets must
|
* This operation will fail if it would trigger a margin call that couldn't be filled. If the margin call hits
|
||||||
* have appropriate asset_ids, even if the amount is zero.
|
* the call price limit then it will fail if the call price is above the settlement price.
|
||||||
*
|
*
|
||||||
* @note this operation can be used to force a market order using the collateral without requiring outside funds.
|
* @note this operation can be used to force a market order using the collateral without requiring outside funds.
|
||||||
*/
|
*/
|
||||||
struct call_order_update_operation
|
struct call_order_update_operation
|
||||||
{
|
{
|
||||||
account_id_type funding_account; ///< pays fee, collateral, and cover
|
|
||||||
asset fee; ///< paid by funding_account
|
asset fee; ///< paid by funding_account
|
||||||
asset collateral_to_add; ///< the amount of collateral to add to the margin position
|
account_id_type funding_account; ///< pays fee, collateral, and cover
|
||||||
asset amount_to_cover; ///< the amount of the debt to be paid off
|
asset delta_collateral; ///< the amount of collateral to add to the margin position
|
||||||
uint16_t maintenance_collateral_ratio = 0; ///< 0 means don't change, 1000 means feed
|
asset delta_debt; ///< the amount of the debt to be paid off, may be negative to issue new debt
|
||||||
|
price call_price; ///< the price at which the collateral will be sold to cover the debt
|
||||||
|
|
||||||
account_id_type fee_payer()const { return funding_account; }
|
account_id_type fee_payer()const { return funding_account; }
|
||||||
void get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&)const;
|
void get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&)const;
|
||||||
|
|
@ -939,8 +854,8 @@ namespace graphene { namespace chain {
|
||||||
void get_balance_delta( balance_accumulator& acc, const operation_result& result = asset())const
|
void get_balance_delta( balance_accumulator& acc, const operation_result& result = asset())const
|
||||||
{
|
{
|
||||||
acc.adjust( fee_payer(), -fee );
|
acc.adjust( fee_payer(), -fee );
|
||||||
acc.adjust( funding_account, -collateral_to_add );
|
acc.adjust( funding_account, -delta_collateral );
|
||||||
acc.adjust( funding_account, -amount_to_cover );
|
acc.adjust( funding_account, delta_debt );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1392,9 +1307,7 @@ namespace graphene { namespace chain {
|
||||||
typedef fc::static_variant<
|
typedef fc::static_variant<
|
||||||
transfer_operation,
|
transfer_operation,
|
||||||
limit_order_create_operation,
|
limit_order_create_operation,
|
||||||
short_order_create_operation,
|
|
||||||
limit_order_cancel_operation,
|
limit_order_cancel_operation,
|
||||||
short_order_cancel_operation,
|
|
||||||
call_order_update_operation,
|
call_order_update_operation,
|
||||||
key_create_operation,
|
key_create_operation,
|
||||||
account_create_operation,
|
account_create_operation,
|
||||||
|
|
@ -1591,10 +1504,7 @@ FC_REFLECT( graphene::chain::limit_order_create_operation,
|
||||||
)
|
)
|
||||||
FC_REFLECT( graphene::chain::fill_order_operation, (fee)(order_id)(account_id)(pays)(receives) )
|
FC_REFLECT( graphene::chain::fill_order_operation, (fee)(order_id)(account_id)(pays)(receives) )
|
||||||
FC_REFLECT( graphene::chain::limit_order_cancel_operation,(fee)(fee_paying_account)(order) )
|
FC_REFLECT( graphene::chain::limit_order_cancel_operation,(fee)(fee_paying_account)(order) )
|
||||||
FC_REFLECT( graphene::chain::short_order_cancel_operation,(fee)(fee_paying_account)(order) )
|
FC_REFLECT( graphene::chain::call_order_update_operation, (fee)(funding_account)(delta_collateral)(delta_debt)(call_price) )
|
||||||
FC_REFLECT( graphene::chain::short_order_create_operation, (fee)(seller)(amount_to_sell)(collateral)
|
|
||||||
(initial_collateral_ratio)(maintenance_collateral_ratio)(expiration) )
|
|
||||||
FC_REFLECT( graphene::chain::call_order_update_operation, (fee)(funding_account)(collateral_to_add)(amount_to_cover)(maintenance_collateral_ratio) )
|
|
||||||
|
|
||||||
FC_REFLECT( graphene::chain::transfer_operation,
|
FC_REFLECT( graphene::chain::transfer_operation,
|
||||||
(fee)(from)(to)(amount)(memo) )
|
(fee)(from)(to)(amount)(memo) )
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,6 @@ namespace graphene { namespace chain {
|
||||||
delegate_object_type,
|
delegate_object_type,
|
||||||
witness_object_type,
|
witness_object_type,
|
||||||
limit_order_object_type,
|
limit_order_object_type,
|
||||||
short_order_object_type,
|
|
||||||
call_order_object_type,
|
call_order_object_type,
|
||||||
custom_object_type,
|
custom_object_type,
|
||||||
proposal_object_type,
|
proposal_object_type,
|
||||||
|
|
@ -152,7 +151,6 @@ namespace graphene { namespace chain {
|
||||||
class force_settlement_object;
|
class force_settlement_object;
|
||||||
class key_object;
|
class key_object;
|
||||||
class limit_order_object;
|
class limit_order_object;
|
||||||
class short_order_object;
|
|
||||||
class call_order_object;
|
class call_order_object;
|
||||||
class custom_object;
|
class custom_object;
|
||||||
class proposal_object;
|
class proposal_object;
|
||||||
|
|
@ -169,7 +167,6 @@ namespace graphene { namespace chain {
|
||||||
typedef object_id< protocol_ids, delegate_object_type, delegate_object> delegate_id_type;
|
typedef object_id< protocol_ids, delegate_object_type, delegate_object> delegate_id_type;
|
||||||
typedef object_id< protocol_ids, witness_object_type, witness_object> witness_id_type;
|
typedef object_id< protocol_ids, witness_object_type, witness_object> witness_id_type;
|
||||||
typedef object_id< protocol_ids, limit_order_object_type, limit_order_object> limit_order_id_type;
|
typedef object_id< protocol_ids, limit_order_object_type, limit_order_object> limit_order_id_type;
|
||||||
typedef object_id< protocol_ids, short_order_object_type, short_order_object> short_order_id_type;
|
|
||||||
typedef object_id< protocol_ids, call_order_object_type, call_order_object> call_order_id_type;
|
typedef object_id< protocol_ids, call_order_object_type, call_order_object> call_order_id_type;
|
||||||
typedef object_id< protocol_ids, custom_object_type, custom_object> custom_id_type;
|
typedef object_id< protocol_ids, custom_object_type, custom_object> custom_id_type;
|
||||||
typedef object_id< protocol_ids, proposal_object_type, proposal_object> proposal_id_type;
|
typedef object_id< protocol_ids, proposal_object_type, proposal_object> proposal_id_type;
|
||||||
|
|
@ -358,7 +355,7 @@ namespace graphene { namespace chain {
|
||||||
uint32_t witness_withdraw_pay_fee; ///< fee for withdrawing witness pay
|
uint32_t witness_withdraw_pay_fee; ///< fee for withdrawing witness pay
|
||||||
uint32_t transfer_fee; ///< fee for transferring some asset
|
uint32_t transfer_fee; ///< fee for transferring some asset
|
||||||
uint32_t limit_order_fee; ///< fee for placing a limit order in the markets
|
uint32_t limit_order_fee; ///< fee for placing a limit order in the markets
|
||||||
uint32_t short_order_fee; ///< fee for placing a short order in the markets
|
uint32_t call_order_fee; ///< fee for placing a call order in the markets
|
||||||
uint32_t publish_feed_fee; ///< fee for publishing a price feed
|
uint32_t publish_feed_fee; ///< fee for publishing a price feed
|
||||||
uint32_t asset_create_fee; ///< the cost to register the cheapest asset
|
uint32_t asset_create_fee; ///< the cost to register the cheapest asset
|
||||||
uint32_t asset_update_fee; ///< the cost to modify a registered asset
|
uint32_t asset_update_fee; ///< the cost to modify a registered asset
|
||||||
|
|
@ -487,7 +484,6 @@ FC_REFLECT_ENUM( graphene::chain::object_type,
|
||||||
(delegate_object_type)
|
(delegate_object_type)
|
||||||
(witness_object_type)
|
(witness_object_type)
|
||||||
(limit_order_object_type)
|
(limit_order_object_type)
|
||||||
(short_order_object_type)
|
|
||||||
(call_order_object_type)
|
(call_order_object_type)
|
||||||
(custom_object_type)
|
(custom_object_type)
|
||||||
(proposal_object_type)
|
(proposal_object_type)
|
||||||
|
|
@ -532,7 +528,7 @@ FC_REFLECT( graphene::chain::fee_schedule_type,
|
||||||
(witness_withdraw_pay_fee)
|
(witness_withdraw_pay_fee)
|
||||||
(transfer_fee)
|
(transfer_fee)
|
||||||
(limit_order_fee)
|
(limit_order_fee)
|
||||||
(short_order_fee)
|
(call_order_fee)
|
||||||
(publish_feed_fee)
|
(publish_feed_fee)
|
||||||
(asset_create_fee)
|
(asset_create_fee)
|
||||||
(asset_update_fee)
|
(asset_update_fee)
|
||||||
|
|
@ -587,7 +583,6 @@ FC_REFLECT_TYPENAME( graphene::chain::force_settlement_id_type )
|
||||||
FC_REFLECT_TYPENAME( graphene::chain::delegate_id_type )
|
FC_REFLECT_TYPENAME( graphene::chain::delegate_id_type )
|
||||||
FC_REFLECT_TYPENAME( graphene::chain::witness_id_type )
|
FC_REFLECT_TYPENAME( graphene::chain::witness_id_type )
|
||||||
FC_REFLECT_TYPENAME( graphene::chain::limit_order_id_type )
|
FC_REFLECT_TYPENAME( graphene::chain::limit_order_id_type )
|
||||||
FC_REFLECT_TYPENAME( graphene::chain::short_order_id_type )
|
|
||||||
FC_REFLECT_TYPENAME( graphene::chain::call_order_id_type )
|
FC_REFLECT_TYPENAME( graphene::chain::call_order_id_type )
|
||||||
FC_REFLECT_TYPENAME( graphene::chain::custom_id_type )
|
FC_REFLECT_TYPENAME( graphene::chain::custom_id_type )
|
||||||
FC_REFLECT_TYPENAME( graphene::chain::proposal_id_type )
|
FC_REFLECT_TYPENAME( graphene::chain::proposal_id_type )
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
#include <graphene/chain/limit_order_evaluator.hpp>
|
#include <graphene/chain/limit_order_evaluator.hpp>
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
#include <graphene/chain/limit_order_object.hpp>
|
#include <graphene/chain/limit_order_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
|
||||||
#include <fc/uint128.hpp>
|
#include <fc/uint128.hpp>
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
@ -104,45 +103,14 @@ object_id_type limit_order_create_evaluator::do_apply( const limit_order_create_
|
||||||
if( converted_some && !db().find(result) ) // then we were filled by call order
|
if( converted_some && !db().find(result) ) // then we were filled by call order
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
const auto& short_order_idx = db().get_index_type<short_order_index>();
|
|
||||||
const auto& sell_price_idx = short_order_idx.indices().get<by_price>();
|
|
||||||
|
|
||||||
FC_ASSERT( max_price.max() >= max_price );
|
|
||||||
auto short_itr = sell_price_idx.lower_bound( max_price.max() );
|
|
||||||
auto short_end = sell_price_idx.upper_bound( max_price );
|
|
||||||
|
|
||||||
while( !filled )
|
|
||||||
{
|
|
||||||
if( limit_itr != limit_end )
|
|
||||||
{
|
|
||||||
if( short_itr != short_end && limit_itr->sell_price < short_itr->sell_price )
|
|
||||||
{
|
|
||||||
auto old_short_itr = short_itr;
|
|
||||||
++short_itr;
|
|
||||||
filled = (db().match( new_order_object, *old_short_itr, old_short_itr->sell_price ) != 2 );
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
while( !filled && limit_itr != limit_end )
|
||||||
{
|
{
|
||||||
auto old_limit_itr = limit_itr;
|
auto old_limit_itr = limit_itr;
|
||||||
++limit_itr;
|
++limit_itr;
|
||||||
filled = (db().match( new_order_object, *old_limit_itr, old_limit_itr->sell_price ) != 2 );
|
filled = (db().match( new_order_object, *old_limit_itr, old_limit_itr->sell_price ) != 2 );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if( short_itr != short_end )
|
|
||||||
{
|
|
||||||
auto old_short_itr = short_itr;
|
|
||||||
++short_itr;
|
|
||||||
filled = (db().match( new_order_object, *old_short_itr, old_short_itr->sell_price ) != 2 );
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else while( !filled && limit_itr != limit_end )
|
|
||||||
{
|
|
||||||
auto old_itr = limit_itr;
|
|
||||||
++limit_itr;
|
|
||||||
filled = (db().match( new_order_object, *old_itr, old_itr->sell_price ) != 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Possible optimization: only check calls if the new order completely filled some old order
|
//Possible optimization: only check calls if the new order completely filled some old order
|
||||||
//Do I need to check both assets?
|
//Do I need to check both assets?
|
||||||
|
|
|
||||||
|
|
@ -391,37 +391,6 @@ share_type limit_order_cancel_operation::calculate_fee(const fee_schedule_type&
|
||||||
return k.limit_order_fee;
|
return k.limit_order_fee;
|
||||||
}
|
}
|
||||||
|
|
||||||
void short_order_create_operation::get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&) const
|
|
||||||
{
|
|
||||||
active_auth_set.insert(seller);
|
|
||||||
}
|
|
||||||
|
|
||||||
void short_order_create_operation::validate()const
|
|
||||||
{
|
|
||||||
FC_ASSERT( fee.amount >= 0 );
|
|
||||||
FC_ASSERT( initial_collateral_ratio >= GRAPHENE_MIN_COLLATERAL_RATIO );
|
|
||||||
FC_ASSERT( initial_collateral_ratio > maintenance_collateral_ratio );
|
|
||||||
FC_ASSERT( initial_collateral_ratio <= GRAPHENE_MAX_COLLATERAL_RATIO );
|
|
||||||
}
|
|
||||||
|
|
||||||
share_type short_order_create_operation::calculate_fee(const fee_schedule_type& k) const
|
|
||||||
{
|
|
||||||
return k.short_order_fee;
|
|
||||||
}
|
|
||||||
void short_order_cancel_operation::get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&) const
|
|
||||||
{
|
|
||||||
active_auth_set.insert(fee_paying_account);
|
|
||||||
}
|
|
||||||
|
|
||||||
void short_order_cancel_operation::validate()const
|
|
||||||
{
|
|
||||||
FC_ASSERT( fee.amount >= 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
share_type short_order_cancel_operation::calculate_fee(const fee_schedule_type& k) const
|
|
||||||
{
|
|
||||||
return k.short_order_fee;
|
|
||||||
}
|
|
||||||
|
|
||||||
void call_order_update_operation::get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&) const
|
void call_order_update_operation::get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&) const
|
||||||
{
|
{
|
||||||
|
|
@ -429,20 +398,17 @@ void call_order_update_operation::get_required_auth(flat_set<account_id_type>& a
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_order_update_operation::validate()const
|
void call_order_update_operation::validate()const
|
||||||
{
|
{ try {
|
||||||
FC_ASSERT( fee.amount >= 0 );
|
FC_ASSERT( fee.amount >= 0 );
|
||||||
FC_ASSERT( collateral_to_add.amount > 0 || amount_to_cover.amount > 0 || maintenance_collateral_ratio > 0 );
|
FC_ASSERT( delta_collateral.asset_id != delta_debt.asset_id );
|
||||||
if( amount_to_cover.amount == 0 ) FC_ASSERT( collateral_to_add.amount >= 0 );
|
FC_ASSERT( delta_debt.asset_id == call_price.base.asset_id );
|
||||||
if( collateral_to_add.amount.value <= 0 ) FC_ASSERT( amount_to_cover.amount.value > 0 );
|
FC_ASSERT( delta_collateral.asset_id == call_price.quote.asset_id );
|
||||||
|
call_price.validate();
|
||||||
FC_ASSERT( amount_to_cover.amount >= 0 );
|
} FC_CAPTURE_AND_RETHROW((*this)) }
|
||||||
FC_ASSERT( amount_to_cover.asset_id != collateral_to_add.asset_id );
|
|
||||||
FC_ASSERT( maintenance_collateral_ratio == 0 || maintenance_collateral_ratio >= 1000 );
|
|
||||||
}
|
|
||||||
|
|
||||||
share_type call_order_update_operation::calculate_fee(const fee_schedule_type& k) const
|
share_type call_order_update_operation::calculate_fee(const fee_schedule_type& k) const
|
||||||
{
|
{
|
||||||
return k.short_order_fee;
|
return k.call_order_fee;
|
||||||
}
|
}
|
||||||
|
|
||||||
proposal_create_operation proposal_create_operation::genesis_proposal(const database& db)
|
proposal_create_operation proposal_create_operation::genesis_proposal(const database& db)
|
||||||
|
|
|
||||||
|
|
@ -1,265 +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/database.hpp>
|
|
||||||
#include <graphene/chain/short_order_evaluator.hpp>
|
|
||||||
#include <graphene/chain/account_object.hpp>
|
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
|
||||||
#include <graphene/chain/limit_order_object.hpp>
|
|
||||||
#include <fc/uint128.hpp>
|
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
|
||||||
object_id_type short_order_create_evaluator::do_evaluate( const short_order_create_operation& op )
|
|
||||||
{
|
|
||||||
database& d = db();
|
|
||||||
|
|
||||||
FC_ASSERT( op.expiration >= d.head_block_time() );
|
|
||||||
|
|
||||||
const asset_object& base_asset = op.amount_to_sell.asset_id(d);
|
|
||||||
const asset_object& quote_asset = op.collateral.asset_id(d);
|
|
||||||
|
|
||||||
FC_ASSERT( base_asset.is_market_issued() );
|
|
||||||
FC_ASSERT( quote_asset.id == base_asset.bitasset_data(d).options.short_backing_asset );
|
|
||||||
_seller = fee_paying_account;
|
|
||||||
_receive_asset = "e_asset;
|
|
||||||
_sell_asset = &base_asset;
|
|
||||||
|
|
||||||
|
|
||||||
FC_ASSERT( !(base_asset.options.flags & white_list) || _seller->is_authorized_asset(base_asset) );
|
|
||||||
FC_ASSERT( !(quote_asset.options.flags & white_list) || _seller->is_authorized_asset(quote_asset) );
|
|
||||||
|
|
||||||
const asset_bitasset_data_object& bitasset_data = _sell_asset->bitasset_data(d);
|
|
||||||
if( bitasset_data.is_prediction_market )
|
|
||||||
{
|
|
||||||
FC_ASSERT( op.initial_collateral_ratio == 0 );
|
|
||||||
FC_ASSERT( op.maintenance_collateral_ratio == 0 );
|
|
||||||
auto p = op.sell_price();
|
|
||||||
|
|
||||||
// the maximum price is 1:1, it does not make sense to charge more than
|
|
||||||
// the collateral backing the position.
|
|
||||||
FC_ASSERT( p.base.amount < p.quote.amount );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FC_ASSERT( op.initial_collateral_ratio >= bitasset_data.current_feed.required_initial_collateral );
|
|
||||||
FC_ASSERT( op.maintenance_collateral_ratio >= bitasset_data.current_feed.required_maintenance_collateral );
|
|
||||||
FC_ASSERT( op.sell_price() >= bitasset_data.current_feed.short_limit );
|
|
||||||
}
|
|
||||||
|
|
||||||
return object_id_type();
|
|
||||||
}
|
|
||||||
|
|
||||||
object_id_type short_order_create_evaluator::do_apply( const short_order_create_operation& op )
|
|
||||||
{
|
|
||||||
db().adjust_balance(op.seller, -op.collateral);
|
|
||||||
|
|
||||||
const auto& new_order_object = db().create<short_order_object>( [&]( short_order_object& obj ){
|
|
||||||
obj.seller = _seller->id;
|
|
||||||
obj.for_sale = op.amount_to_sell.amount;
|
|
||||||
obj.available_collateral = op.collateral.amount;
|
|
||||||
obj.sell_price = op.sell_price();
|
|
||||||
obj.call_price = op.call_price();
|
|
||||||
obj.initial_collateral_ratio = op.initial_collateral_ratio;
|
|
||||||
obj.maintenance_collateral_ratio = op.maintenance_collateral_ratio;
|
|
||||||
obj.expiration = op.expiration;
|
|
||||||
});
|
|
||||||
short_order_id_type new_id = new_order_object.id;
|
|
||||||
|
|
||||||
if( op.collateral.asset_id == asset_id_type() )
|
|
||||||
{
|
|
||||||
auto& bal_obj = fee_paying_account->statistics(db());
|
|
||||||
db().modify( bal_obj, [&]( account_statistics_object& obj ){
|
|
||||||
obj.total_core_in_orders += op.collateral.amount;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Possible optimization: We only need to check calls if both are true:
|
|
||||||
// - The new order is at the front of the book
|
|
||||||
// - The new order is below the call limit price
|
|
||||||
db().check_call_orders(*_sell_asset);
|
|
||||||
|
|
||||||
if( !db().find(new_id) ) // then we were filled by call order
|
|
||||||
return new_id;
|
|
||||||
|
|
||||||
const auto& limit_order_idx = db().get_index_type<limit_order_index>();
|
|
||||||
const auto& limit_price_idx = limit_order_idx.indices().get<by_price>();
|
|
||||||
|
|
||||||
auto min_limit_price = ~op.sell_price();
|
|
||||||
|
|
||||||
auto itr = limit_price_idx.lower_bound( min_limit_price.max() );
|
|
||||||
auto end = limit_price_idx.upper_bound( min_limit_price );
|
|
||||||
|
|
||||||
while( itr != end )
|
|
||||||
{
|
|
||||||
auto old_itr = itr;
|
|
||||||
++itr;
|
|
||||||
if( db().match( *old_itr, new_order_object, old_itr->sell_price ) != 1 )
|
|
||||||
break; // 1 means ONLY old iter filled
|
|
||||||
}
|
|
||||||
|
|
||||||
//Possible optimization: only check calls if the new order completely filled some old order
|
|
||||||
//Do I need to check both assets?
|
|
||||||
db().check_call_orders(*_sell_asset);
|
|
||||||
db().check_call_orders(*_receive_asset);
|
|
||||||
|
|
||||||
return new_id;
|
|
||||||
} // short_order_evaluator::do_apply
|
|
||||||
|
|
||||||
|
|
||||||
asset short_order_cancel_evaluator::do_evaluate( const short_order_cancel_operation& o )
|
|
||||||
{
|
|
||||||
database& d = db();
|
|
||||||
|
|
||||||
_order = &o.order(d);
|
|
||||||
FC_ASSERT( _order->seller == o.fee_paying_account );
|
|
||||||
|
|
||||||
return _order->get_collateral();
|
|
||||||
}
|
|
||||||
|
|
||||||
asset short_order_cancel_evaluator::do_apply( const short_order_cancel_operation& o )
|
|
||||||
{
|
|
||||||
database& d = db();
|
|
||||||
|
|
||||||
auto refunded = _order->get_collateral();
|
|
||||||
d.adjust_balance(o.fee_paying_account, refunded);
|
|
||||||
auto base_asset = _order->sell_price.base.asset_id;
|
|
||||||
auto quote_asset = _order->sell_price.quote.asset_id;
|
|
||||||
|
|
||||||
d.remove( *_order );
|
|
||||||
|
|
||||||
if( refunded.asset_id == asset_id_type() )
|
|
||||||
{
|
|
||||||
auto& stats_obj = fee_paying_account->statistics(d);
|
|
||||||
d.modify( stats_obj, [&]( account_statistics_object& obj ){
|
|
||||||
obj.total_core_in_orders -= refunded.amount;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Possible optimization: order can be called by canceling a short order iff the canceled order was at the top of the book.
|
|
||||||
// Do I need to check calls in both assets?
|
|
||||||
db().check_call_orders(base_asset(d));
|
|
||||||
db().check_call_orders(quote_asset(d));
|
|
||||||
|
|
||||||
return refunded;
|
|
||||||
}
|
|
||||||
|
|
||||||
asset call_order_update_evaluator::do_evaluate(const call_order_update_operation& o)
|
|
||||||
{ try {
|
|
||||||
database& d = db();
|
|
||||||
|
|
||||||
_paying_account = &o.funding_account(d);
|
|
||||||
|
|
||||||
_debt_asset = &o.amount_to_cover.asset_id(d);
|
|
||||||
const asset_bitasset_data_object& bitasset_data = _debt_asset->bitasset_data(d);
|
|
||||||
FC_ASSERT( _debt_asset->is_market_issued(), "Unable to cover ${sym} as it is not a market-issued asset.",
|
|
||||||
("sym", _debt_asset->symbol) );
|
|
||||||
FC_ASSERT( o.collateral_to_add.asset_id == bitasset_data.options.short_backing_asset );
|
|
||||||
|
|
||||||
if( bitasset_data.is_prediction_market )
|
|
||||||
{
|
|
||||||
FC_ASSERT( o.collateral_to_add.amount <= 0 );
|
|
||||||
FC_ASSERT( -o.collateral_to_add.amount == o.amount_to_cover.amount );
|
|
||||||
FC_ASSERT( o.maintenance_collateral_ratio == 0 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FC_ASSERT( o.maintenance_collateral_ratio == 0 ||
|
|
||||||
o.maintenance_collateral_ratio > bitasset_data.current_feed.required_maintenance_collateral );
|
|
||||||
}
|
|
||||||
|
|
||||||
FC_ASSERT( d.get_balance(*_paying_account, *_debt_asset) >= o.amount_to_cover,
|
|
||||||
"Cannot cover by ${c} when payer has ${b}",
|
|
||||||
("c", o.amount_to_cover.amount)("b", d.get_balance(*_paying_account, *_debt_asset).amount) );
|
|
||||||
FC_ASSERT( d.get_balance(*_paying_account, bitasset_data.options.short_backing_asset(d)) >= o.collateral_to_add,
|
|
||||||
"Cannot increase collateral by ${c} when payer has ${b}", ("c", o.amount_to_cover.amount)
|
|
||||||
("b", d.get_balance(*_paying_account, bitasset_data.options.short_backing_asset(d)).amount) );
|
|
||||||
|
|
||||||
auto& call_idx = d.get_index_type<call_order_index>().indices().get<by_account>();
|
|
||||||
auto itr = call_idx.find( boost::make_tuple(o.funding_account, o.amount_to_cover.asset_id) );
|
|
||||||
FC_ASSERT( itr != call_idx.end(), "Could not find call order for ${sym} belonging to ${acct}.",
|
|
||||||
("sym", _debt_asset->symbol)("acct", _paying_account->name) );
|
|
||||||
_order = &*itr;
|
|
||||||
|
|
||||||
FC_ASSERT( o.amount_to_cover.asset_id == _order->debt_type() );
|
|
||||||
|
|
||||||
FC_ASSERT( o.amount_to_cover.amount <= _order->get_debt().amount );
|
|
||||||
|
|
||||||
if( o.amount_to_cover.amount < _order->get_debt().amount )
|
|
||||||
{
|
|
||||||
FC_ASSERT( (_order->get_debt() - o.amount_to_cover) *
|
|
||||||
price::call_price(_order->get_debt() - o.amount_to_cover,
|
|
||||||
_order->get_collateral() + o.collateral_to_add,
|
|
||||||
o.maintenance_collateral_ratio? o.maintenance_collateral_ratio
|
|
||||||
: _order->maintenance_collateral_ratio)
|
|
||||||
< _order->get_collateral(),
|
|
||||||
"Order would be called immediately following this update. Refusing to apply update." );
|
|
||||||
FC_ASSERT( o.amount_to_cover < _order->get_debt(), "Cover amount is greater than debt." );
|
|
||||||
} else {
|
|
||||||
_closing_order = true;
|
|
||||||
FC_ASSERT( o.collateral_to_add.amount == -_order->get_collateral().amount, "",
|
|
||||||
("collateral", _order->get_collateral()) );
|
|
||||||
return _order->get_collateral();
|
|
||||||
}
|
|
||||||
return asset();
|
|
||||||
} FC_CAPTURE_AND_RETHROW( (o) ) }
|
|
||||||
|
|
||||||
asset call_order_update_evaluator::do_apply(const call_order_update_operation& o)
|
|
||||||
{
|
|
||||||
database& d = db();
|
|
||||||
|
|
||||||
d.adjust_balance(_paying_account->get_id(), -o.amount_to_cover);
|
|
||||||
|
|
||||||
// Deduct the debt paid from the total supply of the debt asset.
|
|
||||||
d.modify(_debt_asset->dynamic_asset_data_id(d), [&](asset_dynamic_data_object& dynamic_asset) {
|
|
||||||
dynamic_asset.current_supply -= o.amount_to_cover.amount;
|
|
||||||
assert(dynamic_asset.current_supply >= 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
asset collateral_returned;
|
|
||||||
if( _closing_order )
|
|
||||||
{
|
|
||||||
collateral_returned = _order->get_collateral();
|
|
||||||
// Credit the account's balances for his returned collateral.
|
|
||||||
d.adjust_balance(_paying_account->get_id(), collateral_returned);
|
|
||||||
d.modify(_paying_account->statistics(d), [&](account_statistics_object& stats) {
|
|
||||||
if( _order->get_collateral().asset_id == asset_id_type() )
|
|
||||||
stats.total_core_in_orders -= collateral_returned.amount;
|
|
||||||
});
|
|
||||||
// Remove the call order.
|
|
||||||
d.remove(*_order);
|
|
||||||
} else {
|
|
||||||
// Update the call order.
|
|
||||||
d.modify(*_order, [&o](call_order_object& call) {
|
|
||||||
call.debt -= o.amount_to_cover.amount;
|
|
||||||
call.collateral += o.collateral_to_add.amount;
|
|
||||||
if( o.maintenance_collateral_ratio )
|
|
||||||
call.maintenance_collateral_ratio = o.maintenance_collateral_ratio;
|
|
||||||
call.update_call_price();
|
|
||||||
});
|
|
||||||
if( o.collateral_to_add.amount > 0 )
|
|
||||||
// Deduct the added collateral from the account.
|
|
||||||
d.adjust_balance(_paying_account->get_id(), -o.collateral_to_add);
|
|
||||||
d.modify(_paying_account->statistics(d), [&](account_statistics_object& stats) {
|
|
||||||
if( o.collateral_to_add.asset_id == asset_id_type() )
|
|
||||||
stats.total_core_in_orders += o.collateral_to_add.amount;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return collateral_returned;
|
|
||||||
}
|
|
||||||
|
|
||||||
} } // graphene::chain
|
|
||||||
|
|
@ -60,7 +60,7 @@ namespace graphene { namespace chain {
|
||||||
{
|
{
|
||||||
if( depth == GRAPHENE_MAX_SIG_CHECK_DEPTH )
|
if( depth == GRAPHENE_MAX_SIG_CHECK_DEPTH )
|
||||||
{
|
{
|
||||||
elog("Failing authority verification due to recursion depth.");
|
//elog("Failing authority verification due to recursion depth.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if( check_authority( *dynamic_cast<const account_object*>( &auth_item ), auth_class, depth + 1 ) )
|
if( check_authority( *dynamic_cast<const account_object*>( &auth_item ), auth_class, depth + 1 ) )
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ index& object_database::get_mutable_index(uint8_t space_id, uint8_t type_id)
|
||||||
|
|
||||||
void object_database::flush()
|
void object_database::flush()
|
||||||
{
|
{
|
||||||
ilog("Save object_database in ${d}", ("d", _data_dir));
|
// ilog("Save object_database in ${d}", ("d", _data_dir));
|
||||||
for( uint32_t space = 0; space < _index.size(); ++space )
|
for( uint32_t space = 0; space < _index.size(); ++space )
|
||||||
{
|
{
|
||||||
fc::create_directories( _data_dir / "object_database" / fc::to_string(space) );
|
fc::create_directories( _data_dir / "object_database" / fc::to_string(space) );
|
||||||
|
|
@ -86,7 +86,7 @@ void object_database::wipe(const fc::path& data_dir)
|
||||||
|
|
||||||
void object_database::open(const fc::path& data_dir)
|
void object_database::open(const fc::path& data_dir)
|
||||||
{ try {
|
{ try {
|
||||||
ilog("Open object_database in ${d}", ("d", data_dir));
|
// ilog("Open object_database in ${d}", ("d", data_dir));
|
||||||
_data_dir = data_dir;
|
_data_dir = data_dir;
|
||||||
for( uint32_t space = 0; space < _index.size(); ++space )
|
for( uint32_t space = 0; space < _index.size(); ++space )
|
||||||
for( uint32_t type = 0; type < _index[space].size(); ++type )
|
for( uint32_t type = 0; type < _index[space].size(); ++type )
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit dd1c77b327c6eba807168856c3c12e90173468c4
|
Subproject commit dde8ed9d7ab49807f2556488c0815f3741b11e00
|
||||||
|
|
@ -141,9 +141,7 @@ struct operation_get_impacted_accounts
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()( const limit_order_create_operation& o )const { }
|
void operator()( const limit_order_create_operation& o )const { }
|
||||||
void operator()( const short_order_create_operation& o )const { }
|
|
||||||
void operator()( const limit_order_cancel_operation& o )const { }
|
void operator()( const limit_order_cancel_operation& o )const { }
|
||||||
void operator()( const short_order_cancel_operation& o )const { }
|
|
||||||
void operator()( const call_order_update_operation& o )const { }
|
void operator()( const call_order_update_operation& o )const { }
|
||||||
void operator()( const key_create_operation& o )const { }
|
void operator()( const key_create_operation& o )const { }
|
||||||
void operator()( const custom_operation& o )const { }
|
void operator()( const custom_operation& o )const { }
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
#include <graphene/chain/delegate_object.hpp>
|
#include <graphene/chain/delegate_object.hpp>
|
||||||
#include <graphene/chain/witness_object.hpp>
|
#include <graphene/chain/witness_object.hpp>
|
||||||
#include <graphene/chain/limit_order_object.hpp>
|
#include <graphene/chain/limit_order_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
#include <graphene/chain/proposal_object.hpp>
|
#include <graphene/chain/proposal_object.hpp>
|
||||||
#include <graphene/chain/operation_history_object.hpp>
|
#include <graphene/chain/operation_history_object.hpp>
|
||||||
#include <graphene/chain/withdraw_permission_object.hpp>
|
#include <graphene/chain/withdraw_permission_object.hpp>
|
||||||
|
|
@ -72,8 +72,6 @@ object* create_object( const variant& v )
|
||||||
return create_object_of_type< witness_object >( v );
|
return create_object_of_type< witness_object >( v );
|
||||||
case limit_order_object_type:
|
case limit_order_object_type:
|
||||||
return create_object_of_type< limit_order_object >( v );
|
return create_object_of_type< limit_order_object >( v );
|
||||||
case short_order_object_type:
|
|
||||||
return create_object_of_type< short_order_object >( v );
|
|
||||||
case call_order_object_type:
|
case call_order_object_type:
|
||||||
return create_object_of_type< call_order_object >( v );
|
return create_object_of_type< call_order_object >( v );
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,6 @@ class wallet_api
|
||||||
vector<asset_object> list_assets(const string& lowerbound, uint32_t limit)const;
|
vector<asset_object> list_assets(const string& lowerbound, uint32_t limit)const;
|
||||||
vector<operation_history_object> get_account_history(string name, int limit)const;
|
vector<operation_history_object> get_account_history(string name, int limit)const;
|
||||||
vector<limit_order_object> get_limit_orders(string a, string b, uint32_t limit)const;
|
vector<limit_order_object> get_limit_orders(string a, string b, uint32_t limit)const;
|
||||||
vector<short_order_object> get_short_orders(string a, uint32_t limit)const;
|
|
||||||
vector<call_order_object> get_call_orders(string a, uint32_t limit)const;
|
vector<call_order_object> get_call_orders(string a, uint32_t limit)const;
|
||||||
vector<force_settlement_object> get_settle_orders(string a, uint32_t limit)const;
|
vector<force_settlement_object> get_settle_orders(string a, uint32_t limit)const;
|
||||||
global_property_object get_global_properties() const;
|
global_property_object get_global_properties() const;
|
||||||
|
|
@ -204,7 +203,11 @@ class wallet_api
|
||||||
bool fill_or_kill = false,
|
bool fill_or_kill = false,
|
||||||
bool broadcast = false);
|
bool broadcast = false);
|
||||||
|
|
||||||
signed_transaction short_sell_asset(string seller_name, string amount_to_sell, string asset_symbol,
|
/**
|
||||||
|
* This method will create a transaction with two operations, the first one will borrow amount_to_sell
|
||||||
|
* given amount of collateral
|
||||||
|
*/
|
||||||
|
signed_transaction borrow_asset(string seller_name, string amount_to_sell, string asset_symbol,
|
||||||
string amount_of_collateral, bool broadcast = false);
|
string amount_of_collateral, bool broadcast = false);
|
||||||
|
|
||||||
signed_transaction create_asset(string issuer,
|
signed_transaction create_asset(string issuer,
|
||||||
|
|
@ -272,7 +275,7 @@ FC_API( graphene::wallet::wallet_api,
|
||||||
(upgrade_account)
|
(upgrade_account)
|
||||||
(create_account_with_brain_key)
|
(create_account_with_brain_key)
|
||||||
(sell_asset)
|
(sell_asset)
|
||||||
(short_sell_asset)
|
(borrow_asset)
|
||||||
(transfer)
|
(transfer)
|
||||||
(create_asset)
|
(create_asset)
|
||||||
(issue_asset)
|
(issue_asset)
|
||||||
|
|
@ -289,7 +292,6 @@ FC_API( graphene::wallet::wallet_api,
|
||||||
(load_wallet_file)
|
(load_wallet_file)
|
||||||
(normalize_brain_key)
|
(normalize_brain_key)
|
||||||
(get_limit_orders)
|
(get_limit_orders)
|
||||||
(get_short_orders)
|
|
||||||
(get_call_orders)
|
(get_call_orders)
|
||||||
(get_settle_orders)
|
(get_settle_orders)
|
||||||
(save_wallet_file)
|
(save_wallet_file)
|
||||||
|
|
|
||||||
|
|
@ -1011,7 +1011,7 @@ public:
|
||||||
return sign_transaction( tx, broadcast );
|
return sign_transaction( tx, broadcast );
|
||||||
}
|
}
|
||||||
|
|
||||||
signed_transaction short_sell_asset(string seller_name, string amount_to_sell, string asset_symbol,
|
signed_transaction borrow_asset(string seller_name, string amount_to_sell, string asset_symbol,
|
||||||
string amount_of_collateral, bool broadcast = false)
|
string amount_of_collateral, bool broadcast = false)
|
||||||
{
|
{
|
||||||
account_object seller = get_account(seller_name);
|
account_object seller = get_account(seller_name);
|
||||||
|
|
@ -1019,11 +1019,10 @@ public:
|
||||||
FC_ASSERT(mia.is_market_issued());
|
FC_ASSERT(mia.is_market_issued());
|
||||||
asset_object collateral = get_asset(get_object(*mia.bitasset_data_id).options.short_backing_asset);
|
asset_object collateral = get_asset(get_object(*mia.bitasset_data_id).options.short_backing_asset);
|
||||||
|
|
||||||
short_order_create_operation op;
|
call_order_update_operation op;
|
||||||
op.seller = seller.id;
|
op.funding_account = seller.id;
|
||||||
op.expiration = fc::time_point::now() + fc::days(365*10);
|
op.delta_debt = mia.amount_from_string(amount_to_sell);
|
||||||
op.amount_to_sell = mia.amount_from_string(amount_to_sell);
|
op.delta_collateral = collateral.amount_from_string(amount_of_collateral);
|
||||||
op.collateral = collateral.amount_from_string(amount_of_collateral);
|
|
||||||
|
|
||||||
signed_transaction trx;
|
signed_transaction trx;
|
||||||
trx.operations = {op};
|
trx.operations = {op};
|
||||||
|
|
@ -1040,27 +1039,11 @@ public:
|
||||||
FC_ASSERT(order_id.space() == protocol_ids, "Invalid order ID ${id}", ("id", order_id));
|
FC_ASSERT(order_id.space() == protocol_ids, "Invalid order ID ${id}", ("id", order_id));
|
||||||
signed_transaction trx;
|
signed_transaction trx;
|
||||||
|
|
||||||
switch( order_id.type() )
|
|
||||||
{
|
|
||||||
case short_order_object_type: {
|
|
||||||
short_order_cancel_operation op;
|
|
||||||
op.fee_paying_account = get_object<short_order_object>(order_id).seller;
|
|
||||||
op.order = order_id;
|
|
||||||
op.fee = op.calculate_fee(_remote_db->get_global_properties().parameters.current_fees);
|
|
||||||
trx.operations = {op};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case limit_order_object_type: {
|
|
||||||
limit_order_cancel_operation op;
|
limit_order_cancel_operation op;
|
||||||
op.fee_paying_account = get_object<limit_order_object>(order_id).seller;
|
op.fee_paying_account = get_object<limit_order_object>(order_id).seller;
|
||||||
op.order = order_id;
|
op.order = order_id;
|
||||||
op.fee = op.calculate_fee(_remote_db->get_global_properties().parameters.current_fees);
|
op.fee = op.calculate_fee(_remote_db->get_global_properties().parameters.current_fees);
|
||||||
trx.operations = {op};
|
trx.operations = {op};
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
FC_THROW("Invalid order ID ${id}", ("id", order_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
trx.validate();
|
trx.validate();
|
||||||
return sign_transaction(trx, broadcast);
|
return sign_transaction(trx, broadcast);
|
||||||
|
|
@ -1384,11 +1367,6 @@ vector<limit_order_object> wallet_api::get_limit_orders(string a, string b, uint
|
||||||
return my->_remote_db->get_limit_orders(get_asset(a).id, get_asset(b).id, limit);
|
return my->_remote_db->get_limit_orders(get_asset(a).id, get_asset(b).id, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<short_order_object> wallet_api::get_short_orders(string a, uint32_t limit)const
|
|
||||||
{
|
|
||||||
return my->_remote_db->get_short_orders(get_asset(a).id, limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<call_order_object> wallet_api::get_call_orders(string a, uint32_t limit)const
|
vector<call_order_object> wallet_api::get_call_orders(string a, uint32_t limit)const
|
||||||
{
|
{
|
||||||
return my->_remote_db->get_call_orders(get_asset(a).id, limit);
|
return my->_remote_db->get_call_orders(get_asset(a).id, limit);
|
||||||
|
|
@ -1740,11 +1718,11 @@ signed_transaction wallet_api::sell_asset(string seller_account,
|
||||||
symbol_to_receive, expiration, fill_or_kill, broadcast);
|
symbol_to_receive, expiration, fill_or_kill, broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
signed_transaction wallet_api::short_sell_asset(string seller_name, string amount_to_sell,
|
signed_transaction wallet_api::borrow_asset(string seller_name, string amount_to_sell,
|
||||||
string asset_symbol, string amount_of_collateral, bool broadcast)
|
string asset_symbol, string amount_of_collateral, bool broadcast)
|
||||||
{
|
{
|
||||||
FC_ASSERT(!is_locked());
|
FC_ASSERT(!is_locked());
|
||||||
return my->short_sell_asset(seller_name, amount_to_sell, asset_symbol, amount_of_collateral, broadcast);
|
return my->borrow_asset(seller_name, amount_to_sell, asset_symbol, amount_of_collateral, broadcast);
|
||||||
}
|
}
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
#include <graphene/chain/proposal_object.hpp>
|
#include <graphene/chain/proposal_object.hpp>
|
||||||
#include <graphene/chain/witness_object.hpp>
|
#include <graphene/chain/witness_object.hpp>
|
||||||
#include <graphene/chain/key_object.hpp>
|
#include <graphene/chain/key_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
#include <graphene/chain/limit_order_object.hpp>
|
#include <graphene/chain/limit_order_object.hpp>
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
#include <graphene/chain/block.hpp>
|
#include <graphene/chain/block.hpp>
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
#include <graphene/chain/asset_object.hpp>
|
#include <graphene/chain/asset_object.hpp>
|
||||||
#include <graphene/chain/delegate_object.hpp>
|
#include <graphene/chain/delegate_object.hpp>
|
||||||
#include <graphene/chain/limit_order_object.hpp>
|
#include <graphene/chain/limit_order_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
#include <graphene/chain/vesting_balance_object.hpp>
|
#include <graphene/chain/vesting_balance_object.hpp>
|
||||||
#include <graphene/chain/witness_object.hpp>
|
#include <graphene/chain/witness_object.hpp>
|
||||||
|
|
||||||
|
|
@ -107,7 +107,7 @@ string database_fixture::generate_anon_acct_name()
|
||||||
|
|
||||||
void database_fixture::verify_asset_supplies( )const
|
void database_fixture::verify_asset_supplies( )const
|
||||||
{
|
{
|
||||||
wlog("*** Begin asset supply verification ***");
|
//wlog("*** Begin asset supply verification ***");
|
||||||
const asset_dynamic_data_object& core_asset_data = db.get_core_asset().dynamic_asset_data_id(db);
|
const asset_dynamic_data_object& core_asset_data = db.get_core_asset().dynamic_asset_data_id(db);
|
||||||
BOOST_CHECK(core_asset_data.fee_pool == 0);
|
BOOST_CHECK(core_asset_data.fee_pool == 0);
|
||||||
|
|
||||||
|
|
@ -134,12 +134,6 @@ void database_fixture::verify_asset_supplies( )const
|
||||||
if( for_sale.asset_id == asset_id_type() ) core_in_orders += for_sale.amount;
|
if( for_sale.asset_id == asset_id_type() ) core_in_orders += for_sale.amount;
|
||||||
total_balances[for_sale.asset_id] += for_sale.amount;
|
total_balances[for_sale.asset_id] += for_sale.amount;
|
||||||
}
|
}
|
||||||
for( const short_order_object& o : db.get_index_type<short_order_index>().indices() )
|
|
||||||
{
|
|
||||||
asset col = o.get_collateral();
|
|
||||||
if( col.asset_id == asset_id_type() ) core_in_orders += col.amount;
|
|
||||||
total_balances[col.asset_id] += col.amount;
|
|
||||||
}
|
|
||||||
for( const call_order_object& o : db.get_index_type<call_order_index>().indices() )
|
for( const call_order_object& o : db.get_index_type<call_order_index>().indices() )
|
||||||
{
|
{
|
||||||
asset col = o.get_collateral();
|
asset col = o.get_collateral();
|
||||||
|
|
@ -170,7 +164,7 @@ void database_fixture::verify_asset_supplies( )const
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL( core_in_orders.value , reported_core_in_orders.value );
|
BOOST_CHECK_EQUAL( core_in_orders.value , reported_core_in_orders.value );
|
||||||
BOOST_CHECK_EQUAL( total_balances[asset_id_type()].value , core_asset_data.current_supply.value );
|
BOOST_CHECK_EQUAL( total_balances[asset_id_type()].value , core_asset_data.current_supply.value );
|
||||||
wlog("*** End asset supply verification ***");
|
// wlog("*** End asset supply verification ***");
|
||||||
}
|
}
|
||||||
|
|
||||||
void database_fixture::verify_account_history_plugin_index( )const
|
void database_fixture::verify_account_history_plugin_index( )const
|
||||||
|
|
@ -424,32 +418,6 @@ void database_fixture::issue_uia( const account_object& recipient, asset amount
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const short_order_object*database_fixture::create_short(account_id_type seller, const asset& amount_to_sell, const asset& collateral_provided, uint16_t initial_collateral_ratio, uint16_t maintenance_collateral_ratio)
|
|
||||||
{
|
|
||||||
return create_short(seller(db), amount_to_sell, collateral_provided, initial_collateral_ratio, maintenance_collateral_ratio);
|
|
||||||
}
|
|
||||||
|
|
||||||
const short_order_object* database_fixture::create_short(
|
|
||||||
const account_object& seller,
|
|
||||||
const asset& amount_to_sell,
|
|
||||||
const asset& collateral_provided,
|
|
||||||
uint16_t initial_collateral_ratio /* = 2000 */,
|
|
||||||
uint16_t maintenance_collateral_ratio /* = 1750 */
|
|
||||||
)
|
|
||||||
{
|
|
||||||
short_order_create_operation op;
|
|
||||||
op.seller = seller.id;
|
|
||||||
op.amount_to_sell = amount_to_sell;
|
|
||||||
op.collateral = collateral_provided;
|
|
||||||
op.initial_collateral_ratio = initial_collateral_ratio;
|
|
||||||
op.maintenance_collateral_ratio = maintenance_collateral_ratio;
|
|
||||||
trx.operations.push_back(std::move(op));
|
|
||||||
trx.validate();
|
|
||||||
processed_transaction ptx = db.push_transaction(trx, ~0);
|
|
||||||
trx.operations.clear();
|
|
||||||
return db.find<short_order_object>(ptx.operation_results[0].get<object_id_type>());
|
|
||||||
}
|
|
||||||
|
|
||||||
const account_object& database_fixture::create_account(
|
const account_object& database_fixture::create_account(
|
||||||
const string& name,
|
const string& name,
|
||||||
const key_id_type& key /* = key_id_type() */
|
const key_id_type& key /* = key_id_type() */
|
||||||
|
|
@ -514,7 +482,7 @@ const account_object& database_fixture::create_account(
|
||||||
trx.validate();
|
trx.validate();
|
||||||
|
|
||||||
processed_transaction ptx = db.push_transaction(trx, ~0);
|
processed_transaction ptx = db.push_transaction(trx, ~0);
|
||||||
wdump( (ptx) );
|
//wdump( (ptx) );
|
||||||
const account_object& result = db.get<account_object>(ptx.operation_results[1].get<object_id_type>());
|
const account_object& result = db.get<account_object>(ptx.operation_results[1].get<object_id_type>());
|
||||||
trx.operations.clear();
|
trx.operations.clear();
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -593,6 +561,7 @@ const limit_order_object*database_fixture::create_sell_order(account_id_type use
|
||||||
|
|
||||||
const limit_order_object* database_fixture::create_sell_order( const account_object& user, const asset& amount, const asset& recv )
|
const limit_order_object* database_fixture::create_sell_order( const account_object& user, const asset& amount, const asset& recv )
|
||||||
{
|
{
|
||||||
|
//wdump((amount)(recv));
|
||||||
limit_order_create_operation buy_order;
|
limit_order_create_operation buy_order;
|
||||||
buy_order.seller = user.id;
|
buy_order.seller = user.id;
|
||||||
buy_order.amount_to_sell = amount;
|
buy_order.amount_to_sell = amount;
|
||||||
|
|
@ -602,6 +571,7 @@ const limit_order_object* database_fixture::create_sell_order( const account_obj
|
||||||
trx.validate();
|
trx.validate();
|
||||||
auto processed = db.push_transaction(trx, ~0);
|
auto processed = db.push_transaction(trx, ~0);
|
||||||
trx.operations.clear();
|
trx.operations.clear();
|
||||||
|
//wdump((processed));
|
||||||
return db.find<limit_order_object>( processed.operation_results[0].get<object_id_type>() );
|
return db.find<limit_order_object>( processed.operation_results[0].get<object_id_type>() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -618,18 +588,6 @@ asset database_fixture::cancel_limit_order( const limit_order_object& order )
|
||||||
return processed.operation_results[0].get<asset>();
|
return processed.operation_results[0].get<asset>();
|
||||||
}
|
}
|
||||||
|
|
||||||
asset database_fixture::cancel_short_order( const short_order_object& order )
|
|
||||||
{
|
|
||||||
short_order_cancel_operation cancel_order;
|
|
||||||
cancel_order.fee_paying_account = order.seller;
|
|
||||||
cancel_order.order = order.id;
|
|
||||||
trx.operations.push_back(cancel_order);
|
|
||||||
for( auto& op : trx.operations ) op.visit( operation_set_fee( db.current_fee_schedule() ) );
|
|
||||||
trx.validate();
|
|
||||||
auto processed = db.push_transaction(trx, ~0);
|
|
||||||
trx.operations.clear();
|
|
||||||
return processed.operation_results[0].get<asset>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void database_fixture::transfer(
|
void database_fixture::transfer(
|
||||||
account_id_type from,
|
account_id_type from,
|
||||||
|
|
@ -662,6 +620,63 @@ void database_fixture::transfer(
|
||||||
} FC_CAPTURE_AND_RETHROW( (from.id)(to.id)(amount)(fee) )
|
} FC_CAPTURE_AND_RETHROW( (from.id)(to.id)(amount)(fee) )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void database_fixture::update_feed_producers( const asset_object& mia, flat_set<account_id_type> producers )
|
||||||
|
{ try {
|
||||||
|
trx.set_expiration(db.head_block_time() + fc::minutes(1));
|
||||||
|
trx.operations.clear();
|
||||||
|
asset_update_feed_producers_operation op;
|
||||||
|
op.asset_to_update = mia.id;
|
||||||
|
op.issuer = mia.issuer;
|
||||||
|
op.new_feed_producers = std::move(producers);
|
||||||
|
trx.operations.emplace_back( std::move(op) );
|
||||||
|
|
||||||
|
for( auto& op : trx.operations ) op.visit( operation_set_fee( db.current_fee_schedule() ) );
|
||||||
|
trx.validate();
|
||||||
|
db.push_transaction(trx, ~0);
|
||||||
|
trx.operations.clear();
|
||||||
|
} FC_CAPTURE_AND_RETHROW( (mia)(producers) ) }
|
||||||
|
|
||||||
|
|
||||||
|
void database_fixture::publish_feed( const asset_object& mia, const account_object& by, const price_feed& f )
|
||||||
|
{
|
||||||
|
trx.set_expiration(db.head_block_time() + fc::minutes(1));
|
||||||
|
trx.operations.clear();
|
||||||
|
|
||||||
|
asset_publish_feed_operation op;
|
||||||
|
op.publisher = by.id;
|
||||||
|
op.asset_id = mia.id;
|
||||||
|
op.feed = f;
|
||||||
|
trx.operations.emplace_back( std::move(op) );
|
||||||
|
|
||||||
|
for( auto& op : trx.operations ) op.visit( operation_set_fee( db.current_fee_schedule() ) );
|
||||||
|
trx.validate();
|
||||||
|
db.push_transaction(trx, ~0);
|
||||||
|
trx.operations.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void database_fixture::borrow( const account_object& who, asset what, asset collateral, price call_price )
|
||||||
|
{ try {
|
||||||
|
asset call_price_collateral((collateral.amount.value * 3)/4, collateral.asset_id );
|
||||||
|
trx.set_expiration(db.head_block_time() + fc::minutes(1));
|
||||||
|
trx.operations.clear();
|
||||||
|
trx.operations.push_back( call_order_update_operation({ asset(), who.id, collateral, what, call_price }));;
|
||||||
|
for( auto& op : trx.operations ) op.visit( operation_set_fee( db.current_fee_schedule() ) );
|
||||||
|
trx.validate();
|
||||||
|
db.push_transaction(trx, ~0);
|
||||||
|
trx.operations.clear();
|
||||||
|
} FC_CAPTURE_AND_RETHROW( (who.name)(what)(collateral) ) }
|
||||||
|
|
||||||
|
void database_fixture::cover( const account_object& who, asset what, asset collateral, price call_price )
|
||||||
|
{ try {
|
||||||
|
trx.set_expiration(db.head_block_time() + fc::minutes(1));
|
||||||
|
trx.operations.clear();
|
||||||
|
trx.operations.push_back( call_order_update_operation({ asset(), who.id, -collateral, -what, call_price }));
|
||||||
|
for( auto& op : trx.operations ) op.visit( operation_set_fee( db.current_fee_schedule() ) );
|
||||||
|
trx.validate();
|
||||||
|
db.push_transaction(trx, ~0);
|
||||||
|
trx.operations.clear();
|
||||||
|
} FC_CAPTURE_AND_RETHROW( (who.name)(what)(collateral) ) }
|
||||||
|
|
||||||
void database_fixture::fund_fee_pool( const account_object& from, const asset_object& asset_to_fund, const share_type amount )
|
void database_fixture::fund_fee_pool( const account_object& from, const asset_object& asset_to_fund, const share_type amount )
|
||||||
{
|
{
|
||||||
trx.operations.push_back( asset_fund_fee_pool_operation({asset(), from.id, asset_to_fund.id, amount}) );
|
trx.operations.push_back( asset_fund_fee_pool_operation({asset(), from.id, asset_to_fund.id, amount}) );
|
||||||
|
|
@ -761,15 +776,6 @@ string database_fixture::pretty( const asset& a )const
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void database_fixture::print_short_order( const short_order_object& cur )const
|
|
||||||
{
|
|
||||||
std::cout << std::setw(10) << cur.seller(db).name << " ";
|
|
||||||
std::cout << std::setw(10) << "SHORT" << " ";
|
|
||||||
std::cout << std::setw(16) << pretty( cur.amount_for_sale() ) << " ";
|
|
||||||
std::cout << std::setw(16) << pretty( cur.amount_to_receive() ) << " ";
|
|
||||||
std::cout << std::setw(16) << (~cur.sell_price).to_real() << " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
void database_fixture::print_limit_order( const limit_order_object& cur )const
|
void database_fixture::print_limit_order( const limit_order_object& cur )const
|
||||||
{
|
{
|
||||||
std::cout << std::setw(10) << cur.seller(db).name << " ";
|
std::cout << std::setw(10) << cur.seller(db).name << " ";
|
||||||
|
|
@ -817,68 +823,16 @@ void database_fixture::print_joint_market( const string& syma, const string& sym
|
||||||
|
|
||||||
const auto& limit_idx = db.get_index_type<limit_order_index>();
|
const auto& limit_idx = db.get_index_type<limit_order_index>();
|
||||||
const auto& limit_price_idx = limit_idx.indices().get<by_price>();
|
const auto& limit_price_idx = limit_idx.indices().get<by_price>();
|
||||||
const auto& short_idx = db.get_index_type<short_order_index>();
|
|
||||||
const auto& sell_price_idx = short_idx.indices().get<by_price>();
|
|
||||||
|
|
||||||
auto limit_itr = limit_price_idx.begin();
|
auto limit_itr = limit_price_idx.begin();
|
||||||
auto short_itr = sell_price_idx.rbegin();
|
while( limit_itr != limit_price_idx.end() )
|
||||||
while( true )
|
|
||||||
{
|
{
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
if( limit_itr != limit_price_idx.end() )
|
|
||||||
{
|
|
||||||
if( short_itr != sell_price_idx.rend() && limit_itr->sell_price > ~short_itr->sell_price )
|
|
||||||
{
|
|
||||||
print_short_order( *short_itr );
|
|
||||||
++short_itr;
|
|
||||||
}
|
|
||||||
else // print the limit
|
|
||||||
{
|
|
||||||
print_limit_order( *limit_itr );
|
print_limit_order( *limit_itr );
|
||||||
++limit_itr;
|
++limit_itr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( short_itr != sell_price_idx.rend() )
|
|
||||||
{
|
|
||||||
print_short_order( *short_itr );
|
|
||||||
++short_itr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void database_fixture::print_short_market( const string& syma, const string& symb )const
|
|
||||||
{
|
|
||||||
const auto& limit_idx = db.get_index_type<short_order_index>();
|
|
||||||
const auto& price_idx = limit_idx.indices().get<by_price>();
|
|
||||||
|
|
||||||
cout << std::fixed;
|
|
||||||
cout.precision(5);
|
|
||||||
cout << std::setw(10) << std::left << "NAME" << " ";
|
|
||||||
cout << std::setw(16) << std::right << "FOR SHORT" << " ";
|
|
||||||
cout << std::setw(16) << std::right << "COLLATERAL" << " ";
|
|
||||||
cout << std::setw(10) << std::right << "PRICE" << " ";
|
|
||||||
cout << std::setw(10) << std::right << "1/PRICE" << " ";
|
|
||||||
cout << std::setw(10) << std::right << "CALL PRICE" << " ";
|
|
||||||
cout << std::setw(10) << std::right << "I-Ratio" << " ";
|
|
||||||
cout << std::setw(10) << std::right << "M-Ratio" << "\n";
|
|
||||||
cout << string(100, '=') << std::endl;
|
|
||||||
auto cur = price_idx.begin();
|
|
||||||
while( cur != price_idx.end() )
|
|
||||||
{
|
|
||||||
cout << std::setw( 10 ) << std::left << cur->seller(db).name << " ";
|
|
||||||
cout << std::setw( 16 ) << std::right << pretty( cur->amount_for_sale() ) << " ";
|
|
||||||
cout << std::setw( 16 ) << std::right << pretty( cur->get_collateral() ) << " ";
|
|
||||||
cout << std::setw( 10 ) << std::right << cur->sell_price.to_real() << " ";
|
|
||||||
cout << std::setw( 10 ) << std::right << (~cur->sell_price).to_real() << " ";
|
|
||||||
cout << std::setw( 10 ) << std::right << (cur->call_price).to_real() << " ";
|
|
||||||
cout << std::setw( 10 ) << std::right << (cur->initial_collateral_ratio)/double(1000) << " ";
|
|
||||||
cout << std::setw( 10 ) << std::right << (cur->maintenance_collateral_ratio)/double(1000) << " ";
|
|
||||||
cout << "\n";
|
|
||||||
++cur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t database_fixture::get_balance( account_id_type account, asset_id_type a )const
|
int64_t database_fixture::get_balance( account_id_type account, asset_id_type a )const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -76,10 +76,13 @@ using namespace graphene::db;
|
||||||
key_id_type name ## _key_id = register_key(name ## _private_key.get_public_key()).get_id();
|
key_id_type name ## _key_id = register_key(name ## _private_key.get_public_key()).get_id();
|
||||||
#define ACTOR(name) \
|
#define ACTOR(name) \
|
||||||
PREP_ACTOR(name) \
|
PREP_ACTOR(name) \
|
||||||
account_id_type name ## _id = create_account(BOOST_PP_STRINGIZE(name), name ## _key_id).id;
|
const auto& name = create_account(BOOST_PP_STRINGIZE(name), name ## _key_id); \
|
||||||
|
account_id_type name ## _id = name.id; (void)name ## _id;
|
||||||
|
|
||||||
#define GET_ACTOR(name) \
|
#define GET_ACTOR(name) \
|
||||||
fc::ecc::private_key name ## _private_key = generate_private_key(BOOST_PP_STRINGIZE(name)); \
|
fc::ecc::private_key name ## _private_key = generate_private_key(BOOST_PP_STRINGIZE(name)); \
|
||||||
account_id_type name ## _id = get_account(BOOST_PP_STRINGIZE(name)).id; \
|
const account_object& name = get_account(BOOST_PP_STRINGIZE(name)); \
|
||||||
|
account_id_type name ## _id = name.id; \
|
||||||
key_id_type name ## _key_id = name ## _id(db).active.auths.begin()->first;
|
key_id_type name ## _key_id = name ## _id(db).active.auths.begin()->first;
|
||||||
|
|
||||||
#define ACTORS_IMPL(r, data, elem) ACTOR(elem)
|
#define ACTORS_IMPL(r, data, elem) ACTOR(elem)
|
||||||
|
|
@ -144,6 +147,11 @@ struct database_fixture {
|
||||||
key_id_type key = key_id_type()
|
key_id_type key = key_id_type()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void update_feed_producers( const asset_object& mia, flat_set<account_id_type> producers );
|
||||||
|
void publish_feed( const asset_object& mia, const account_object& by, const price_feed& f );
|
||||||
|
void borrow( const account_object& who, asset what, asset collateral, price call_price = price());
|
||||||
|
void cover( const account_object& who, asset what, asset collateral_freed, price call_price = price());
|
||||||
|
|
||||||
const asset_object& get_asset( const string& symbol )const;
|
const asset_object& get_asset( const string& symbol )const;
|
||||||
const account_object& get_account( const string& name )const;
|
const account_object& get_account( const string& name )const;
|
||||||
const asset_object& create_bitasset(const string& name,
|
const asset_object& create_bitasset(const string& name,
|
||||||
|
|
@ -153,20 +161,6 @@ struct database_fixture {
|
||||||
const asset_object& create_user_issued_asset( const string& name );
|
const asset_object& create_user_issued_asset( const string& name );
|
||||||
void issue_uia( const account_object& recipient, asset amount );
|
void issue_uia( const account_object& recipient, asset amount );
|
||||||
|
|
||||||
const short_order_object* create_short(
|
|
||||||
account_id_type seller,
|
|
||||||
const asset& amount_to_sell,
|
|
||||||
const asset& collateral_provided,
|
|
||||||
uint16_t initial_collateral_ratio = 2000,
|
|
||||||
uint16_t maintenance_collateral_ratio = 1750
|
|
||||||
);
|
|
||||||
const short_order_object* create_short(
|
|
||||||
const account_object& seller,
|
|
||||||
const asset& amount_to_sell,
|
|
||||||
const asset& collateral_provided,
|
|
||||||
uint16_t initial_collateral_ratio = 2000,
|
|
||||||
uint16_t maintenance_collateral_ratio = 1750
|
|
||||||
);
|
|
||||||
|
|
||||||
const account_object& create_account(
|
const account_object& create_account(
|
||||||
const string& name,
|
const string& name,
|
||||||
|
|
@ -203,7 +197,6 @@ struct database_fixture {
|
||||||
const limit_order_object* create_sell_order( account_id_type user, const asset& amount, const asset& recv );
|
const limit_order_object* create_sell_order( account_id_type user, const asset& amount, const asset& recv );
|
||||||
const limit_order_object* create_sell_order( const account_object& user, const asset& amount, const asset& recv );
|
const limit_order_object* create_sell_order( const account_object& user, const asset& amount, const asset& recv );
|
||||||
asset cancel_limit_order( const limit_order_object& order );
|
asset cancel_limit_order( const limit_order_object& order );
|
||||||
asset cancel_short_order( const short_order_object& order );
|
|
||||||
void transfer( account_id_type from, account_id_type to, const asset& amount, const asset& fee = asset() );
|
void transfer( account_id_type from, account_id_type to, const asset& amount, const asset& fee = asset() );
|
||||||
void transfer( const account_object& from, const account_object& to, const asset& amount, const asset& fee = asset() );
|
void transfer( const account_object& from, const account_object& to, const asset& amount, const asset& fee = asset() );
|
||||||
void fund_fee_pool( const account_object& from, const asset_object& asset_to_fund, const share_type amount );
|
void fund_fee_pool( const account_object& from, const asset_object& asset_to_fund, const share_type amount );
|
||||||
|
|
@ -214,11 +207,9 @@ struct database_fixture {
|
||||||
void upgrade_to_annual_member( const account_object& account );
|
void upgrade_to_annual_member( const account_object& account );
|
||||||
void print_market( const string& syma, const string& symb )const;
|
void print_market( const string& syma, const string& symb )const;
|
||||||
string pretty( const asset& a )const;
|
string pretty( const asset& a )const;
|
||||||
void print_short_order( const short_order_object& cur )const;
|
|
||||||
void print_limit_order( const limit_order_object& cur )const;
|
void print_limit_order( const limit_order_object& cur )const;
|
||||||
void print_call_orders( )const;
|
void print_call_orders( )const;
|
||||||
void print_joint_market( const string& syma, const string& symb )const;
|
void print_joint_market( const string& syma, const string& symb )const;
|
||||||
void print_short_market( const string& syma, const string& symb )const;
|
|
||||||
int64_t get_balance( account_id_type account, asset_id_type a )const;
|
int64_t get_balance( account_id_type account, asset_id_type a )const;
|
||||||
int64_t get_balance( const account_object& account, const asset_object& a )const;
|
int64_t get_balance( const account_object& account, const asset_object& a )const;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -966,14 +966,12 @@ BOOST_FIXTURE_TEST_CASE( bogus_signature, database_fixture )
|
||||||
|
|
||||||
flat_set<account_id_type> active_set, owner_set;
|
flat_set<account_id_type> active_set, owner_set;
|
||||||
xfer_op.get<transfer_operation>().get_required_auth(active_set, owner_set);
|
xfer_op.get<transfer_operation>().get_required_auth(active_set, owner_set);
|
||||||
wdump( (active_set)(owner_set)(alice_key_id)
|
// wdump( (active_set)(owner_set)(alice_key_id) (alice_account_object) );
|
||||||
(alice_account_object) );
|
|
||||||
|
|
||||||
PUSH_TX( db, trx, skip );
|
PUSH_TX( db, trx, skip );
|
||||||
|
|
||||||
trx.operations.push_back( xfer_op );
|
trx.operations.push_back( xfer_op );
|
||||||
// Alice's signature is now invalid
|
// Alice's signature is now invalid
|
||||||
edump((trx));
|
|
||||||
BOOST_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception );
|
BOOST_REQUIRE_THROW( PUSH_TX( db, trx, skip ), fc::exception );
|
||||||
// Re-sign, now OK (sig is replaced)
|
// Re-sign, now OK (sig is replaced)
|
||||||
trx.sign( alice_key_id, alice_key );
|
trx.sign( alice_key_id, alice_key );
|
||||||
|
|
@ -1013,10 +1011,10 @@ BOOST_FIXTURE_TEST_CASE( voting_account, database_fixture )
|
||||||
delegate_id_type nathan_delegate = create_delegate(nathan_id(db)).id;
|
delegate_id_type nathan_delegate = create_delegate(nathan_id(db)).id;
|
||||||
delegate_id_type vikram_delegate = create_delegate(vikram_id(db)).id;
|
delegate_id_type vikram_delegate = create_delegate(vikram_id(db)).id;
|
||||||
|
|
||||||
wdump((db.get_balance(account_id_type(), asset_id_type())));
|
//wdump((db.get_balance(account_id_type(), asset_id_type())));
|
||||||
generate_block();
|
generate_block();
|
||||||
|
|
||||||
wdump((db.get_balance(account_id_type(), asset_id_type())));
|
//wdump((db.get_balance(account_id_type(), asset_id_type())));
|
||||||
transfer(account_id_type(), nathan_id, asset(1000000));
|
transfer(account_id_type(), nathan_id, asset(1000000));
|
||||||
transfer(account_id_type(), vikram_id, asset(100));
|
transfer(account_id_type(), vikram_id, asset(100));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
#include <graphene/chain/key_object.hpp>
|
#include <graphene/chain/key_object.hpp>
|
||||||
#include <graphene/chain/limit_order_object.hpp>
|
#include <graphene/chain/limit_order_object.hpp>
|
||||||
#include <graphene/chain/proposal_object.hpp>
|
#include <graphene/chain/proposal_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
#include <graphene/chain/witness_schedule_object.hpp>
|
#include <graphene/chain/witness_schedule_object.hpp>
|
||||||
|
|
||||||
#include <fc/crypto/digest.hpp>
|
#include <fc/crypto/digest.hpp>
|
||||||
|
|
@ -71,29 +71,28 @@ BOOST_AUTO_TEST_CASE( block_database_test )
|
||||||
{
|
{
|
||||||
if( i > 0 ) b.previous = b.id();
|
if( i > 0 ) b.previous = b.id();
|
||||||
b.witness = witness_id_type(i+1);
|
b.witness = witness_id_type(i+1);
|
||||||
edump((b));
|
|
||||||
bdb.store( b.id(), b );
|
bdb.store( b.id(), b );
|
||||||
|
|
||||||
auto fetch = bdb.fetch_by_number( b.block_num() );
|
auto fetch = bdb.fetch_by_number( b.block_num() );
|
||||||
idump((fetch));
|
//idump((fetch));
|
||||||
FC_ASSERT( fetch.valid() );
|
FC_ASSERT( fetch.valid() );
|
||||||
FC_ASSERT( fetch->witness == b.witness );
|
FC_ASSERT( fetch->witness == b.witness );
|
||||||
fetch = bdb.fetch_by_number( i+1 );
|
fetch = bdb.fetch_by_number( i+1 );
|
||||||
idump((fetch));
|
//idump((fetch));
|
||||||
FC_ASSERT( fetch.valid() );
|
FC_ASSERT( fetch.valid() );
|
||||||
FC_ASSERT( fetch->witness == b.witness );
|
FC_ASSERT( fetch->witness == b.witness );
|
||||||
fetch = bdb.fetch_optional( b.id() );
|
fetch = bdb.fetch_optional( b.id() );
|
||||||
idump((fetch));
|
//idump((fetch));
|
||||||
FC_ASSERT( fetch.valid() );
|
FC_ASSERT( fetch.valid() );
|
||||||
FC_ASSERT( fetch->witness == b.witness );
|
FC_ASSERT( fetch->witness == b.witness );
|
||||||
}
|
}
|
||||||
ilog("-----------" );
|
//ilog("-----------" );
|
||||||
|
|
||||||
for( uint32_t i = 1; i < 5; ++i )
|
for( uint32_t i = 1; i < 5; ++i )
|
||||||
{
|
{
|
||||||
auto blk = bdb.fetch_by_number( i );
|
auto blk = bdb.fetch_by_number( i );
|
||||||
FC_ASSERT( blk.valid() );
|
FC_ASSERT( blk.valid() );
|
||||||
idump((blk)(i));
|
//idump((blk)(i));
|
||||||
FC_ASSERT( blk->witness == witness_id_type(blk->block_num()) );
|
FC_ASSERT( blk->witness == witness_id_type(blk->block_num()) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,7 +110,7 @@ BOOST_AUTO_TEST_CASE( block_database_test )
|
||||||
{
|
{
|
||||||
auto blk = bdb.fetch_by_number( i+1 );
|
auto blk = bdb.fetch_by_number( i+1 );
|
||||||
FC_ASSERT( blk.valid() );
|
FC_ASSERT( blk.valid() );
|
||||||
idump((blk)(i));
|
//idump((blk)(i));
|
||||||
FC_ASSERT( blk->witness == witness_id_type(blk->block_num()) );
|
FC_ASSERT( blk->witness == witness_id_type(blk->block_num()) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,7 +149,7 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks )
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
wlog( "------------------------------------------------" );
|
//wlog( "------------------------------------------------" );
|
||||||
database db;
|
database db;
|
||||||
db.open(data_dir.path() );
|
db.open(data_dir.path() );
|
||||||
BOOST_CHECK_EQUAL( db.head_block_num(), 200 );
|
BOOST_CHECK_EQUAL( db.head_block_num(), 200 );
|
||||||
|
|
@ -190,15 +189,15 @@ BOOST_AUTO_TEST_CASE( undo_block )
|
||||||
BOOST_CHECK( db.head_block_num() == 5 );
|
BOOST_CHECK( db.head_block_num() == 5 );
|
||||||
db.pop_block();
|
db.pop_block();
|
||||||
now -= db.block_interval();
|
now -= db.block_interval();
|
||||||
wdump( (witness_schedule_id_type()(db)) );
|
//wdump( (witness_schedule_id_type()(db)) );
|
||||||
BOOST_CHECK( db.head_block_num() == 4 );
|
BOOST_CHECK( db.head_block_num() == 4 );
|
||||||
db.pop_block();
|
db.pop_block();
|
||||||
now -= db.block_interval();
|
now -= db.block_interval();
|
||||||
wdump( (witness_schedule_id_type()(db)) );
|
//wdump( (witness_schedule_id_type()(db)) );
|
||||||
BOOST_CHECK( db.head_block_num() == 3 );
|
BOOST_CHECK( db.head_block_num() == 3 );
|
||||||
db.pop_block();
|
db.pop_block();
|
||||||
now -= db.block_interval();
|
now -= db.block_interval();
|
||||||
wdump( (witness_schedule_id_type()(db)) );
|
//wdump( (witness_schedule_id_type()(db)) );
|
||||||
BOOST_CHECK( db.head_block_num() == 2 );
|
BOOST_CHECK( db.head_block_num() == 2 );
|
||||||
for( uint32_t i = 0; i < 5; ++i )
|
for( uint32_t i = 0; i < 5; ++i )
|
||||||
{
|
{
|
||||||
|
|
@ -540,53 +539,6 @@ BOOST_FIXTURE_TEST_CASE( maintenance_interval, database_fixture )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Orders should specify a valid expiration time and they will ba automatically canceled if not filled by that time.
|
|
||||||
* This feature allows people to safely submit orders that have a limited lifetime, which is essential to some
|
|
||||||
* traders.
|
|
||||||
*/
|
|
||||||
BOOST_FIXTURE_TEST_CASE( short_order_expiration, database_fixture )
|
|
||||||
{ try {
|
|
||||||
//Get a sane head block time
|
|
||||||
generate_block();
|
|
||||||
|
|
||||||
auto* test = &create_bitasset("TEST");
|
|
||||||
auto* core = &asset_id_type()(db);
|
|
||||||
auto* nathan = &create_account("nathan");
|
|
||||||
auto* genesis = &account_id_type()(db);
|
|
||||||
|
|
||||||
transfer(*genesis, *nathan, core->amount(50000));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL( get_balance(*nathan, *core), 50000 );
|
|
||||||
|
|
||||||
short_order_create_operation op;
|
|
||||||
op.seller = nathan->id;
|
|
||||||
op.amount_to_sell = test->amount(500);
|
|
||||||
op.collateral = core->amount(500);
|
|
||||||
op.expiration = db.head_block_time() + fc::seconds(10);
|
|
||||||
trx.operations.push_back(op);
|
|
||||||
auto ptrx = PUSH_TX( db, trx, ~0 );
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL( get_balance(*nathan, *core), 49500 );
|
|
||||||
|
|
||||||
auto ptrx_id = ptrx.operation_results.back().get<object_id_type>();
|
|
||||||
auto short_index = db.get_index_type<short_order_index>().indices();
|
|
||||||
auto short_itr = short_index.begin();
|
|
||||||
BOOST_REQUIRE( short_itr != short_index.end() );
|
|
||||||
BOOST_REQUIRE( short_itr->id == ptrx_id );
|
|
||||||
BOOST_REQUIRE( db.find_object(short_itr->id) );
|
|
||||||
BOOST_CHECK_EQUAL( get_balance(*nathan, *core), 49500 );
|
|
||||||
auto id = short_itr->id;
|
|
||||||
|
|
||||||
generate_blocks(op.expiration, false);
|
|
||||||
test = &get_asset("TEST");
|
|
||||||
core = &asset_id_type()(db);
|
|
||||||
nathan = &get_account("nathan");
|
|
||||||
genesis = &account_id_type()(db);
|
|
||||||
|
|
||||||
BOOST_CHECK(db.find_object(id) == nullptr);
|
|
||||||
BOOST_CHECK_EQUAL( get_balance(*nathan, *core), 50000 );
|
|
||||||
} FC_LOG_AND_RETHROW() }
|
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_CASE( limit_order_expiration, database_fixture )
|
BOOST_FIXTURE_TEST_CASE( limit_order_expiration, database_fixture )
|
||||||
{ try {
|
{ try {
|
||||||
|
|
@ -690,7 +642,11 @@ BOOST_FIXTURE_TEST_CASE( change_block_interval, database_fixture )
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_CASE( force_settlement, database_fixture )
|
BOOST_FIXTURE_TEST_CASE( force_settlement, database_fixture )
|
||||||
{ try {
|
{ try {
|
||||||
|
FC_ASSERT( !"TODO" );
|
||||||
|
/*
|
||||||
auto private_key = delegate_priv_key;
|
auto private_key = delegate_priv_key;
|
||||||
|
auto private_key = generate_private_key("genesis");
|
||||||
|
>>>>>>> short_refactor
|
||||||
account_id_type nathan_id = create_account("nathan").get_id();
|
account_id_type nathan_id = create_account("nathan").get_id();
|
||||||
account_id_type shorter1_id = create_account("shorter1").get_id();
|
account_id_type shorter1_id = create_account("shorter1").get_id();
|
||||||
account_id_type shorter2_id = create_account("shorter2").get_id();
|
account_id_type shorter2_id = create_account("shorter2").get_id();
|
||||||
|
|
@ -810,6 +766,7 @@ BOOST_FIXTURE_TEST_CASE( force_settlement, database_fixture )
|
||||||
BOOST_CHECK(db.find(settle_id));
|
BOOST_CHECK(db.find(settle_id));
|
||||||
BOOST_CHECK_EQUAL(get_balance(nathan_id, asset_id_type()), 5878);
|
BOOST_CHECK_EQUAL(get_balance(nathan_id, asset_id_type()), 5878);
|
||||||
BOOST_CHECK(!db.get_index_type<call_order_index>().indices().empty());
|
BOOST_CHECK(!db.get_index_type<call_order_index>().indices().empty());
|
||||||
|
*/
|
||||||
} FC_LOG_AND_RETHROW() }
|
} FC_LOG_AND_RETHROW() }
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_CASE( pop_block_twice, database_fixture )
|
BOOST_FIXTURE_TEST_CASE( pop_block_twice, database_fixture )
|
||||||
|
|
@ -883,9 +840,7 @@ BOOST_FIXTURE_TEST_CASE( witness_scheduler_missed_blocks, database_fixture )
|
||||||
});
|
});
|
||||||
|
|
||||||
near_schedule = db.get_near_witness_schedule();
|
near_schedule = db.get_near_witness_schedule();
|
||||||
idump((db.head_block_time()));
|
|
||||||
generate_block(0, delegate_priv_key, 2);
|
generate_block(0, delegate_priv_key, 2);
|
||||||
idump((db.head_block_time()));
|
|
||||||
BOOST_CHECK(db.get_dynamic_global_properties().current_witness == near_schedule[2]);
|
BOOST_CHECK(db.get_dynamic_global_properties().current_witness == near_schedule[2]);
|
||||||
|
|
||||||
near_schedule.erase(near_schedule.begin(), near_schedule.begin() + 3);
|
near_schedule.erase(near_schedule.begin(), near_schedule.begin() + 3);
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -25,7 +25,7 @@
|
||||||
#include <graphene/chain/account_object.hpp>
|
#include <graphene/chain/account_object.hpp>
|
||||||
#include <graphene/chain/witness_object.hpp>
|
#include <graphene/chain/witness_object.hpp>
|
||||||
#include <graphene/chain/delegate_object.hpp>
|
#include <graphene/chain/delegate_object.hpp>
|
||||||
#include <graphene/chain/short_order_object.hpp>
|
#include <graphene/chain/call_order_object.hpp>
|
||||||
#include <graphene/chain/vesting_balance_object.hpp>
|
#include <graphene/chain/vesting_balance_object.hpp>
|
||||||
#include <graphene/chain/withdraw_permission_object.hpp>
|
#include <graphene/chain/withdraw_permission_object.hpp>
|
||||||
|
|
||||||
|
|
@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE( withdraw_permission_nominal_case )
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
const withdraw_permission_object& permit_object = permit(db);
|
const withdraw_permission_object& permit_object = permit(db);
|
||||||
wdump( (permit_object) );
|
//wdump( (permit_object) );
|
||||||
withdraw_permission_claim_operation op;
|
withdraw_permission_claim_operation op;
|
||||||
op.withdraw_permission = permit;
|
op.withdraw_permission = permit;
|
||||||
op.withdraw_from_account = nathan_id;
|
op.withdraw_from_account = nathan_id;
|
||||||
|
|
@ -336,48 +336,32 @@ BOOST_AUTO_TEST_CASE( mia_feeds )
|
||||||
const asset_object& bit_usd = bit_usd_id(db);
|
const asset_object& bit_usd = bit_usd_id(db);
|
||||||
asset_publish_feed_operation op({asset(), vikram_id});
|
asset_publish_feed_operation op({asset(), vikram_id});
|
||||||
op.asset_id = bit_usd_id;
|
op.asset_id = bit_usd_id;
|
||||||
op.feed.call_limit = price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(30));
|
op.feed.settlement_price = price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(30));
|
||||||
op.feed.short_limit = ~price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(10));
|
|
||||||
// We'll expire margins after a month
|
// We'll expire margins after a month
|
||||||
op.feed.max_margin_period_sec = fc::days(30).to_seconds();
|
|
||||||
// Accept defaults for required collateral
|
// Accept defaults for required collateral
|
||||||
trx.operations.emplace_back(op);
|
trx.operations.emplace_back(op);
|
||||||
PUSH_TX( db, trx, ~0 );
|
PUSH_TX( db, trx, ~0 );
|
||||||
|
|
||||||
const asset_bitasset_data_object& bitasset = bit_usd.bitasset_data(db);
|
const asset_bitasset_data_object& bitasset = bit_usd.bitasset_data(db);
|
||||||
BOOST_CHECK(bitasset.current_feed.call_limit.to_real() == GRAPHENE_BLOCKCHAIN_PRECISION / 30.0);
|
BOOST_CHECK(bitasset.current_feed.settlement_price.to_real() == GRAPHENE_BLOCKCHAIN_PRECISION / 30.0);
|
||||||
BOOST_CHECK_EQUAL(bitasset.current_feed.short_limit.to_real(), 10.0 / GRAPHENE_BLOCKCHAIN_PRECISION);
|
BOOST_CHECK(bitasset.current_feed.maintenance_collateral_ratio == GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO);
|
||||||
BOOST_CHECK(bitasset.current_feed.max_margin_period_sec == fc::days(30).to_seconds());
|
|
||||||
BOOST_CHECK(bitasset.current_feed.required_initial_collateral == GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO);
|
|
||||||
BOOST_CHECK(bitasset.current_feed.required_maintenance_collateral == GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO);
|
|
||||||
|
|
||||||
op.publisher = ben_id;
|
op.publisher = ben_id;
|
||||||
op.feed.call_limit = price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(25));
|
op.feed.settlement_price = price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(25));
|
||||||
op.feed.short_limit = ~price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(20));
|
|
||||||
op.feed.max_margin_period_sec = fc::days(10).to_seconds();
|
|
||||||
trx.operations.back() = op;
|
trx.operations.back() = op;
|
||||||
PUSH_TX( db, trx, ~0 );
|
PUSH_TX( db, trx, ~0 );
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(bitasset.current_feed.call_limit.to_real(), GRAPHENE_BLOCKCHAIN_PRECISION / 25.0);
|
BOOST_CHECK_EQUAL(bitasset.current_feed.settlement_price.to_real(), GRAPHENE_BLOCKCHAIN_PRECISION / 25.0);
|
||||||
BOOST_CHECK_EQUAL(bitasset.current_feed.short_limit.to_real(), 20.0 / GRAPHENE_BLOCKCHAIN_PRECISION);
|
BOOST_CHECK(bitasset.current_feed.maintenance_collateral_ratio == GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO);
|
||||||
BOOST_CHECK(bitasset.current_feed.max_margin_period_sec == fc::days(30).to_seconds());
|
|
||||||
BOOST_CHECK(bitasset.current_feed.required_initial_collateral == GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO);
|
|
||||||
BOOST_CHECK(bitasset.current_feed.required_maintenance_collateral == GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO);
|
|
||||||
|
|
||||||
op.publisher = dan_id;
|
op.publisher = dan_id;
|
||||||
op.feed.call_limit = price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(40));
|
op.feed.settlement_price = price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(40));
|
||||||
op.feed.short_limit = ~price(asset(GRAPHENE_BLOCKCHAIN_PRECISION),bit_usd.amount(10));
|
op.feed.maintenance_collateral_ratio = 1000;
|
||||||
op.feed.max_margin_period_sec = fc::days(100).to_seconds();
|
|
||||||
op.feed.required_initial_collateral = 1001;
|
|
||||||
op.feed.required_maintenance_collateral = 1000;
|
|
||||||
trx.operations.back() = op;
|
trx.operations.back() = op;
|
||||||
PUSH_TX( db, trx, ~0 );
|
PUSH_TX( db, trx, ~0 );
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(bitasset.current_feed.call_limit.to_real(), GRAPHENE_BLOCKCHAIN_PRECISION / 30.0);
|
BOOST_CHECK_EQUAL(bitasset.current_feed.settlement_price.to_real(), GRAPHENE_BLOCKCHAIN_PRECISION / 30.0);
|
||||||
BOOST_CHECK_EQUAL(bitasset.current_feed.short_limit.to_real(), 10.0 / GRAPHENE_BLOCKCHAIN_PRECISION);
|
BOOST_CHECK(bitasset.current_feed.maintenance_collateral_ratio == GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO);
|
||||||
BOOST_CHECK(bitasset.current_feed.max_margin_period_sec == fc::days(30).to_seconds());
|
|
||||||
BOOST_CHECK(bitasset.current_feed.required_initial_collateral == GRAPHENE_DEFAULT_INITIAL_COLLATERAL_RATIO);
|
|
||||||
BOOST_CHECK(bitasset.current_feed.required_maintenance_collateral == GRAPHENE_DEFAULT_MAINTENANCE_COLLATERAL_RATIO);
|
|
||||||
|
|
||||||
op.publisher = nathan_id;
|
op.publisher = nathan_id;
|
||||||
trx.operations.back() = op;
|
trx.operations.back() = op;
|
||||||
|
|
@ -452,6 +436,8 @@ BOOST_AUTO_TEST_CASE( witness_create )
|
||||||
BOOST_AUTO_TEST_CASE( global_settle_test )
|
BOOST_AUTO_TEST_CASE( global_settle_test )
|
||||||
{ try {
|
{ try {
|
||||||
ACTORS((nathan)(ben)(valentine)(dan));
|
ACTORS((nathan)(ben)(valentine)(dan));
|
||||||
|
FC_ASSERT( !"TODO - Reimplement this" );
|
||||||
|
/*
|
||||||
asset_id_type bit_usd_id = create_bitasset("BITUSD", nathan_id, 100, global_settle | charge_market_fee).get_id();
|
asset_id_type bit_usd_id = create_bitasset("BITUSD", nathan_id, 100, global_settle | charge_market_fee).get_id();
|
||||||
transfer(genesis_account, ben_id, asset(10000));
|
transfer(genesis_account, ben_id, asset(10000));
|
||||||
transfer(genesis_account, valentine_id, asset(10000));
|
transfer(genesis_account, valentine_id, asset(10000));
|
||||||
|
|
@ -490,6 +476,7 @@ BOOST_AUTO_TEST_CASE( global_settle_test )
|
||||||
BOOST_CHECK_EQUAL(get_balance(ben_id, asset_id_type()), 10091);
|
BOOST_CHECK_EQUAL(get_balance(ben_id, asset_id_type()), 10091);
|
||||||
BOOST_CHECK_EQUAL(get_balance(dan_id, bit_usd_id), 0);
|
BOOST_CHECK_EQUAL(get_balance(dan_id, bit_usd_id), 0);
|
||||||
BOOST_CHECK_EQUAL(get_balance(dan_id, asset_id_type()), 9850);
|
BOOST_CHECK_EQUAL(get_balance(dan_id, asset_id_type()), 9850);
|
||||||
|
*/
|
||||||
} FC_LOG_AND_RETHROW() }
|
} FC_LOG_AND_RETHROW() }
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( worker_create_test )
|
BOOST_AUTO_TEST_CASE( worker_create_test )
|
||||||
|
|
@ -684,7 +671,11 @@ BOOST_AUTO_TEST_CASE( refund_worker_test )
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( force_settlement_unavailable )
|
BOOST_AUTO_TEST_CASE( force_settlement_unavailable )
|
||||||
{ try {
|
{ try {
|
||||||
|
FC_ASSERT( !"TODO - Reimplement this" );
|
||||||
|
/*
|
||||||
auto private_key = delegate_priv_key;
|
auto private_key = delegate_priv_key;
|
||||||
|
auto private_key = generate_private_key("genesis");
|
||||||
|
>>>>>>> short_refactor
|
||||||
account_id_type nathan_id = create_account("nathan").get_id();
|
account_id_type nathan_id = create_account("nathan").get_id();
|
||||||
account_id_type shorter1_id = create_account("shorter1").get_id();
|
account_id_type shorter1_id = create_account("shorter1").get_id();
|
||||||
account_id_type shorter2_id = create_account("shorter2").get_id();
|
account_id_type shorter2_id = create_account("shorter2").get_id();
|
||||||
|
|
@ -739,7 +730,6 @@ BOOST_AUTO_TEST_CASE( force_settlement_unavailable )
|
||||||
price_feed feed;
|
price_feed feed;
|
||||||
feed.settlement_price = price(asset(1),asset(1, bit_usd));
|
feed.settlement_price = price(asset(1),asset(1, bit_usd));
|
||||||
feed.call_limit = price::min(0, bit_usd);
|
feed.call_limit = price::min(0, bit_usd);
|
||||||
feed.short_limit = price::min(bit_usd, 0);
|
|
||||||
pop.feed = feed;
|
pop.feed = feed;
|
||||||
trx.operations.push_back(pop);
|
trx.operations.push_back(pop);
|
||||||
}
|
}
|
||||||
|
|
@ -797,6 +787,7 @@ BOOST_AUTO_TEST_CASE( force_settlement_unavailable )
|
||||||
BOOST_CHECK(db.get_index_type<force_settlement_index>().indices().empty());
|
BOOST_CHECK(db.get_index_type<force_settlement_index>().indices().empty());
|
||||||
BOOST_CHECK_EQUAL(get_balance(nathan_id, bit_usd), bit_usd(db).dynamic_data(db).current_supply.value);
|
BOOST_CHECK_EQUAL(get_balance(nathan_id, bit_usd), bit_usd(db).dynamic_data(db).current_supply.value);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
} FC_LOG_AND_RETHROW() }
|
} FC_LOG_AND_RETHROW() }
|
||||||
|
|
||||||
// TODO: Write linear VBO tests
|
// TODO: Write linear VBO tests
|
||||||
|
|
|
||||||
|
|
@ -63,9 +63,7 @@ BOOST_AUTO_TEST_CASE( json_tests )
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
auto var = fc::json::variants_from_string( "10.6 " );
|
auto var = fc::json::variants_from_string( "10.6 " );
|
||||||
wdump((var));
|
|
||||||
var = fc::json::variants_from_string( "10.5" );
|
var = fc::json::variants_from_string( "10.5" );
|
||||||
wdump((var));
|
|
||||||
} catch ( const fc::exception& e )
|
} catch ( const fc::exception& e )
|
||||||
{
|
{
|
||||||
edump((e.to_detail_string()));
|
edump((e.to_detail_string()));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue