mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
litcli: update payinvoice for multirfq
With the introduction of multi-rfq send in taproot assets (see related PR https://github.com/lightninglabs/taproot-assets/pull/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).
This commit is contained in:
parent
a2625731d0
commit
dd90147d63
1 changed files with 49 additions and 45 deletions
|
|
@ -5,7 +5,6 @@ import (
|
|||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
|
|
@ -13,6 +12,7 @@ import (
|
|||
"github.com/lightninglabs/taproot-assets/rfqmath"
|
||||
"github.com/lightninglabs/taproot-assets/rpcutils"
|
||||
"github.com/lightninglabs/taproot-assets/taprpc"
|
||||
"github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
|
||||
tchrpc "github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc"
|
||||
"github.com/lightningnetwork/lnd/cmd/commands"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
|
|
@ -236,48 +236,21 @@ type resultStreamWrapper struct {
|
|||
//
|
||||
// NOTE: This method is part of the PaymentResultStream interface.
|
||||
func (w *resultStreamWrapper) Recv() (*lnrpc.Payment, error) {
|
||||
resp, err := w.stream.Recv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := resp.Result
|
||||
switch r := res.(type) {
|
||||
// The very first response might be an accepted sell order, which we
|
||||
// just print out.
|
||||
case *tchrpc.SendPaymentResponse_AcceptedSellOrder:
|
||||
quote := r.AcceptedSellOrder
|
||||
// printQuote unmarshals and prints an accepted quote.
|
||||
printQuote := func(quote *rfqrpc.PeerAcceptedSellQuote) error {
|
||||
rpcRate := quote.BidAssetRate
|
||||
rate, err := rpcutils.UnmarshalRfqFixedPoint(rpcRate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal fixed "+
|
||||
"point: %w", err)
|
||||
return fmt.Errorf("unable to unmarshal fixed point: %w",
|
||||
err)
|
||||
}
|
||||
|
||||
amountMsat := lnwire.MilliSatoshi(w.amountMsat)
|
||||
milliSatsFP := rfqmath.MilliSatoshiToUnits(amountMsat, *rate)
|
||||
numUnits := milliSatsFP.ScaleTo(0).ToUint64()
|
||||
|
||||
// If the calculated number of units is 0 then the asset rate
|
||||
// was not sufficient to represent the value of this payment.
|
||||
if numUnits == 0 {
|
||||
// We will calculate the minimum amount that can be
|
||||
// effectively sent with this asset by calculating the
|
||||
// value of a single asset unit, based on the provided
|
||||
// asset rate.
|
||||
|
||||
// We create the single unit.
|
||||
unit := rfqmath.FixedPointFromUint64[rfqmath.BigInt](
|
||||
1, 0,
|
||||
)
|
||||
|
||||
// We derive the minimum amount.
|
||||
minAmt := rfqmath.UnitsToMilliSatoshi(unit, *rate)
|
||||
|
||||
// We return the error to the user.
|
||||
return nil, fmt.Errorf("smallest payment with asset "+
|
||||
"rate %v is %v, cannot send %v",
|
||||
rate.ToUint64(), minAmt, amountMsat)
|
||||
return nil
|
||||
}
|
||||
|
||||
msatPerUnit := uint64(w.amountMsat) / numUnits
|
||||
|
|
@ -286,24 +259,55 @@ func (w *resultStreamWrapper) Recv() (*lnrpc.Payment, error) {
|
|||
"peer %s with SCID %d\n", numUnits, msatPerUnit,
|
||||
quote.Peer, quote.Scid)
|
||||
|
||||
resp, err = w.stream.Recv()
|
||||
return nil
|
||||
}
|
||||
|
||||
// A boolean to indicate whether the first quote was printed via the
|
||||
// legacy single-rfq response field.
|
||||
legacyFirstPrint := false
|
||||
|
||||
for {
|
||||
resp, err := w.stream.Recv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp == nil || resp.Result == nil ||
|
||||
resp.GetPaymentResult() == nil {
|
||||
res := resp.Result
|
||||
|
||||
return nil, errors.New("unexpected nil result")
|
||||
switch r := res.(type) {
|
||||
case *tchrpc.SendPaymentResponse_AcceptedSellOrder:
|
||||
err := printQuote(r.AcceptedSellOrder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
legacyFirstPrint = true
|
||||
|
||||
case *tchrpc.SendPaymentResponse_AcceptedSellOrders:
|
||||
quotes := r.AcceptedSellOrders.AcceptedSellOrders
|
||||
|
||||
for _, quote := range quotes {
|
||||
// If the first item was returned via the legacy
|
||||
// field then skip printing it again here. This
|
||||
// skip only applies to the first element.
|
||||
if legacyFirstPrint {
|
||||
legacyFirstPrint = false
|
||||
continue
|
||||
}
|
||||
|
||||
err := printQuote(quote)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
case *tchrpc.SendPaymentResponse_PaymentResult:
|
||||
return r.PaymentResult, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected response type: %T",
|
||||
r)
|
||||
}
|
||||
|
||||
return resp.GetPaymentResult(), nil
|
||||
|
||||
case *tchrpc.SendPaymentResponse_PaymentResult:
|
||||
return r.PaymentResult, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected response type: %T", r)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue