diff --git a/rpcserver.go b/rpcserver.go index 140f9bb61..cb965e8ee 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -6989,6 +6989,65 @@ func (r *rpcServer) EncodeCustomRecords(_ context.Context, } } +// fetchSendRfqQuote fetches a sell quote from the RFQ manager to fulfill an +// invoice with the given set of params. +func (r *rpcServer) fetchSendRfqQuote(ctx context.Context, assetID asset.ID, + invoiceAmt lnwire.MilliSatoshi, peerPubKey *route.Vertex, + expiryTimestamp time.Time) (*rfqrpc.PeerAcceptedSellQuote, error) { + + // We can now query the asset channels we have. + assetChan, err := r.rfqChannel(ctx, assetID, peerPubKey) + if err != nil { + return nil, fmt.Errorf("error finding asset channel to "+ + "use: %w", err) + } + + // Even if the user didn't specify the peer public key before, we + // definitely know it now. So let's make sure it's always set. + peerPubKey = &assetChan.channelInfo.PubKeyBytes + + sendQuote, err := r.AddAssetSellOrder( + ctx, &rfqrpc.AddAssetSellOrderRequest{ + AssetSpecifier: &rfqrpc.AssetSpecifier{ + Id: &rfqrpc.AssetSpecifier_AssetId{ + AssetId: assetID[:], + }, + }, + PaymentMaxAmt: uint64(invoiceAmt), + Expiry: uint64(expiryTimestamp.Unix()), + PeerPubKey: peerPubKey[:], + TimeoutSeconds: uint32( + rfq.DefaultTimeout.Seconds(), + ), + }, + ) + if err != nil { + return nil, fmt.Errorf("error adding sell order: %w", err) + } + + var acceptedQuote *rfqrpc.PeerAcceptedSellQuote + switch r := sendQuote.Response.(type) { + case *rfqrpc.AddAssetSellOrderResponse_AcceptedQuote: + acceptedQuote = r.AcceptedQuote + + case *rfqrpc.AddAssetSellOrderResponse_InvalidQuote: + return nil, fmt.Errorf("peer %v sent back an invalid "+ + "quote, status: %v", r.InvalidQuote.Peer, + r.InvalidQuote.Status.String()) + + case *rfqrpc.AddAssetSellOrderResponse_RejectedQuote: + return nil, fmt.Errorf("peer %v rejected the quote, code: "+ + "%v, error message: %v", r.RejectedQuote.Peer, + r.RejectedQuote.ErrorCode, + r.RejectedQuote.ErrorMessage) + + default: + return nil, fmt.Errorf("unexpected response type: %T", r) + } + + return acceptedQuote, nil +} + // SendPayment is a wrapper around lnd's routerrpc.SendPaymentV2 RPC method // with asset specific parameters. It allows RPC users to send asset keysend // payments (direct payments) or payments to an invoice with a specified asset @@ -7113,18 +7172,6 @@ func (r *rpcServer) SendPayment(req *tchrpc.SendPaymentRequest, peerPubKey = &parsedKey } - // We can now query the asset channels we have. - assetChan, err := r.rfqChannel(ctx, assetID, peerPubKey) - if err != nil { - return fmt.Errorf("error finding asset channel to "+ - "use: %w", err) - } - - // Even if the user didn't specify the peer public key before, - // we definitely know it now. So let's make sure it's always - // set. - peerPubKey = &assetChan.channelInfo.PubKeyBytes - // paymentMaxAmt is the maximum amount that the counterparty is // expected to pay. This is the amount that the invoice is // asking for plus the fee limit in milli-satoshis. @@ -7157,43 +7204,12 @@ func (r *rpcServer) SendPayment(req *tchrpc.SendPaymentRequest, paymentMaxAmt += feeLimit expiryTimestamp := invoice.Timestamp.Add(invoice.Expiry()) - resp, err := r.AddAssetSellOrder( - ctx, &rfqrpc.AddAssetSellOrderRequest{ - AssetSpecifier: &rfqrpc.AssetSpecifier{ - Id: &rfqrpc.AssetSpecifier_AssetId{ - AssetId: assetID[:], - }, - }, - PaymentMaxAmt: uint64(paymentMaxAmt), - Expiry: uint64(expiryTimestamp.Unix()), - PeerPubKey: peerPubKey[:], - TimeoutSeconds: uint32( - rfq.DefaultTimeout.Seconds(), - ), - }, + acceptedQuote, err := r.fetchSendRfqQuote( + ctx, assetID, paymentMaxAmt, peerPubKey, + expiryTimestamp, ) if err != nil { - return fmt.Errorf("error adding sell order: %w", err) - } - - var acceptedQuote *rfqrpc.PeerAcceptedSellQuote - switch r := resp.Response.(type) { - case *rfqrpc.AddAssetSellOrderResponse_AcceptedQuote: - acceptedQuote = r.AcceptedQuote - - case *rfqrpc.AddAssetSellOrderResponse_InvalidQuote: - return fmt.Errorf("peer %v sent back an invalid "+ - "quote, status: %v", r.InvalidQuote.Peer, - r.InvalidQuote.Status.String()) - - case *rfqrpc.AddAssetSellOrderResponse_RejectedQuote: - return fmt.Errorf("peer %v rejected the quote, code: "+ - "%v, error message: %v", r.RejectedQuote.Peer, - r.RejectedQuote.ErrorCode, - r.RejectedQuote.ErrorMessage) - - default: - return fmt.Errorf("unexpected response type: %T", r) + return fmt.Errorf("error sending RFQ quote: %w", err) } // Send out the information about the quote on the stream.