Merge pull request #75 from halseth/batcher-impl

SwapPublicationDeadline for LoopOut contracts
pull/109/head
Alex Bosworth 5 years ago committed by GitHub
commit 278820432e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -68,7 +68,7 @@ func loopIn(ctx *cli.Context) error {
} }
limits := getInLimits(amt, quote) limits := getInLimits(amt, quote)
err = displayLimits(swap.TypeIn, amt, limits, external) err = displayLimits(swap.TypeIn, amt, limits, external, "")
if err != nil { if err != nil {
return err return err
} }

@ -3,6 +3,7 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"time"
"github.com/lightninglabs/loop" "github.com/lightninglabs/loop"
"github.com/lightninglabs/loop/looprpc" "github.com/lightninglabs/loop/looprpc"
@ -44,6 +45,16 @@ var loopOutCommand = cli.Command{
"should be swept within", "should be swept within",
Value: uint64(loop.DefaultSweepConfTarget), Value: uint64(loop.DefaultSweepConfTarget),
}, },
cli.BoolFlag{
Name: "fast",
Usage: "Indicate you want to swap immediately, " +
"paying potentially a higher fee. If not " +
"set the swap server might choose to wait up " +
"to 30 minutes before publishing the swap " +
"HTLC on-chain, to save on chain fees. Not " +
"setting this flag might result in a lower " +
"swap fee.",
},
}, },
Action: loopOut, Action: loopOut,
} }
@ -92,9 +103,19 @@ func loopOut(ctx *cli.Context) error {
return err return err
} }
limits := getLimits(amt, quote) // Show a warning if a slow swap was requested.
fast := ctx.Bool("fast")
warning := ""
if fast {
warning = "Fast swap requested."
} else {
warning = fmt.Sprintf("Regular swap speed requested, it "+
"might take up to %v for the swap to be executed.",
defaultSwapWaitTime)
}
err = displayLimits(swap.TypeOut, amt, limits, false) limits := getLimits(amt, quote)
err = displayLimits(swap.TypeOut, amt, limits, false, warning)
if err != nil { if err != nil {
return err return err
} }
@ -104,16 +125,24 @@ func loopOut(ctx *cli.Context) error {
unchargeChannel = ctx.Uint64("channel") unchargeChannel = ctx.Uint64("channel")
} }
// Set our maximum swap wait time. If a fast swap is requested we set
// it to now, otherwise to 30 minutes in the future.
swapDeadline := time.Now()
if !fast {
swapDeadline = time.Now().Add(defaultSwapWaitTime)
}
resp, err := client.LoopOut(context.Background(), &looprpc.LoopOutRequest{ resp, err := client.LoopOut(context.Background(), &looprpc.LoopOutRequest{
Amt: int64(amt), Amt: int64(amt),
Dest: destAddr, Dest: destAddr,
MaxMinerFee: int64(limits.maxMinerFee), MaxMinerFee: int64(limits.maxMinerFee),
MaxPrepayAmt: int64(*limits.maxPrepayAmt), MaxPrepayAmt: int64(*limits.maxPrepayAmt),
MaxSwapFee: int64(limits.maxSwapFee), MaxSwapFee: int64(limits.maxSwapFee),
MaxPrepayRoutingFee: int64(*limits.maxPrepayRoutingFee), MaxPrepayRoutingFee: int64(*limits.maxPrepayRoutingFee),
MaxSwapRoutingFee: int64(*limits.maxSwapRoutingFee), MaxSwapRoutingFee: int64(*limits.maxSwapRoutingFee),
LoopOutChannel: unchargeChannel, LoopOutChannel: unchargeChannel,
SweepConfTarget: sweepConfTarget, SweepConfTarget: sweepConfTarget,
SwapPublicationDeadline: uint64(swapDeadline.Unix()),
}) })
if err != nil { if err != nil {
return err return err

@ -26,6 +26,8 @@ var (
maxRoutingFeeBase = btcutil.Amount(10) maxRoutingFeeBase = btcutil.Amount(10)
maxRoutingFeeRate = int64(20000) maxRoutingFeeRate = int64(20000)
defaultSwapWaitTime = 30 * time.Minute
) )
func printRespJSON(resp proto.Message) { func printRespJSON(resp proto.Message) {
@ -117,7 +119,7 @@ func getLimits(amt btcutil.Amount, quote *looprpc.QuoteResponse) *limits {
} }
func displayLimits(swapType swap.Type, amt btcutil.Amount, l *limits, func displayLimits(swapType swap.Type, amt btcutil.Amount, l *limits,
externalHtlc bool) error { externalHtlc bool, warning string) error {
totalSuccessMax := l.maxMinerFee + l.maxSwapFee totalSuccessMax := l.maxMinerFee + l.maxSwapFee
if l.maxSwapRoutingFee != nil { if l.maxSwapRoutingFee != nil {
@ -138,6 +140,10 @@ func displayLimits(swapType swap.Type, amt btcutil.Amount, l *limits,
amt, swapType, totalSuccessMax, amt, swapType, totalSuccessMax,
) )
if warning != "" {
fmt.Println(warning)
}
fmt.Printf("CONTINUE SWAP? (y/n), expand fee detail (x): ") fmt.Printf("CONTINUE SWAP? (y/n), expand fee detail (x): ")
var answer string var answer string

@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"sort" "sort"
"time"
"github.com/lightningnetwork/lnd/queue" "github.com/lightningnetwork/lnd/queue"
@ -76,6 +77,9 @@ func (s *swapClientServer) LoopOut(ctx context.Context,
MaxSwapRoutingFee: btcutil.Amount(in.MaxSwapRoutingFee), MaxSwapRoutingFee: btcutil.Amount(in.MaxSwapRoutingFee),
MaxSwapFee: btcutil.Amount(in.MaxSwapFee), MaxSwapFee: btcutil.Amount(in.MaxSwapFee),
SweepConfTarget: sweepConfTarget, SweepConfTarget: sweepConfTarget,
SwapPublicationDeadline: time.Unix(
int64(in.SwapPublicationDeadline), 0,
),
} }
if in.LoopOutChannel != 0 { if in.LoopOutChannel != 0 {
req.LoopOutChannel = &in.LoopOutChannel req.LoopOutChannel = &in.LoopOutChannel

@ -64,8 +64,12 @@ type OutRequest struct {
SweepConfTarget int32 SweepConfTarget int32
// LoopOutChannel optionally specifies the short channel id of the // LoopOutChannel optionally specifies the short channel id of the
// channel to uncharge. // channel to loop out.
LoopOutChannel *uint64 LoopOutChannel *uint64
// SwapPublicationDeadline can be set by the client to allow the server
// delaying publication of the swap HTLC to save on chain fees.
SwapPublicationDeadline time.Time
} }
// Out contains the full details of a loop out request. This includes things // Out contains the full details of a loop out request. This includes things
@ -149,7 +153,7 @@ type LoopInRequest struct {
// MaxSwapFee is the maximum we are willing to pay the server for the // MaxSwapFee is the maximum we are willing to pay the server for the
// swap. This value is not disclosed in the swap initiation call, but if // swap. This value is not disclosed in the swap initiation call, but if
// the server asks for a higher fee, we abort the swap. Typically this // the server asks for a higher fee, we abort the swap. Typically this
// value is taken from the response of the UnchargeQuote call. It // value is taken from the response of the LoopInQuote call. It
// includes the prepay amount. // includes the prepay amount.
MaxSwapFee btcutil.Amount MaxSwapFee btcutil.Amount
@ -157,7 +161,7 @@ type LoopInRequest struct {
// spent. If we publish the on-chain htlc and the fee estimate turns out // spent. If we publish the on-chain htlc and the fee estimate turns out
// higher than this value, we cancel the swap. // higher than this value, we cancel the swap.
// //
// MaxMinerFee is typically taken from the response of the UnchargeQuote // MaxMinerFee is typically taken from the response of the LoopInQuote
// call. // call.
MaxMinerFee btcutil.Amount MaxMinerFee btcutil.Amount
@ -166,7 +170,7 @@ type LoopInRequest struct {
HtlcConfTarget int32 HtlcConfTarget int32
// LoopInChannel optionally specifies the short channel id of the // LoopInChannel optionally specifies the short channel id of the
// channel to charge. // channel to loop in.
LoopInChannel *uint64 LoopInChannel *uint64
// ExternalHtlc specifies whether the htlc is published by an external // ExternalHtlc specifies whether the htlc is published by an external
@ -174,7 +178,7 @@ type LoopInRequest struct {
ExternalHtlc bool ExternalHtlc bool
} }
// LoopInTerms are the server terms on which it executes charge swaps. // LoopInTerms are the server terms on which it executes loop in swaps.
type LoopInTerms struct { type LoopInTerms struct {
// MinSwapAmount is the minimum amount that the server requires for a // MinSwapAmount is the minimum amount that the server requires for a
// swap. // swap.

@ -45,6 +45,12 @@ type LoopOutContract struct {
// MaxPrepayRoutingFee is the maximum off-chain fee in msat that may be // MaxPrepayRoutingFee is the maximum off-chain fee in msat that may be
// paid for the prepayment to the server. // paid for the prepayment to the server.
MaxPrepayRoutingFee btcutil.Amount MaxPrepayRoutingFee btcutil.Amount
// SwapPublicationDeadline is a timestamp that the server commits to
// have the on-chain swap published by. It is set by the client to
// allow the server to delay the publication in exchange for possibly
// lower fees.
SwapPublicationDeadline time.Time
} }
// LoopOut is a combination of the contract and the updates. // LoopOut is a combination of the contract and the updates.
@ -158,6 +164,13 @@ func deserializeLoopOutContract(value []byte, chainParams *chaincfg.Params) (
contract.UnchargeChannel = &unchargeChannel contract.UnchargeChannel = &unchargeChannel
} }
var deadlineNano int64
err = binary.Read(r, byteOrder, &deadlineNano)
if err != nil {
return nil, err
}
contract.SwapPublicationDeadline = time.Unix(0, deadlineNano)
return &contract, nil return &contract, nil
} }
@ -243,5 +256,10 @@ func serializeLoopOutContract(swap *LoopOutContract) (
return nil, err return nil, err
} }
err = binary.Write(&b, byteOrder, swap.SwapPublicationDeadline.UnixNano())
if err != nil {
return nil, err
}
return b.Bytes(), nil return b.Bytes(), nil
} }

@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/btcsuite/btcd/chaincfg"
"github.com/coreos/bbolt" "github.com/coreos/bbolt"
) )
@ -24,14 +25,17 @@ var (
// migration is a function which takes a prior outdated version of the database // migration is a function which takes a prior outdated version of the database
// instances and mutates the key/bucket structure to arrive at a more // instances and mutates the key/bucket structure to arrive at a more
// up-to-date version of the database. // up-to-date version of the database.
type migration func(tx *bbolt.Tx) error type migration func(tx *bbolt.Tx, chainParams *chaincfg.Params) error
var ( var (
// dbVersions is storing all versions of database. If current version // dbVersions is storing all versions of database. If current version
// of database don't match with latest version this list will be used // of database don't match with latest version this list will be used
// for retrieving all migration function that are need to apply to the // for retrieving all migration function that are need to apply to the
// current db. // current db.
migrations = []migration{migrateCosts} migrations = []migration{
migrateCosts,
migrateSwapPublicationDeadline,
}
latestDBVersion = uint32(len(migrations)) latestDBVersion = uint32(len(migrations))
) )
@ -76,7 +80,7 @@ func setDBVersion(tx *bbolt.Tx, version uint32) error {
// syncVersions function is used for safe db version synchronization. It // syncVersions function is used for safe db version synchronization. It
// applies migration functions to the current database and recovers the // applies migration functions to the current database and recovers the
// previous state of db if at least one error/panic appeared during migration. // previous state of db if at least one error/panic appeared during migration.
func syncVersions(db *bbolt.DB) error { func syncVersions(db *bbolt.DB, chainParams *chaincfg.Params) error {
currentVersion, err := getDBVersion(db) currentVersion, err := getDBVersion(db)
if err != nil { if err != nil {
return err return err
@ -112,7 +116,7 @@ func syncVersions(db *bbolt.DB) error {
log.Infof("Applying migration #%v", v+1) log.Infof("Applying migration #%v", v+1)
migration := migrations[v] migration := migrations[v]
if err := migration(tx); err != nil { if err := migration(tx, chainParams); err != nil {
log.Infof("Unable to apply migration #%v", log.Infof("Unable to apply migration #%v",
v+1) v+1)
return err return err

@ -4,12 +4,13 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/btcsuite/btcd/chaincfg"
"github.com/coreos/bbolt" "github.com/coreos/bbolt"
) )
// noMigrationAvailable is the fall back migration in case there is no migration // noMigrationAvailable is the fall back migration in case there is no migration
// implemented. // implemented.
func migrateCosts(tx *bbolt.Tx) error { func migrateCosts(tx *bbolt.Tx, _ *chaincfg.Params) error {
if err := migrateCostsForBucket(tx, loopInBucketKey); err != nil { if err := migrateCostsForBucket(tx, loopInBucketKey); err != nil {
return err return err
} }

@ -0,0 +1,58 @@
package loopdb
import (
"bytes"
"errors"
"fmt"
"github.com/btcsuite/btcd/chaincfg"
"github.com/coreos/bbolt"
)
// migrateSwapPublicationDeadline migrates the database to v02, by adding the
// SwapPublicationDeadline field to loop out contracts.
func migrateSwapPublicationDeadline(tx *bbolt.Tx, chainParams *chaincfg.Params) error {
rootBucket := tx.Bucket(loopOutBucketKey)
if rootBucket == nil {
return errors.New("bucket does not exist")
}
return rootBucket.ForEach(func(swapHash, v []byte) error {
// Only go into things that we know are sub-bucket
// keys.
if v != nil {
return nil
}
// From the root bucket, we'll grab the next swap
// bucket for this swap from its swaphash.
swapBucket := rootBucket.Bucket(swapHash)
if swapBucket == nil {
return fmt.Errorf("swap bucket %x not found",
swapHash)
}
// With the main swap bucket obtained, we'll grab the
// raw swap contract bytes.
contractBytes := swapBucket.Get(contractKey)
if contractBytes == nil {
return errors.New("contract not found")
}
// Write the current contract serialization into a buffer.
b := &bytes.Buffer{}
if _, err := b.Write(contractBytes); err != nil {
return err
}
// We migrate to the new format by copying the first 8 bytes
// (the creation time) to the end (the swap deadline)
var swapDeadline [8]byte
copy(swapDeadline[:], contractBytes[:8])
if _, err := b.Write(swapDeadline[:]); err != nil {
return err
}
return swapBucket.Put(contractKey, b.Bytes())
})
}

@ -135,7 +135,7 @@ func NewBoltSwapStore(dbPath string, chainParams *chaincfg.Params) (
// Finally, before we start, we'll sync the DB versions to pick up any // Finally, before we start, we'll sync the DB versions to pick up any
// possible DB migrations. // possible DB migrations.
err = syncVersions(bdb) err = syncVersions(bdb, chainParams)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -82,12 +82,13 @@ func TestLoopOutStore(t *testing.T) {
// doesn't interfere with DeepEqual. // doesn't interfere with DeepEqual.
InitiationTime: time.Unix(0, initiationTime.UnixNano()), InitiationTime: time.Unix(0, initiationTime.UnixNano()),
}, },
MaxPrepayRoutingFee: 40, MaxPrepayRoutingFee: 40,
PrepayInvoice: "prepayinvoice", PrepayInvoice: "prepayinvoice",
DestAddr: destAddr, DestAddr: destAddr,
SwapInvoice: "swapinvoice", SwapInvoice: "swapinvoice",
MaxSwapRoutingFee: 30, MaxSwapRoutingFee: 30,
SweepConfTarget: 2, SweepConfTarget: 2,
SwapPublicationDeadline: time.Unix(0, initiationTime.UnixNano()),
} }
// checkSwap is a test helper function that'll assert the state of a // checkSwap is a test helper function that'll assert the state of a

@ -79,29 +79,36 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig,
// the server revocation key and the swap and prepay invoices. // the server revocation key and the swap and prepay invoices.
log.Infof("Initiating swap request at height %v", currentHeight) log.Infof("Initiating swap request at height %v", currentHeight)
swapResp, err := cfg.server.NewLoopOutSwap(globalCtx, swapHash, // The swap deadline will be given to the server for it to use as the
request.Amount, receiverKey, // latest swap publication time.
swapResp, err := cfg.server.NewLoopOutSwap(
globalCtx, swapHash, request.Amount, receiverKey,
request.SwapPublicationDeadline,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot initiate swap: %v", err) return nil, fmt.Errorf("cannot initiate swap: %v", err)
} }
err = validateLoopOutContract(cfg.lnd, currentHeight, request, swapHash, swapResp) err = validateLoopOutContract(
cfg.lnd, currentHeight, request, swapHash, swapResp,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Instantiate a struct that contains all required data to start the swap. // Instantiate a struct that contains all required data to start the
// swap.
initiationTime := time.Now() initiationTime := time.Now()
contract := loopdb.LoopOutContract{ contract := loopdb.LoopOutContract{
SwapInvoice: swapResp.swapInvoice, SwapInvoice: swapResp.swapInvoice,
DestAddr: request.DestAddr, DestAddr: request.DestAddr,
MaxSwapRoutingFee: request.MaxSwapRoutingFee, MaxSwapRoutingFee: request.MaxSwapRoutingFee,
SweepConfTarget: request.SweepConfTarget, SweepConfTarget: request.SweepConfTarget,
UnchargeChannel: request.LoopOutChannel, UnchargeChannel: request.LoopOutChannel,
PrepayInvoice: swapResp.prepayInvoice, PrepayInvoice: swapResp.prepayInvoice,
MaxPrepayRoutingFee: request.MaxPrepayRoutingFee, MaxPrepayRoutingFee: request.MaxPrepayRoutingFee,
SwapPublicationDeadline: request.SwapPublicationDeadline,
SwapContract: loopdb.SwapContract{ SwapContract: loopdb.SwapContract{
InitiationHeight: currentHeight, InitiationHeight: currentHeight,
InitiationTime: initiationTime, InitiationTime: initiationTime,

@ -158,10 +158,17 @@ type LoopOutRequest struct {
//* //*
//The number of blocks from the on-chain HTLC's confirmation height that it //The number of blocks from the on-chain HTLC's confirmation height that it
//should be swept within. //should be swept within.
SweepConfTarget int32 `protobuf:"varint,9,opt,name=sweep_conf_target,json=sweepConfTarget,proto3" json:"sweep_conf_target,omitempty"` 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:"-"` //The latest time (in unix seconds) we allow the server to wait before
XXX_sizecache int32 `json:"-"` //publishing the HTLC on chain. Setting this to a larger value will give the
//server the opportunity to batch multiple swaps together, and wait for
//low-fee periods before publishing the HTLC, potentially resulting in a
//lower total swap fee.
SwapPublicationDeadline uint64 `protobuf:"varint,10,opt,name=swap_publication_deadline,json=swapPublicationDeadline,proto3" json:"swap_publication_deadline,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *LoopOutRequest) Reset() { *m = LoopOutRequest{} } func (m *LoopOutRequest) Reset() { *m = LoopOutRequest{} }
@ -252,6 +259,13 @@ func (m *LoopOutRequest) GetSweepConfTarget() int32 {
return 0 return 0
} }
func (m *LoopOutRequest) GetSwapPublicationDeadline() uint64 {
if m != nil {
return m.SwapPublicationDeadline
}
return 0
}
type LoopInRequest struct { type LoopInRequest struct {
//* //*
//Requested swap amount in sat. This does not include the swap and miner //Requested swap amount in sat. This does not include the swap and miner
@ -804,74 +818,76 @@ func init() {
func init() { proto.RegisterFile("client.proto", fileDescriptor_014de31d7ac8c57c) } func init() { proto.RegisterFile("client.proto", fileDescriptor_014de31d7ac8c57c) }
var fileDescriptor_014de31d7ac8c57c = []byte{ var fileDescriptor_014de31d7ac8c57c = []byte{
// 1061 bytes of a gzipped FileDescriptorProto // 1096 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x4f, 0x73, 0xda, 0x46, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0x4f, 0x73, 0xda, 0xc6,
0x1c, 0x8d, 0x40, 0x18, 0xf1, 0xb3, 0x90, 0xc5, 0x3a, 0x71, 0x08, 0x6d, 0x26, 0x94, 0x36, 0x29, 0x1b, 0x8e, 0x40, 0x18, 0xf1, 0x5a, 0xc8, 0x62, 0x9d, 0xd8, 0x98, 0xdf, 0x2f, 0x13, 0xaa, 0x36,
0xe3, 0x83, 0x69, 0x9d, 0x53, 0x7b, 0xa3, 0x98, 0xc4, 0x78, 0x6c, 0xe3, 0x0a, 0x9c, 0x99, 0xf6, 0x29, 0xe3, 0x43, 0x68, 0x93, 0x53, 0x73, 0xa3, 0x40, 0x12, 0x3c, 0xb6, 0xa1, 0x02, 0x67, 0xa6,
0xa2, 0x6e, 0x61, 0xb1, 0x35, 0x83, 0x76, 0x15, 0x69, 0xf1, 0x9f, 0xe9, 0xe4, 0xd2, 0xaf, 0xd0, 0xbd, 0xa8, 0x1b, 0x58, 0x6c, 0xcd, 0x48, 0x2b, 0x45, 0x5a, 0xfc, 0x67, 0x3a, 0xb9, 0xf4, 0x2b,
0x4f, 0xd2, 0x99, 0x7e, 0x93, 0xde, 0x7b, 0xea, 0xf4, 0x73, 0x74, 0xf6, 0xb7, 0x42, 0x16, 0x26, 0xf4, 0xd6, 0x6f, 0xd1, 0x99, 0x7e, 0x93, 0xde, 0x7b, 0xea, 0xf4, 0x73, 0x74, 0xf6, 0x5d, 0x81,
0xbe, 0xe4, 0x66, 0x9e, 0xde, 0xbe, 0xdf, 0x1f, 0xbd, 0xb7, 0x32, 0xd8, 0x93, 0x79, 0xc0, 0xb8, 0x85, 0x89, 0x2f, 0xb9, 0x99, 0x67, 0x9f, 0x7d, 0xde, 0x3f, 0xfb, 0xbc, 0xaf, 0x0c, 0xe6, 0x34,
0xdc, 0x8b, 0x62, 0x21, 0x05, 0x29, 0xcf, 0x85, 0x88, 0xe2, 0x68, 0xd2, 0xf8, 0xfc, 0x42, 0x88, 0xf0, 0x19, 0x17, 0xcf, 0xe3, 0x24, 0x12, 0x11, 0x29, 0x07, 0x51, 0x14, 0x27, 0xf1, 0xb4, 0xf1,
0x8b, 0x39, 0xeb, 0xd0, 0x28, 0xe8, 0x50, 0xce, 0x85, 0xa4, 0x32, 0x10, 0x3c, 0xd1, 0xb4, 0xd6, 0xff, 0xf3, 0x28, 0x3a, 0x0f, 0x58, 0x9b, 0xc6, 0x7e, 0x9b, 0x72, 0x1e, 0x09, 0x2a, 0xfc, 0x88,
0x3f, 0x05, 0x70, 0x8e, 0x85, 0x88, 0x86, 0x0b, 0xe9, 0xb1, 0xf7, 0x0b, 0x96, 0x48, 0xe2, 0x42, 0xa7, 0x8a, 0xe6, 0xfc, 0x5e, 0x04, 0xeb, 0x38, 0x8a, 0xe2, 0xe1, 0x42, 0xb8, 0xec, 0xc3, 0x82,
0x91, 0x86, 0xb2, 0x6e, 0x34, 0x8d, 0x76, 0xd1, 0x53, 0x7f, 0x12, 0x02, 0xe6, 0x94, 0x25, 0xb2, 0xa5, 0x82, 0xd8, 0x50, 0xa4, 0xa1, 0xa8, 0x6b, 0x4d, 0xad, 0x55, 0x74, 0xe5, 0x9f, 0x84, 0x80,
0x5e, 0x68, 0x1a, 0xed, 0x8a, 0x87, 0x7f, 0x93, 0x0e, 0x3c, 0x0e, 0xe9, 0x8d, 0x9f, 0x5c, 0xd3, 0x3e, 0x63, 0xa9, 0xa8, 0x17, 0x9a, 0x5a, 0xab, 0xe2, 0xe2, 0xdf, 0xa4, 0x0d, 0x0f, 0x43, 0x7a,
0xc8, 0x8f, 0xc5, 0x42, 0x06, 0xfc, 0xc2, 0x9f, 0x31, 0x56, 0x2f, 0xe2, 0xb1, 0x5a, 0x48, 0x6f, 0xed, 0xa5, 0x57, 0x34, 0xf6, 0x92, 0x68, 0x21, 0x7c, 0x7e, 0xee, 0xcd, 0x19, 0xab, 0x17, 0xf1,
0x46, 0xd7, 0x34, 0xf2, 0xf4, 0x93, 0x37, 0x8c, 0x91, 0xd7, 0xb0, 0xa3, 0x0e, 0x44, 0x31, 0x8b, 0x5a, 0x2d, 0xa4, 0xd7, 0xe3, 0x2b, 0x1a, 0xbb, 0xea, 0xe4, 0x35, 0x63, 0xe4, 0x25, 0xec, 0xc9,
0xe8, 0xed, 0xca, 0x11, 0x13, 0x8f, 0x6c, 0x87, 0xf4, 0xe6, 0x0c, 0x1f, 0xe6, 0x0e, 0x35, 0xc1, 0x0b, 0x71, 0xc2, 0x62, 0x7a, 0xb3, 0x76, 0x45, 0xc7, 0x2b, 0xbb, 0x21, 0xbd, 0x1e, 0xe1, 0x61,
0xce, 0xaa, 0x28, 0x6a, 0x09, 0xa9, 0x90, 0xaa, 0x2b, 0xc6, 0x57, 0xe0, 0xe4, 0x64, 0x55, 0xe3, 0xee, 0x52, 0x13, 0xcc, 0x55, 0x14, 0x49, 0x2d, 0x21, 0x15, 0x32, 0x75, 0xc9, 0xf8, 0x0a, 0xac,
0x1b, 0xc8, 0xb1, 0x33, 0xb9, 0x6e, 0x28, 0x49, 0x0b, 0xaa, 0x8a, 0x15, 0x06, 0x9c, 0xc5, 0x28, 0x9c, 0xac, 0x4c, 0x7c, 0x0b, 0x39, 0xe6, 0x4a, 0xae, 0x13, 0x0a, 0xe2, 0x40, 0x55, 0xb2, 0x42,
0x54, 0x46, 0xd2, 0x66, 0x48, 0x6f, 0x4e, 0x14, 0xa6, 0x94, 0xda, 0xe0, 0xaa, 0x9d, 0xf9, 0x62, 0x9f, 0xb3, 0x04, 0x85, 0xca, 0x48, 0xda, 0x0e, 0xe9, 0xf5, 0x89, 0xc4, 0xa4, 0x52, 0x0b, 0x6c,
0x21, 0xfd, 0xc9, 0x25, 0xe5, 0x9c, 0xcd, 0xeb, 0x56, 0xd3, 0x68, 0x9b, 0x9e, 0x33, 0xd7, 0x1b, 0xd9, 0x33, 0x2f, 0x5a, 0x08, 0x6f, 0x7a, 0x41, 0x39, 0x67, 0x41, 0xdd, 0x68, 0x6a, 0x2d, 0xdd,
0xea, 0x69, 0x94, 0xec, 0x42, 0x2d, 0xb9, 0x66, 0x2c, 0xf2, 0x27, 0x82, 0xcf, 0x7c, 0x49, 0xe3, 0xb5, 0x02, 0xd5, 0xa1, 0xae, 0x42, 0xc9, 0x21, 0xd4, 0xd2, 0x2b, 0xc6, 0x62, 0x6f, 0x1a, 0xf1,
0x0b, 0x26, 0xeb, 0x95, 0xa6, 0xd1, 0x2e, 0x79, 0x5b, 0xf8, 0xa0, 0x27, 0xf8, 0x6c, 0x8c, 0x70, 0xb9, 0x27, 0x68, 0x72, 0xce, 0x44, 0xbd, 0xd2, 0xd4, 0x5a, 0x25, 0x77, 0x07, 0x0f, 0xba, 0x11,
0xeb, 0x2f, 0x03, 0xaa, 0x6a, 0xc1, 0x03, 0xfe, 0xf0, 0x7e, 0xef, 0x4f, 0x59, 0x58, 0x9b, 0x72, 0x9f, 0x4f, 0x10, 0x26, 0xaf, 0xe0, 0x00, 0xb3, 0x8f, 0x17, 0xef, 0x03, 0x7f, 0x8a, 0xbd, 0xf7,
0xad, 0xff, 0xe2, 0x7a, 0xff, 0xaf, 0x60, 0x0b, 0xfb, 0x0f, 0x78, 0xd6, 0xbe, 0x89, 0xed, 0x57, 0x66, 0x8c, 0xce, 0x02, 0x9f, 0xb3, 0x3a, 0xa0, 0xfc, 0xbe, 0x24, 0x8c, 0x6e, 0xcf, 0x7b, 0xd9,
0xe7, 0x58, 0x7f, 0xd9, 0xfd, 0x97, 0x50, 0x65, 0x37, 0x92, 0xc5, 0x9c, 0xce, 0xfd, 0x4b, 0x39, 0xb1, 0xf3, 0xa7, 0x06, 0x55, 0xf9, 0x38, 0x03, 0x7e, 0xff, 0xdb, 0xdc, 0xed, 0x50, 0x61, 0xa3,
0x9f, 0xe0, 0x52, 0x2d, 0xcf, 0x5e, 0x82, 0x87, 0x72, 0x3e, 0x69, 0x75, 0xc1, 0xc6, 0xf7, 0xc7, 0x43, 0x1b, 0xb5, 0x17, 0x37, 0x6b, 0x7f, 0x06, 0x3b, 0x58, 0xbb, 0xcf, 0x57, 0xa5, 0xeb, 0x98,
0x92, 0x48, 0xf0, 0x84, 0x11, 0x07, 0x0a, 0xc1, 0x14, 0x7b, 0xae, 0x78, 0x85, 0x60, 0x4a, 0xbe, 0x5b, 0x35, 0xc0, 0xf8, 0xcb, 0xca, 0xbf, 0x84, 0x2a, 0xbb, 0x16, 0x2c, 0xe1, 0x34, 0xf0, 0x2e,
0x00, 0x5b, 0x9d, 0xf5, 0xe9, 0x74, 0x1a, 0xb3, 0x24, 0x49, 0xad, 0xb1, 0xa9, 0xb0, 0xae, 0x86, 0x44, 0x30, 0xc5, 0x07, 0x31, 0x5c, 0x73, 0x09, 0xbe, 0x15, 0xc1, 0xd4, 0xe9, 0x80, 0x89, 0x6f,
0x5a, 0x2e, 0x38, 0x27, 0x82, 0x07, 0x52, 0xc4, 0xe9, 0xe4, 0xca, 0x6c, 0xa0, 0x54, 0x47, 0x92, 0xcf, 0xd2, 0x38, 0xe2, 0x29, 0x23, 0x16, 0x14, 0xfc, 0x19, 0xe6, 0x5c, 0x71, 0x0b, 0xfe, 0x8c,
0xca, 0x45, 0xf2, 0x91, 0x45, 0xe8, 0x2a, 0x85, 0xac, 0xca, 0x4b, 0x30, 0xe5, 0x6d, 0xa4, 0xa7, 0x7c, 0x01, 0xa6, 0xbc, 0xeb, 0xd1, 0xd9, 0x2c, 0x61, 0x69, 0x9a, 0xd9, 0x6a, 0x5b, 0x62, 0x1d,
0x75, 0xf6, 0x6b, 0x7b, 0xa9, 0xa7, 0xf7, 0x94, 0xc8, 0xf8, 0x36, 0x62, 0x1e, 0x3e, 0x26, 0x6d, 0x05, 0x39, 0x36, 0x58, 0x27, 0x11, 0xf7, 0x45, 0x94, 0x64, 0x95, 0x3b, 0x7f, 0x17, 0x00, 0xa4,
0x28, 0x25, 0x92, 0x4a, 0xed, 0x24, 0x67, 0x9f, 0xac, 0xf0, 0x54, 0x31, 0xe6, 0x69, 0x02, 0xf9, 0xea, 0x58, 0x50, 0xb1, 0x48, 0x3f, 0xd1, 0x08, 0x15, 0xa5, 0xb0, 0x8a, 0xf2, 0x14, 0x74, 0x71,
0x1a, 0xb6, 0x02, 0x1e, 0xc8, 0x00, 0x33, 0xe0, 0xcb, 0x20, 0x5c, 0x5a, 0xca, 0xb9, 0x83, 0xc7, 0x13, 0xab, 0x6a, 0xad, 0x17, 0xb5, 0xe7, 0xd9, 0x3c, 0x3c, 0x97, 0x22, 0x93, 0x9b, 0x98, 0xb9,
0x41, 0xa8, 0xcd, 0x40, 0x13, 0xe9, 0x2f, 0xa2, 0x29, 0x95, 0x4c, 0x33, 0xb5, 0xb1, 0x1c, 0x85, 0x78, 0x4c, 0x5a, 0x50, 0x4a, 0x05, 0x15, 0xca, 0x85, 0xd6, 0x0b, 0xb2, 0xc6, 0x93, 0xc1, 0x98,
0x9f, 0x23, 0x8c, 0xcc, 0xfb, 0x9b, 0x28, 0xaf, 0x6d, 0x82, 0xbc, 0x80, 0xcd, 0x89, 0x48, 0xa4, 0xab, 0x08, 0xe4, 0x6b, 0xd8, 0xf1, 0xb9, 0x2f, 0x7c, 0xf5, 0x86, 0xc2, 0x0f, 0x97, 0x76, 0xb4,
0x9f, 0xb0, 0xf8, 0x8a, 0xc5, 0x68, 0xaa, 0xa2, 0x07, 0x0a, 0x1a, 0x21, 0xa2, 0x34, 0x90, 0x20, 0x6e, 0xe1, 0x89, 0x1f, 0x2a, 0x23, 0xd1, 0x54, 0x78, 0x8b, 0x78, 0x46, 0x05, 0x53, 0x4c, 0x65,
0xf8, 0xe4, 0x92, 0x06, 0x1c, 0xbd, 0x54, 0xf4, 0xf0, 0xd0, 0x50, 0x43, 0xea, 0xad, 0x69, 0xca, 0x4a, 0x4b, 0xe2, 0x67, 0x08, 0x23, 0xf3, 0x6e, 0x27, 0xca, 0x1b, 0x9d, 0x20, 0x4f, 0x60, 0x7b,
0x6c, 0xa6, 0x39, 0xa0, 0x6d, 0x8e, 0x9c, 0x14, 0x6b, 0x39, 0x60, 0x8f, 0x59, 0x1c, 0x26, 0xcb, 0x1a, 0xa5, 0xc2, 0x4b, 0x59, 0x72, 0xc9, 0x12, 0x34, 0x64, 0xd1, 0x05, 0x09, 0x8d, 0x11, 0x91,
0x85, 0x7f, 0x80, 0x6a, 0xfa, 0x3b, 0x7d, 0x8d, 0xaf, 0x60, 0x2b, 0x0c, 0xb8, 0x76, 0x1a, 0x0d, 0x1a, 0x48, 0x88, 0xf8, 0xf4, 0x82, 0xfa, 0x1c, 0x7d, 0x58, 0x74, 0xf1, 0xd2, 0x50, 0x41, 0xf2,
0xc5, 0x82, 0xcb, 0x74, 0xfe, 0x6a, 0x18, 0x70, 0xb5, 0xad, 0x2e, 0x82, 0xc8, 0x5b, 0x3a, 0x32, 0xd5, 0x14, 0x65, 0x3e, 0x57, 0x1c, 0x50, 0x23, 0x82, 0x9c, 0x0c, 0x73, 0x2c, 0x30, 0x27, 0x2c,
0xe5, 0x6d, 0xa4, 0x3c, 0x6d, 0x4a, 0xcd, 0x3b, 0x32, 0x2d, 0xc3, 0x2d, 0x1c, 0x99, 0x56, 0xc1, 0x09, 0xd3, 0x65, 0xc3, 0x3f, 0x42, 0x35, 0xfb, 0x9d, 0x3d, 0xe3, 0x33, 0xd8, 0x09, 0x7d, 0xae,
0x2d, 0x1e, 0x99, 0x56, 0xd1, 0x35, 0x8f, 0x4c, 0xcb, 0x74, 0x4b, 0x47, 0xa6, 0x55, 0x76, 0xad, 0x9c, 0x46, 0xc3, 0x68, 0xc1, 0x45, 0x56, 0x7f, 0x35, 0xf4, 0xb9, 0xec, 0x56, 0x07, 0x41, 0xe4,
0xd6, 0x0c, 0xec, 0x1f, 0x17, 0x42, 0xb2, 0x87, 0x9d, 0x8f, 0x9b, 0xb9, 0xcb, 0x50, 0x01, 0x33, 0x2d, 0x1d, 0x99, 0xf1, 0xb6, 0x32, 0x9e, 0x32, 0xa5, 0xe2, 0x1d, 0xe9, 0x86, 0x66, 0x17, 0x8e,
0x04, 0x93, 0x2c, 0x3e, 0xeb, 0x66, 0x2d, 0x7e, 0xc4, 0xac, 0x7f, 0x1a, 0x50, 0x4d, 0x0b, 0xa5, 0x74, 0xa3, 0x60, 0x17, 0x8f, 0x74, 0xa3, 0x68, 0xeb, 0x47, 0xba, 0xa1, 0xdb, 0xa5, 0x23, 0xdd,
0x73, 0x3e, 0x03, 0x2b, 0x4b, 0x93, 0x2e, 0x57, 0x4e, 0xd2, 0x28, 0x3d, 0x07, 0xc8, 0x5d, 0x16, 0x28, 0xdb, 0x86, 0x33, 0x07, 0xf3, 0x87, 0x45, 0x24, 0xd8, 0xfd, 0xce, 0xc7, 0xce, 0xdc, 0xce,
0x3a, 0x6a, 0x95, 0x28, 0xbb, 0x29, 0x3e, 0x83, 0xca, 0xfd, 0x94, 0x59, 0xe1, 0x32, 0x62, 0x18, 0x5f, 0x01, 0xe7, 0x0f, 0xa6, 0xb7, 0xa3, 0xb7, 0x61, 0xd6, 0xe2, 0x27, 0xcc, 0xfa, 0x87, 0x06,
0x7c, 0x1a, 0xf9, 0x11, 0xbd, 0x0d, 0x19, 0x97, 0x3e, 0xde, 0x8a, 0xca, 0x74, 0xb6, 0x0a, 0x3e, 0xd5, 0x2c, 0x50, 0x56, 0xe7, 0x01, 0x18, 0xab, 0x69, 0x52, 0xe1, 0xca, 0x69, 0x36, 0x4a, 0x8f,
0x8d, 0xce, 0x34, 0x7e, 0xa0, 0x86, 0x7d, 0x0e, 0x30, 0x99, 0xcb, 0x2b, 0x7f, 0xca, 0xe6, 0x92, 0x01, 0x72, 0x8b, 0x46, 0x8d, 0x5a, 0x25, 0x5e, 0x6d, 0x99, 0xff, 0x41, 0xe5, 0xee, 0x94, 0x19,
0xe2, 0x96, 0x4b, 0x5e, 0x45, 0x21, 0x07, 0x0a, 0xd8, 0x7d, 0x09, 0xd6, 0xd2, 0xc5, 0xc4, 0x06, 0xe1, 0x72, 0xc4, 0x70, 0x69, 0xc8, 0x45, 0x40, 0x6f, 0x42, 0xc6, 0x85, 0x87, 0x1b, 0x55, 0x9a,
0xeb, 0x78, 0x38, 0x3c, 0xf3, 0x87, 0xe7, 0x63, 0xf7, 0x11, 0xd9, 0x84, 0x32, 0xfe, 0x1a, 0x9c, 0xce, 0x94, 0x4b, 0x83, 0xc6, 0x23, 0x85, 0xf7, 0x64, 0xb1, 0x8f, 0x01, 0xa6, 0x81, 0xb8, 0xf4,
0xba, 0xc6, 0x6e, 0x02, 0x95, 0xcc, 0xc4, 0xa4, 0x0a, 0x95, 0xc1, 0xe9, 0x60, 0x3c, 0xe8, 0x8e, 0x66, 0x2c, 0x10, 0x14, 0xbb, 0x5c, 0x72, 0x2b, 0x12, 0xe9, 0x49, 0xe0, 0xf0, 0x29, 0x18, 0x4b,
0xfb, 0x07, 0xee, 0x23, 0xf2, 0x04, 0x6a, 0x67, 0x5e, 0x7f, 0x70, 0xd2, 0x7d, 0xdb, 0xf7, 0xbd, 0x17, 0x13, 0x13, 0x8c, 0xe3, 0xe1, 0x70, 0xe4, 0x0d, 0xcf, 0x26, 0xf6, 0x03, 0xb2, 0x0d, 0x65,
0xfe, 0xbb, 0x7e, 0xf7, 0xb8, 0x7f, 0xe0, 0x1a, 0x84, 0x80, 0x73, 0x38, 0x3e, 0xee, 0xf9, 0x67, 0xfc, 0x35, 0x38, 0xb5, 0xb5, 0xc3, 0x14, 0x2a, 0x2b, 0x13, 0x93, 0x2a, 0x54, 0x06, 0xa7, 0x83,
0xe7, 0x3f, 0x1c, 0x0f, 0x46, 0x87, 0xfd, 0x03, 0xb7, 0xa0, 0x34, 0x47, 0xe7, 0xbd, 0x5e, 0x7f, 0xc9, 0xa0, 0x33, 0xe9, 0xf7, 0xec, 0x07, 0xe4, 0x11, 0xd4, 0x46, 0x6e, 0x7f, 0x70, 0xd2, 0x79,
0x34, 0x72, 0x8b, 0x04, 0x60, 0xe3, 0x4d, 0x77, 0xa0, 0xc8, 0x26, 0xd9, 0x86, 0xad, 0xc1, 0xe9, 0xd3, 0xf7, 0xdc, 0xfe, 0xbb, 0x7e, 0xe7, 0xb8, 0xdf, 0xb3, 0x35, 0x42, 0xc0, 0x7a, 0x3b, 0x39,
0xbb, 0xe1, 0xa0, 0xd7, 0xf7, 0x47, 0xfd, 0xf1, 0x58, 0x81, 0xa5, 0xfd, 0xff, 0x4c, 0x9d, 0xd3, 0xee, 0x7a, 0xa3, 0xb3, 0xef, 0x8f, 0x07, 0xe3, 0xb7, 0xfd, 0x9e, 0x5d, 0x90, 0x9a, 0xe3, 0xb3,
0x1e, 0x7e, 0x50, 0x88, 0x07, 0xe5, 0xf4, 0x13, 0x41, 0x9e, 0x66, 0xd1, 0x5a, 0xfd, 0x68, 0x34, 0x6e, 0xb7, 0x3f, 0x1e, 0xdb, 0x45, 0x02, 0xb0, 0xf5, 0xba, 0x33, 0x90, 0x64, 0x9d, 0xec, 0xc2,
0x9e, 0xac, 0x64, 0x6e, 0xf9, 0x1e, 0x5a, 0x4f, 0x7f, 0xff, 0xfb, 0xdf, 0x3f, 0x0a, 0xb5, 0x96, 0xce, 0xe0, 0xf4, 0xdd, 0x70, 0xd0, 0xed, 0x7b, 0xe3, 0xfe, 0x64, 0x22, 0xc1, 0xd2, 0x8b, 0x7f,
0xdd, 0xb9, 0xfa, 0xb6, 0xa3, 0x18, 0x1d, 0xb1, 0x90, 0xdf, 0x1b, 0xbb, 0x64, 0x08, 0x1b, 0xfa, 0x75, 0x35, 0xa7, 0x5d, 0xfc, 0x18, 0x11, 0x17, 0xca, 0xd9, 0xe7, 0x85, 0xec, 0xaf, 0x46, 0x6b,
0x56, 0x24, 0x3b, 0x2b, 0x92, 0xd9, 0x35, 0xf9, 0x90, 0xe2, 0x0e, 0x2a, 0xba, 0xad, 0xcd, 0x4c, 0xfd, 0x83, 0xd3, 0x78, 0xb4, 0x36, 0x73, 0xcb, 0x77, 0x70, 0xf6, 0x7f, 0xfd, 0xeb, 0x9f, 0xdf,
0x31, 0xe0, 0x4a, 0xf0, 0x3b, 0x28, 0xa7, 0xb7, 0x4d, 0xae, 0xc9, 0xd5, 0xfb, 0xa7, 0xb1, 0xbd, 0x0a, 0x35, 0xc7, 0x6c, 0x5f, 0x7e, 0xdb, 0x96, 0x8c, 0x76, 0xb4, 0x10, 0xaf, 0xb4, 0x43, 0x32,
0x76, 0x31, 0x2c, 0x92, 0x6f, 0x0c, 0xf2, 0x13, 0xd8, 0xe9, 0x34, 0x18, 0x16, 0x72, 0x57, 0x39, 0x84, 0x2d, 0xb5, 0x15, 0xc9, 0xde, 0x9a, 0xe4, 0x6a, 0x4d, 0xde, 0xa7, 0xb8, 0x87, 0x8a, 0xb6,
0x1f, 0xa6, 0xc6, 0xce, 0x7d, 0x38, 0xed, 0xa8, 0x81, 0x1d, 0x3d, 0x26, 0x24, 0x3f, 0x63, 0x47, 0xb3, 0xbd, 0x52, 0xf4, 0xb9, 0x14, 0xfc, 0x0e, 0xca, 0xd9, 0xb6, 0xc9, 0x25, 0xb9, 0xbe, 0x7f,
0xa2, 0x94, 0x9f, 0x49, 0xa3, 0x3f, 0x73, 0xd2, 0xf9, 0x60, 0xe4, 0xa4, 0x57, 0x6c, 0xdc, 0x6a, 0x1a, 0xbb, 0x1b, 0x8b, 0x61, 0x91, 0x7e, 0xa3, 0x91, 0x1f, 0xc1, 0xcc, 0xaa, 0xc1, 0x61, 0x21,
0xa2, 0x74, 0x83, 0xd4, 0x57, 0xa4, 0xdf, 0x2b, 0x4e, 0xe7, 0x37, 0x1a, 0xca, 0x0f, 0xe4, 0x67, 0xb7, 0x91, 0xf3, 0xc3, 0xd4, 0xd8, 0xbb, 0x0b, 0x67, 0x19, 0x35, 0x30, 0xa3, 0x87, 0x84, 0xe4,
0x70, 0xde, 0x32, 0xa9, 0x37, 0xf7, 0x49, 0xdd, 0x3f, 0xc3, 0x12, 0xdb, 0xa4, 0x96, 0xdb, 0x67, 0x6b, 0x6c, 0x0b, 0x94, 0xf2, 0x56, 0xd2, 0xe8, 0xcf, 0x9c, 0x74, 0x7e, 0x30, 0x72, 0xd2, 0x6b,
0xda, 0xfc, 0x2f, 0x39, 0xed, 0x4f, 0x6a, 0xff, 0x05, 0x6a, 0x3f, 0x23, 0x4f, 0xf3, 0xda, 0xb9, 0x36, 0x76, 0x9a, 0x28, 0xdd, 0x20, 0xf5, 0x35, 0xe9, 0x0f, 0x92, 0xd3, 0xfe, 0x85, 0x86, 0xe2,
0xee, 0x7f, 0xdd, 0xc0, 0x7f, 0x42, 0x5e, 0xff, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x26, 0x06, 0x26, 0x23, 0xf9, 0x09, 0xac, 0x37, 0x4c, 0xa8, 0xce, 0x7d, 0x56, 0xf6, 0x07, 0x18, 0x62, 0x97, 0xd4,
0x30, 0xbb, 0x08, 0x00, 0x00, 0x72, 0xfd, 0xcc, 0x92, 0xff, 0x39, 0xa7, 0xfd, 0x59, 0xe9, 0x3f, 0x41, 0xed, 0x03, 0xb2, 0x9f,
0xd7, 0xce, 0x65, 0xff, 0x7e, 0x0b, 0xff, 0x81, 0x79, 0xf9, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff,
0xc2, 0x6b, 0xe2, 0x2f, 0xf7, 0x08, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.

@ -146,6 +146,15 @@ message LoopOutRequest {
should be swept within. should be swept within.
*/ */
int32 sweep_conf_target = 9; int32 sweep_conf_target = 9;
/**
The latest time (in unix seconds) we allow the server to wait before
publishing the HTLC on chain. Setting this to a larger value will give the
server the opportunity to batch multiple swaps together, and wait for
low-fee periods before publishing the HTLC, potentially resulting in a
lower total swap fee.
*/
uint64 swap_publication_deadline = 10;
} }
message LoopInRequest { message LoopInRequest {

@ -265,6 +265,11 @@
"type": "integer", "type": "integer",
"format": "int32", "format": "int32",
"description": "*\nThe number of blocks from the on-chain HTLC's confirmation height that it\nshould be swept within." "description": "*\nThe number of blocks from the on-chain HTLC's confirmation height that it\nshould be swept within."
},
"swap_publication_deadline": {
"type": "string",
"format": "uint64",
"description": "*\nThe latest time (in unix seconds) we allow the server to wait before\npublishing the HTLC on chain. Setting this to a larger value will give the\nserver the opportunity to batch multiple swaps together, and wait for\nlow-fee periods before publishing the HTLC, potentially resulting in a\nlower total swap fee."
} }
} }
}, },

@ -24,12 +24,14 @@ var _ = math.Inf
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type ServerLoopOutRequest struct { type ServerLoopOutRequest struct {
ReceiverKey []byte `protobuf:"bytes,1,opt,name=receiver_key,json=receiverKey,proto3" json:"receiver_key,omitempty"` ReceiverKey []byte `protobuf:"bytes,1,opt,name=receiver_key,json=receiverKey,proto3" json:"receiver_key,omitempty"`
SwapHash []byte `protobuf:"bytes,2,opt,name=swap_hash,json=swapHash,proto3" json:"swap_hash,omitempty"` SwapHash []byte `protobuf:"bytes,2,opt,name=swap_hash,json=swapHash,proto3" json:"swap_hash,omitempty"`
Amt uint64 `protobuf:"varint,3,opt,name=amt,proto3" json:"amt,omitempty"` Amt uint64 `protobuf:"varint,3,opt,name=amt,proto3" json:"amt,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` /// The unix time in seconds we want the on-chain swap to be published by.
XXX_unrecognized []byte `json:"-"` SwapPublicationDeadline int64 `protobuf:"varint,4,opt,name=swap_publication_deadline,json=swapPublicationDeadline,proto3" json:"swap_publication_deadline,omitempty"`
XXX_sizecache int32 `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *ServerLoopOutRequest) Reset() { *m = ServerLoopOutRequest{} } func (m *ServerLoopOutRequest) Reset() { *m = ServerLoopOutRequest{} }
@ -78,6 +80,13 @@ func (m *ServerLoopOutRequest) GetAmt() uint64 {
return 0 return 0
} }
func (m *ServerLoopOutRequest) GetSwapPublicationDeadline() int64 {
if m != nil {
return m.SwapPublicationDeadline
}
return 0
}
type ServerLoopOutResponse struct { type ServerLoopOutResponse struct {
SwapInvoice string `protobuf:"bytes,1,opt,name=swap_invoice,json=swapInvoice,proto3" json:"swap_invoice,omitempty"` SwapInvoice string `protobuf:"bytes,1,opt,name=swap_invoice,json=swapInvoice,proto3" json:"swap_invoice,omitempty"`
PrepayInvoice string `protobuf:"bytes,2,opt,name=prepay_invoice,json=prepayInvoice,proto3" json:"prepay_invoice,omitempty"` PrepayInvoice string `protobuf:"bytes,2,opt,name=prepay_invoice,json=prepayInvoice,proto3" json:"prepay_invoice,omitempty"`
@ -671,48 +680,50 @@ func init() {
func init() { proto.RegisterFile("server.proto", fileDescriptor_ad098daeda4239f7) } func init() { proto.RegisterFile("server.proto", fileDescriptor_ad098daeda4239f7) }
var fileDescriptor_ad098daeda4239f7 = []byte{ var fileDescriptor_ad098daeda4239f7 = []byte{
// 641 bytes of a gzipped FileDescriptorProto // 674 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0x6b, 0x4e, 0xdb, 0x4c, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0xdd, 0x4e, 0xdb, 0x4c,
0x14, 0x95, 0xed, 0x10, 0xbe, 0x5c, 0x12, 0xf8, 0x98, 0x3e, 0x64, 0x02, 0xa9, 0xc0, 0x52, 0x11, 0x10, 0x95, 0xed, 0x10, 0xbe, 0x0c, 0x09, 0x7c, 0x6c, 0xff, 0x4c, 0x20, 0x15, 0x58, 0x2a, 0x42,
0x42, 0x2d, 0x48, 0xed, 0x0a, 0xa8, 0x10, 0x2a, 0x2a, 0x2a, 0xc5, 0xf0, 0xdf, 0x9a, 0x26, 0xb7, 0xa8, 0x05, 0xa9, 0xbd, 0xeb, 0x1d, 0x15, 0x42, 0x45, 0x45, 0xa5, 0x18, 0xee, 0xad, 0x25, 0x99,
0xc4, 0x6a, 0xec, 0x99, 0xda, 0x93, 0x40, 0x36, 0xd0, 0x35, 0xb4, 0x0b, 0xeb, 0x42, 0xba, 0x83, 0x82, 0xd5, 0x78, 0x77, 0x6b, 0x6f, 0x02, 0x79, 0x81, 0x3e, 0x43, 0x7b, 0xdf, 0x57, 0xea, 0x83,
0x6a, 0x1e, 0x26, 0x7e, 0x42, 0x91, 0xfa, 0x8f, 0x39, 0xf7, 0x70, 0xef, 0xb9, 0x67, 0xce, 0x38, 0xf4, 0x0d, 0xaa, 0xfd, 0x31, 0xb1, 0x9d, 0x84, 0x14, 0xa9, 0x77, 0xec, 0x99, 0xc3, 0xec, 0x99,
0xd0, 0x4d, 0x31, 0x99, 0x61, 0x72, 0xc0, 0x13, 0x26, 0x18, 0x59, 0x9e, 0x30, 0xc6, 0x13, 0x3e, 0x33, 0x67, 0x1d, 0x68, 0x66, 0x98, 0x0e, 0x31, 0xdd, 0x13, 0x29, 0x97, 0x9c, 0x2c, 0xf6, 0x39,
0xec, 0x6f, 0x5d, 0x33, 0x76, 0x3d, 0xc1, 0x43, 0xca, 0xc3, 0x43, 0x1a, 0xc7, 0x4c, 0x50, 0x11, 0x17, 0xa9, 0xe8, 0xb6, 0x37, 0xae, 0x38, 0xbf, 0xea, 0xe3, 0x3e, 0x15, 0xf1, 0x3e, 0x65, 0x8c,
0xb2, 0x38, 0xd5, 0x34, 0x6f, 0x0c, 0x4f, 0x2f, 0xd5, 0xbf, 0x9d, 0x31, 0xc6, 0xcf, 0xa7, 0xc2, 0x4b, 0x2a, 0x63, 0xce, 0x32, 0x43, 0x0b, 0x7e, 0x3a, 0xf0, 0xf8, 0x5c, 0xff, 0xdf, 0x09, 0xe7,
0xc7, 0x6f, 0x53, 0x4c, 0x05, 0xd9, 0x81, 0x6e, 0x82, 0x43, 0x0c, 0x67, 0x98, 0x04, 0x5f, 0x71, 0xe2, 0x74, 0x20, 0x43, 0xfc, 0x3a, 0xc0, 0x4c, 0x92, 0x2d, 0x68, 0xa6, 0xd8, 0xc5, 0x78, 0x88,
0xee, 0x5a, 0xdb, 0xd6, 0x5e, 0xd7, 0x5f, 0xc9, 0xb0, 0x0f, 0x38, 0x27, 0x9b, 0xd0, 0x49, 0x6f, 0x69, 0xf4, 0x05, 0x47, 0xbe, 0xb3, 0xe9, 0xec, 0x34, 0xc3, 0xa5, 0x1c, 0xfb, 0x80, 0x23, 0xb2,
0x28, 0x0f, 0xc6, 0x34, 0x1d, 0xbb, 0xb6, 0xaa, 0xff, 0x27, 0x81, 0xf7, 0x34, 0x1d, 0x93, 0xff, 0x0e, 0x8d, 0xec, 0x86, 0x8a, 0xe8, 0x9a, 0x66, 0xd7, 0xbe, 0xab, 0xeb, 0xff, 0x29, 0xe0, 0x3d,
0xc1, 0xa1, 0x91, 0x70, 0x9d, 0x6d, 0x6b, 0xaf, 0xe5, 0xcb, 0x3f, 0xbd, 0x1f, 0x16, 0x3c, 0x2b, 0xcd, 0xae, 0xc9, 0xff, 0xe0, 0xd1, 0x44, 0xfa, 0xde, 0xa6, 0xb3, 0x53, 0x0b, 0xd5, 0x9f, 0xe4,
0x8d, 0x4a, 0x39, 0x8b, 0x53, 0x94, 0xb3, 0x54, 0xa3, 0x30, 0x9e, 0xb1, 0x70, 0x88, 0x6a, 0x56, 0x2d, 0xac, 0x69, 0xba, 0x18, 0x5c, 0xf6, 0xe3, 0xae, 0x56, 0x11, 0xf5, 0x90, 0xf6, 0xfa, 0x31,
0xc7, 0x5f, 0x91, 0xd8, 0xa9, 0x86, 0xc8, 0x4b, 0x58, 0xe5, 0x09, 0x72, 0x3a, 0xbf, 0x23, 0xd9, 0x43, 0xbf, 0xb6, 0xe9, 0xec, 0x78, 0xe1, 0x33, 0x45, 0xf8, 0x34, 0xae, 0x1f, 0xda, 0x72, 0xf0,
0x8a, 0xd4, 0xd3, 0x68, 0x46, 0x1b, 0x00, 0xa4, 0x18, 0x8f, 0x8c, 0x66, 0x47, 0x69, 0xea, 0x68, 0xdd, 0x81, 0x27, 0x15, 0x99, 0x99, 0xe0, 0x2c, 0x43, 0xa5, 0x53, 0x77, 0x8d, 0xd9, 0x90, 0xc7,
0x44, 0x2a, 0x7e, 0x0e, 0x6d, 0xbc, 0xe5, 0x61, 0x32, 0x77, 0x5b, 0xdb, 0xd6, 0xde, 0x92, 0x6f, 0x5d, 0xd4, 0x3a, 0x1b, 0xe1, 0x92, 0xc2, 0x8e, 0x0d, 0x44, 0x5e, 0xc0, 0xb2, 0x48, 0x51, 0xd0,
0x4e, 0xde, 0x6b, 0xd8, 0x28, 0x28, 0xbb, 0x98, 0x32, 0x81, 0x99, 0x13, 0x66, 0x13, 0x6b, 0xb1, 0xd1, 0x1d, 0xc9, 0xd5, 0xa4, 0x96, 0x41, 0x73, 0x5a, 0x07, 0x20, 0x43, 0xd6, 0xb3, 0xf3, 0x7a,
0xc9, 0x4f, 0x1b, 0x48, 0x95, 0x4f, 0xf6, 0x61, 0x5d, 0xad, 0xc1, 0xe9, 0x3c, 0xc2, 0x58, 0x04, 0x7a, 0x9e, 0x86, 0x41, 0xd4, 0xb4, 0x4f, 0xa1, 0x8e, 0xb7, 0x22, 0x4e, 0x47, 0x5a, 0xeb, 0x42,
0x23, 0x4c, 0x85, 0xd9, 0x65, 0x4d, 0x16, 0x3e, 0x69, 0xfc, 0x58, 0x36, 0xdd, 0x00, 0x65, 0x55, 0x68, 0x4f, 0xc1, 0x2b, 0x58, 0x2b, 0x29, 0x3b, 0x1b, 0x70, 0x89, 0xb9, 0x8b, 0xd6, 0x05, 0xe7,
0xf0, 0x05, 0xf5, 0x26, 0x8e, 0xbf, 0x2c, 0xcf, 0x27, 0x88, 0x64, 0x17, 0x7a, 0x59, 0x29, 0x48, 0xce, 0x85, 0xe0, 0x87, 0x0b, 0x64, 0x92, 0x4f, 0x76, 0x61, 0xd5, 0x98, 0x43, 0x47, 0x09, 0x32,
0xa8, 0x40, 0xb5, 0x86, 0xf3, 0xce, 0x76, 0x2d, 0x6d, 0xc9, 0x09, 0xa2, 0x4f, 0x85, 0xda, 0xd5, 0x19, 0xf5, 0x30, 0x93, 0x76, 0x96, 0x15, 0x6d, 0x8a, 0xc1, 0x0f, 0x55, 0xd3, 0x35, 0xd0, 0x36,
0x58, 0x22, 0xe5, 0xb5, 0x94, 0xbc, 0x8e, 0x46, 0x8e, 0x22, 0x41, 0xf6, 0x61, 0x2d, 0x0a, 0xe3, 0x47, 0x9f, 0xd1, 0x4c, 0xe2, 0x85, 0x8b, 0xea, 0x7c, 0x84, 0x48, 0xb6, 0xa1, 0x95, 0x97, 0xa2,
0x40, 0xb5, 0xa2, 0x11, 0x9b, 0xc6, 0xc2, 0x5d, 0x92, 0x1c, 0xd5, 0xa8, 0x17, 0x85, 0xf1, 0xe5, 0x94, 0x4a, 0xd4, 0x63, 0x78, 0xef, 0x5c, 0xdf, 0x31, 0x96, 0x1c, 0x21, 0x86, 0x54, 0xea, 0x59,
0x0d, 0xe5, 0x47, 0xaa, 0xa0, 0xb8, 0xf4, 0xb6, 0xc0, 0x6d, 0xe7, 0xb8, 0xf4, 0x36, 0xc7, 0x1d, 0xad, 0x25, 0x4a, 0x5e, 0x4d, 0xcb, 0x6b, 0x18, 0xe4, 0x20, 0x91, 0x64, 0x17, 0x56, 0x92, 0x98,
0x00, 0x0c, 0x27, 0x62, 0x16, 0x8c, 0x70, 0x22, 0xa8, 0xbb, 0xac, 0x7c, 0xec, 0x48, 0xe4, 0x58, 0x45, 0xba, 0x15, 0x4d, 0xf8, 0x80, 0x49, 0x7f, 0x41, 0x71, 0x74, 0xa3, 0x56, 0x12, 0xb3, 0xf3,
0x02, 0xde, 0x66, 0xc9, 0xca, 0x2b, 0x4c, 0xa2, 0xd4, 0x58, 0xe9, 0x8d, 0x4a, 0xbe, 0xa9, 0x22, 0x1b, 0x2a, 0x0e, 0x74, 0x41, 0x73, 0xe9, 0x6d, 0x89, 0x5b, 0x2f, 0x70, 0xe9, 0x6d, 0x81, 0xdb,
0xd9, 0xad, 0x2a, 0xd5, 0x66, 0x97, 0x54, 0xee, 0x56, 0x55, 0xda, 0x86, 0x97, 0x57, 0xe8, 0x7d, 0x01, 0xe8, 0xf6, 0xe5, 0x30, 0xea, 0x61, 0x5f, 0x52, 0x7f, 0x51, 0xfb, 0xd8, 0x50, 0xc8, 0xa1,
0xb7, 0xe0, 0xc9, 0x62, 0xcc, 0x69, 0x9c, 0x5d, 0x64, 0x31, 0x1c, 0x56, 0x39, 0x1c, 0x8f, 0x8b, 0x02, 0x82, 0xf5, 0x8a, 0x95, 0x17, 0x98, 0x26, 0x99, 0xb5, 0x32, 0xe8, 0x55, 0x7c, 0xd3, 0x45,
0x73, 0x25, 0xb4, 0xad, 0x4a, 0x68, 0xbd, 0x8b, 0xfc, 0xdb, 0x92, 0x3a, 0x16, 0x79, 0x7f, 0xe8, 0xb2, 0x3d, 0xa9, 0xd4, 0x98, 0x5d, 0x51, 0xb9, 0x3d, 0xa9, 0xd2, 0xb5, 0xbc, 0xa2, 0xc2, 0xe0,
0x6d, 0x2d, 0x92, 0x6a, 0x17, 0x92, 0xfa, 0x0a, 0xdc, 0x7c, 0xcb, 0x07, 0x82, 0xfa, 0xcb, 0xca, 0x9b, 0x03, 0x8f, 0xc6, 0xd7, 0x1c, 0xb3, 0x7c, 0x91, 0xe5, 0x70, 0x38, 0xd5, 0x70, 0x3c, 0xf0,
0xdf, 0xc6, 0x1d, 0xdd, 0xc8, 0xc8, 0x67, 0xd0, 0x7a, 0x20, 0x83, 0x76, 0x7d, 0x06, 0x6b, 0x42, 0x29, 0x54, 0x43, 0x5b, 0x9b, 0x08, 0x6d, 0x70, 0x56, 0x7c, 0x97, 0x4a, 0xc7, 0x38, 0xef, 0xf3,
0xd6, 0x7a, 0x44, 0xc8, 0x96, 0xfe, 0x2e, 0x64, 0xed, 0x72, 0xc8, 0xfa, 0x45, 0x17, 0x0a, 0x19, 0xde, 0xe5, 0x38, 0xa9, 0x6e, 0x29, 0xa9, 0x2f, 0xc1, 0x2f, 0xb6, 0x9c, 0x13, 0xd4, 0x5f, 0x4e,
0x1b, 0xc2, 0x7a, 0xa5, 0xf6, 0xaf, 0x23, 0xf6, 0xe6, 0xb7, 0x03, 0x20, 0x8f, 0x7a, 0x12, 0x39, 0x71, 0x1b, 0x77, 0x74, 0x2b, 0xa3, 0x98, 0x41, 0x67, 0x4e, 0x06, 0xdd, 0xe9, 0x19, 0x9c, 0x12,
0x87, 0x6e, 0x21, 0xd1, 0xde, 0x81, 0xf9, 0xf8, 0x1e, 0x34, 0xbe, 0x85, 0xfe, 0xe6, 0x3d, 0x1c, 0xb2, 0xda, 0x03, 0x42, 0xb6, 0xf0, 0x77, 0x21, 0xab, 0x57, 0x43, 0xd6, 0x2e, 0xbb, 0x50, 0xca,
0x72, 0x0e, 0xab, 0x1f, 0xf1, 0xc6, 0x40, 0x72, 0x10, 0x19, 0xd4, 0xd3, 0xb3, 0x6e, 0x2f, 0x9a, 0x58, 0x17, 0x56, 0x27, 0x6a, 0xff, 0x3a, 0x62, 0xaf, 0x7f, 0x7b, 0x00, 0xea, 0x68, 0x6e, 0x22,
0xca, 0xe6, 0xae, 0x17, 0x0a, 0xf5, 0xb7, 0xaa, 0x41, 0x61, 0x3e, 0x4f, 0x4d, 0x0a, 0x75, 0x83, 0xa7, 0xd0, 0x2c, 0x25, 0x3a, 0xd8, 0xb3, 0x5f, 0xee, 0xbd, 0x99, 0x6f, 0xa1, 0xbd, 0x7e, 0x0f,
0x33, 0x58, 0xc9, 0x1b, 0xbc, 0x53, 0xc3, 0x2d, 0x5e, 0x4c, 0xbf, 0xdf, 0x4c, 0x21, 0x67, 0xd0, 0x87, 0x9c, 0xc2, 0xf2, 0x47, 0xbc, 0xb1, 0x90, 0xba, 0x88, 0x74, 0xa6, 0xd3, 0xf3, 0x6e, 0xcf,
0x33, 0xfb, 0x9e, 0xaa, 0xeb, 0x20, 0x5b, 0xb5, 0xe4, 0xac, 0xd5, 0xa0, 0xa1, 0x6a, 0x96, 0xbd, 0x67, 0x95, 0xed, 0xae, 0xc7, 0x0a, 0xcd, 0xb7, 0x6a, 0x86, 0xc2, 0x62, 0x9e, 0x66, 0x29, 0x34,
0xca, 0xb4, 0x69, 0xa9, 0xf5, 0xda, 0x0a, 0xab, 0x7a, 0xf7, 0x51, 0x74, 0xd7, 0xcf, 0x6d, 0xf5, 0x0d, 0x4e, 0x60, 0xa9, 0x68, 0xf0, 0xd6, 0x14, 0x6e, 0x79, 0x31, 0xed, 0xf6, 0x6c, 0x0a, 0x39,
0x83, 0xf9, 0xf6, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf1, 0xf9, 0x2f, 0x6f, 0x67, 0x07, 0x00, 0x81, 0x96, 0x9d, 0xf7, 0x58, 0xaf, 0x83, 0x6c, 0x4c, 0x25, 0xe7, 0xad, 0x3a, 0x33, 0xaa, 0x76,
0x00, 0xd8, 0x8b, 0x5c, 0x9b, 0x91, 0x3a, 0x5d, 0x5b, 0x69, 0xd4, 0xe0, 0x3e, 0x8a, 0xe9, 0x7a, 0x59,
0xd7, 0xbf, 0xb6, 0x6f, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x91, 0x34, 0x08, 0x26, 0xa4, 0x07,
0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.

@ -24,6 +24,9 @@ message ServerLoopOutRequest {
bytes swap_hash = 2; bytes swap_hash = 2;
uint64 amt = 3; uint64 amt = 3;
/// The unix time in seconds we want the on-chain swap to be published by.
int64 swap_publication_deadline = 4;
} }
message ServerLoopOutResponse { message ServerLoopOutResponse {

@ -53,7 +53,7 @@ func newServerMock() *serverMock {
func (s *serverMock) NewLoopOutSwap(ctx context.Context, func (s *serverMock) NewLoopOutSwap(ctx context.Context,
swapHash lntypes.Hash, amount btcutil.Amount, swapHash lntypes.Hash, amount btcutil.Amount,
receiverKey [33]byte) ( receiverKey [33]byte, _ time.Time) (
*newLoopOutResponse, error) { *newLoopOutResponse, error) {
_, senderKey := test.CreateKey(100) _, senderKey := test.CreateKey(100)

@ -6,6 +6,7 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"time"
"github.com/lightninglabs/loop/looprpc" "github.com/lightninglabs/loop/looprpc"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
@ -31,7 +32,8 @@ type swapServerClient interface {
NewLoopOutSwap(ctx context.Context, NewLoopOutSwap(ctx context.Context,
swapHash lntypes.Hash, amount btcutil.Amount, swapHash lntypes.Hash, amount btcutil.Amount,
receiverKey [33]byte) ( receiverKey [33]byte,
swapPublicationDeadline time.Time) (
*newLoopOutResponse, error) *newLoopOutResponse, error)
NewLoopInSwap(ctx context.Context, NewLoopInSwap(ctx context.Context,
@ -153,15 +155,17 @@ func (s *grpcSwapServerClient) GetLoopInQuote(ctx context.Context,
func (s *grpcSwapServerClient) NewLoopOutSwap(ctx context.Context, func (s *grpcSwapServerClient) NewLoopOutSwap(ctx context.Context,
swapHash lntypes.Hash, amount btcutil.Amount, swapHash lntypes.Hash, amount btcutil.Amount,
receiverKey [33]byte) (*newLoopOutResponse, error) { receiverKey [33]byte, swapPublicationDeadline time.Time) (
*newLoopOutResponse, error) {
rpcCtx, rpcCancel := context.WithTimeout(ctx, serverRPCTimeout) rpcCtx, rpcCancel := context.WithTimeout(ctx, serverRPCTimeout)
defer rpcCancel() defer rpcCancel()
swapResp, err := s.server.NewLoopOutSwap(rpcCtx, swapResp, err := s.server.NewLoopOutSwap(rpcCtx,
&looprpc.ServerLoopOutRequest{ &looprpc.ServerLoopOutRequest{
SwapHash: swapHash[:], SwapHash: swapHash[:],
Amt: uint64(amount), Amt: uint64(amount),
ReceiverKey: receiverKey[:], ReceiverKey: receiverKey[:],
SwapPublicationDeadline: swapPublicationDeadline.Unix(),
}, },
) )
if err != nil { if err != nil {

Loading…
Cancel
Save