diff --git a/itest/assets_test.go b/itest/assets_test.go index e6edeb366..0a3e67089 100644 --- a/itest/assets_test.go +++ b/itest/assets_test.go @@ -1423,8 +1423,10 @@ func sendAssetKeySendPayment(t *testing.T, src, dst *HarnessNode, amt uint64, return } - result, _, err := getAssetPaymentResult(t, stream, false) - require.NoError(t, err) + tapResult := getAssetPaymentResult(t, stream, false) + require.NoError(t, tapResult.err) + + result := tapResult.lndResult if result.Status == lnrpc.Payment_FAILED { t.Logf("Failure reason: %v", result.FailureReason) } @@ -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( + tapResult := getAssetPaymentResult( t, stream, cfg.payStatus == lnrpc.Payment_IN_FLIGHT, ) - require.NoError(t, err) + require.NoError(t, tapResult.err) + + result := tapResult.lndResult require.Equal(t, cfg.payStatus, result.Status) require.Equal(t, cfg.failureReason, result.FailureReason) amountMsat := lnwire.MilliSatoshi(decodedInvoice.NumMsat) + + rateVal = tapResult.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..7324acfbb 100644 --- a/itest/litd_accounts_test.go +++ b/itest/litd_accounts_test.go @@ -445,10 +445,24 @@ func getPaymentResult(stream routerrpc.Router_SendPaymentV2Client, } } +// TapPaymentResult encapsulates all the information related to the outcome of +// a tap asset payment. It may also contain an error, in which case the rest of +// the values should be ignored, even if set. +type TapPaymentResult struct { + // lndResult contains the lnd part of the payment result. + lndResult *lnrpc.Payment + + // assetRate contains the asset rate that was used to convert the assets + // to sats. + assetRate rfqmath.FixedPoint[rfqmath.BigInt] + + // err contains the returned error from the payment. + err error +} + func getAssetPaymentResult(t *testing.T, s tapchannelrpc.TaprootAssetChannels_SendPaymentClient, - isHodl bool) (*lnrpc.Payment, rfqmath.FixedPoint[rfqmath.BigInt], - error) { + isHodl bool) TapPaymentResult { // 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 +475,11 @@ func getAssetPaymentResult(t *testing.T, for { msg, err := s.Recv() if err != nil { - return nil, rateVal, err + return TapPaymentResult{ + lndResult: nil, + assetRate: rateVal, + err: err, + } } // Ignore RFQ quote acceptance messages read from the send @@ -501,8 +519,18 @@ 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 TapPaymentResult{ + lndResult: nil, + assetRate: rateVal, + err: err, + } + } + + result := TapPaymentResult{ + lndResult: payment, + assetRate: rateVal, + err: nil, } // If this is a hodl payment, then we'll return the first @@ -510,10 +538,10 @@ func getAssetPaymentResult(t *testing.T, // clears to we can observe the other payment states. switch { case isHodl: - return payment, rateVal, nil + return result case payment.Status != lnrpc.Payment_IN_FLIGHT: - return payment, rateVal, nil + return result } } } 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