From 9aeb99d0e7fe4d904551dfbb88d03812190b1d55 Mon Sep 17 00:00:00 2001 From: abitmore Date: Wed, 16 Sep 2020 20:09:25 -0400 Subject: [PATCH] Add database APIs for liquidity pool --- libraries/app/application.cpp | 5 + libraries/app/database_api.cpp | 135 ++++++++++++++++++ libraries/app/database_api_impl.hxx | 57 ++++++++ .../app/include/graphene/app/application.hpp | 1 + .../app/include/graphene/app/database_api.hpp | 83 +++++++++++ .../graphene/chain/liquidity_pool_object.hpp | 8 +- 6 files changed, 288 insertions(+), 1 deletion(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index bd1c631a9b..48984faa74 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -326,6 +326,9 @@ void application_impl::set_api_limit() { if(_options->count("api-limit-get-withdraw-permissions-by-recipient")) { _app_options.api_limit_get_withdraw_permissions_by_recipient = _options->at("api-limit-get-withdraw-permissions-by-recipient").as(); } + if(_options->count("api-limit-get-liquidity-pools")) { + _app_options.api_limit_get_liquidity_pools = _options->at("api-limit-get-liquidity-pools").as(); + } } void application_impl::startup() @@ -1054,6 +1057,8 @@ void application::set_program_options(boost::program_options::options_descriptio "For database_api_impl::get_withdraw_permissions_by_giver to set max limit value") ("api-limit-get-withdraw-permissions-by-recipient",boost::program_options::value()->default_value(101), "For database_api_impl::get_withdraw_permissions_by_recipient to set max limit value") + ("api-limit-get-liquidity-pools",boost::program_options::value()->default_value(101), + "For database_api_impl::get_liquidity_pools_* to set max limit value") ; command_line_options.add(configuration_file_options); command_line_options.add_options() diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 8d1f0e5f29..3590bcb0c2 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -1736,6 +1736,141 @@ vector database_api_impl::get_trade_history_by_sequence( return result; } +////////////////////////////////////////////////////////////////////// +// // +// Liquidity pools // +// // +////////////////////////////////////////////////////////////////////// + +vector database_api::get_liquidity_pools_by_asset_a( + std::string asset_symbol_or_id, + optional limit, + optional start_id )const +{ + return my->get_liquidity_pools_by_asset_a( + asset_symbol_or_id, + limit, + start_id ); +} + +vector database_api_impl::get_liquidity_pools_by_asset_a( + std::string asset_symbol_or_id, + optional limit, + optional start_id )const +{ + return get_liquidity_pools_by_asset_x( + asset_symbol_or_id, + limit, + start_id ); +} + +vector database_api::get_liquidity_pools_by_asset_b( + std::string asset_symbol_or_id, + optional limit, + optional start_id )const +{ + return my->get_liquidity_pools_by_asset_b( + asset_symbol_or_id, + limit, + start_id ); +} + +vector database_api_impl::get_liquidity_pools_by_asset_b( + std::string asset_symbol_or_id, + optional limit, + optional start_id )const +{ + return get_liquidity_pools_by_asset_x( + asset_symbol_or_id, + limit, + start_id ); +} + +vector database_api::get_liquidity_pools_by_both_assets( + std::string asset_symbol_or_id_a, + std::string asset_symbol_or_id_b, + optional limit, + optional start_id )const +{ + return my->get_liquidity_pools_by_both_assets( + asset_symbol_or_id_a, + asset_symbol_or_id_b, + limit, + start_id ); +} + +vector database_api_impl::get_liquidity_pools_by_both_assets( + std::string asset_symbol_or_id_a, + std::string asset_symbol_or_id_b, + optional olimit, + optional ostart_id )const +{ + uint32_t limit = olimit.valid() ? *olimit : 101; + + FC_ASSERT( _app_options, "Internal error" ); + const auto configured_limit = _app_options->api_limit_get_liquidity_pools; + FC_ASSERT( limit <= configured_limit, + "limit can not be greater than ${configured_limit}", + ("configured_limit", configured_limit) ); + + vector results; + + asset_id_type asset_id_a = get_asset_from_string(asset_symbol_or_id_a)->id; + asset_id_type asset_id_b = get_asset_from_string(asset_symbol_or_id_b)->id; + if( asset_id_a > asset_id_b ) + std::swap( asset_id_a, asset_id_b ); + + liquidity_pool_id_type start_id = ostart_id.valid() ? *ostart_id : liquidity_pool_id_type(); + + const auto& idx = _db.get_index_type().indices().get(); + auto lower_itr = idx.lower_bound( std::make_tuple( asset_id_a, asset_id_b, start_id ) ); + auto upper_itr = idx.upper_bound( std::make_tuple( asset_id_a, asset_id_b ) ); + + results.reserve( limit ); + uint32_t count = 0; + for ( ; lower_itr != upper_itr && count < limit; ++lower_itr, ++count) + { + results.emplace_back( *lower_itr ); + } + + return results; +} + +vector> database_api::get_liquidity_pools_by_share_asset( + const vector& asset_symbols_or_ids, + optional subscribe )const +{ + return my->get_liquidity_pools_by_share_asset( + asset_symbols_or_ids, + subscribe ); +} + +vector> database_api_impl::get_liquidity_pools_by_share_asset( + const vector& asset_symbols_or_ids, + optional subscribe )const +{ + FC_ASSERT( _app_options, "Internal error" ); + const auto configured_limit = _app_options->api_limit_get_liquidity_pools; + FC_ASSERT( asset_symbols_or_ids.size() <= configured_limit, + "size of the querying list can not be greater than ${configured_limit}", + ("configured_limit", configured_limit) ); + + bool to_subscribe = get_whether_to_subscribe( subscribe ); + vector> result; result.reserve(asset_symbols_or_ids.size()); + std::transform(asset_symbols_or_ids.begin(), asset_symbols_or_ids.end(), std::back_inserter(result), + [this,to_subscribe](std::string id_or_name) -> optional { + + const asset_object* asset_obj = get_asset_from_string( id_or_name, false ); + if( asset_obj == nullptr || !asset_obj->is_liquidity_pool_share_asset() ) + return {}; + const liquidity_pool_object& lp_obj = (*asset_obj->for_liquidity_pool)(_db); + if( to_subscribe ) + subscribe_to_item( lp_obj.id ); + return lp_obj; + }); + return result; +} + ////////////////////////////////////////////////////////////////////// // // // Witnesses // diff --git a/libraries/app/database_api_impl.hxx b/libraries/app/database_api_impl.hxx index 4d249a7cb4..c6053eefa8 100644 --- a/libraries/app/database_api_impl.hxx +++ b/libraries/app/database_api_impl.hxx @@ -138,6 +138,24 @@ class database_api_impl : public std::enable_shared_from_this int64_t start, fc::time_point_sec stop, unsigned limit = 100 )const; + // Liquidity pools + vector get_liquidity_pools_by_asset_a( + std::string asset_symbol_or_id, + optional limit = 101, + optional start_id = optional() )const; + vector get_liquidity_pools_by_asset_b( + std::string asset_symbol_or_id, + optional limit = 101, + optional start_id = optional() )const; + vector get_liquidity_pools_by_both_assets( + std::string asset_symbol_or_id_a, + std::string asset_symbol_or_id_b, + optional limit = 101, + optional start_id = optional() )const; + vector> get_liquidity_pools_by_share_asset( + const vector& asset_symbols_or_ids, + optional subscribe = optional() )const; + // Witnesses vector> get_witnesses(const vector& witness_ids)const; fc::optional get_witness_by_account(const std::string account_id_or_name)const; @@ -239,6 +257,45 @@ class database_api_impl : public std::enable_shared_from_this vector get_limit_orders( const asset_id_type a, const asset_id_type b, const uint32_t limit )const; + //////////////////////////////////////////////// + // Liquidity pools + //////////////////////////////////////////////// + + // template function to reduce duplicate code + template + vector get_liquidity_pools_by_asset_x( + std::string asset_symbol_or_id, + optional olimit, + optional ostart_id )const + { + uint32_t limit = olimit.valid() ? *olimit : 101; + + FC_ASSERT( _app_options, "Internal error" ); + const auto configured_limit = _app_options->api_limit_get_liquidity_pools; + FC_ASSERT( limit <= configured_limit, + "limit can not be greater than ${configured_limit}", + ("configured_limit", configured_limit) ); + + vector results; + + const asset_id_type asset_id = get_asset_from_string(asset_symbol_or_id)->id; + + liquidity_pool_id_type start_id = ostart_id.valid() ? *ostart_id : liquidity_pool_id_type(); + + const auto& idx = _db.get_index_type().indices().get(); + auto lower_itr = idx.lower_bound( std::make_tuple( asset_id, start_id ) ); + auto upper_itr = idx.upper_bound( asset_id ); + + results.reserve( limit ); + uint32_t count = 0; + for ( ; lower_itr != upper_itr && count < limit; ++lower_itr, ++count) + { + results.emplace_back( *lower_itr ); + } + + return results; + } + //////////////////////////////////////////////// // Subscription //////////////////////////////////////////////// diff --git a/libraries/app/include/graphene/app/application.hpp b/libraries/app/include/graphene/app/application.hpp index 3e318e34a5..5d9be78b92 100644 --- a/libraries/app/include/graphene/app/application.hpp +++ b/libraries/app/include/graphene/app/application.hpp @@ -72,6 +72,7 @@ namespace graphene { namespace app { uint64_t api_limit_get_trade_history_by_sequence = 100; uint64_t api_limit_get_withdraw_permissions_by_giver = 101; uint64_t api_limit_get_withdraw_permissions_by_recipient = 101; + uint64_t api_limit_get_liquidity_pools = 101; }; class application diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index da22f1c5a3..6df0d49433 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,7 @@ class database_api * - lookup_accounts * - get_full_accounts * - get_htlc + * - get_liquidity_pools_by_share_asset * * Note: auto-subscription is enabled by default * @@ -625,6 +627,81 @@ class database_api unsigned limit = 100 )const; + ///////////////////// + // Liquidity pools // + ///////////////////// + + /** + * @brief Get a list of liquidity pools by the symbol or ID of the first asset in the pool + * @param asset_symbol_or_id symbol name or ID of the asset + * @param limit The limitation of items each query can fetch, not greater than a configured value + * @param start_id Start liquidity pool id, fetch pools whose IDs are greater than or equal to this ID + * @return The liquidity pools + * + * @note + * 1. if @p asset_symbol_or_id cannot be tied to an asset, an error will be returned + * 2. @p limit can be omitted or be null, if so the default value 101 will be used + * 3. @p start_id can be omitted or be null, if so the api will return the "first page" of pools + * 4. can only omit one or more arguments in the end of the list, but not one or more in the middle + */ + vector get_liquidity_pools_by_asset_a( + std::string asset_symbol_or_id, + optional limit = 101, + optional start_id = optional() )const; + + /** + * @brief Get a list of liquidity pools by the symbol or ID of the second asset in the pool + * @param asset_symbol_or_id symbol name or ID of the asset + * @param limit The limitation of items each query can fetch, not greater than a configured value + * @param start_id Start liquidity pool id, fetch pools whose IDs are greater than or equal to this ID + * @return The liquidity pools + * + * @note + * 1. if @p asset_symbol_or_id cannot be tied to an asset, an error will be returned + * 2. @p limit can be omitted or be null, if so the default value 101 will be used + * 3. @p start_id can be omitted or be null, if so the api will return the "first page" of pools + * 4. can only omit one or more arguments in the end of the list, but not one or more in the middle + */ + vector get_liquidity_pools_by_asset_b( + std::string asset_symbol_or_id, + optional limit = 101, + optional start_id = optional() )const; + + /** + * @brief Get a list of liquidity pools by the symbols or IDs of the two assets in the pool + * @param asset_symbol_or_id_a symbol name or ID of one asset + * @param asset_symbol_or_id_b symbol name or ID of the other asset + * @param limit The limitation of items each query can fetch, not greater than a configured value + * @param start_id Start liquidity pool id, fetch pools whose IDs are greater than or equal to this ID + * @return The liquidity pools + * + * @note + * 1. if @p asset_symbol_or_id_a or @p asset_symbol_or_id_b cannot be tied to an asset, + * an error will be returned + * 2. @p limit can be omitted or be null, if so the default value 101 will be used + * 3. @p start_id can be omitted or be null, if so the api will return the "first page" of pools + * 4. can only omit one or more arguments in the end of the list, but not one or more in the middle + */ + vector get_liquidity_pools_by_both_assets( + std::string asset_symbol_or_id_a, + std::string asset_symbol_or_id_b, + optional limit = 101, + optional start_id = optional() )const; + + /** + * @brief Get a list of liquidity pools by their share asset symbols or IDs + * @param asset_symbols_or_ids symbol names or IDs of the share assets + * @param subscribe @a true to subscribe to the queried objects; @a false to not subscribe; + * @a null to subscribe or not subscribe according to current auto-subscription setting + * (see @ref set_auto_subscription) + * @return The liquidity pools that the assets are for + * + * @note if an asset in the list can not be found or is not a share asset of any liquidity pool, + * the corresponding data in the returned list is null. + */ + vector> get_liquidity_pools_by_share_asset( + const vector& asset_symbols_or_ids, + optional subscribe = optional() )const; /////////////// // Witnesses // @@ -996,6 +1073,12 @@ FC_API(graphene::app::database_api, (get_trade_history) (get_trade_history_by_sequence) + // Liquidity pools + (get_liquidity_pools_by_asset_a) + (get_liquidity_pools_by_asset_b) + (get_liquidity_pools_by_both_assets) + (get_liquidity_pools_by_share_asset) + // Witnesses (get_witnesses) (get_witness_by_account) diff --git a/libraries/chain/include/graphene/chain/liquidity_pool_object.hpp b/libraries/chain/include/graphene/chain/liquidity_pool_object.hpp index a5b61e5cd7..82a4b72943 100644 --- a/libraries/chain/include/graphene/chain/liquidity_pool_object.hpp +++ b/libraries/chain/include/graphene/chain/liquidity_pool_object.hpp @@ -65,6 +65,7 @@ class liquidity_pool_object : public abstract_object struct by_share_asset; struct by_asset_a; struct by_asset_b; +struct by_asset_ab; /** * @ingroup object_index @@ -78,14 +79,19 @@ typedef multi_index_container< ordered_unique< tag, composite_key< liquidity_pool_object, member< liquidity_pool_object, asset_id_type, &liquidity_pool_object::asset_a >, - member< liquidity_pool_object, asset_id_type, &liquidity_pool_object::asset_b >, member< object, object_id_type, &object::id> > >, ordered_unique< tag, composite_key< liquidity_pool_object, member< liquidity_pool_object, asset_id_type, &liquidity_pool_object::asset_b >, + member< object, object_id_type, &object::id> + > + >, + ordered_unique< tag, + composite_key< liquidity_pool_object, member< liquidity_pool_object, asset_id_type, &liquidity_pool_object::asset_a >, + member< liquidity_pool_object, asset_id_type, &liquidity_pool_object::asset_b >, member< object, object_id_type, &object::id> > >