Skip to content

Commit 18593dc

Browse files
committed
all quote changes
1 parent dedf848 commit 18593dc

13 files changed

+1132
-966
lines changed

client.go

+15-5
Original file line numberDiff line numberDiff line change
@@ -645,9 +645,9 @@ func (s *Client) LoopIn(globalCtx context.Context,
645645
return swapInfo, nil
646646
}
647647

648-
// LoopInQuote takes an amount and returns a break down of estimated
649-
// costs for the client. Both the swap server and the on-chain fee estimator are
650-
// queried to get to build the quote response.
648+
// LoopInQuote takes an amount and returns a breakdown of estimated costs for
649+
// the client. Both the swap server and the on-chain fee estimator are queried
650+
// to get to build the quote response.
651651
func (s *Client) LoopInQuote(ctx context.Context,
652652
request *LoopInQuoteRequest) (*LoopInQuote, error) {
653653

@@ -683,7 +683,8 @@ func (s *Client) LoopInQuote(ctx context.Context,
683683
// Because the Private flag is set, we'll generate our own
684684
// set of hop hints and use that
685685
request.RouteHints, err = SelectHopHints(
686-
ctx, s.lndServices, request.Amount, DefaultMaxHopHints, includeNodes,
686+
ctx, s.lndServices, request.Amount, DefaultMaxHopHints,
687+
includeNodes,
687688
)
688689
if err != nil {
689690
return nil, err
@@ -692,7 +693,7 @@ func (s *Client) LoopInQuote(ctx context.Context,
692693

693694
quote, err := s.Server.GetLoopInQuote(
694695
ctx, request.Amount, s.lndServices.NodePubkey, request.LastHop,
695-
request.RouteHints, request.Initiator,
696+
request.RouteHints, request.Initiator, request.NumDeposits,
696697
)
697698
if err != nil {
698699
return nil, err
@@ -709,6 +710,15 @@ func (s *Client) LoopInQuote(ctx context.Context,
709710
}, nil
710711
}
711712

713+
// We don't calculate the on-chain fee if the loop in is funded by
714+
// static address deposits because we don't publish the HTLC on-chain.
715+
if request.NumDeposits > 0 {
716+
return &LoopInQuote{
717+
SwapFee: swapFee,
718+
MinerFee: 0,
719+
}, nil
720+
}
721+
712722
// Get estimate for miner fee. If estimating the miner fee for the
713723
// requested amount is not possible because lnd's wallet cannot
714724
// construct a sample TX, we just return zero instead of failing the

cmd/loop/quote.go

+66-11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"context"
55
"fmt"
6+
"github.com/btcsuite/btcd/btcutil"
67
"os"
78
"time"
89

@@ -19,10 +20,11 @@ var quoteCommand = cli.Command{
1920
}
2021

2122
var quoteInCommand = cli.Command{
22-
Name: "in",
23-
Usage: "get a quote for the cost of a loop in swap",
24-
ArgsUsage: "amt",
25-
Description: "Allows to determine the cost of a swap up front",
23+
Name: "in",
24+
Usage: "get a quote for the cost of a loop in swap",
25+
ArgsUsage: "amt",
26+
Description: "Allows to determine the cost of a swap up front." +
27+
"Either specify an amount or deposit outpoints.",
2628
Flags: []cli.Flag{
2729
cli.StringFlag{
2830
Name: lastHopFlag.Name,
@@ -33,20 +35,36 @@ var quoteInCommand = cli.Command{
3335
verboseFlag,
3436
privateFlag,
3537
routeHintsFlag,
38+
cli.StringSliceFlag{
39+
Name: "deposit_outpoint",
40+
Usage: "one or more static address deposit outpoints " +
41+
"to quote for. Deposit outpoints are not to " +
42+
"be used in combination with an amount.",
43+
},
3644
},
3745
Action: quoteIn,
3846
}
3947

4048
func quoteIn(ctx *cli.Context) error {
4149
// Show command help if the incorrect number arguments was provided.
42-
if ctx.NArg() != 1 {
50+
if ctx.NArg() != 1 && !ctx.IsSet("deposit_outpoint") {
4351
return cli.ShowCommandHelp(ctx, "in")
4452
}
4553

46-
args := ctx.Args()
47-
amt, err := parseAmt(args[0])
48-
if err != nil {
49-
return err
54+
var (
55+
manualAmt btcutil.Amount
56+
depositAmt btcutil.Amount
57+
depositOutpoints []string
58+
err error
59+
ctxb = context.Background()
60+
)
61+
62+
if ctx.NArg() == 1 {
63+
args := ctx.Args()
64+
manualAmt, err = parseAmt(args[0])
65+
if err != nil {
66+
return err
67+
}
5068
}
5169

5270
client, cleanup, err := getClient(ctx)
@@ -62,11 +80,20 @@ func quoteIn(ctx *cli.Context) error {
6280
return err
6381
}
6482

83+
if ctx.IsSet("deposit_outpoint") {
84+
depositOutpoints = ctx.StringSlice("deposit_outpoint")
85+
depositAmt, err = depositAmount(ctxb, client, depositOutpoints)
86+
if err != nil {
87+
return err
88+
}
89+
}
90+
6591
quoteReq := &looprpc.QuoteRequest{
66-
Amt: int64(amt),
92+
Amt: int64(manualAmt),
6793
ConfTarget: int32(ctx.Uint64("conf_target")),
6894
LoopInRouteHints: hints,
6995
Private: ctx.Bool(privateFlag.Name),
96+
DepositOutpoints: depositOutpoints,
7097
}
7198

7299
if ctx.IsSet(lastHopFlag.Name) {
@@ -80,7 +107,6 @@ func quoteIn(ctx *cli.Context) error {
80107
quoteReq.LoopInLastHop = lastHopVertex[:]
81108
}
82109

83-
ctxb := context.Background()
84110
quoteResp, err := client.GetLoopInQuote(ctxb, quoteReq)
85111
if err != nil {
86112
return err
@@ -98,10 +124,39 @@ func quoteIn(ctx *cli.Context) error {
98124
"amount.\n")
99125
}
100126

127+
// If the user specified static address deposits, we quoted for their
128+
// total value and need to display that value instead of the manually
129+
// selected one.
130+
if manualAmt == 0 {
131+
quoteReq.Amt = int64(depositAmt)
132+
}
101133
printQuoteInResp(quoteReq, quoteResp, ctx.Bool("verbose"))
102134
return nil
103135
}
104136

137+
func depositAmount(ctx context.Context, client looprpc.SwapClientClient,
138+
depositOutpoints []string) (btcutil.Amount, error) {
139+
140+
var (
141+
depositAmt btcutil.Amount
142+
)
143+
144+
addressSummary, err := client.GetStaticAddressSummary(
145+
ctx, &looprpc.StaticAddressSummaryRequest{
146+
Outpoints: depositOutpoints,
147+
},
148+
)
149+
if err != nil {
150+
return 0, err
151+
}
152+
153+
for _, deposit := range addressSummary.FilteredDeposits {
154+
depositAmt += btcutil.Amount(deposit.Value)
155+
}
156+
157+
return depositAmt, nil
158+
}
159+
105160
var quoteOutCommand = cli.Command{
106161
Name: "out",
107162
Usage: "get a quote for the cost of a loop out swap",

interface.go

+2
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,8 @@ type LoopInQuoteRequest struct {
288288
// initiated the swap (loop CLI, autolooper, LiT UI and so on) and is
289289
// appended to the user agent string.
290290
Initiator string
291+
292+
NumDeposits uint32
291293
}
292294

293295
// LoopInQuote contains estimates for the fees making up the total swap cost

loopd/swapclient_server.go

+48-4
Original file line numberDiff line numberDiff line change
@@ -748,13 +748,31 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
748748

749749
log.Infof("Loop in quote request received")
750750

751+
var (
752+
numDeposits = uint32(len(req.DepositOutpoints))
753+
err error
754+
)
755+
751756
htlcConfTarget, err := validateLoopInRequest(
752-
req.ConfTarget, req.ExternalHtlc,
757+
req.ConfTarget, req.ExternalHtlc, numDeposits, req.Amt,
753758
)
754759
if err != nil {
755760
return nil, err
756761
}
757762

763+
// Retrieve deposits to calculate their total value.
764+
var summary *clientrpc.StaticAddressSummaryResponse
765+
if len(req.DepositOutpoints) > 0 {
766+
summary, err = s.GetStaticAddressSummary(
767+
ctx, &clientrpc.StaticAddressSummaryRequest{
768+
Outpoints: req.DepositOutpoints,
769+
},
770+
)
771+
if err != nil {
772+
return nil, err
773+
}
774+
}
775+
758776
var (
759777
routeHints [][]zpay32.HopHint
760778
lastHop *route.Vertex
@@ -777,14 +795,26 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
777795
}
778796
}
779797

798+
// The requested amount is 0 here if the request contained deposit
799+
// outpoints. In case we quote for deposits we send the server both the
800+
// total value and the number of deposits. This is so the server can
801+
// probe the total amount and calculate the per input fee.
802+
amount := btcutil.Amount(req.Amt)
803+
if amount == 0 && len(summary.FilteredDeposits) > 0 {
804+
for _, deposit := range summary.FilteredDeposits {
805+
amount += btcutil.Amount(deposit.Value)
806+
}
807+
}
808+
780809
quote, err := s.impl.LoopInQuote(ctx, &loop.LoopInQuoteRequest{
781-
Amount: btcutil.Amount(req.Amt),
810+
Amount: amount,
782811
HtlcConfTarget: htlcConfTarget,
783812
ExternalHtlc: req.ExternalHtlc,
784813
LastHop: lastHop,
785814
RouteHints: routeHints,
786815
Private: req.Private,
787816
Initiator: defaultLoopdInitiator,
817+
NumDeposits: numDeposits,
788818
})
789819
if err != nil {
790820
return nil, err
@@ -881,7 +911,7 @@ func (s *swapClientServer) LoopIn(ctx context.Context,
881911
log.Infof("Loop in request received")
882912

883913
htlcConfTarget, err := validateLoopInRequest(
884-
in.HtlcConfTarget, in.ExternalHtlc,
914+
in.HtlcConfTarget, in.ExternalHtlc, 0, in.Amt,
885915
)
886916
if err != nil {
887917
return nil, err
@@ -1708,7 +1738,15 @@ func validateConfTarget(target, defaultTarget int32) (int32, error) {
17081738

17091739
// validateLoopInRequest fails if the mutually exclusive conf target and
17101740
// external parameters are both set.
1711-
func validateLoopInRequest(htlcConfTarget int32, external bool) (int32, error) {
1741+
func validateLoopInRequest(htlcConfTarget int32, external bool,
1742+
numDeposits uint32, amount int64) (int32, error) {
1743+
1744+
if amount > 0 && numDeposits > 0 {
1745+
return 0, errors.New("amount and deposits cannot both be set")
1746+
} else if amount == 0 && numDeposits == 0 {
1747+
return 0, errors.New("either amount or deposits must be set")
1748+
}
1749+
17121750
// If the htlc is going to be externally set, the htlcConfTarget should
17131751
// not be set, because it has no relevance when the htlc is external.
17141752
if external && htlcConfTarget != 0 {
@@ -1722,6 +1760,12 @@ func validateLoopInRequest(htlcConfTarget int32, external bool) (int32, error) {
17221760
return 0, nil
17231761
}
17241762

1763+
// If the loop in uses static address deposits, we do not need to set a
1764+
// confirmation target since the HTLC won't be published by the client.
1765+
if numDeposits > 0 {
1766+
return 0, nil
1767+
}
1768+
17251769
return validateConfTarget(htlcConfTarget, loop.DefaultHtlcConfTarget)
17261770
}
17271771

loopd/swapclient_server_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func TestValidateLoopInRequest(t *testing.T) {
193193
t.Run(test.name, func(t *testing.T) {
194194
external := test.external
195195
conf, err := validateLoopInRequest(
196-
test.confTarget, external,
196+
test.confTarget, external, 0,
197197
)
198198

199199
if test.expectErr {

loopin.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
128128
// hints.
129129
quote, err := cfg.server.GetLoopInQuote(
130130
globalCtx, request.Amount, cfg.lnd.NodePubkey, request.LastHop,
131-
request.RouteHints, request.Initiator,
131+
request.RouteHints, request.Initiator, 0,
132132
)
133133
if err != nil {
134134
return nil, wrapGrpcError("loop in terms", err)

0 commit comments

Comments
 (0)