Browse Source

Merge pull request #65 from wpaulino/sweep-conf-target

multi: expose confirmation target for loop out HTLC sweeps
Olaoluwa Osuntokun 1 year ago
committed by GitHub
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 229 additions and 83 deletions
  1. +6
  2. +11
  3. +15
  4. +37
  5. +33
  6. +92
  7. +8
  8. +14
  9. +13

+ 6
- 0
client.go View File

@ -42,6 +42,12 @@ var (
// is too soon for us.
ErrExpiryTooFar = errors.New("swap expiry too far")
// ErrSweepConfTargetTooFar is returned when the client proposes a
// confirmation target to sweep the on-chain HTLC of a Loop Out that is
// beyond the expiration height proposed by the server.
ErrSweepConfTargetTooFar = errors.New("sweep confirmation target is " +
"beyond swap expiration height")
serverRPCTimeout = 30 * time.Second
republishDelay = 10 * time.Second

+ 11
- 1
cmd/loop/loopout.go View File

@ -36,6 +36,13 @@ var loopOutCommand = cli.Command{
Name: "amt",
Usage: "the amount in satoshis to loop out",
Name: "conf_target",
Usage: "the number of blocks from the swap " +
"initiation height that the on-chain HTLC " +
"should be swept within",
Value: uint64(loop.DefaultSweepConfTarget),
Action: loopOut,
@ -75,8 +82,10 @@ func loopOut(ctx *cli.Context) error {
defer cleanup()
sweepConfTarget := int32(ctx.Uint64("conf_target"))
quoteReq := &looprpc.QuoteRequest{
Amt: int64(amt),
Amt: int64(amt),
ConfTarget: sweepConfTarget,
quote, err := client.LoopOutQuote(context.Background(), quoteReq)
if err != nil {
@ -103,6 +112,7 @@ func loopOut(ctx *cli.Context) error {
MaxPrepayRoutingFee: int64(*limits.maxPrepayRoutingFee),
MaxSwapRoutingFee: int64(*limits.maxSwapRoutingFee),
LoopOutChannel: unchargeChannel,
SweepConfTarget: sweepConfTarget,
if err != nil {
return err

+ 15
- 4
cmd/loop/quote.go View File

@ -12,12 +12,22 @@ var quoteCommand = cli.Command{
Usage: "get a quote for the cost of a swap",
ArgsUsage: "amt",
Description: "Allows to determine the cost of a swap up front",
Action: quote,
Flags: []cli.Flag{
Name: "conf_target",
Usage: "the number of blocks from the swap " +
"initiation height that the on-chain HTLC " +
"should be swept within in a Loop Out",
Value: 6,
Action: quote,
func quote(ctx *cli.Context) error {
// Show command help if no arguments and flags were provided.
if ctx.NArg() < 1 {
// Show command help if the incorrect number arguments and/or flags were
// provided.
if ctx.NArg() != 1 || ctx.NumFlags() > 1 {
cli.ShowCommandHelp(ctx, "quote")
return nil
@ -36,7 +46,8 @@ func quote(ctx *cli.Context) error {
ctxb := context.Background()
resp, err := client.LoopOutQuote(ctxb, &looprpc.QuoteRequest{
Amt: int64(amt),
Amt: int64(amt),
ConfTarget: int32(ctx.Uint64("conf_target")),
if err != nil {
return err

+ 37
- 3
cmd/loopd/swapclient_server.go View File

@ -16,7 +16,14 @@ import (
const completedSwapsCount = 5
const (
completedSwapsCount = 5
// minConfTarget is the minimum confirmation target we'll allow clients
// to specify. This is driven by the minimum confirmation target allowed
// by the backing fee estimator.
minConfTarget = 2
// swapClientServer implements the grpc service exposed by loopd.
type swapClientServer struct {
@ -34,6 +41,13 @@ func (s *swapClientServer) LoopOut(ctx context.Context,
logger.Infof("Loop out request received")
sweepConfTarget, err := validateConfTarget(
in.SweepConfTarget, loop.DefaultSweepConfTarget,
if err != nil {
return nil, err
var sweepAddr btcutil.Address
if in.Dest == "" {
// Generate sweep address if none specified.
@ -60,7 +74,7 @@ func (s *swapClientServer) LoopOut(ctx context.Context,
MaxPrepayRoutingFee: btcutil.Amount(in.MaxPrepayRoutingFee),
MaxSwapRoutingFee: btcutil.Amount(in.MaxSwapRoutingFee),
MaxSwapFee: btcutil.Amount(in.MaxSwapFee),
SweepConfTarget: defaultConfTarget,
SweepConfTarget: sweepConfTarget,
if in.LoopOutChannel != 0 {
req.LoopOutChannel = &in.LoopOutChannel
@ -242,9 +256,15 @@ func (s *swapClientServer) LoopOutTerms(ctx context.Context,
func (s *swapClientServer) LoopOutQuote(ctx context.Context,
req *looprpc.QuoteRequest) (*looprpc.QuoteResponse, error) {
confTarget, err := validateConfTarget(
req.ConfTarget, loop.DefaultSweepConfTarget,
if err != nil {
return nil, err
quote, err := s.impl.LoopOutQuote(ctx, &loop.LoopOutQuoteRequest{
Amount: btcutil.Amount(req.Amt),
SweepConfTarget: defaultConfTarget,
SweepConfTarget: confTarget,
if err != nil {
return nil, err
@ -323,3 +343,17 @@ func (s *swapClientServer) LoopIn(ctx context.Context,
HtlcAddress: htlc.String(),
}, nil
// validateConfTarget ensures the given confirmation target is valid. If one
// isn't specified (0 value), then the default target is used.
func validateConfTarget(target, defaultTarget int32) (int32, error) {
switch {
// Ensure the target respects our minimum threshold.
case target < minConfTarget:
return 0, fmt.Errorf("a confirmation target of at least %v "+
"must be provided", minConfTarget)
return target, nil

+ 33
- 10
loopout.go View File

@ -20,7 +20,18 @@ import (
var (
// MinLoopOutPreimageRevealDelta configures the minimum number of
// remaining blocks before htlc expiry required to reveal preimage.
MinLoopOutPreimageRevealDelta = int32(20)
MinLoopOutPreimageRevealDelta int32 = 20
// DefaultSweepConfTarget is the default confirmation target we'll use
// when sweeping on-chain HTLCs.
DefaultSweepConfTarget int32 = 6
// DefaultSweepConfTargetDelta is the delta of blocks from a Loop Out
// swap's expiration height at which we begin to use the default sweep
// confirmation target.
// TODO(wilmer): tune?
DefaultSweepConfTargetDelta int32 = DefaultSweepConfTarget * 2
// loopOutSwap contains all the in-memory state related to a pending loop out
@ -577,22 +588,29 @@ func (s *loopOutSwap) sweep(ctx context.Context,
htlcValue btcutil.Amount) error {
witnessFunc := func(sig []byte) (wire.TxWitness, error) {
return s.htlc.GenSuccessWitness(
sig, s.Preimage,
return s.htlc.GenSuccessWitness(sig, s.Preimage)
// Calculate sweep tx fee
// Calculate the transaction fee based on the confirmation target
// required to sweep the HTLC before the timeout. We'll use the
// confirmation target provided by the client unless we've come too
// close to the expiration height, in which case we'll use the default
// if it is better than what the client provided.
confTarget := s.SweepConfTarget
if s.CltvExpiry-s.height >= DefaultSweepConfTargetDelta &&
confTarget > DefaultSweepConfTarget {
confTarget = DefaultSweepConfTarget
fee, err := s.sweeper.GetSweepFee(
ctx, s.htlc.AddSuccessToEstimator,
ctx, s.htlc.AddSuccessToEstimator, confTarget,
if err != nil {
return err
// Ensure it doesn't exceed our maximum fee allowed.
if fee > s.MaxMinerFee {
s.log.Warnf("Required miner fee %v exceeds max of %v",
s.log.Warnf("Required fee %v exceeds max miner fee of %v",
fee, s.MaxMinerFee)
if s.state == loopdb.StatePreimageRevealed {
@ -608,8 +626,7 @@ func (s *loopOutSwap) sweep(ctx context.Context,
// Create sweep tx.
sweepTx, err := s.sweeper.CreateSweepTx(
ctx, s.height, s.htlc, htlcOutpoint,
s.ReceiverKey, witnessFunc,
ctx, s.height, s.htlc, htlcOutpoint, s.ReceiverKey, witnessFunc,
htlcValue, fee, s.DestAddr,
if err != nil {
@ -686,5 +703,11 @@ func validateLoopOutContract(lnd *lndclient.LndServices,
return ErrExpiryTooSoon
// Ensure the client has provided a sweep confirmation target that does
// not exceed the height at which we revert back to using the default.
if height+request.SweepConfTarget >= response.expiry-DefaultSweepConfTargetDelta {
return ErrSweepConfTargetTooFar
return nil

+ 92
- 65
looprpc/client.pb.go View File

@ -154,7 +154,11 @@ type LoopOutRequest struct {
//The channel to loop out, the channel to loop out is selected based on the
//lowest routing fee for the swap payment to the server.
LoopOutChannel uint64 `protobuf:"varint,8,opt,name=loop_out_channel,json=loopOutChannel,proto3" json:"loop_out_channel,omitempty"`
LoopOutChannel uint64 `protobuf:"varint,8,opt,name=loop_out_channel,json=loopOutChannel,proto3" json:"loop_out_channel,omitempty"`
//The number of blocks from the on-chain HTLC's confirmation height that it
//should be swept within.
SweepConfTarget int32 `protobuf:"varint,9,opt,name=sweep_conf_target,json=sweepConfTarget,proto3" json:"sweep_conf_target,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -241,6 +245,13 @@ func (m *LoopOutRequest) GetLoopOutChannel() uint64 {
return 0
func (m *LoopOutRequest) GetSweepConfTarget() int32 {
if m != nil {
return m.SweepConfTarget
return 0
type LoopInRequest struct {
//Requested swap amount in sat. This does not include the swap and miner
@ -683,7 +694,13 @@ func (m *TermsResponse) GetCltvDelta() int32 {
type QuoteRequest struct {
//The amount to swap in satoshis.
Amt int64 `protobuf:"varint,1,opt,name=amt,proto3" json:"amt,omitempty"`
Amt int64 `protobuf:"varint,1,opt,name=amt,proto3" json:"amt,omitempty"`
//The confirmation target that should be used either for the sweep of the
//on-chain HTLC broadcast by the swap server in the case of a Loop Out, or for
//the confirmation of the on-chain HTLC broadcast by the swap client in the
//case of a Loop In.
ConfTarget int32 `protobuf:"varint,2,opt,name=conf_target,json=confTarget,proto3" json:"conf_target,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -721,6 +738,13 @@ func (m *QuoteRequest) GetAmt() int64 {
return 0
func (m *QuoteRequest) GetConfTarget() int32 {
if m != nil {
return m.ConfTarget
return 0
type QuoteResponse struct {
//The fee that the swap server is charging for the swap.
@ -799,69 +823,72 @@ func init() {
func init() { proto.RegisterFile("client.proto", fileDescriptor_014de31d7ac8c57c) }
var fileDescriptor_014de31d7ac8c57c = []byte{
// 992 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x4f, 0x73, 0xda, 0x46,
0x1c, 0x0d, 0x02, 0x1b, 0xf8, 0x59, 0xc8, 0x78, 0x9d, 0x38, 0x94, 0x36, 0x53, 0xaa, 0x36, 0x29,
0xe3, 0x83, 0x69, 0x9d, 0x43, 0xa7, 0xbd, 0x74, 0x08, 0x28, 0xb1, 0x66, 0xb0, 0xa1, 0x02, 0x67,
0xa6, 0x27, 0xcd, 0x06, 0xd6, 0xb6, 0x66, 0xa4, 0x5d, 0x45, 0x5a, 0x39, 0x78, 0x3a, 0xbd, 0xf4,
0x1b, 0xb4, 0xfd, 0x26, 0x9d, 0x7e, 0x93, 0xde, 0x7b, 0xea, 0x07, 0xe9, 0xec, 0x1f, 0x14, 0x04,
0xf1, 0x25, 0x37, 0xfc, 0xf6, 0xed, 0xdb, 0xdf, 0xfe, 0x7e, 0xef, 0xad, 0x0c, 0xe6, 0x3c, 0x0c,
0x08, 0xe5, 0x27, 0x71, 0xc2, 0x38, 0x43, 0xd5, 0x90, 0xb1, 0x38, 0x89, 0xe7, 0xed, 0xcf, 0xae,
0x19, 0xbb, 0x0e, 0x49, 0x0f, 0xc7, 0x41, 0x0f, 0x53, 0xca, 0x38, 0xe6, 0x01, 0xa3, 0xa9, 0xa2,
0xd9, 0x7f, 0x19, 0x60, 0x8d, 0x18, 0x8b, 0xc7, 0x19, 0xf7, 0xc8, 0xdb, 0x8c, 0xa4, 0x1c, 0x35,
0xa1, 0x8c, 0x23, 0xde, 0x2a, 0x75, 0x4a, 0xdd, 0xb2, 0x27, 0x7e, 0x22, 0x04, 0x95, 0x05, 0x49,
0x79, 0xcb, 0xe8, 0x94, 0xba, 0x75, 0x4f, 0xfe, 0x46, 0x3d, 0x78, 0x18, 0xe1, 0xa5, 0x9f, 0xbe,
0xc3, 0xb1, 0x9f, 0xb0, 0x8c, 0x07, 0xf4, 0xda, 0xbf, 0x22, 0xa4, 0x55, 0x96, 0xdb, 0x0e, 0x22,
0xbc, 0x9c, 0xbe, 0xc3, 0xb1, 0xa7, 0x56, 0x5e, 0x12, 0x82, 0x9e, 0xc3, 0x91, 0xd8, 0x10, 0x27,
0x24, 0xc6, 0x77, 0x85, 0x2d, 0x15, 0xb9, 0xe5, 0x30, 0xc2, 0xcb, 0x89, 0x5c, 0x5c, 0xdb, 0xd4,
0x01, 0x33, 0x3f, 0x45, 0x50, 0x77, 0x24, 0x15, 0xb4, 0xba, 0x60, 0x7c, 0x05, 0xd6, 0x9a, 0xac,
0x28, 0x7c, 0x57, 0x72, 0xcc, 0x5c, 0xae, 0x1f, 0x71, 0x64, 0x43, 0x43, 0xb0, 0xa2, 0x80, 0x92,
0x44, 0x0a, 0x55, 0x25, 0x69, 0x2f, 0xc2, 0xcb, 0x73, 0x81, 0x09, 0xa5, 0x2e, 0x34, 0x45, 0xcf,
0x7c, 0x96, 0x71, 0x7f, 0x7e, 0x83, 0x29, 0x25, 0x61, 0xab, 0xd6, 0x29, 0x75, 0x2b, 0x9e, 0x15,
0xaa, 0x0e, 0x0d, 0x14, 0x6a, 0xff, 0x5d, 0x82, 0x86, 0x68, 0x9a, 0x4b, 0xef, 0xef, 0xd9, 0x66,
0xe5, 0xc6, 0x56, 0xe5, 0x5b, 0x35, 0x95, 0xb7, 0x6b, 0x7a, 0x06, 0xfb, 0xb2, 0xa6, 0x80, 0xe6,
0x25, 0x55, 0x64, 0x49, 0x8d, 0x50, 0x9e, 0xaf, 0x2b, 0x42, 0x5f, 0x42, 0x83, 0x2c, 0x39, 0x49,
0x28, 0x0e, 0xfd, 0x1b, 0x1e, 0xce, 0x65, 0xa3, 0x6a, 0x9e, 0xb9, 0x02, 0xcf, 0x78, 0x38, 0xb7,
0xfb, 0x60, 0xca, 0x99, 0x90, 0x34, 0x66, 0x34, 0x25, 0xc8, 0x02, 0x23, 0x58, 0xc8, 0x9a, 0xeb,
0x9e, 0x11, 0x2c, 0xd0, 0x17, 0x60, 0x8a, 0xbd, 0x3e, 0x5e, 0x2c, 0x12, 0x92, 0xa6, 0x7a, 0xdc,
0x7b, 0x02, 0xeb, 0x2b, 0xc8, 0x6e, 0x82, 0x75, 0xce, 0x68, 0xc0, 0x59, 0xa2, 0x6f, 0x6e, 0xff,
0x6b, 0x00, 0x08, 0xd5, 0x29, 0xc7, 0x3c, 0x4b, 0x3f, 0xd0, 0x08, 0x75, 0x8a, 0x91, 0x9f, 0xf2,
0x14, 0x2a, 0xfc, 0x2e, 0x56, 0xb7, 0xb5, 0x4e, 0x0f, 0x4e, 0xb4, 0x4f, 0x4f, 0x84, 0xc8, 0xec,
0x2e, 0x26, 0x9e, 0x5c, 0x46, 0x5d, 0xd8, 0x49, 0x39, 0xe6, 0xca, 0x1d, 0xd6, 0x29, 0x2a, 0xf0,
0xc4, 0x61, 0xc4, 0x53, 0x04, 0xf4, 0x35, 0xec, 0x07, 0x34, 0xe0, 0x81, 0xf4, 0xb5, 0xcf, 0x83,
0x68, 0x65, 0x13, 0xeb, 0x3d, 0x3c, 0x0b, 0x22, 0x35, 0x60, 0x9c, 0x72, 0x3f, 0x8b, 0x17, 0x98,
0x13, 0xc5, 0x54, 0x66, 0xb1, 0x04, 0x7e, 0x29, 0x61, 0xc9, 0xdc, 0xec, 0x44, 0x75, 0xab, 0x13,
0xe8, 0x73, 0xd8, 0x9b, 0xb3, 0x94, 0xfb, 0x29, 0x49, 0x6e, 0x49, 0x22, 0x8d, 0x52, 0xf6, 0x40,
0x40, 0x53, 0x89, 0x08, 0x0d, 0x49, 0x60, 0x74, 0x7e, 0x83, 0x03, 0xda, 0xaa, 0xab, 0xe9, 0x0a,
0x6c, 0xac, 0x20, 0x31, 0x35, 0x45, 0xb9, 0xba, 0x52, 0x1c, 0x50, 0xd6, 0x95, 0x1c, 0x8d, 0xd9,
0x16, 0x98, 0x33, 0x92, 0x44, 0xe9, 0xaa, 0xe1, 0xbf, 0x1b, 0xd0, 0xd0, 0x80, 0x9e, 0xe3, 0x31,
0x1c, 0x48, 0x9b, 0xc5, 0xf8, 0x2e, 0x22, 0x94, 0xfb, 0x32, 0xab, 0x6a, 0xac, 0xfb, 0x62, 0x61,
0xa2, 0xf0, 0xa1, 0x30, 0xaa, 0x0d, 0x8d, 0x95, 0x25, 0xfd, 0x37, 0x38, 0x5d, 0xf9, 0x72, 0x2f,
0x55, 0xa6, 0x7c, 0x81, 0x53, 0x52, 0xe0, 0x24, 0x62, 0x04, 0xe5, 0x02, 0xc7, 0x13, 0x4d, 0x7f,
0x02, 0xb0, 0x16, 0x39, 0x95, 0xe0, 0x7a, 0x9c, 0xe7, 0xed, 0x19, 0xec, 0x47, 0x01, 0x55, 0xee,
0xc7, 0x11, 0xcb, 0x28, 0xd7, 0x33, 0x69, 0x44, 0x01, 0x15, 0x13, 0xec, 0x4b, 0x50, 0xf2, 0x56,
0x29, 0xd1, 0xbc, 0x5d, 0xcd, 0x53, 0x41, 0xd1, 0xbc, 0x27, 0x00, 0xf3, 0x90, 0xdf, 0xfa, 0x0b,
0x12, 0x72, 0x2c, 0xc7, 0xb1, 0xe3, 0xd5, 0x05, 0x32, 0x14, 0x80, 0xdd, 0x01, 0xf3, 0xa7, 0x8c,
0x71, 0x72, 0x6f, 0x1c, 0xed, 0x2b, 0x68, 0x68, 0x86, 0x6e, 0xda, 0x27, 0x50, 0xcb, 0xb3, 0xa9,
0x78, 0x55, 0x7d, 0xbf, 0x8d, 0xbb, 0x19, 0x9b, 0x77, 0xfb, 0x14, 0xea, 0x9b, 0x99, 0xad, 0x45,
0x3a, 0xb0, 0xc7, 0x4f, 0xa1, 0xb6, 0x32, 0x32, 0x32, 0xa1, 0x36, 0x1a, 0x8f, 0x27, 0xfe, 0xf8,
0x72, 0xd6, 0x7c, 0x80, 0xf6, 0xa0, 0x2a, 0xff, 0x72, 0x2f, 0x9a, 0xa5, 0xe3, 0x14, 0xea, 0xb9,
0x8f, 0x51, 0x03, 0xea, 0xee, 0x85, 0x3b, 0x73, 0xfb, 0x33, 0x67, 0xd8, 0x7c, 0x80, 0x1e, 0xc1,
0xc1, 0xc4, 0x73, 0xdc, 0xf3, 0xfe, 0x2b, 0xc7, 0xf7, 0x9c, 0xd7, 0x4e, 0x7f, 0xe4, 0x0c, 0x9b,
0x25, 0x84, 0xc0, 0x3a, 0x9b, 0x8d, 0x06, 0xfe, 0xe4, 0xf2, 0xc5, 0xc8, 0x9d, 0x9e, 0x39, 0xc3,
0xa6, 0x21, 0x34, 0xa7, 0x97, 0x83, 0x81, 0x33, 0x9d, 0x36, 0xcb, 0x08, 0x60, 0xf7, 0x65, 0xdf,
0x15, 0xe4, 0x0a, 0x3a, 0x84, 0x7d, 0xf7, 0xe2, 0xf5, 0xd8, 0x1d, 0x38, 0xfe, 0xd4, 0x99, 0xcd,
0x04, 0xb8, 0x73, 0xfa, 0x47, 0x45, 0x45, 0x75, 0x20, 0xbf, 0x13, 0xc8, 0x83, 0xaa, 0x7e, 0xf9,
0xd1, 0xe3, 0x3c, 0x5d, 0xc5, 0x6f, 0x41, 0xfb, 0x51, 0x21, 0x76, 0xab, 0xe6, 0xd9, 0x8f, 0x7f,
0xfb, 0xe7, 0xbf, 0x3f, 0x8d, 0x03, 0xdb, 0xec, 0xdd, 0x7e, 0xdb, 0x13, 0x8c, 0x1e, 0xcb, 0xf8,
0x0f, 0xa5, 0x63, 0xf4, 0x1d, 0xec, 0xaa, 0x87, 0x11, 0x1d, 0x15, 0x24, 0xf3, 0x97, 0xf2, 0x1e,
0x45, 0xf4, 0x3d, 0x54, 0xf5, 0xc3, 0xb2, 0x56, 0x4c, 0xf1, 0xa9, 0x69, 0x1f, 0x6e, 0xbd, 0x01,
0x59, 0xfa, 0x4d, 0x09, 0xfd, 0x0c, 0xa6, 0xae, 0x5a, 0xc6, 0x02, 0xbd, 0x3f, 0x61, 0x3d, 0x37,
0xed, 0xa3, 0x4d, 0x58, 0xdf, 0xa5, 0x2d, 0xef, 0xf2, 0x10, 0xa1, 0xf5, 0xbb, 0xf4, 0xb8, 0x94,
0xf2, 0x73, 0x69, 0x69, 0x9e, 0x35, 0xe9, 0x75, 0xbb, 0xad, 0x49, 0x17, 0x3c, 0x66, 0x77, 0xa4,
0x74, 0x1b, 0xb5, 0x0a, 0xd2, 0x6f, 0x05, 0xa7, 0xf7, 0x0b, 0x8e, 0xf8, 0xaf, 0xe8, 0x47, 0xb0,
0x5e, 0x11, 0xae, 0x3a, 0xf4, 0x31, 0xd5, 0x17, 0x04, 0x3e, 0xa6, 0xc6, 0x37, 0xbb, 0xf2, 0xff,
0x80, 0xe7, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0xf8, 0xf2, 0xb9, 0x76, 0x3e, 0x08, 0x00, 0x00,
// 1028 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x5d, 0x73, 0x1a, 0x37,
0x14, 0x0d, 0x0b, 0x36, 0x70, 0x0d, 0x0b, 0x56, 0x12, 0x87, 0xd2, 0x66, 0x4a, 0x69, 0x93, 0x32,
0x7e, 0x30, 0xad, 0xf3, 0xd0, 0x69, 0x5f, 0x3a, 0x04, 0x93, 0x98, 0x19, 0xdb, 0xb8, 0x0b, 0xce,
0x4c, 0x9f, 0x34, 0x0a, 0x08, 0x7b, 0x67, 0x76, 0xa5, 0xcd, 0x4a, 0xf8, 0x63, 0x3a, 0x7d, 0xe9,
0x3f, 0x68, 0xfb, 0x57, 0xfa, 0x4f, 0xfa, 0xde, 0xa7, 0xfe, 0x90, 0x8e, 0xae, 0x96, 0x35, 0x0b,
0xf5, 0x4b, 0xde, 0xf0, 0xd1, 0xd1, 0xd1, 0xd5, 0xbd, 0xe7, 0x68, 0x0d, 0x95, 0x69, 0xe0, 0x73,
0xa1, 0x0f, 0xa2, 0x58, 0x6a, 0x49, 0x8a, 0x81, 0x94, 0x51, 0x1c, 0x4d, 0x9b, 0x9f, 0x5d, 0x4a,
0x79, 0x19, 0xf0, 0x2e, 0x8b, 0xfc, 0x2e, 0x13, 0x42, 0x6a, 0xa6, 0x7d, 0x29, 0x94, 0xa5, 0xb5,
0xff, 0x71, 0xc0, 0x3d, 0x91, 0x32, 0x1a, 0x2d, 0xb4, 0xc7, 0x3f, 0x2c, 0xb8, 0xd2, 0xa4, 0x0e,
0x79, 0x16, 0xea, 0x46, 0xae, 0x95, 0xeb, 0xe4, 0x3d, 0xf3, 0x93, 0x10, 0x28, 0xcc, 0xb8, 0xd2,
0x0d, 0xa7, 0x95, 0xeb, 0x94, 0x3d, 0xfc, 0x4d, 0xba, 0xf0, 0x24, 0x64, 0xb7, 0x54, 0xdd, 0xb0,
0x88, 0xc6, 0x72, 0xa1, 0x7d, 0x71, 0x49, 0xe7, 0x9c, 0x37, 0xf2, 0xb8, 0x6d, 0x37, 0x64, 0xb7,
0xe3, 0x1b, 0x16, 0x79, 0x76, 0xe5, 0x0d, 0xe7, 0xe4, 0x15, 0xec, 0x99, 0x0d, 0x51, 0xcc, 0x23,
0x76, 0x97, 0xd9, 0x52, 0xc0, 0x2d, 0x8f, 0x43, 0x76, 0x7b, 0x8e, 0x8b, 0x2b, 0x9b, 0x5a, 0x50,
0x49, 0x4f, 0x31, 0xd4, 0x2d, 0xa4, 0x42, 0xa2, 0x6e, 0x18, 0x5f, 0x81, 0xbb, 0x22, 0x6b, 0x0a,
0xdf, 0x46, 0x4e, 0x25, 0x95, 0xeb, 0x85, 0x9a, 0xb4, 0xa1, 0x6a, 0x58, 0xa1, 0x2f, 0x78, 0x8c,
0x42, 0x45, 0x24, 0xed, 0x84, 0xec, 0xf6, 0xd4, 0x60, 0x46, 0xa9, 0x03, 0x75, 0xd3, 0x33, 0x2a,
0x17, 0x9a, 0x4e, 0xaf, 0x98, 0x10, 0x3c, 0x68, 0x94, 0x5a, 0xb9, 0x4e, 0xc1, 0x73, 0x03, 0xdb,
0xa1, 0xbe, 0x45, 0xc9, 0x3e, 0xec, 0xaa, 0x1b, 0xce, 0x23, 0x3a, 0x95, 0x62, 0x4e, 0x35, 0x8b,
0x2f, 0xb9, 0x6e, 0x94, 0x5b, 0xb9, 0xce, 0x96, 0x57, 0xc3, 0x85, 0xbe, 0x14, 0xf3, 0x09, 0xc2,
0xed, 0xbf, 0x72, 0x50, 0x35, 0x0d, 0x1e, 0x8a, 0x87, 0xfb, 0xbb, 0x7e, 0x4b, 0x67, 0xe3, 0x96,
0x1b, 0xf5, 0xe7, 0x37, 0xeb, 0x7f, 0x09, 0x35, 0xac, 0xdf, 0x17, 0x69, 0xf9, 0x05, 0x2c, 0xbf,
0x1a, 0xe0, 0xf9, 0xcb, 0xea, 0xbf, 0x84, 0x2a, 0xbf, 0xd5, 0x3c, 0x16, 0x2c, 0xa0, 0x57, 0x3a,
0x98, 0x62, 0x53, 0x4b, 0x5e, 0x65, 0x09, 0x1e, 0xeb, 0x60, 0xda, 0xee, 0x41, 0x05, 0xe7, 0xc7,
0x55, 0x24, 0x85, 0xe2, 0xc4, 0x05, 0xc7, 0x9f, 0x61, 0xcd, 0x65, 0xcf, 0xf1, 0x67, 0xe4, 0x0b,
0xa8, 0x98, 0xbd, 0x94, 0xcd, 0x66, 0x31, 0x57, 0x2a, 0xb1, 0xc6, 0x8e, 0xc1, 0x7a, 0x16, 0x6a,
0xd7, 0xc1, 0x3d, 0x95, 0xc2, 0xd7, 0x32, 0x4e, 0x6e, 0x6e, 0xcc, 0x06, 0x46, 0x75, 0xac, 0x99,
0x5e, 0xa8, 0xff, 0x69, 0x84, 0x3d, 0xc5, 0x49, 0x4f, 0x79, 0x01, 0x05, 0x7d, 0x17, 0xd9, 0xdb,
0xba, 0x87, 0xbb, 0x07, 0x89, 0xa7, 0x0f, 0x8c, 0xc8, 0xe4, 0x2e, 0xe2, 0x1e, 0x2e, 0x93, 0x0e,
0x6c, 0x29, 0xcd, 0xb4, 0x75, 0x92, 0x7b, 0x48, 0x32, 0x3c, 0x73, 0x18, 0xf7, 0x2c, 0x81, 0x7c,
0x0d, 0x35, 0x5f, 0xf8, 0xda, 0xc7, 0x0c, 0x50, 0xed, 0x87, 0x4b, 0x4b, 0xb9, 0xf7, 0xf0, 0xc4,
0x0f, 0xad, 0x19, 0x98, 0xd2, 0x74, 0x11, 0xcd, 0x98, 0xe6, 0x96, 0x69, 0x8d, 0xe5, 0x1a, 0xfc,
0x02, 0x61, 0x64, 0xae, 0x77, 0xa2, 0xb8, 0xd1, 0x09, 0xf2, 0x39, 0xec, 0x4c, 0xa5, 0xd2, 0x54,
0xf1, 0xf8, 0x9a, 0xc7, 0x68, 0xaa, 0xbc, 0x07, 0x06, 0x1a, 0x23, 0x62, 0x34, 0x90, 0x20, 0xc5,
0xf4, 0x8a, 0xf9, 0x02, 0xbd, 0x94, 0xf7, 0x70, 0xd3, 0xc8, 0x42, 0x66, 0x6a, 0x96, 0x32, 0x9f,
0x5b, 0x0e, 0x58, 0x9b, 0x23, 0x27, 0xc1, 0xda, 0x2e, 0x54, 0x26, 0x3c, 0x0e, 0xd5, 0xb2, 0xe1,
0xbf, 0x3b, 0x50, 0x4d, 0x80, 0x64, 0x8e, 0x68, 0x5d, 0x16, 0xd1, 0x88, 0xdd, 0x85, 0x5c, 0x68,
0x8a, 0xb9, 0xb6, 0x63, 0xad, 0x99, 0x85, 0x73, 0x8b, 0x1f, 0x19, 0xa3, 0xb6, 0xa1, 0xba, 0xb4,
0x24, 0x7d, 0xcf, 0xd4, 0xd2, 0x97, 0x3b, 0xca, 0x9a, 0xf2, 0x35, 0x53, 0x3c, 0xc3, 0x89, 0xcd,
0x08, 0xf2, 0x19, 0x8e, 0x67, 0x9a, 0xfe, 0x1c, 0x60, 0x25, 0x9e, 0x36, 0xed, 0xe5, 0x28, 0xcd,
0xe6, 0x4b, 0xa8, 0x85, 0xbe, 0xb0, 0xee, 0x67, 0xa1, 0x5c, 0x08, 0x9d, 0xcc, 0xa4, 0x1a, 0xfa,
0xc2, 0x4c, 0xb0, 0x87, 0x20, 0xf2, 0x96, 0x29, 0x49, 0x78, 0xdb, 0x09, 0xcf, 0x06, 0x25, 0xe1,
0x3d, 0x07, 0x98, 0x06, 0xfa, 0x9a, 0xce, 0x78, 0xa0, 0x19, 0x8e, 0x63, 0xcb, 0x2b, 0x1b, 0xe4,
0xc8, 0x00, 0xc6, 0xd9, 0x3f, 0x2d, 0xa4, 0xe6, 0x0f, 0xc7, 0x11, 0xc7, 0x75, 0x1f, 0x6c, 0x07,
0x15, 0x60, 0x7a, 0x9f, 0xe9, 0x39, 0x54, 0x13, 0x89, 0xa4, 0xab, 0x9f, 0x40, 0x29, 0x0d, 0xaf,
0x15, 0x2a, 0x26, 0x0d, 0x58, 0xbb, 0xbc, 0xb3, 0x7e, 0xf9, 0x4f, 0xa1, 0xbc, 0x1e, 0xea, 0x52,
0x98, 0x24, 0x7a, 0xff, 0x05, 0x94, 0x96, 0x4e, 0x27, 0x15, 0x28, 0x9d, 0x8c, 0x46, 0xe7, 0x74,
0x74, 0x31, 0xa9, 0x3f, 0x22, 0x3b, 0x50, 0xc4, 0xbf, 0x86, 0x67, 0xf5, 0xdc, 0xbe, 0x82, 0x72,
0x6a, 0x74, 0x52, 0x85, 0xf2, 0xf0, 0x6c, 0x38, 0x19, 0xf6, 0x26, 0x83, 0xa3, 0xfa, 0x23, 0xf2,
0x14, 0x76, 0xcf, 0xbd, 0xc1, 0xf0, 0xb4, 0xf7, 0x76, 0x40, 0xbd, 0xc1, 0xbb, 0x41, 0xef, 0x64,
0x70, 0x54, 0xcf, 0x11, 0x02, 0xee, 0xf1, 0xe4, 0xa4, 0x4f, 0xcf, 0x2f, 0x5e, 0x9f, 0x0c, 0xc7,
0xc7, 0x83, 0xa3, 0xba, 0x63, 0x34, 0xc7, 0x17, 0xfd, 0xfe, 0x60, 0x3c, 0xae, 0xe7, 0x09, 0xc0,
0xf6, 0x9b, 0xde, 0xd0, 0x90, 0x0b, 0xe4, 0x31, 0xd4, 0x86, 0x67, 0xef, 0x46, 0xc3, 0xfe, 0x80,
0x8e, 0x07, 0x93, 0x89, 0x01, 0xb7, 0x0e, 0xff, 0x28, 0xd8, 0x2c, 0xf7, 0xf1, 0xa3, 0x43, 0x3c,
0x28, 0x26, 0x9f, 0x11, 0xf2, 0x2c, 0x8d, 0x5f, 0xf6, 0xc3, 0xd2, 0x7c, 0x9a, 0xc9, 0xe5, 0xb2,
0x79, 0xed, 0x67, 0xbf, 0xfd, 0xfd, 0xef, 0x9f, 0xce, 0x6e, 0xbb, 0xd2, 0xbd, 0xfe, 0xb6, 0x6b,
0x18, 0x5d, 0xb9, 0xd0, 0x3f, 0xe4, 0xf6, 0xc9, 0x77, 0xb0, 0x6d, 0x5f, 0x4e, 0xb2, 0x97, 0x91,
0x4c, 0x9f, 0xd2, 0x07, 0x14, 0xc9, 0xf7, 0x50, 0x4c, 0x5e, 0x9e, 0x95, 0x62, 0xb2, 0x6f, 0x51,
0xf3, 0xf1, 0xc6, 0x23, 0xb1, 0x50, 0xdf, 0xe4, 0xc8, 0xcf, 0x50, 0x49, 0xaa, 0xc6, 0xdc, 0x90,
0xfb, 0x13, 0x56, 0x83, 0xd5, 0xdc, 0x5b, 0x87, 0x93, 0xbb, 0x34, 0xf1, 0x2e, 0x4f, 0x08, 0x59,
0xbd, 0x4b, 0x57, 0xa3, 0x14, 0x4d, 0xa5, 0xd1, 0x3c, 0x2b, 0xd2, 0xab, 0x7e, 0x5c, 0x91, 0xce,
0x78, 0xac, 0xdd, 0x42, 0xe9, 0x26, 0x69, 0x64, 0xa4, 0x3f, 0x18, 0x4e, 0xf7, 0x17, 0x16, 0xea,
0x5f, 0xc9, 0x8f, 0xe0, 0xbe, 0xe5, 0xda, 0x76, 0xe8, 0x63, 0xaa, 0xcf, 0x08, 0x7c, 0x4c, 0x8d,
0xef, 0xb7, 0xf1, 0x9f, 0x8a, 0x57, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x09, 0x80, 0x8f, 0x06,
0x8b, 0x08, 0x00, 0x00,
// Reference imports to suppress errors if they are not otherwise used.

+ 8
- 0
looprpc/ View File

@ -50,6 +50,10 @@ func request_SwapClient_LoopOutTerms_0(ctx context.Context, marshaler runtime.Ma
var (
filter_SwapClient_LoopOutQuote_0 = &utilities.DoubleArray{Encoding: map[string]int{"amt": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
func request_SwapClient_LoopOutQuote_0(ctx context.Context, marshaler runtime.Marshaler, client SwapClientClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QuoteRequest
var metadata runtime.ServerMetadata
@ -72,6 +76,10 @@ func request_SwapClient_LoopOutQuote_0(ctx context.Context, marshaler runtime.Ma
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "amt", err)
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_SwapClient_LoopOutQuote_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
msg, err := client.LoopOutQuote(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err

+ 14
- 0
looprpc/client.proto View File

@ -127,6 +127,12 @@ message LoopOutRequest {
lowest routing fee for the swap payment to the server.
uint64 loop_out_channel = 8;
The number of blocks from the on-chain HTLC's confirmation height that it
should be swept within.
int32 sweep_conf_target = 9;
message LoopInRequest {
@ -328,6 +334,14 @@ message QuoteRequest {
The amount to swap in satoshis.
int64 amt = 1;
The confirmation target that should be used either for the sweep of the
on-chain HTLC broadcast by the swap server in the case of a Loop Out, or for
the confirmation of the on-chain HTLC broadcast by the swap client in the
case of a Loop In.
int32 conf_target = 2;
message QuoteResponse {

+ 13
- 0
looprpc/client.swagger.json View File

@ -61,6 +61,14 @@
"required": true,
"type": "string",
"format": "int64"
"name": "conf_target",
"description": "*\nThe confirmation target that should be used either for the sweep of the\non-chain HTLC broadcast by the swap server in the case of a Loop Out, or for\nthe confirmation of the on-chain HTLC broadcast by the swap client in the\ncase of a Loop In.",
"in": "query",
"required": false,
"type": "integer",
"format": "int32"
"tags": [
@ -128,6 +136,11 @@
"type": "string",
"format": "uint64",
"description": "*\nThe channel to loop out, the channel to loop out is selected based on the\nlowest routing fee for the swap payment to the server."
"sweep_conf_target": {
"type": "integer",
"format": "int32",
"description": "*\nThe number of blocks from the on-chain HTLC's confirmation height that it\nshould be swept within."