From efac97e060560db5b94b329e6ec0cfee084cc786 Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Tue, 1 Sep 2015 14:19:34 -0400 Subject: [PATCH] cli_wallet: Implement withdrawal for vesting balance objects #286 --- libraries/app/api.cpp | 15 ++++ libraries/app/include/graphene/app/api.hpp | 2 + .../graphene/chain/vesting_balance_object.hpp | 5 ++ libraries/chain/vesting_balance_object.cpp | 7 ++ .../wallet/include/graphene/wallet/wallet.hpp | 42 ++++++++++ libraries/wallet/wallet.cpp | 80 +++++++++++++++++++ 6 files changed, 151 insertions(+) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index dff9626d..871f20bc 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -1186,6 +1186,21 @@ namespace graphene { namespace app { return result; } FC_CAPTURE_AND_RETHROW( (objs) ) } + vector database_api::get_vesting_balances( account_id_type account_id )const + { + try + { + vector result; + auto vesting_range = _db.get_index_type().indices().get().equal_range(account_id); + std::for_each(vesting_range.first, vesting_range.second, + [&result](const vesting_balance_object& balance) { + result.emplace_back(balance); + }); + return result; + } + FC_CAPTURE_AND_RETHROW( (account_id) ); + } + vector database_api::get_balance_objects( const vector
& addrs )const { try { const auto& bal_idx = _db.get_index_type(); diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index 82c82cae..649eea3f 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -322,6 +322,7 @@ namespace graphene { namespace app { vector get_vested_balances( const vector& objs )const; + vector get_vesting_balances( account_id_type account_id )const; /** * This API will take a partially signed transaction and a set of public keys that the owner has the ability to sign for @@ -579,6 +580,7 @@ FC_API(graphene::app::database_api, (get_margin_positions) (get_balance_objects) (get_vested_balances) + (get_vesting_balances) (get_required_signatures) (get_potential_signatures) (verify_authority) diff --git a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp index 3386d021..ee14dc89 100644 --- a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp +++ b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp @@ -155,6 +155,11 @@ namespace graphene { namespace chain { */ void withdraw(const fc::time_point_sec& now, const asset& amount); bool is_withdraw_allowed(const fc::time_point_sec& now, const asset& amount)const; + + /** + * Get amount of allowed withdrawal. + */ + asset get_allowed_withdraw(const time_point_sec& now)const; }; /** * @ingroup object_index diff --git a/libraries/chain/vesting_balance_object.cpp b/libraries/chain/vesting_balance_object.cpp index d4f70d75..799863f1 100644 --- a/libraries/chain/vesting_balance_object.cpp +++ b/libraries/chain/vesting_balance_object.cpp @@ -182,6 +182,7 @@ VESTING_VISITOR(on_withdraw,); VESTING_VISITOR(is_deposit_allowed, const); VESTING_VISITOR(is_deposit_vested_allowed, const); VESTING_VISITOR(is_withdraw_allowed, const); +VESTING_VISITOR(get_allowed_withdraw, const); bool vesting_balance_object::is_deposit_allowed(const time_point_sec& now, const asset& amount)const { @@ -224,4 +225,10 @@ void vesting_balance_object::withdraw(const time_point_sec& now, const asset& am balance -= amount; } +asset vesting_balance_object::get_allowed_withdraw(const time_point_sec& now)const +{ + asset amount = asset(); + return policy.visit(get_allowed_withdraw_visitor(balance, now, amount)); +} + } } // graphene::chain diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 49cb5b71..e7f0b367 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -222,6 +222,22 @@ struct signed_block_with_info : public signed_block fc::ecc::public_key signing_key; }; +struct vesting_balance_object_with_info : public vesting_balance_object +{ + vesting_balance_object_with_info( const vesting_balance_object& vbo, fc::time_point_sec now ); + vesting_balance_object_with_info( const vesting_balance_object_with_info& vbo ) = default; + + /** + * How much is allowed to be withdrawn. + */ + asset allowed_withdraw; + + /** + * The time at which allowed_withdrawal was calculated. + */ + fc::time_point_sec allowed_withdraw_time; +}; + namespace detail { class wallet_api_impl; } @@ -1099,6 +1115,27 @@ class wallet_api string block_signing_key, bool broadcast = false); + /** + * Get information about a vesting balance object. + * + * @param account_name An account name, account ID, or vesting balance object ID. + */ + vector< vesting_balance_object_with_info > get_vesting_balances( string account_name ); + + /** + * Withdraw a vesting balance. + * + * @param witness_name The account name of the witness, also accepts account ID or vesting balance ID type. + * @param amount The amount to withdraw. + * @param asset_symbol The symbol of the asset to withdraw. + * @param broadcast true if you wish to broadcast the transaction + */ + signed_transaction withdraw_vesting( + string witness_name, + string amount, + string asset_symbol, + bool broadcast = false); + /** Vote for a given committee_member. * * An account can publish a list of all committee_memberes they approve of. This @@ -1327,6 +1364,9 @@ FC_REFLECT( graphene::wallet::approval_delta, FC_REFLECT_DERIVED( graphene::wallet::signed_block_with_info, (graphene::chain::signed_block), (block_id)(signing_key) ) +FC_REFLECT_DERIVED( graphene::wallet::vesting_balance_object_with_info, (graphene::chain::vesting_balance_object), + (allowed_withdraw)(allowed_withdraw_time) ) + FC_API( graphene::wallet::wallet_api, (help) (gethelp) @@ -1378,6 +1418,8 @@ FC_API( graphene::wallet::wallet_api, (list_committee_members) (create_witness) (update_witness) + (get_vesting_balances) + (withdraw_vesting) (vote_for_committee_member) (vote_for_witness) (set_voting_proxy) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 655685bc..10c4a72a 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1343,6 +1343,65 @@ public: return sign_transaction( tx, broadcast ); } FC_CAPTURE_AND_RETHROW( (witness_name)(url)(block_signing_key)(broadcast) ) } + vector< vesting_balance_object_with_info > get_vesting_balances( string account_name ) + { try { + fc::optional vbid = maybe_id( account_name ); + std::vector result; + fc::time_point_sec now = _remote_db->get_dynamic_global_properties().time; + + if( vbid ) + { + result.emplace_back( get_object(*vbid), now ); + return result; + } + + // try casting to avoid a round-trip if we were given an account ID + fc::optional acct_id = maybe_id( account_name ); + if( !acct_id ) + acct_id = get_account( account_name ).id; + + vector< vesting_balance_object > vbos = _remote_db->get_vesting_balances( *acct_id ); + if( vbos.size() == 0 ) + return result; + + for( const vesting_balance_object& vbo : vbos ) + result.emplace_back( vbo, now ); + + return result; + } FC_CAPTURE_AND_RETHROW( (account_name) ) + } + + signed_transaction withdraw_vesting( + string witness_name, + string amount, + string asset_symbol, + bool broadcast = false ) + { try { + asset_object asset_obj = get_asset( asset_symbol ); + fc::optional vbid = maybe_id(witness_name); + if( !vbid ) + { + witness_object wit = get_witness( witness_name ); + FC_ASSERT( wit.pay_vb ); + vbid = wit.pay_vb; + } + + vesting_balance_object vbo = get_object< vesting_balance_object >( *vbid ); + vesting_balance_withdraw_operation vesting_balance_withdraw_op; + + vesting_balance_withdraw_op.vesting_balance = *vbid; + vesting_balance_withdraw_op.owner = vbo.owner; + vesting_balance_withdraw_op.amount = asset_obj.amount_from_string(amount); + + signed_transaction tx; + tx.operations.push_back( vesting_balance_withdraw_op ); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees ); + tx.validate(); + + return sign_transaction( tx, broadcast ); + } FC_CAPTURE_AND_RETHROW( (witness_name)(amount) ) + } + signed_transaction vote_for_committee_member(string voting_account, string committee_member, bool approve, @@ -2580,6 +2639,20 @@ signed_transaction wallet_api::update_witness( return my->update_witness(witness_name, url, block_signing_key, broadcast); } +vector< vesting_balance_object_with_info > wallet_api::get_vesting_balances( string account_name ) +{ + return my->get_vesting_balances( account_name ); +} + +signed_transaction wallet_api::withdraw_vesting( + string witness_name, + string amount, + string asset_symbol, + bool broadcast /* = false */) +{ + return my->withdraw_vesting( witness_name, amount, asset_symbol, broadcast ); +} + signed_transaction wallet_api::vote_for_committee_member(string voting_account, string witness, bool approve, @@ -3430,6 +3503,13 @@ signed_block_with_info::signed_block_with_info( const signed_block& block ) signing_key = signee(); } +vesting_balance_object_with_info::vesting_balance_object_with_info( const vesting_balance_object& vbo, fc::time_point_sec now ) + : vesting_balance_object( vbo ) +{ + allowed_withdraw = get_allowed_withdraw( now ); + allowed_withdraw_time = now; +} + } } // graphene::wallet void fc::to_variant(const account_multi_index_type& accts, fc::variant& vo)