@@ -53,6 +53,7 @@ funds can be swept after the force-close transaction was confirmed.
5353Supported remote force-closed channel types are:
5454 - STATIC_REMOTE_KEY (a.k.a. tweakless channels)
5555 - ANCHOR (a.k.a. anchor output channels)
56+ - SIMPLE_TAPROOT (a.k.a. simple taproot channels)
5657` ,
5758 Example : `chantools sweepremoteclosed \
5859 --recoverywindow 300 \
@@ -113,12 +114,13 @@ func (c *sweepRemoteClosedCommand) Execute(_ *cobra.Command, _ []string) error {
113114}
114115
115116type targetAddr struct {
116- addr btcutil.Address
117- pubKey * btcec.PublicKey
118- path string
119- keyDesc * keychain.KeyDescriptor
120- vouts []* btc.Vout
121- script []byte
117+ addr btcutil.Address
118+ pubKey * btcec.PublicKey
119+ path string
120+ keyDesc * keychain.KeyDescriptor
121+ vouts []* btc.Vout
122+ script []byte
123+ scriptTree * input.CommitScriptTree
122124}
123125
124126func sweepRemoteClosed (extendedKey * hdkeychain.ExtendedKey , apiURL ,
@@ -196,18 +198,6 @@ func sweepRemoteClosed(extendedKey *hdkeychain.ExtendedKey, apiURL,
196198 err )
197199 }
198200
199- sequence := wire .MaxTxInSequenceNum
200- switch target .addr .(type ) {
201- case * btcutil.AddressWitnessPubKeyHash :
202- estimator .AddP2WKHInput ()
203-
204- case * btcutil.AddressWitnessScriptHash :
205- estimator .AddWitnessInput (
206- input .ToRemoteConfirmedWitnessSize ,
207- )
208- sequence = 1
209- }
210-
211201 prevOutPoint := wire.OutPoint {
212202 Hash : * txHash ,
213203 Index : uint32 (vout .Outspend .Vin ),
@@ -217,18 +207,76 @@ func sweepRemoteClosed(extendedKey *hdkeychain.ExtendedKey, apiURL,
217207 Value : int64 (vout .Value ),
218208 }
219209 prevOutFetcher .AddPrevOut (prevOutPoint , prevTxOut )
220- sweepTx . TxIn = append ( sweepTx . TxIn , & wire.TxIn {
210+ txIn := & wire.TxIn {
221211 PreviousOutPoint : prevOutPoint ,
222- Sequence : sequence ,
223- })
212+ Sequence : wire .MaxTxInSequenceNum ,
213+ }
214+ sweepTx .TxIn = append (sweepTx .TxIn , txIn )
215+ inputIndex := len (sweepTx .TxIn ) - 1
224216
225- signDescs = append (signDescs , & input.SignDescriptor {
226- KeyDesc : * target .keyDesc ,
227- WitnessScript : target .script ,
228- Output : prevTxOut ,
229- HashType : txscript .SigHashAll ,
230- PrevOutputFetcher : prevOutFetcher ,
231- })
217+ var signDesc * input.SignDescriptor
218+ switch target .addr .(type ) {
219+ case * btcutil.AddressWitnessPubKeyHash :
220+ estimator .AddP2WKHInput ()
221+
222+ signDesc = & input.SignDescriptor {
223+ KeyDesc : * target .keyDesc ,
224+ WitnessScript : target .script ,
225+ Output : prevTxOut ,
226+ HashType : txscript .SigHashAll ,
227+ PrevOutputFetcher : prevOutFetcher ,
228+ InputIndex : inputIndex ,
229+ }
230+
231+ case * btcutil.AddressWitnessScriptHash :
232+ estimator .AddWitnessInput (
233+ input .ToRemoteConfirmedWitnessSize ,
234+ )
235+ txIn .Sequence = 1
236+
237+ signDesc = & input.SignDescriptor {
238+ KeyDesc : * target .keyDesc ,
239+ WitnessScript : target .script ,
240+ Output : prevTxOut ,
241+ HashType : txscript .SigHashAll ,
242+ PrevOutputFetcher : prevOutFetcher ,
243+ InputIndex : inputIndex ,
244+ }
245+
246+ case * btcutil.AddressTaproot :
247+ estimator .AddWitnessInput (
248+ input .TaprootToRemoteWitnessSize ,
249+ )
250+ txIn .Sequence = 1
251+
252+ tree := target .scriptTree
253+ controlBlock , err := tree .CtrlBlockForPath (
254+ input .ScriptPathSuccess ,
255+ )
256+ if err != nil {
257+ return err
258+ }
259+ controlBlockBytes , err := controlBlock .ToBytes ()
260+ if err != nil {
261+ return err
262+ }
263+
264+ script := tree .SettleLeaf .Script
265+ signMethod := input .TaprootScriptSpendSignMethod
266+ signDesc = & input.SignDescriptor {
267+ KeyDesc : * target .keyDesc ,
268+ WitnessScript : script ,
269+ Output : prevTxOut ,
270+ HashType : txscript .SigHashDefault ,
271+ PrevOutputFetcher : prevOutFetcher ,
272+ ControlBlock : controlBlockBytes ,
273+ InputIndex : inputIndex ,
274+ SignMethod : signMethod ,
275+ TapTweak : tree .TapscriptRoot ,
276+ }
277+ }
278+
279+ signDescs = append (signDescs , signDesc )
232280 }
233281 }
234282
@@ -270,15 +318,29 @@ func sweepRemoteClosed(extendedKey *hdkeychain.ExtendedKey, apiURL,
270318 desc .SigHashes = sigHashes
271319 desc .InputIndex = idx
272320
273- if len (desc .WitnessScript ) > 0 {
321+ switch {
322+ // Simple Taproot Channels.
323+ case desc .SignMethod == input .TaprootScriptSpendSignMethod :
324+ witness , err := input .TaprootCommitSpendSuccess (
325+ signer , desc , sweepTx , nil ,
326+ )
327+ if err != nil {
328+ return err
329+ }
330+ sweepTx .TxIn [idx ].Witness = witness
331+
332+ // Anchor Channels.
333+ case len (desc .WitnessScript ) > 0 :
274334 witness , err := input .CommitSpendToRemoteConfirmed (
275335 signer , desc , sweepTx ,
276336 )
277337 if err != nil {
278338 return err
279339 }
280340 sweepTx .TxIn [idx ].Witness = witness
281- } else {
341+
342+ // Static Remote Key Channels.
343+ default :
282344 // The txscript library expects the witness script of a
283345 // P2WKH descriptor to be set to the pkScript of the
284346 // output...
@@ -320,7 +382,9 @@ func queryAddressBalances(pubKey *btcec.PublicKey, path string,
320382 error ) {
321383
322384 var targets []* targetAddr
323- queryAddr := func (address btcutil.Address , script []byte ) error {
385+ queryAddr := func (address btcutil.Address , script []byte ,
386+ scriptTree * input.CommitScriptTree ) error {
387+
324388 unspent , err := api .Unspent (address .EncodeAddress ())
325389 if err != nil {
326390 return fmt .Errorf ("could not query unspent: %w" , err )
@@ -330,12 +394,13 @@ func queryAddressBalances(pubKey *btcec.PublicKey, path string,
330394 log .Infof ("Found %d unspent outputs for address %v" ,
331395 len (unspent ), address .EncodeAddress ())
332396 targets = append (targets , & targetAddr {
333- addr : address ,
334- pubKey : pubKey ,
335- path : path ,
336- keyDesc : keyDesc ,
337- vouts : unspent ,
338- script : script ,
397+ addr : address ,
398+ pubKey : pubKey ,
399+ path : path ,
400+ keyDesc : keyDesc ,
401+ vouts : unspent ,
402+ script : script ,
403+ scriptTree : scriptTree ,
339404 })
340405 }
341406
@@ -346,15 +411,23 @@ func queryAddressBalances(pubKey *btcec.PublicKey, path string,
346411 if err != nil {
347412 return nil , err
348413 }
349- if err := queryAddr (p2wkh , nil ); err != nil {
414+ if err := queryAddr (p2wkh , nil , nil ); err != nil {
350415 return nil , err
351416 }
352417
353418 p2anchor , script , err := lnd .P2AnchorStaticRemote (pubKey , chainParams )
354419 if err != nil {
355420 return nil , err
356421 }
357- if err := queryAddr (p2anchor , script ); err != nil {
422+ if err := queryAddr (p2anchor , script , nil ); err != nil {
423+ return nil , err
424+ }
425+
426+ p2tr , scriptTree , err := lnd .P2TaprootStaticRemove (pubKey , chainParams )
427+ if err != nil {
428+ return nil , err
429+ }
430+ if err := queryAddr (p2tr , nil , scriptTree ); err != nil {
358431 return nil , err
359432 }
360433
0 commit comments