diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 89ab2b2785..8b09f0d3fe 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -80,7 +80,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "sendmany", 5 , "replaceable" }, { "sendmany", 6 , "conf_target" }, { "sendmany", 10, "fee_rate"}, - { "sendmany", 11, "verbose" }, + { "sendmany", 12, "verbose" }, { "deriveaddresses", 1, "range" }, { "scantxoutset", 1, "scanobjects" }, { "addmultisigaddress", 0, "nrequired" }, diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index 34f0d8305a..500979b609 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -305,6 +305,7 @@ RPCHelpMan sendmany() }, {"ignoreblindfail", RPCArg::Type::BOOL, RPCArg::Default{true}, "Return a transaction even when a blinding attempt fails due to number of blinded inputs/outputs."}, {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, + {"fee_asset", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"not set, fall back to asset being sent"}, "label or hex ID of asset used for fees"}, {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra information about the transaction."}, }, { @@ -377,7 +378,18 @@ RPCHelpMan sendmany() std::vector recipients; ParseRecipients(sendTo, assets, subtractFeeFromAmount, recipients); - bool verbose = request.params[11].isNull() ? false : request.params[11].get_bool(); + if (g_con_any_asset_fees && !recipients.empty()) { + CAsset feeAsset = recipients[0].asset; + if (request.params.size() > 11) { + std::string strFeeAsset = request.params[11].get_str(); + feeAsset = GetAssetFromString(strFeeAsset); + if (feeAsset.IsNull()) { + throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Unknown label and invalid asset hex for fee: %s", feeAsset.GetHex())); + } + } + coin_control.m_fee_asset = feeAsset; + } + bool verbose = request.params[12].isNull() ? false : request.params[12].get_bool(); return SendMoney(*pwallet, coin_control, recipients, std::move(mapValue), verbose, ignore_blind_fail); }, diff --git a/test/functional/feature_any_asset_fee.py b/test/functional/feature_any_asset_fee.py index 82d2ba452b..33ae8f1e85 100755 --- a/test/functional/feature_any_asset_fee.py +++ b/test/functional/feature_any_asset_fee.py @@ -18,7 +18,7 @@ def set_test_params(self): self.num_nodes = 2 self.extra_args = [[ "-blindedaddresses=1", - "-initialfreecoins=1000000000", + "-initialfreecoins=10000000000", "-con_blocksubsidy=0", "-con_connect_genesis_outputs=1", "-con_any_asset_fees=1", @@ -106,7 +106,7 @@ def transfer_asset_to_node1(self): assert_equal(node1_new_balance["trusted"][self.asset], Decimal('2') - Decimal('1') - Decimal('0.00049820')) assert_equal(node1_new_balance["immature"][self.asset], Decimal('0.00049820')) - def multiple_asset_fees_transfers(self): + def multiple_asset_fees_transfers_with_sendtoaddress(self): node0_balance = self.nodes[0].getbalances()["mine"] node1_balance = self.nodes[1].getbalances()["mine"] assert len(node0_balance["trusted"]) == 3 @@ -148,6 +148,36 @@ def multiple_asset_fees_transfers(self): assert_equal(node1_new_balance["trusted"]["gasset"], Decimal('7')) assert_equal(node1_new_balance["trusted"][self.asset], node1_balance["trusted"][self.asset] + Decimal('3')) + def multiple_asset_fees_transfers_with_sendmany(self): + node0_balance = self.nodes[0].getbalances()["mine"]["trusted"] + node1_balance = self.nodes[1].getbalances()["mine"]["trusted"] + assert len(node0_balance) == 3 + assert len(node1_balance) == 2 + + tx1_id = self.nodes[0].sendmany( + amounts={ self.node1_address: 1.0 }, + output_assets={ self.node1_address: self.asset }, + fee_asset=self.asset) + tx1 = self.nodes[0].gettransaction(tx1_id) + + tx2_id = self.nodes[0].sendmany( + amounts={ self.node1_address: 2.0 }, + output_assets={ self.node1_address: self.asset }, + fee_asset='gasset') + tx2 = self.nodes[0].gettransaction(tx2_id) + + self.generatetoaddress(self.nodes[0], 1, self.node0_address) + self.sync_all() + + node0_new_balance = self.nodes[0].getbalances()['mine']['trusted'] + assert_equal(node0_new_balance[self.asset], node0_balance[self.asset] - Decimal('3') + tx1['fee'][self.asset]) + assert_equal(node0_new_balance['gasset'], node0_balance['gasset'] + tx2['fee']['gasset']) + + node1_new_balance = self.nodes[1].getbalances()['mine']['trusted'] + assert len(node1_new_balance) == 2 + assert_equal(node1_new_balance['gasset'], Decimal('7')) + assert_equal(node1_new_balance[self.asset], node1_balance[self.asset] + Decimal('3')) + def transfer_asset_amount_including_fee(self): node1_balance = self.nodes[1].getbalances()["mine"] assert len(node1_balance["trusted"]) == 2 @@ -194,7 +224,9 @@ def run_test(self): self.transfer_asset_to_node1() - self.multiple_asset_fees_transfers() + self.multiple_asset_fees_transfers_with_sendtoaddress() + + self.multiple_asset_fees_transfers_with_sendmany() self.transfer_asset_amount_including_fee()