cmd: prettify loop quote in/out responses

pull/348/head
yyforyongyu 3 years ago
parent c4d46a24a0
commit 82401ff1ba
No known key found for this signature in database
GPG Key ID: 9BCD95C4FF296868

@ -4,7 +4,6 @@ import (
"context"
"fmt"
"github.com/btcsuite/btcutil"
"github.com/lightninglabs/loop"
"github.com/lightninglabs/loop/labels"
"github.com/lightninglabs/loop/looprpc"
@ -61,6 +60,7 @@ var (
confTargetFlag,
lastHopFlag,
labelFlag,
verboseFlag,
},
Action: loopIn,
}
@ -109,14 +109,12 @@ func loopIn(ctx *cli.Context) error {
return err
}
quote, err := client.GetLoopInQuote(
context.Background(),
&looprpc.QuoteRequest{
Amt: int64(amt),
ConfTarget: htlcConfTarget,
ExternalHtlc: external,
},
)
quoteReq := &looprpc.QuoteRequest{
Amt: int64(amt),
ConfTarget: htlcConfTarget,
ExternalHtlc: external,
}
quote, err := client.GetLoopInQuote(context.Background(), quoteReq)
if err != nil {
return err
}
@ -136,9 +134,7 @@ func loopIn(ctx *cli.Context) error {
}
limits := getInLimits(quote)
err = displayInLimits(
amt, btcutil.Amount(quote.HtlcPublishFeeSat), limits, external,
)
err = displayInDetails(quoteReq, quote, ctx.Bool("verbose"))
if err != nil {
return err
}

