Skip to content

Commit dd90147

Browse files
committed
litcli: update payinvoice for multirfq
With the introduction of multi-rfq send in taproot assets (see related PR lightninglabs/taproot-assets#1613) we extended the behavior of the SendPayment RPC slightly. Now we may not specify an RFQ peer in order for a list of peers to be created & used automatically. When that happens, we will return multiple quotes over the RPC. The content of this commit changes our client wrapper around the handling of the payment result. Previously we'd expect for exactly a single quote to be returned over the stream (for the single defined peer). Now we read all of the quotes that are returned in the new quotes array field of the RPC. To maintain backwards compatibility we also kept the previous single-quote RPC field, which we make sure to only read once now that we read both fields (avoid a duplicate quote from appearing in the logs).
1 parent a262573 commit dd90147

File tree

1 file changed

+47
-43
lines changed

1 file changed

+47
-43
lines changed

cmd/litcli/ln.go

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import (
55
"context"
66
"crypto/rand"
77
"encoding/hex"
8-
"errors"
98
"fmt"
109
"time"
1110

1211
"github.com/lightninglabs/taproot-assets/rfq"
1312
"github.com/lightninglabs/taproot-assets/rfqmath"
1413
"github.com/lightninglabs/taproot-assets/rpcutils"
1514
"github.com/lightninglabs/taproot-assets/taprpc"
15+
"github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
1616
tchrpc "github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc"
1717
"github.com/lightningnetwork/lnd/cmd/commands"
1818
"github.com/lightningnetwork/lnd/lnrpc"
@@ -236,48 +236,21 @@ type resultStreamWrapper struct {
236236
//
237237
// NOTE: This method is part of the PaymentResultStream interface.
238238
func (w *resultStreamWrapper) Recv() (*lnrpc.Payment, error) {
239-
resp, err := w.stream.Recv()
240-
if err != nil {
241-
return nil, err
242-
}
243-
244-
res := resp.Result
245-
switch r := res.(type) {
246-
// The very first response might be an accepted sell order, which we
247-
// just print out.
248-
case *tchrpc.SendPaymentResponse_AcceptedSellOrder:
249-
quote := r.AcceptedSellOrder
239+
// printQuote unmarshals and prints an accepted quote.
240+
printQuote := func(quote *rfqrpc.PeerAcceptedSellQuote) error {
250241
rpcRate := quote.BidAssetRate
251242
rate, err := rpcutils.UnmarshalRfqFixedPoint(rpcRate)
252243
if err != nil {
253-
return nil, fmt.Errorf("unable to unmarshal fixed "+
254-
"point: %w", err)
244+
return fmt.Errorf("unable to unmarshal fixed point: %w",
245+
err)
255246
}
256247

257248
amountMsat := lnwire.MilliSatoshi(w.amountMsat)
258249
milliSatsFP := rfqmath.MilliSatoshiToUnits(amountMsat, *rate)
259250
numUnits := milliSatsFP.ScaleTo(0).ToUint64()
260251

261-
// If the calculated number of units is 0 then the asset rate
262-
// was not sufficient to represent the value of this payment.
263252
if numUnits == 0 {
264-
// We will calculate the minimum amount that can be
265-
// effectively sent with this asset by calculating the
266-
// value of a single asset unit, based on the provided
267-
// asset rate.
268-
269-
// We create the single unit.
270-
unit := rfqmath.FixedPointFromUint64[rfqmath.BigInt](
271-
1, 0,
272-
)
273-
274-
// We derive the minimum amount.
275-
minAmt := rfqmath.UnitsToMilliSatoshi(unit, *rate)
276-
277-
// We return the error to the user.
278-
return nil, fmt.Errorf("smallest payment with asset "+
279-
"rate %v is %v, cannot send %v",
280-
rate.ToUint64(), minAmt, amountMsat)
253+
return nil
281254
}
282255

283256
msatPerUnit := uint64(w.amountMsat) / numUnits
@@ -286,24 +259,55 @@ func (w *resultStreamWrapper) Recv() (*lnrpc.Payment, error) {
286259
"peer %s with SCID %d\n", numUnits, msatPerUnit,
287260
quote.Peer, quote.Scid)
288261

289-
resp, err = w.stream.Recv()
262+
return nil
263+
}
264+
265+
// A boolean to indicate whether the first quote was printed via the
266+
// legacy single-rfq response field.
267+
legacyFirstPrint := false
268+
269+
for {
270+
resp, err := w.stream.Recv()
290271
if err != nil {
291272
return nil, err
292273
}
293274

294-
if resp == nil || resp.Result == nil ||
295-
resp.GetPaymentResult() == nil {
275+
res := resp.Result
296276

297-
return nil, errors.New("unexpected nil result")
298-
}
277+
switch r := res.(type) {
278+
case *tchrpc.SendPaymentResponse_AcceptedSellOrder:
279+
err := printQuote(r.AcceptedSellOrder)
280+
if err != nil {
281+
return nil, err
282+
}
299283

300-
return resp.GetPaymentResult(), nil
284+
legacyFirstPrint = true
301285

302-
case *tchrpc.SendPaymentResponse_PaymentResult:
303-
return r.PaymentResult, nil
286+
case *tchrpc.SendPaymentResponse_AcceptedSellOrders:
287+
quotes := r.AcceptedSellOrders.AcceptedSellOrders
304288

305-
default:
306-
return nil, fmt.Errorf("unexpected response type: %T", r)
289+
for _, quote := range quotes {
290+
// If the first item was returned via the legacy
291+
// field then skip printing it again here. This
292+
// skip only applies to the first element.
293+
if legacyFirstPrint {
294+
legacyFirstPrint = false
295+
continue
296+
}
297+
298+
err := printQuote(quote)
299+
if err != nil {
300+
return nil, err
301+
}
302+
}
303+
304+
case *tchrpc.SendPaymentResponse_PaymentResult:
305+
return r.PaymentResult, nil
306+
307+
default:
308+
return nil, fmt.Errorf("unexpected response type: %T",
309+
r)
310+
}
307311
}
308312
}
309313

0 commit comments

Comments
 (0)