diff --git a/itest/assets_test.go b/itest/assets_test.go index e6edeb366..40e4f5c7c 100644 --- a/itest/assets_test.go +++ b/itest/assets_test.go @@ -1423,13 +1423,15 @@ func sendAssetKeySendPayment(t *testing.T, src, dst *HarnessNode, amt uint64, return } - result, _, err := getAssetPaymentResult(t, stream, false) + tapPayment, err := getAssetPaymentResult(t, stream, false) require.NoError(t, err) - if result.Status == lnrpc.Payment_FAILED { - t.Logf("Failure reason: %v", result.FailureReason) + + payment := tapPayment.lndPayment + if payment.Status == lnrpc.Payment_FAILED { + t.Logf("Failure reason: %v", payment.FailureReason) } - require.Equal(t, cfg.payStatus, result.Status) - require.Equal(t, cfg.failureReason, result.FailureReason) + require.Equal(t, cfg.payStatus, payment.Status) + require.Equal(t, cfg.failureReason, payment.FailureReason) } func sendKeySendPayment(t *testing.T, src, dst *HarnessNode, @@ -1755,12 +1757,13 @@ func payInvoiceWithAssets(t *testing.T, payer, rfqPeer *HarnessNode, sendReq.MaxShardSizeMsat = 80_000_000 } - var rfqBytes, peerPubKey []byte + var rfqBytes []byte cfg.rfq.WhenSome(func(i rfqmsg.ID) { rfqBytes = make([]byte, len(i[:])) copy(rfqBytes, i[:]) }) + var peerPubKey []byte if rfqPeer != nil { peerPubKey = rfqPeer.PubKey[:] } @@ -1785,7 +1788,7 @@ func payInvoiceWithAssets(t *testing.T, payer, rfqPeer *HarnessNode, // If an error is returned by the RPC method (meaning the stream itself // was established, no network or auth error), we expect the error to be - // returned on the first read on the stream. + // returned on the stream. if cfg.errSubStr != "" { msg, err := stream.Recv() @@ -1804,14 +1807,18 @@ func payInvoiceWithAssets(t *testing.T, payer, rfqPeer *HarnessNode, rateVal rfqmath.FixedPoint[rfqmath.BigInt] ) - result, rateVal, err := getAssetPaymentResult( + tapPayment, err := getAssetPaymentResult( t, stream, cfg.payStatus == lnrpc.Payment_IN_FLIGHT, ) require.NoError(t, err) - require.Equal(t, cfg.payStatus, result.Status) - require.Equal(t, cfg.failureReason, result.FailureReason) + + payment := tapPayment.lndPayment + require.Equal(t, cfg.payStatus, payment.Status) + require.Equal(t, cfg.failureReason, payment.FailureReason) amountMsat := lnwire.MilliSatoshi(decodedInvoice.NumMsat) + + rateVal = tapPayment.assetRate milliSatsFP := rfqmath.MilliSatoshiToUnits(amountMsat, rateVal) numUnits = milliSatsFP.ScaleTo(0).ToUint64() diff --git a/itest/litd_accounts_test.go b/itest/litd_accounts_test.go index 47e02a36d..3f097465d 100644 --- a/itest/litd_accounts_test.go +++ b/itest/litd_accounts_test.go @@ -445,10 +445,21 @@ func getPaymentResult(stream routerrpc.Router_SendPaymentV2Client, } } +// TapPayment encapsulates all the information related to the outcome of a tap +// asset payment. It contains the outcome of the LND payment and also the asset +// rate that was used to swap the assets to satoshis. +type TapPayment struct { + // lndPayment contains the lnd part of the payment result. + lndPayment *lnrpc.Payment + + // assetRate contains the asset rate that was used to convert the assets + // to sats. + assetRate rfqmath.FixedPoint[rfqmath.BigInt] +} + func getAssetPaymentResult(t *testing.T, s tapchannelrpc.TaprootAssetChannels_SendPaymentClient, - isHodl bool) (*lnrpc.Payment, rfqmath.FixedPoint[rfqmath.BigInt], - error) { + isHodl bool) (*TapPayment, error) { // No idea why it makes a difference whether we wait before calling // s.Recv() or not, but it does. Without the sleep, the test will fail @@ -461,7 +472,7 @@ func getAssetPaymentResult(t *testing.T, for { msg, err := s.Recv() if err != nil { - return nil, rateVal, err + return nil, err } // Ignore RFQ quote acceptance messages read from the send @@ -501,8 +512,13 @@ func getAssetPaymentResult(t *testing.T, payment := msg.GetPaymentResult() if payment == nil { - return nil, rateVal, - fmt.Errorf("unexpected message: %v", msg) + err := fmt.Errorf("unexpected message: %v", msg) + return nil, err + } + + result := &TapPayment{ + lndPayment: payment, + assetRate: rateVal, } // If this is a hodl payment, then we'll return the first @@ -510,10 +526,10 @@ func getAssetPaymentResult(t *testing.T, // clears to we can observe the other payment states. switch { case isHodl: - return payment, rateVal, nil + return result, nil case payment.Status != lnrpc.Payment_IN_FLIGHT: - return payment, rateVal, nil + return result, nil } } } diff --git a/itest/litd_custom_channels_test.go b/itest/litd_custom_channels_test.go index 6fa37cf46..cc16305be 100644 --- a/itest/litd_custom_channels_test.go +++ b/itest/litd_custom_channels_test.go @@ -2959,6 +2959,42 @@ func testCustomChannelsLiquidityEdgeCasesCore(ctx context.Context, payInvoiceWithSatoshi( t.t, dave, invoiceResp, withFeeLimit(100_000_000), ) + + logBalance(t.t, nodes, assetID, "after policy checks") + + resBuy, err := daveTap.RfqClient.AddAssetBuyOrder( + ctx, &rfqrpc.AddAssetBuyOrderRequest{ + AssetSpecifier: &assetSpecifier, + AssetMaxAmt: 1_000, + Expiry: uint64(inOneHour.Unix()), + PeerPubKey: charlie.PubKey[:], + TimeoutSeconds: 100, + }, + ) + require.NoError(t.t, err) + + scid := resBuy.GetAcceptedQuote().Scid + + invResp := createAssetInvoice( + t.t, charlie, dave, 1_000, assetID, + withInvGroupKey(groupID), withRouteHints([]*lnrpc.RouteHint{ + { + HopHints: []*lnrpc.HopHint{ + { + NodeId: charlie.PubKeyStr, + ChanId: scid, + }, + }, + }, + }), + ) + + payInvoiceWithAssets( + t.t, charlie, dave, invResp.PaymentRequest, assetID, + withGroupKey(groupID), + ) + + logBalance(t.t, nodes, assetID, "after invoice with route hints") } // testCustomChannelsLiquidityEdgeCases is a test that runs through some