@@ -1541,8 +1541,9 @@ func (a *AuxSweeper) resolveContract(
15411541 }
15421542
15431543 var (
1544- sweepDesc lfn.Result [tapscriptSweepDescs ]
1545- assetOutputs []* cmsg.AssetOutput
1544+ sweepDesc lfn.Result [tapscriptSweepDescs ]
1545+ assetOutputs []* cmsg.AssetOutput
1546+ needsSecondLevel bool
15461547 )
15471548
15481549 switch req .Type {
@@ -1645,6 +1646,8 @@ func (a *AuxSweeper) resolveContract(
16451646 // sweep desc.
16461647 sweepDesc = localHtlcTimeoutSweepDesc (req )
16471648
1649+ needsSecondLevel = true
1650+
16481651 // In this case, we've broadcast a commitment, with an incoming HTLC
16491652 // that we can sweep. We'll annotate the sweepDesc with the information
16501653 // needed to sweep both this output, as well as the second level
@@ -1659,6 +1662,8 @@ func (a *AuxSweeper) resolveContract(
16591662 // sweep desc.
16601663 sweepDesc = localHtlcSucessSweepDesc (req )
16611664
1665+ needsSecondLevel = true
1666+
16621667 default :
16631668 return lfn .Errf [returnType ]("unknown resolution type: %v" ,
16641669 req .Type )
@@ -1674,35 +1679,94 @@ func (a *AuxSweeper) resolveContract(
16741679 log .Infof ("Sweeping %v asset outputs: %v" , len (assetOutputs ),
16751680 limitSpewer .Sdump (assetOutputs ))
16761681
1677- firstLevelSweepDesc := lfn .AndThen (
1678- sweepDesc ,
1679- func (sweepDesc tapscriptSweepDescs ) lfn.Result [tapscriptSweepDesc ] { //nolint:lll
1680- return lfn .Ok (sweepDesc .firstLevel )
1681- },
1682- )
1682+ tapSweepDesc , err := sweepDesc .Unpack ()
1683+ if err != nil {
1684+ return lfn.Err [tlv.Blob ](err )
1685+ }
1686+
1687+ // With the sweep desc constructed above, we'll create vPackets for each
1688+ // of the local assets, then sign them all.
1689+ firstLevelPkts , err := a .createAndSignSweepVpackets (
1690+ assetOutputs , req , lfn .Ok (tapSweepDesc .firstLevel ),
1691+ ).Unpack ()
1692+ if err != nil {
1693+ return lfn.Err [tlv.Blob ](err )
1694+ }
16831695
1684- // With the sweep desc constructed above, we'll create vPackets for
1685- // each of the local assets, then sign them all.
1686- sPkts := a .createAndSignSweepVpackets (
1687- assetOutputs , req , firstLevelSweepDesc ,
1696+ var (
1697+ secondLevelPkts []* tappsbt.VPacket
1698+ secondLevelSigDesc lfn.Option [cmsg.TapscriptSigDesc ]
16881699 )
16891700
1690- // With the vPackets fully generated and signed above, we'll serialize
1691- // it into a resolution blob to return.
1692- return lfn .AndThen (
1693- sPkts , func (vPkts []* tappsbt.VPacket ) lfn.Result [tlv.Blob ] {
1694- res := cmsg .NewContractResolution (
1695- vPkts , nil , lfn .None [cmsg.TapscriptSigDesc ](),
1696- )
1701+ // We'll only need a set of second level packets if we're sweeping a set
1702+ // of HTLC outputs on the local party's commitment transaction.
1703+ if needsSecondLevel {
1704+ log .Infof ("Creating+signing 2nd level vPkts" )
1705+
1706+ // We'll make a place holder for the second level output based
1707+ // on the assetID+value tuple.
1708+ secondLevelInputs := []* cmsg.AssetOutput {cmsg .NewAssetOutput (
1709+ assetOutputs [0 ].AssetID .Val ,
1710+ assetOutputs [0 ].Amount .Val , assetOutputs [0 ].Proof .Val ,
1711+ )}
1712+
1713+ // Unlike the first level packets, we can't yet sign the second
1714+ // level packets yet, as we don't know what the sweeping
1715+ // transaction will look like. So we'll just create them.
1716+ secondLevelPkts , err = lfn .MapOption (
1717+ //nolint:lll
1718+ func (desc tapscriptSweepDesc ) lfn.Result [[]* tappsbt.VPacket ] {
1719+ return a .createSweepVpackets (
1720+ secondLevelInputs , lfn .Ok (desc ), req ,
1721+ )
1722+ },
1723+ )(tapSweepDesc .secondLevel ).UnwrapOr (
1724+ lfn.Ok [[]* tappsbt.VPacket ](nil ),
1725+ ).Unpack ()
1726+ if err != nil {
1727+ return lfn .Errf [tlv.Blob ]("unable to make " +
1728+ "second level pkts: %w" , err )
1729+ }
1730+
1731+ // We'll update some of the details of the 2nd level pkt based
1732+ // on the first lvl packet created above (as we don't yet have
1733+ // the full proof for the first lvl packet above).
1734+ for pktIdx , vPkt := range secondLevelPkts {
1735+ prevAsset := firstLevelPkts [pktIdx ].Outputs [0 ].Asset
1736+
1737+ for inputIdx , vIn := range vPkt .Inputs {
1738+ //nolint:lll
1739+ prevScriptKey := prevAsset .ScriptKey
1740+ vIn .PrevID .ScriptKey = asset .ToSerialized (
1741+ prevScriptKey .PubKey ,
1742+ )
16971743
1698- var b bytes.Buffer
1699- if err := res .Encode (& b ); err != nil {
1700- return lfn.Err [returnType ](err )
1744+ vPkt .SetInputAsset (inputIdx , prevAsset )
17011745 }
1746+ }
17021747
1703- return lfn .Ok (b .Bytes ())
1704- },
1748+ // With the vPackets fully generated and signed above, we'll
1749+ // serialize it into a resolution blob to return.
1750+ secondLevelSigDesc = lfn .MapOption (
1751+ func (d tapscriptSweepDesc ) cmsg.TapscriptSigDesc {
1752+ return cmsg .NewTapscriptSigDesc (
1753+ d .scriptTree .TapTweak (),
1754+ d .ctrlBlockBytes ,
1755+ )
1756+ },
1757+ )(tapSweepDesc .secondLevel )
1758+ }
1759+
1760+ res := cmsg .NewContractResolution (
1761+ firstLevelPkts , secondLevelPkts , secondLevelSigDesc ,
17051762 )
1763+
1764+ var b bytes.Buffer
1765+ if err := res .Encode (& b ); err != nil {
1766+ return lfn.Err [tlv.Blob ](err )
1767+ }
1768+
1769+ return lfn .Ok (b .Bytes ())
17061770}
17071771
17081772// preimageDesc is a helper struct that contains the preimage and the witness
0 commit comments