Skip to content
10 changes: 10 additions & 0 deletions doc/release-notes-24118.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
New RPCs
--------

- The `sendall` RPC spends specific UTXOs to one or more recipients
without creating change. By default, the `sendall` RPC will spend
every UTXO in the wallet. `sendall` is useful to empty wallets or to
create a changeless payment from select UTXOs. When creating a payment
from a specific amount for which the recipient incurs the transaction
fee, continue to use the `subtractfeefromamount` option via the
`send`, `sendtoaddress`, or `sendmany` RPCs. (#24118)
4 changes: 4 additions & 0 deletions src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "send", 1, "conf_target" },
{ "send", 3, "fee_rate"},
{ "send", 4, "options" },
{ "sendall", 0, "recipients" },
{ "sendall", 1, "conf_target" },
{ "sendall", 3, "fee_rate"},
{ "sendall", 4, "options" },
{ "simulaterawtransaction", 0, "rawtxs" },
{ "simulaterawtransaction", 1, "options" },
{ "importprivkey", 2, "rescan" },
Expand Down
432 changes: 345 additions & 87 deletions src/wallet/rpc/spend.cpp

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/wallet/rpc/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,7 @@ RPCHelpMan sendmany();
RPCHelpMan settxfee();
RPCHelpMan fundrawtransaction();
RPCHelpMan send();
RPCHelpMan sendall();
RPCHelpMan walletprocesspsbt();
RPCHelpMan walletcreatefundedpsbt();
RPCHelpMan signrawtransactionwithwallet();
Expand Down Expand Up @@ -1229,6 +1230,7 @@ Span<const CRPCCommand> GetWalletRPCCommands()
{"wallet", &signmessage},
{"wallet", &signrawtransactionwithwallet},
{"wallet", &simulaterawtransaction},
{"wallet", &sendall},
{"wallet", &unloadwallet},
{"wallet", &upgradewallet},
{"wallet", &upgradetohd},
Expand Down
2 changes: 2 additions & 0 deletions test/functional/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,8 @@
'wallet_create_tx.py --legacy-wallet',
'wallet_send.py --legacy-wallet',
'wallet_send.py --descriptors',
'wallet_sendall.py --legacy-wallet',
'wallet_sendall.py --descriptors',
'wallet_create_tx.py --descriptors',
'p2p_fingerprint.py',
'rpc_external_queue.py',
Expand Down
10 changes: 2 additions & 8 deletions test/functional/wallet_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -628,15 +628,9 @@ def run_test(self):

# ==Check that wallet prefers to use coins that don't exceed mempool limits =====

# Get all non-zero utxos together
# Get all non-zero utxos together and split into two chains
chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()]
singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True)
self.generate(self.nodes[0], 1, sync_fun=self.no_op)
node0_balance = self.nodes[0].getbalance()
# Split into two chains
rawtx = self.nodes[0].createrawtransaction([{"txid": singletxid, "vout": 0}], {chain_addrs[0]: node0_balance // 2 - Decimal('0.01'), chain_addrs[1]: node0_balance // 2 - Decimal('0.01')})
signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx)
singletxid = self.nodes[0].sendrawtransaction(hexstring=signedtx["hex"], maxfeerate=0)
self.nodes[0].sendall(recipients=chain_addrs)
self.generate(self.nodes[0], 1, sync_fun=self.no_op)

# Make a long chain of unconfirmed payments without hitting mempool limit
Expand Down
4 changes: 2 additions & 2 deletions test/functional/wallet_fundrawtransaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ def test_many_inputs_fee(self):
self.log.info("Test fundrawtxn fee with many inputs")

# Empty node1, send some small coins from node0 to node1.
self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True)
self.nodes[1].sendall(recipients=[self.nodes[0].getnewaddress()])
self.generate(self.nodes[1], 1)

for _ in range(20):
Expand All @@ -629,7 +629,7 @@ def test_many_inputs_send(self):
self.log.info("Test fundrawtxn sign+send with many inputs")

# Again, empty node1, send some small coins from node0 to node1.
self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True)
self.nodes[1].sendall(recipients=[self.nodes[0].getnewaddress()])
self.generate(self.nodes[1], 1)

for _ in range(20):
Expand Down
2 changes: 1 addition & 1 deletion test/functional/wallet_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def run_test(self):
assert_equal(2, len(tx6["vout"]))

# Empty out node2's wallet
self.nodes[2].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=self.nodes[2].getbalance(), subtractfeefromamount=True)
self.nodes[2].sendall(recipients=[self.nodes[0].getnewaddress()])
self.sync_all()
self.generate(self.nodes[0], 1)

Expand Down
Loading
Loading