diff --git a/cmd/loop/main.go b/cmd/loop/main.go index cc9e0ea4..9d1d4621 100644 --- a/cmd/loop/main.go +++ b/cmd/loop/main.go @@ -103,6 +103,13 @@ const ( // Amount: 50 USD assetAmtFmt = "%-36s %12d %s\n" + // rateFmt formats an exchange rate into a one line string, intended to + // prettify the terminal output. For Instance, + // fmt.Printf(f, "Exchange rate:", rate, "USD") + // prints out as, + // Exchange rate: 0.0002 USD/SAT + rateFmt = "%-36s %12.4f %s/SAT\n" + // blkFmt formats the number of blocks into a one line string, intended // to prettify the terminal output. For Instance, // fmt.Printf(f, "Conf target", target) diff --git a/cmd/loop/quote.go b/cmd/loop/quote.go index c5198efa..7e344d31 100644 --- a/cmd/loop/quote.go +++ b/cmd/loop/quote.go @@ -9,6 +9,9 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/lightninglabs/loop" "github.com/lightninglabs/loop/looprpc" + "github.com/lightninglabs/taproot-assets/rfqmath" + "github.com/lightninglabs/taproot-assets/taprpc/rfqrpc" + "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing/route" "github.com/urfave/cli" ) @@ -268,7 +271,19 @@ func printQuoteOutResp(req *looprpc.QuoteRequest, totalFee := resp.HtlcSweepFeeSat + resp.SwapFeeSat if resp.AssetRfqInfo != nil { + assetAmtSwap, err := getAssetAmt( + req.Amt, resp.AssetRfqInfo.SwapAssetRate, + ) + if err != nil { + fmt.Printf("Error converting asset amount: %v\n", err) + return + } + exchangeRate := float64(assetAmtSwap) / float64(req.Amt) fmt.Printf(assetAmtFmt, "Send off-chain:", + assetAmtSwap, resp.AssetRfqInfo.AssetName) + fmt.Printf(rateFmt, "Exchange rate:", + exchangeRate, resp.AssetRfqInfo.AssetName) + fmt.Printf(assetAmtFmt, "Limit Send off-chain:", resp.AssetRfqInfo.MaxSwapAssetAmt, resp.AssetRfqInfo.AssetName) } else { @@ -288,7 +303,17 @@ func printQuoteOutResp(req *looprpc.QuoteRequest, fmt.Printf(satAmtFmt, "Estimated total fee:", totalFee) fmt.Println() if resp.AssetRfqInfo != nil { + assetAmtPrepay, err := getAssetAmt( + resp.PrepayAmtSat, resp.AssetRfqInfo.PrepayAssetRate, + ) + if err != nil { + fmt.Printf("Error converting asset amount: %v\n", err) + return + } fmt.Printf(assetAmtFmt, "No show penalty (prepay):", + assetAmtPrepay, + resp.AssetRfqInfo.AssetName) + fmt.Printf(assetAmtFmt, "Limit no show penalty (prepay):", resp.AssetRfqInfo.MaxPrepayAssetAmt, resp.AssetRfqInfo.AssetName) } else { @@ -302,3 +327,33 @@ func printQuoteOutResp(req *looprpc.QuoteRequest, time.Unix(int64(req.SwapPublicationDeadline), 0), ) } + +// getAssetAmt returns the asset amount for the given amount in satoshis and +// the asset rate. +func getAssetAmt(amt int64, assetRate *looprpc.FixedPoint) ( + uint64, error) { + + askAssetRate, err := unmarshalFixedPoint(assetRate) + if err != nil { + return 0, err + } + + msatAmt := lnwire.MilliSatoshi((amt * 1000)) + + assetAmt := rfqmath.MilliSatoshiToUnits(msatAmt, *askAssetRate) + + return assetAmt.ToUint64(), nil +} + +// unmarshalFixedPoint converts an RPC FixedPoint to a BigIntFixedPoint. +func unmarshalFixedPoint(fp *looprpc.FixedPoint) (*rfqmath.BigIntFixedPoint, + error) { + + // convert the looprpc.FixedPoint to a rfqrpc.FixedPoint + rfqrpcFP := &rfqrpc.FixedPoint{ + Coefficient: fp.Coefficient, + Scale: fp.Scale, + } + + return rfqrpc.UnmarshalFixedPoint(rfqrpcFP) +}