@@ -28,6 +28,7 @@ import (
2828 "github.com/lightninglabs/taproot-assets/rfq"
2929 cmsg "github.com/lightninglabs/taproot-assets/tapchannelmsg"
3030 "github.com/lightninglabs/taproot-assets/tapdb"
31+ "github.com/lightninglabs/taproot-assets/tapfeatures"
3132 "github.com/lightninglabs/taproot-assets/tapfreighter"
3233 "github.com/lightninglabs/taproot-assets/tapgarden"
3334 "github.com/lightninglabs/taproot-assets/tappsbt"
@@ -41,6 +42,7 @@ import (
4142 "github.com/lightningnetwork/lnd/lnwallet/chainfee"
4243 "github.com/lightningnetwork/lnd/lnwire"
4344 "github.com/lightningnetwork/lnd/msgmux"
45+ "github.com/lightningnetwork/lnd/routing/route"
4446)
4547
4648const (
@@ -269,6 +271,11 @@ type FundingControllerCfg struct {
269271 // a proof should be ignored.
270272 IgnoreChecker lfn.Option [proof.IgnoreChecker ]
271273
274+ // AuxChanNegotiator is responsible for producing the extra tlv blob
275+ // that is encapsulated in the init and reestablish peer messages. This
276+ // helps us communicate custom feature bits with our peer.
277+ AuxChanNegotiator * tapfeatures.AuxChannelNegotiator
278+
272279 // ErrChan is used to report errors back to the main server.
273280 ErrChan chan <- error
274281}
@@ -419,6 +426,8 @@ type pendingAssetFunding struct {
419426
420427 initiator bool
421428
429+ stxo bool
430+
422431 amt uint64
423432
424433 pushAmt btcutil.Amount
@@ -462,14 +471,32 @@ func (p *pendingAssetFunding) assetOutputs() []*cmsg.AssetOutput {
462471}
463472
464473// addToFundingCommitment adds a new asset to the funding commitment.
465- func (p * pendingAssetFunding ) addToFundingCommitment (a * asset.Asset ) error {
474+ func (p * pendingAssetFunding ) addToFundingCommitment (a * asset.Asset ,
475+ stxo bool ) error {
476+
466477 newCommitment , err := commitment .FromAssets (
467478 fn .Ptr (commitment .TapCommitmentV2 ), a ,
468479 )
469480 if err != nil {
470481 return fmt .Errorf ("unable to create commitment: %w" , err )
471482 }
472483
484+ // If our peer supports STXO we go ahead and append the
485+ // appropriate alt leaves to the VOutput.
486+ if stxo {
487+ altLeaves , err := asset .CollectSTXO (a )
488+ if err != nil {
489+ return err
490+ }
491+
492+ err = newCommitment .MergeAltLeaves (altLeaves )
493+ if err != nil {
494+ return err
495+ }
496+
497+ p .stxo = stxo
498+ }
499+
473500 newCommitment , err = commitment .TrimSplitWitnesses (
474501 & newCommitment .Version , newCommitment ,
475502 )
@@ -524,7 +551,8 @@ func (p *pendingAssetFunding) addInputProofChunk(
524551func newCommitBlobAndLeaves (pendingFunding * pendingAssetFunding ,
525552 lndOpenChan lnwallet.AuxChanState , assetOpenChan * cmsg.OpenChannel ,
526553 keyRing lntypes.Dual [lnwallet.CommitmentKeyRing ],
527- whoseCommit lntypes.ChannelParty ) ([]byte , lnwallet.CommitAuxLeaves ,
554+ whoseCommit lntypes.ChannelParty ,
555+ stxo bool ) ([]byte , lnwallet.CommitAuxLeaves ,
528556 error ) {
529557
530558 chanAssets := assetOpenChan .FundedAssets .Val .Outputs
@@ -571,7 +599,7 @@ func newCommitBlobAndLeaves(pendingFunding *pendingAssetFunding,
571599 fakePrevState , lndOpenChan , assetOpenChan , whoseCommit ,
572600 localSatBalance , remoteSatBalance , fakeView ,
573601 pendingFunding .chainParams , keyRing .GetForParty (whoseCommit ),
574- false ,
602+ stxo ,
575603 )
576604 if err != nil {
577605 return nil , lnwallet.CommitAuxLeaves {}, err
@@ -614,12 +642,14 @@ func (p *pendingAssetFunding) toAuxFundingDesc(req *bindFundingReq,
614642 // This will be the information for the very first state (state 0).
615643 localCommitBlob , localAuxLeaves , err := newCommitBlobAndLeaves (
616644 p , req .openChan , openChanDesc , req .keyRing , lntypes .Local ,
645+ p .stxo ,
617646 )
618647 if err != nil {
619648 return nil , err
620649 }
621650 remoteCommitBlob , remoteAuxLeaves , err := newCommitBlobAndLeaves (
622651 p , req .openChan , openChanDesc , req .keyRing , lntypes .Remote ,
652+ p .stxo ,
623653 )
624654 if err != nil {
625655 return nil , err
@@ -1087,14 +1117,19 @@ func (f *FundingController) signAllVPackets(ctx context.Context,
10871117// complete, but unsigned PSBT packet that can be used to create out asset
10881118// channel.
10891119func (f * FundingController ) anchorVPackets (fundedPkt * tapsend.FundedPsbt ,
1090- allPackets []* tappsbt.VPacket ) ([]* proof.Proof , error ) {
1120+ allPackets []* tappsbt.VPacket , stxo bool ) ([]* proof.Proof , error ) {
10911121
10921122 log .Infof ("Anchoring funding vPackets to funding PSBT" )
10931123
1124+ var opts []tapsend.OutputCommitmentOption
1125+ if ! stxo {
1126+ opts = append (opts , tapsend .WithNoSTXOProofs ())
1127+ }
1128+
10941129 // Given the set of vPackets we've created, we'll now merge them all to
10951130 // create a map from output index to final tap commitment.
10961131 outputCommitments , err := tapsend .CreateOutputCommitments (
1097- allPackets , tapsend . WithNoSTXOProofs () ,
1132+ allPackets , opts ... ,
10981133 )
10991134 if err != nil {
11001135 return nil , fmt .Errorf ("unable to create new output " +
@@ -1123,11 +1158,16 @@ func (f *FundingController) anchorVPackets(fundedPkt *tapsend.FundedPsbt,
11231158 for idx := range allPackets {
11241159 vPkt := allPackets [idx ]
11251160
1161+ var opts []proof.GenOption
1162+ if ! stxo {
1163+ opts = append (opts , proof .WithNoSTXOProofs ())
1164+ }
1165+
11261166 for vOutIdx := range vPkt .Outputs {
11271167 proofSuffix , err := tapsend .CreateProofSuffix (
11281168 fundedPkt .Pkt .UnsignedTx , fundedPkt .Pkt .Outputs ,
11291169 vPkt , outputCommitments , vOutIdx , allPackets ,
1130- proof . WithNoSTXOProofs () ,
1170+ opts ... ,
11311171 )
11321172 if err != nil {
11331173 return nil , fmt .Errorf ("unable to create " +
@@ -1220,7 +1260,8 @@ func (f *FundingController) sendAssetFundingCreated(ctx context.Context,
12201260// ultimately broadcasting the funding transaction.
12211261func (f * FundingController ) completeChannelFunding (ctx context.Context ,
12221262 fundingState * pendingAssetFunding ,
1223- fundedVpkt * tapfreighter.FundedVPacket ) (* wire.OutPoint , error ) {
1263+ fundedVpkt * tapfreighter.FundedVPacket ,
1264+ stxoEnabled bool ) (* wire.OutPoint , error ) {
12241265
12251266 log .Debugf ("Finalizing funding vPackets and PSBT..." )
12261267
@@ -1331,7 +1372,7 @@ func (f *FundingController) completeChannelFunding(ctx context.Context,
13311372 // PSBT. This'll update all the pkScripts for our funding output and
13321373 // change.
13331374 fundingOutputProofs , err := f .anchorVPackets (
1334- finalFundedPsbt , signedPkts ,
1375+ finalFundedPsbt , signedPkts , stxoEnabled ,
13351376 )
13361377 if err != nil {
13371378 return nil , fmt .Errorf ("unable to anchor vPackets: %w" , err )
@@ -1546,11 +1587,17 @@ func (f *FundingController) processFundingMsg(ctx context.Context,
15461587 "proof: %w" , err )
15471588 }
15481589
1590+ features := f .cfg .AuxChanNegotiator .GetPeerFeatures (
1591+ route .Vertex (msg .PeerPub .SerializeCompressed ()),
1592+ )
1593+
1594+ supportSTXO := features .HasFeature (tapfeatures .STXOOptional )
1595+
15491596 // If we reached this point, then the asset output and all
15501597 // inputs are valid, so we'll store the funding asset
15511598 // commitment.
15521599 err = assetFunding .addToFundingCommitment (
1553- & assetProof .AssetOutput .Val ,
1600+ & assetProof .AssetOutput .Val , supportSTXO ,
15541601 )
15551602 if err != nil {
15561603 return tempPID , fmt .Errorf ("unable to create " +
@@ -1739,6 +1786,15 @@ func (f *FundingController) processFundingReq(fundingFlows fundingFlowIndex,
17391786 maxNumAssetIDs )
17401787 }
17411788
1789+ // Now let's see if we should be using STXOs for this channel funding.
1790+ features := f .cfg .AuxChanNegotiator .GetPeerFeatures (
1791+ route .Vertex (fundReq .PeerPub .SerializeCompressed ()),
1792+ )
1793+
1794+ supportSTXO := features .HasFeature (tapfeatures .STXOOptional )
1795+
1796+ fundingState .stxo = supportSTXO
1797+
17421798 // Now that we know the final funding asset root along with the splits,
17431799 // we can derive the tapscript root that'll be used alongside the
17441800 // internal key (which we'll only learn from lnd later as we finalize
@@ -1751,7 +1807,7 @@ func (f *FundingController) processFundingReq(fundingFlows fundingFlowIndex,
17511807 }
17521808
17531809 err = fundingState .addToFundingCommitment (
1754- fundingOut .Asset .Copy (),
1810+ fundingOut .Asset .Copy (), supportSTXO ,
17551811 )
17561812 if err != nil {
17571813 return fmt .Errorf ("unable to add asset to funding " +
@@ -1815,7 +1871,7 @@ func (f *FundingController) processFundingReq(fundingFlows fundingFlowIndex,
18151871 }
18161872
18171873 chanPoint , err := f .completeChannelFunding (
1818- fundReq .ctx , fundingState , fundingVpkt ,
1874+ fundReq .ctx , fundingState , fundingVpkt , supportSTXO ,
18191875 )
18201876 if err != nil {
18211877 // If anything went wrong during the funding process,
0 commit comments