@ -74,6 +74,7 @@ var loopOutCommand = cli.Command{
"result in a lower swap fee.",
},
labelFlag,
verboseFlag,
},
Action: loopOut,
}
@ -175,8 +176,8 @@ func loopOut(ctx *cli.Context) error {
ctx.Int64("max_swap_routing_fee"),
)
}
err = displayOutLimits(
amt, btcutil.Amount(quote.HtlcSweepFeeSat), limits, warning,
err = displayOutDetails(
limits, warning, quoteReq, quote, ctx.Bool("verbose"),
)
if err != nil {
return err

@ -74,6 +74,27 @@ var (
Usage: "path to macaroon file",
Value: loopd.DefaultMacaroonPath,
}
verboseFlag = cli.BoolFlag{
Name: "verbose, v",
Usage: "show expanded details",
}
)
const (
// satAmtFmt formats a satoshi value into a one line string, intended to
// prettify the terminal output. For Instance,
// fmt.Printf(f, "Estimated on-chain fee:", fee)
// prints out as,
// Estimated on-chain fee: 7262 sat
satAmtFmt = "%-36s %12d 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)
// prints out as,
// Conf target: 9 block
blkFmt = "%-36s %12d block\n"
)
func printJSON(resp interface{}) {
@ -246,89 +267,56 @@ func getOutLimits(amt btcutil.Amount,
}
}
func displayInLimits(amt, minerFees btcutil.Amount, l *inLimits,
externalHtlc bool) error {
func displayInDetails(req *looprpc.QuoteRequest,
resp *looprpc.InQuoteResponse, verbose bool) error {
totalSuccessMax := l.maxMinerFee + l.maxSwapFee
if externalHtlc {
if req.ExternalHtlc {
fmt.Printf("On-chain fee for external loop in is not " +
"included.\nSufficient fees will need to be paid " +
"when constructing the transaction in the external " +
"wallet.\n\n")
}
fmt.Printf("Max swap fees for %d sat Loop %v: %d sat\n", amt, swap.TypeIn,
totalSuccessMax)
printQuoteInResp(req, resp, verbose)
fmt.Printf("CONTINUE SWAP? (y/n), expand fee detail (x): ")
fmt.Printf("\nCONTINUE SWAP? (y/n): ")
var answer string
fmt.Scanln(&answer)
switch answer {
case "y":
if answer == "y" {
return nil
case "x":
fmt.Println()
f := "%-36s %d sat\n"
if !externalHtlc {
fmt.Printf(f, "Estimated on-chain HTLC fee:",
minerFees)
}
fmt.Printf(f, "Max swap fee:", l.maxSwapFee)
fmt.Printf("CONTINUE SWAP? (y/n): ")
fmt.Scanln(&answer)
if answer == "y" {
return nil
}
}
return errors.New("swap canceled")
}
func displayOutLimits(amt, minerFees btcutil.Amount, l *outLimits,
warning string) error {
func displayOutDetails(l *outLimits, warning string, req *looprpc.QuoteRequest,
resp *looprpc.OutQuoteResponse, verbose bool) error {
totalSuccessMax := l.maxMinerFee + l.maxSwapFee + l.maxSwapRoutingFee +
l.maxPrepayRoutingFee
printQuoteOutResp(req, resp, verbose)
fmt.Printf("Max swap fees for %d sat Loop %v: %d sat\n", amt, swap.TypeOut,
totalSuccessMax)
// Display fee limits.
if verbose {
fmt.Println()
fmt.Printf(satAmtFmt, "Max on-chain fee:", l.maxMinerFee)
fmt.Printf(satAmtFmt,
"Max off-chain swap routing fee:", l.maxSwapRoutingFee,
)
fmt.Printf(satAmtFmt, "Max off-chain prepay routing fee:",
l.maxPrepayRoutingFee)
}
// show warning
if warning != "" {
fmt.Println(warning)
fmt.Printf("\n%s\n\n", warning)
}
fmt.Printf("CONTINUE SWAP? (y/n), expand fee detail (x): ")
fmt.Printf("CONTINUE SWAP? (y/n): ")
var answer string
fmt.Scanln(&answer)
switch answer {
case "y":
if answer == "y" {
return nil
case "x":
fmt.Println()
f := "%-36s %d sat\n"
fmt.Printf(f, "Estimated on-chain sweep fee:", minerFees)
fmt.Printf(f, "Max on-chain sweep fee:", l.maxMinerFee)
fmt.Printf(f, "Max off-chain swap routing fee:",
l.maxSwapRoutingFee)
fmt.Printf(f, "Max no show penalty (prepay):", l.maxPrepayAmt)
fmt.Printf(f, "Max off-chain prepay routing fee:",
l.maxPrepayRoutingFee)
fmt.Printf(f, "Max swap fee:", l.maxSwapFee)
fmt.Printf("CONTINUE SWAP? (y/n): ")
fmt.Scanln(&answer)
if answer == "y" {
return nil
}
}
return errors.New("swap canceled")

@ -22,7 +22,7 @@ var quoteInCommand = cli.Command{
Usage: "get a quote for the cost of a loop in swap",
ArgsUsage: "amt",
Description: "Allows to determine the cost of a swap up front",
Flags: []cli.Flag{confTargetFlag},
Flags: []cli.Flag{confTargetFlag, verboseFlag},
Action: quoteIn,
}
@ -66,7 +66,7 @@ func quoteIn(ctx *cli.Context) error {
"amount.\n")
}
printRespJSON(quoteResp)
printQuoteInResp(quoteReq, quoteResp, ctx.Bool("verbose"))
return nil
}
@ -93,6 +93,7 @@ var quoteOutCommand = cli.Command{
"setting this flag might result in a lower " +
"swap fee.",
},
verboseFlag,
},
Action: quoteOut,
}
@ -132,6 +133,68 @@ func quoteOut(ctx *cli.Context) error {
return err
}
printRespJSON(quoteResp)
printQuoteOutResp(quoteReq, quoteResp, ctx.Bool("verbose"))
return nil
}
func printQuoteInResp(req *looprpc.QuoteRequest,
resp *looprpc.InQuoteResponse, verbose bool) {
totalFee := resp.HtlcPublishFeeSat + resp.SwapFeeSat
fmt.Printf(satAmtFmt, "Send on-chain:", req.Amt)
fmt.Printf(satAmtFmt, "Receive off-chain:", req.Amt-totalFee)
switch {
case req.ExternalHtlc && !verbose:
// If it's external then we don't know the miner fee hence the
// total cost.
fmt.Printf(satAmtFmt, "Loop service fee:", resp.SwapFeeSat)
case req.ExternalHtlc && verbose:
fmt.Printf(satAmtFmt, "Loop service fee:", resp.SwapFeeSat)
fmt.Println()
fmt.Printf(blkFmt, "CLTV expiry delta:", resp.CltvDelta)
case verbose:
fmt.Println()
fmt.Printf(
satAmtFmt, "Estimated on-chain fee:",
resp.HtlcPublishFeeSat,
)
fmt.Printf(satAmtFmt, "Loop service fee:", resp.SwapFeeSat)
fmt.Printf(satAmtFmt, "Estimated total fee:", totalFee)
fmt.Println()
fmt.Printf(blkFmt, "Conf target:", resp.ConfTarget)
fmt.Printf(blkFmt, "CLTV expiry delta:", resp.CltvDelta)
default:
fmt.Printf(satAmtFmt, "Estimated total fee:", totalFee)
}
}
func printQuoteOutResp(req *looprpc.QuoteRequest,
resp *looprpc.OutQuoteResponse, verbose bool) {
totalFee := resp.HtlcSweepFeeSat + resp.SwapFeeSat
fmt.Printf(satAmtFmt, "Send off-chain:", req.Amt)
fmt.Printf(satAmtFmt, "Receive on-chain:", req.Amt-totalFee)
if !verbose {
fmt.Printf(satAmtFmt, "Estimated total fee:", totalFee)
return
}
fmt.Println()
fmt.Printf(satAmtFmt, "Estimated on-chain fee:", resp.HtlcSweepFeeSat)
fmt.Printf(satAmtFmt, "Loop service fee:", resp.SwapFeeSat)
fmt.Printf(satAmtFmt, "Estimated total fee:", totalFee)
fmt.Println()
fmt.Printf(satAmtFmt, "No show penalty (prepay):", resp.PrepayAmtSat)
fmt.Printf(blkFmt, "Conf target:", resp.ConfTarget)
fmt.Printf(blkFmt, "CLTV expiry delta:", resp.CltvDelta)
fmt.Printf("%-38s %s\n",
"Publication deadline:",
time.Unix(int64(req.SwapPublicationDeadline), 0),
)
}

@ -15,7 +15,11 @@ This file tracks release notes for the loop client.
## Next release
#### New Features
* A new flag, `--verbose`, or `-v`, is added to `loop in`, `loop out` and
`loop quote`. Responses from these commands are also updated to provide more
verbose info, giving users a more intuitive view about money paid
on/off-chain and fees incurred. Use `loop in -v`, `loop out -v`,
`loop quote in -v` or `loop quote out -v` to view the details.
#### Breaking Changes

Loading…
Cancel
Save