@@ -125,6 +125,9 @@ type sweep struct {
125125
126126 // presigned is set, if the sweep should be handled in presigned mode.
127127 presigned bool
128+
129+ // change is the optional change output of the sweep.
130+ change * wire.TxOut
128131}
129132
130133// batchState is the state of the batch.
@@ -1236,10 +1239,13 @@ func (b *batch) createPsbt(unsignedTx *wire.MsgTx, sweeps []sweep) ([]byte,
12361239}
12371240
12381241// constructUnsignedTx creates unsigned tx from the sweeps, paying to the addr.
1239- // It also returns absolute fee (from weight and clamped).
1242+ // It also returns absolute fee (from weight and clamped). The main output is
1243+ // the first output of the transaction, followed by an optional list of change
1244+ // outputs.
12401245func constructUnsignedTx (sweeps []sweep , address btcutil.Address ,
1241- currentHeight int32 , feeRate chainfee.SatPerKWeight ) (* wire.MsgTx ,
1242- lntypes.WeightUnit , btcutil.Amount , btcutil.Amount , error ) {
1246+ currentHeight int32 , feeRate chainfee.SatPerKWeight ) (
1247+ * wire.MsgTx , lntypes.WeightUnit , btcutil.Amount , btcutil.Amount ,
1248+ error ) {
12431249
12441250 // Sanity check, there should be at least 1 sweep in this batch.
12451251 if len (sweeps ) == 0 {
@@ -1252,6 +1258,13 @@ func constructUnsignedTx(sweeps []sweep, address btcutil.Address,
12521258 LockTime : uint32 (currentHeight ),
12531259 }
12541260
1261+ var changeOutputs []* wire.TxOut
1262+ for _ , sweep := range sweeps {
1263+ if sweep .change != nil {
1264+ changeOutputs = append (changeOutputs , sweep .change )
1265+ }
1266+ }
1267+
12551268 // Add transaction inputs and estimate its weight.
12561269 var weightEstimate input.TxWeightEstimator
12571270 for _ , sweep := range sweeps {
@@ -1297,6 +1310,11 @@ func constructUnsignedTx(sweeps []sweep, address btcutil.Address,
12971310 "failed: %w" , err )
12981311 }
12991312
1313+ // Add the optional change outputs to weight estimates.
1314+ for _ , _ = range changeOutputs {
1315+ weightEstimate .AddP2TROutput ()
1316+ }
1317+
13001318 // Keep track of the total amount this batch is sweeping back.
13011319 batchAmt := btcutil .Amount (0 )
13021320 for _ , sweep := range sweeps {
@@ -1318,11 +1336,50 @@ func constructUnsignedTx(sweeps []sweep, address btcutil.Address,
13181336 fee := clampBatchFee (feeForWeight , batchAmt )
13191337
13201338 // Add the batch transaction output, which excludes the fees paid to
1321- // miners.
1322- batchTx .AddTxOut (& wire.TxOut {
1323- PkScript : batchPkScript ,
1324- Value : int64 (batchAmt - fee ),
1325- })
1339+ // miners. Reduce the amount by the sum of change outputs, if any.
1340+ if len (changeOutputs ) == 0 {
1341+ batchTx .AddTxOut (& wire.TxOut {
1342+ PkScript : batchPkScript ,
1343+ Value : int64 (batchAmt - fee ),
1344+ })
1345+ } else {
1346+ // Reduce the batch output by the sum of change outputs.
1347+ var sumChange int64
1348+ for _ , change := range changeOutputs {
1349+ sumChange += change .Value
1350+ }
1351+ // Add the main output first.
1352+ batchTx .AddTxOut (& wire.TxOut {
1353+ PkScript : batchPkScript ,
1354+ Value : int64 (batchAmt - fee ) - sumChange ,
1355+ })
1356+ // Then add change outputs.
1357+ for _ , txOut := range changeOutputs {
1358+ batchTx .AddTxOut (& wire.TxOut {
1359+ PkScript : txOut .PkScript ,
1360+ Value : txOut .Value ,
1361+ })
1362+ }
1363+ }
1364+
1365+ // Check that for each swap, inputs exceed the change outputs.
1366+ swap2Inputs := make (map [lntypes.Hash ]btcutil.Amount )
1367+ swap2Change := make (map [lntypes.Hash ]btcutil.Amount )
1368+ for _ , sweep := range sweeps {
1369+ swap2Inputs [sweep .swapHash ] += sweep .value
1370+ if sweep .change != nil {
1371+ swap2Change [sweep .swapHash ] +=
1372+ btcutil .Amount (sweep .change .Value )
1373+ }
1374+ }
1375+
1376+ for swapHash , inputs := range swap2Inputs {
1377+ change := swap2Change [swapHash ]
1378+ if inputs <= change {
1379+ return nil , 0 , 0 , 0 , fmt .Errorf ("inputs %v <= change " +
1380+ "%v for swap %x" , inputs , change , swapHash [:6 ])
1381+ }
1382+ }
13261383
13271384 return batchTx , weight , feeForWeight , fee , nil
13281385}
@@ -1396,7 +1453,9 @@ func (b *batch) publishMixedBatch(ctx context.Context) (btcutil.Amount, error,
13961453 attempt )
13971454
13981455 // Construct unsigned batch transaction.
1399- var err error
1456+ var (
1457+ err error
1458+ )
14001459 tx , weight , feeForWeight , fee , err = constructUnsignedTx (
14011460 sweeps , address , b .currentHeight , b .rbfCache .FeeRate ,
14021461 )
0 commit comments