diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 89ba5e85..cf193ec5 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1567,6 +1567,28 @@ class wallet_api sidechain_type sidechain, bool broadcast = false); + /** Broadcast signed transaction for manually sidechain withdrawal + * @param son_name_or_id ID or name of the son account + * @param sidechain Sidechain type (bitcoin, HIVE, etc) + * @param peerplays_uid peerplays_uid + * @param transaction_id ID of transaction + * @param peerplays_from Sidechain address transaction from + * @param withdraw_sidechain Withdraw sidechain + * @param withdraw_address Withdraw address + * @param withdraw_currency Withdraw currency + * @param withdraw_amount Withdraw amount + * @returns the signed transaction. + */ + signed_transaction sidechain_withdrawal_transaction(const string &son_name_or_id, + const sidechain_type& sidechain, + const std::string &peerplays_uid, + const std::string &peerplays_transaction_id, + const chain::account_id_type &peerplays_from, + const sidechain_type& withdraw_sidechain, + const std::string &withdraw_address, + const std::string &withdraw_currency, + const string &withdraw_amount); + /** Retrieves all sidechain addresses owned by given account. * * @param account the name or id of the account who owns the address @@ -2723,6 +2745,7 @@ FC_API( graphene::wallet::wallet_api, (get_son_wallets) (add_sidechain_address) (delete_sidechain_address) + (sidechain_withdrawal_transaction) (get_sidechain_addresses_by_account) (get_sidechain_addresses_by_sidechain) (get_sidechain_address_by_account_and_sidechain) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 40c6f361..73915564 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2361,6 +2361,63 @@ public: } FC_CAPTURE_AND_RETHROW() } + signed_transaction sidechain_withdrawal_transaction(const string &son_name_or_id, + const sidechain_type& sidechain, + const std::string &peerplays_uid, + const std::string &peerplays_transaction_id, + const chain::account_id_type &peerplays_from, + const sidechain_type& withdraw_sidechain, + const std::string &withdraw_address, + const std::string &withdraw_currency, + const string &withdraw_amount) + { try{ + const global_property_object& gpo = get_global_properties(); + const auto dynamic_props = get_dynamic_global_properties(); + const auto son_obj = get_son(son_name_or_id); + + fc::optional peerplays_asset = get_asset(withdraw_currency); + FC_ASSERT(peerplays_asset, "Could not find asset matching ${asset}", ("asset", peerplays_asset)); + const auto asset_val = peerplays_asset->amount_from_string(withdraw_amount); + const auto asset_price = peerplays_asset->options.core_exchange_rate; + + price withdraw_currency_price = {}; + if ("BTC" == withdraw_currency) { + fc::optional a = get_asset( gpo.parameters.btc_asset()); + withdraw_currency_price = a->options.core_exchange_rate; + } else + if ("HBD" == withdraw_currency) { + fc::optional a = get_asset( gpo.parameters.hbd_asset()); + withdraw_currency_price = a->options.core_exchange_rate; + } else + if ("HIVE" == withdraw_currency) { + fc::optional a = get_asset( gpo.parameters.hive_asset()); + withdraw_currency_price = a->options.core_exchange_rate; + } else { + FC_THROW("withdraw_currency ${withdraw_currency}", ("withdraw_currency", withdraw_currency)); + } + + //! Create transaction + signed_transaction son_wallet_withdraw_create_transaction; + son_wallet_withdraw_create_operation op; + op.payer = son_obj.son_account; + op.son_id = son_obj.id; + op.timestamp = dynamic_props.time; + op.block_num = dynamic_props.head_block_number; + op.sidechain = sidechain; + op.peerplays_uid = peerplays_uid; + op.peerplays_transaction_id = peerplays_transaction_id; + op.peerplays_from = peerplays_from; + op.peerplays_asset = asset(asset_val.amount * asset_price.base.amount / asset_price.quote.amount); + op.withdraw_sidechain = withdraw_sidechain; + op.withdraw_address = withdraw_address; + op.withdraw_currency = withdraw_currency; + op.withdraw_amount = asset_val.amount; + + son_wallet_withdraw_create_transaction.operations.push_back(op); + + return sign_transaction(son_wallet_withdraw_create_transaction, true); + } FC_CAPTURE_AND_RETHROW( (withdraw_currency) ) } + signed_transaction create_witness(string owner_account, string url, bool broadcast /* = false */) @@ -5308,6 +5365,27 @@ signed_transaction wallet_api::delete_sidechain_address(string account, return my->delete_sidechain_address(account, sidechain, broadcast); } +signed_transaction wallet_api::sidechain_withdrawal_transaction(const string &son_name_or_id, + const sidechain_type& sidechain, + const std::string &peerplays_uid, + const std::string &peerplays_transaction_id, + const chain::account_id_type &peerplays_from, + const sidechain_type& withdraw_sidechain, + const std::string &withdraw_address, + const std::string &withdraw_currency, + const string &withdraw_amount) +{ + return my->sidechain_withdrawal_transaction(son_name_or_id, + sidechain, + peerplays_uid, + peerplays_transaction_id, + peerplays_from, + withdraw_sidechain, + withdraw_address, + withdraw_currency, + withdraw_amount); +} + vector> wallet_api::get_sidechain_addresses_by_account(string account) { account_id_type account_id = get_account_id(account); diff --git a/tests/cli/son.cpp b/tests/cli/son.cpp index 26cee70e..a6f1805b 100644 --- a/tests/cli/son.cpp +++ b/tests/cli/son.cpp @@ -849,6 +849,87 @@ BOOST_AUTO_TEST_CASE( sidechain_deposit_transaction_test ) BOOST_TEST_MESSAGE("SON sidechain_deposit_transaction_test cli wallet tests end"); } +BOOST_AUTO_TEST_CASE( sidechain_withdraw_transaction_test ) +{ + BOOST_TEST_MESSAGE("SON sidechain_withdraw_transaction_test cli wallet tests begin"); + son_test_helper sth(*this); + + std::string name("sonaccount1"); + + global_property_object gpo; + gpo = con.wallet_api_ptr->get_global_properties(); + unsigned int son_number = gpo.parameters.maximum_son_count(); + + flat_map sidechain_public_keys; + + // create son accounts + for(unsigned int i = 0; i < son_number + 1; i++) + { + sidechain_public_keys.clear(); + sidechain_public_keys[sidechain_type::bitcoin] = "bitcoin_address " + fc::to_pretty_string(i); + sidechain_public_keys[sidechain_type::hive] = "hive account " + fc::to_pretty_string(i); + sth.create_son("sonaccount" + fc::to_pretty_string(i), + "http://son" + fc::to_pretty_string(i), + sidechain_public_keys, + false); + } + BOOST_CHECK(generate_maintenance_block()); + + BOOST_TEST_MESSAGE("Voting for SONs"); + for(unsigned int i = 1; i < son_number + 1; i++) + { + con.wallet_api_ptr->transfer( + "nathan", "sonaccount" + fc::to_pretty_string(i), "1000", "1.3.0", "Here are some CORE tokens for your new account", true ); + con.wallet_api_ptr->create_vesting_balance("sonaccount" + fc::to_pretty_string(i), "500", "1.3.0", vesting_balance_type::gpos, true); + con.wallet_api_ptr->vote_for_son("sonaccount" + fc::to_pretty_string(i), name, true, true); + } + BOOST_CHECK(generate_maintenance_block()); + + son_object son_obj = con.wallet_api_ptr->get_son(name); + BOOST_CHECK(son_obj.status == son_status::active); + + // create son account + std::string account_name("peerplaystest"); + graphene::wallet::brain_key_info bki = con.wallet_api_ptr->suggest_brain_key(); + BOOST_CHECK(!bki.brain_priv_key.empty()); + signed_transaction create_tx = con.wallet_api_ptr->create_account_with_brain_key(bki.brain_priv_key, account_name, "nathan", "nathan", true); + + generate_block(); + + // Deposit + //BOOST_TEST_MESSAGE("Deposit"); + //signed_transaction deposit_tx = con.wallet_api_ptr->transfer("nathan", account_name, "5", "BTC", "", true); + //generate_block(); + + // Withdraw + BOOST_TEST_MESSAGE("Withdraw"); + signed_transaction withdraw_tx = con.wallet_api_ptr->transfer(account_name, "son-acount", "1", "BTC", "", true); + generate_block(); + BOOST_TEST_MESSAGE("Withdraw done"); + + graphene::chain::transaction_id_type trx_id_type = con.wallet_api_ptr->get_transaction_id(withdraw_tx); + std::string peerplays_transaction_id = trx_id_type.str(); + + std::string peerplays_transaction_id_str = "peerplays_transaction_id = " + peerplays_transaction_id; + BOOST_TEST_MESSAGE(peerplays_transaction_id_str); + + std::string peerplays_uid = "peerplays-" + peerplays_transaction_id + "0"; + graphene::chain::account_id_type peerplays_from = con.wallet_api_ptr->get_account(account_name).id; + std::string withdraw_address = "2MtTPtraZawsvNGc8eCdx98hXbi4gaYy8L6"; + + signed_transaction txs = con.wallet_api_ptr->sidechain_withdrawal_transaction(account_name, sidechain_type::peerplays, + peerplays_uid, + peerplays_transaction_id, + peerplays_from, + sidechain_type::bitcoin, + withdraw_address, + "BTC", + "1"); + + + BOOST_TEST_MESSAGE("SON sidechain_withdraw_transaction_test cli wallet tests end"); +} + BOOST_AUTO_TEST_SUITE_END()