@@ -838,6 +838,74 @@ func createAssetInvoice(t *testing.T, dstRfqPeer, dst *HarnessNode,
838838 return resp .InvoiceResult
839839}
840840
841+ type assetHodlInvoice struct {
842+ preimage lntypes.Preimage
843+ payReq string
844+ }
845+
846+ func createAssetHodlInvoice (t * testing.T , dstRfqPeer , dst * HarnessNode ,
847+ assetAmount uint64 , assetID []byte ) assetHodlInvoice {
848+
849+ ctxb := context .Background ()
850+ ctxt , cancel := context .WithTimeout (ctxb , defaultTimeout )
851+ defer cancel ()
852+
853+ timeoutSeconds := int64 (rfq .DefaultInvoiceExpiry .Seconds ())
854+
855+ t .Logf ("Asking peer %x for quote to buy assets to receive for " +
856+ "invoice over %d units; waiting up to %ds" ,
857+ dstRfqPeer .PubKey [:], assetAmount , timeoutSeconds )
858+
859+ dstTapd := newTapClient (t , dst )
860+
861+ // As this is a hodl invoice, we'll also need to create a preimage external
862+ // to lnd.
863+ var preimage lntypes.Preimage
864+ _ , err := rand .Read (preimage [:])
865+ require .NoError (t , err )
866+
867+ payHash := preimage .Hash ()
868+
869+ resp , err := dstTapd .AddInvoice (ctxt , & tchrpc.AddInvoiceRequest {
870+ AssetId : assetID ,
871+ AssetAmount : assetAmount ,
872+ PeerPubkey : dstRfqPeer .PubKey [:],
873+ InvoiceRequest : & lnrpc.Invoice {
874+ Memo : fmt .Sprintf ("this is an asset invoice over " +
875+ "%d units" , assetAmount ),
876+ Expiry : timeoutSeconds ,
877+ },
878+ HodlInvoice : & tchrpc.HodlInvoice {
879+ PaymentHash : payHash [:],
880+ },
881+ })
882+ require .NoError (t , err )
883+
884+ decodedInvoice , err := dst .DecodePayReq (ctxt , & lnrpc.PayReqString {
885+ PayReq : resp .InvoiceResult .PaymentRequest ,
886+ })
887+ require .NoError (t , err )
888+
889+ rpcRate := resp .AcceptedBuyQuote .AskAssetRate
890+ rate , err := rfqrpc .UnmarshalFixedPoint (rpcRate )
891+ require .NoError (t , err )
892+
893+ assetUnits := rfqmath .NewBigIntFixedPoint (assetAmount , 0 )
894+ numMSats := rfqmath .UnitsToMilliSatoshi (assetUnits , * rate )
895+ mSatPerUnit := float64 (decodedInvoice .NumMsat ) / float64 (assetAmount )
896+
897+ require .EqualValues (t , uint64 (numMSats ), uint64 (decodedInvoice .NumMsat ))
898+
899+ t .Logf ("Got quote for %d sats at %v msat/unit from peer %x with SCID " +
900+ "%d" , decodedInvoice .NumMsat , mSatPerUnit , dstRfqPeer .PubKey [:],
901+ resp .AcceptedBuyQuote .Scid )
902+
903+ return assetHodlInvoice {
904+ preimage : preimage ,
905+ payReq : resp .InvoiceResult .PaymentRequest ,
906+ }
907+ }
908+
841909func waitForSendEvent (t * testing.T ,
842910 sendEvents taprpc.TaprootAssets_SubscribeSendEventsClient ,
843911 expectedState tapfreighter.SendState ) {
@@ -1349,6 +1417,16 @@ func assertAssetBalance(t *testing.T, client *tapClient, assetID []byte,
13491417
13501418 t .Logf ("Failed to assert expected balance of %d, current " +
13511419 "assets: %v" , expectedBalance , toProtoJSON (t , r ))
1420+
1421+ utxos , err3 := client .ListUtxos (ctxb , & taprpc.ListUtxosRequest {})
1422+ require .NoError (t , err3 )
1423+
1424+ t .Logf ("Current UTXOs: %v" , toProtoJSON (t , utxos ))
1425+
1426+ t .Fatalf ("Failed to assert balance: %v" , err )
1427+ }
1428+ }
1429+
13521430// assertSpendableBalance differs from assertAssetBalance in that it asserts
13531431// that the entire balance is spendable. We consider something spendable if we
13541432// have a local script key for it.
0 commit comments