@@ -1067,7 +1067,8 @@ func allowCORS(handler http.Handler, origins []string) http.Handler {
10671067// address to a specified output value to be sent to that address.
10681068func (r * rpcServer ) sendCoinsOnChain (paymentMap map [string ]int64 ,
10691069 feeRate chainfee.SatPerKWeight , minConfs int32 , label string ,
1070- strategy wallet.CoinSelectionStrategy ) (* chainhash.Hash , error ) {
1070+ strategy wallet.CoinSelectionStrategy ,
1071+ selectedUtxos fn.Set [wire.OutPoint ]) (* chainhash.Hash , error ) {
10711072
10721073 outputs , err := addrPairsToOutputs (paymentMap , r .cfg .ActiveNetParams .Params )
10731074 if err != nil {
@@ -1077,7 +1078,7 @@ func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
10771078 // We first do a dry run, to sanity check we won't spend our wallet
10781079 // balance below the reserved amount.
10791080 authoredTx , err := r .server .cc .Wallet .CreateSimpleTx (
1080- nil , outputs , feeRate , minConfs , strategy , true ,
1081+ selectedUtxos , outputs , feeRate , minConfs , strategy , true ,
10811082 )
10821083 if err != nil {
10831084 return nil , err
@@ -1098,7 +1099,7 @@ func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
10981099 // If that checks out, we're fairly confident that creating sending to
10991100 // these outputs will keep the wallet balance above the reserve.
11001101 tx , err := r .server .cc .Wallet .SendOutputs (
1101- nil , outputs , feeRate , minConfs , label , strategy ,
1102+ selectedUtxos , outputs , feeRate , minConfs , label , strategy ,
11021103 )
11031104 if err != nil {
11041105 return nil , err
@@ -1290,9 +1291,9 @@ func (r *rpcServer) SendCoins(ctx context.Context,
12901291 }
12911292
12921293 rpcsLog .Infof ("[sendcoins] addr=%v, amt=%v, sat/kw=%v, min_confs=%v, " +
1293- "send_all=%v" ,
1294+ "send_all=%v, select_outpoints=%v " ,
12941295 in .Addr , btcutil .Amount (in .Amount ), int64 (feePerKw ), minConfs ,
1295- in .SendAll )
1296+ in .SendAll , len ( in . Outpoints ) )
12961297
12971298 // Decode the address receiving the coins, we need to check whether the
12981299 // address is valid for this network.
@@ -1337,6 +1338,22 @@ func (r *rpcServer) SendCoins(ctx context.Context,
13371338 wallet := r .server .cc .Wallet
13381339 maxFeeRate := r .cfg .Sweeper .MaxFeeRate .FeePerKWeight ()
13391340
1341+ var selectOutpoints fn.Set [wire.OutPoint ]
1342+ if len (in .Outpoints ) != 0 {
1343+ wireOutpoints , err := toWireOutpoints (in .Outpoints )
1344+ if err != nil {
1345+ return nil , fmt .Errorf ("can't create outpoints " +
1346+ "%w" , err )
1347+ }
1348+
1349+ if fn .HasDuplicates (wireOutpoints ) {
1350+ return nil , fmt .Errorf ("selected outpoints contain " +
1351+ "duplicate values" )
1352+ }
1353+
1354+ selectOutpoints = fn .NewSet (wireOutpoints ... )
1355+ }
1356+
13401357 // If the send all flag is active, then we'll attempt to sweep all the
13411358 // coins in the wallet in a single transaction (if possible),
13421359 // otherwise, we'll respect the amount, and attempt a regular 2-output
@@ -1363,7 +1380,7 @@ func (r *rpcServer) SendCoins(ctx context.Context,
13631380 sweepTxPkg , err := sweep .CraftSweepAllTx (
13641381 feePerKw , maxFeeRate , uint32 (bestHeight ), nil ,
13651382 targetAddr , wallet , wallet , wallet .WalletController ,
1366- r .server .cc .Signer , minConfs , nil ,
1383+ r .server .cc .Signer , minConfs , selectOutpoints ,
13671384 )
13681385 if err != nil {
13691386 return nil , err
@@ -1417,7 +1434,7 @@ func (r *rpcServer) SendCoins(ctx context.Context,
14171434 feePerKw , maxFeeRate , uint32 (bestHeight ),
14181435 outputs , targetAddr , wallet , wallet ,
14191436 wallet .WalletController ,
1420- r .server .cc .Signer , minConfs , nil ,
1437+ r .server .cc .Signer , minConfs , selectOutpoints ,
14211438 )
14221439 if err != nil {
14231440 return nil , err
@@ -1443,7 +1460,7 @@ func (r *rpcServer) SendCoins(ctx context.Context,
14431460 return nil , err
14441461 }
14451462
1446- rpcsLog .Debugf ("Sweeping all coins from wallet to addr=%v, " +
1463+ rpcsLog .Debugf ("Sweeping coins from wallet to addr=%v, " +
14471464 "with tx=%v" , in .Addr , spew .Sdump (sweepTxPkg .SweepTx ))
14481465
14491466 // As our sweep transaction was created, successfully, we'll
@@ -1468,8 +1485,8 @@ func (r *rpcServer) SendCoins(ctx context.Context,
14681485 paymentMap := map [string ]int64 {targetAddr .String (): in .Amount }
14691486 err := wallet .WithCoinSelectLock (func () error {
14701487 newTXID , err := r .sendCoinsOnChain (
1471- paymentMap , feePerKw , minConfs ,
1472- label , coinSelectionStrategy ,
1488+ paymentMap , feePerKw , minConfs , label ,
1489+ coinSelectionStrategy , selectOutpoints ,
14731490 )
14741491 if err != nil {
14751492 return err
@@ -1540,8 +1557,8 @@ func (r *rpcServer) SendMany(ctx context.Context,
15401557 wallet := r .server .cc .Wallet
15411558 err = wallet .WithCoinSelectLock (func () error {
15421559 sendManyTXID , err := r .sendCoinsOnChain (
1543- in .AddrToAmount , feePerKw , minConfs ,
1544- label , coinSelectionStrategy ,
1560+ in .AddrToAmount , feePerKw , minConfs , label ,
1561+ coinSelectionStrategy , nil ,
15451562 )
15461563 if err != nil {
15471564 return err
0 commit comments