Merge pull request #263 from carlaKC/205-addlabelling

multi: add labelling to swaps
pull/264/head
Carla Kirk-Cohen 4 years ago committed by GitHub
commit e15549e9af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,6 +6,7 @@ import (
"github.com/btcsuite/btcutil"
"github.com/lightninglabs/loop"
"github.com/lightninglabs/loop/labels"
"github.com/lightninglabs/loop/looprpc"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/urfave/cli"
@ -24,6 +25,14 @@ var (
"confirm within",
}
labelFlag = cli.StringFlag{
Name: "label",
Usage: fmt.Sprintf("an optional label for this swap,"+
"limited to %v characters. The label may not start "+
"with our reserved prefix: %v.",
labels.MaxLength, labels.Reserved),
}
loopInCommand = cli.Command{
Name: "in",
Usage: "perform an on-chain to off-chain swap (loop in)",
@ -51,6 +60,7 @@ var (
},
confTargetFlag,
lastHopFlag,
labelFlag,
},
Action: loopIn,
}
@ -93,6 +103,12 @@ func loopIn(ctx *cli.Context) error {
return fmt.Errorf("external and conf_target both set")
}
// Validate our label early so that we can fail before getting a quote.
label := ctx.String(labelFlag.Name)
if err := labels.Validate(label); err != nil {
return err
}
quote, err := client.GetLoopInQuote(
context.Background(),
&looprpc.QuoteRequest{
@ -133,6 +149,7 @@ func loopIn(ctx *cli.Context) error {
MaxSwapFee: int64(limits.maxSwapFee),
ExternalHtlc: external,
HtlcConfTarget: htlcConfTarget,
Label: label,
}
if ctx.IsSet(lastHopFlag.Name) {

@ -9,6 +9,7 @@ import (
"github.com/btcsuite/btcutil"
"github.com/lightninglabs/loop"
"github.com/lightninglabs/loop/labels"
"github.com/lightninglabs/loop/looprpc"
"github.com/urfave/cli"
)
@ -64,6 +65,7 @@ var loopOutCommand = cli.Command{
"Not setting this flag therefore might " +
"result in a lower swap fee.",
},
labelFlag,
},
Action: loopOut,
}
@ -104,6 +106,12 @@ func loopOut(ctx *cli.Context) error {
}
}
// Validate our label early so that we can fail before getting a quote.
label := ctx.String(labelFlag.Name)
if err := labels.Validate(label); err != nil {
return err
}
var destAddr string
switch {
case ctx.IsSet("addr"):
@ -172,6 +180,7 @@ func loopOut(ctx *cli.Context) error {
OutgoingChanSet: outgoingChanSet,
SweepConfTarget: sweepConfTarget,
SwapPublicationDeadline: uint64(swapDeadline.Unix()),
Label: label,
})
if err != nil {
return err

@ -74,6 +74,9 @@ type OutRequest struct {
// Expiry is the absolute expiry height of the on-chain htlc.
Expiry int32
// Label contains an optional label for the swap.
Label string
}
// Out contains the full details of a loop out request. This includes things
@ -186,6 +189,9 @@ type LoopInRequest struct {
// ExternalHtlc specifies whether the htlc is published by an external
// source.
ExternalHtlc bool
// Label contains an optional label for the swap.
Label string
}
// LoopInTerms are the server terms on which it executes loop in swaps.

@ -0,0 +1,46 @@
package labels
import (
"errors"
)
const (
// MaxLength is the maximum length we allow for labels.
MaxLength = 500
// Reserved is used as a prefix to separate labels that are created by
// loopd from those created by users.
Reserved = "[reserved]"
)
var (
// ErrLabelTooLong is returned when a label exceeds our length limit.
ErrLabelTooLong = errors.New("label exceeds maximum length")
// ErrReservedPrefix is returned when a label contains the prefix
// which is reserved for internally produced labels.
ErrReservedPrefix = errors.New("label contains reserved prefix")
)
// Validate checks that a label is of appropriate length and is not in our list
// of reserved labels.
func Validate(label string) error {
if len(label) > MaxLength {
return ErrLabelTooLong
}
// If the label is shorter than our reserved prefix, it cannot contain
// it.
if len(label) < len(Reserved) {
return nil
}
// Check if our label begins with our reserved prefix. We don't mind if
// it has our reserved prefix in another case, we just need to be able
// to reserve a subset of labels with this prefix.
if label[0:len(Reserved)] == Reserved {
return ErrReservedPrefix
}
return nil
}

@ -0,0 +1,53 @@
package labels
import (
"fmt"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
// TestValidate tests validation of labels.
func TestValidate(t *testing.T) {
tests := []struct {
name string
label string
err error
}{
{
name: "label ok",
label: "label",
err: nil,
},
{
name: "exceeds limit",
label: strings.Repeat(" ", MaxLength+1),
err: ErrLabelTooLong,
},
{
name: "exactly reserved prefix",
label: Reserved,
err: ErrReservedPrefix,
},
{
name: "starts with reserved prefix",
label: fmt.Sprintf("%v test", Reserved),
err: ErrReservedPrefix,
},
{
name: "ends with reserved prefix",
label: fmt.Sprintf("test %v", Reserved),
err: nil,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
require.Equal(t, test.err, Validate(test.label))
})
}
}

@ -89,6 +89,7 @@ func (s *swapClientServer) LoopOut(ctx context.Context,
SwapPublicationDeadline: time.Unix(
int64(in.SwapPublicationDeadline), 0,
),
Label: in.Label,
}
switch {
@ -214,6 +215,7 @@ func (s *swapClientServer) marshallSwap(loopSwap *loop.SwapInfo) (
CostServer: int64(loopSwap.Cost.Server),
CostOnchain: int64(loopSwap.Cost.Onchain),
CostOffchain: int64(loopSwap.Cost.Offchain),
Label: loopSwap.Label,
}, nil
}
@ -478,6 +480,7 @@ func (s *swapClientServer) LoopIn(ctx context.Context,
MaxSwapFee: btcutil.Amount(in.MaxSwapFee),
HtlcConfTarget: htlcConfTarget,
ExternalHtlc: in.ExternalHtlc,
Label: in.Label,
}
if in.LastHop != nil {
lastHop, err := route.NewVertexFromBytes(in.LastHop)

@ -43,6 +43,9 @@ type SwapContract struct {
// InitiationTime is the time at which the swap was initiated.
InitiationTime time.Time
// Label contains an optional label for the swap.
Label string
}
// Loop contains fields shared between LoopIn and LoopOut

@ -6,6 +6,8 @@ import (
"fmt"
"time"
"github.com/coreos/bbolt"
"github.com/lightninglabs/loop/labels"
"github.com/lightningnetwork/lnd/routing/route"
)
@ -24,6 +26,10 @@ type LoopInContract struct {
// ExternalHtlc specifies whether the htlc is published by an external
// source.
ExternalHtlc bool
// Label contains an optional label for the swap. Note that this field
// is stored separately to the rest of the contract on disk.
Label string
}
// LoopIn is a combination of the contract and the updates.
@ -112,6 +118,31 @@ func serializeLoopInContract(swap *LoopInContract) (
return b.Bytes(), nil
}
// putLabel performs validation of a label and writes it to the bucket provided
// under the label key if it is non-zero.
func putLabel(bucket *bbolt.Bucket, label string) error {
if len(label) == 0 {
return nil
}
if err := labels.Validate(label); err != nil {
return err
}
return bucket.Put(labelKey, []byte(label))
}
// getLabel attempts to get an optional label stored under the label key in a
// bucket. If it is not present, an empty label is returned.
func getLabel(bucket *bbolt.Bucket) string {
label := bucket.Get(labelKey)
if label == nil {
return ""
}
return string(label)
}
// deserializeLoopInContract deserializes the loop in contract from a byte slice.
func deserializeLoopInContract(value []byte) (*LoopInContract, error) {
r := bytes.NewReader(value)

@ -60,6 +60,15 @@ var (
// value: time || rawSwapState
contractKey = []byte("contract")
// labelKey is the key that stores an optional label for the swap. If
// a swap was created before we started adding labels, or was created
// without a label, this key will not be present.
//
// path: loopInBucket/loopOutBucket -> swapBucket[hash] -> labelKey
//
// value: string label
labelKey = []byte("label")
// outgoingChanSetKey is the key that stores a list of channel ids that
// restrict the loop out swap payment.
//
@ -207,6 +216,9 @@ func (s *boltSwapStore) FetchLoopOutSwaps() ([]*LoopOut, error) {
return err
}
// Get our label for this swap, if it is present.
contract.Label = getLabel(swapBucket)
// Read the list of concatenated outgoing channel ids
// that form the outgoing set.
setBytes := swapBucket.Get(outgoingChanSetKey)
@ -352,6 +364,9 @@ func (s *boltSwapStore) FetchLoopInSwaps() ([]*LoopIn, error) {
return err
}
// Get our label for this swap, if it is present.
contract.Label = getLabel(swapBucket)
updates, err := deserializeUpdates(swapBucket)
if err != nil {
return err
@ -434,6 +449,10 @@ func (s *boltSwapStore) CreateLoopOut(hash lntypes.Hash,
return err
}
if err := putLabel(swapBucket, swap.Label); err != nil {
return err
}
// Write the outgoing channel set.
var b bytes.Buffer
for _, chanID := range swap.OutgoingChanSet {
@ -447,6 +466,11 @@ func (s *boltSwapStore) CreateLoopOut(hash lntypes.Hash,
return err
}
// Write label to disk if we have one.
if err := putLabel(swapBucket, swap.Label); err != nil {
return err
}
// Finally, we'll create an empty updates bucket for this swap
// to track any future updates to the swap itself.
_, err = swapBucket.CreateBucket(updatesBucketKey)
@ -485,6 +509,11 @@ func (s *boltSwapStore) CreateLoopIn(hash lntypes.Hash,
return err
}
// Write label to disk if we have one.
if err := putLabel(swapBucket, swap.Label); err != nil {
return err
}
// Finally, we'll create an empty updates bucket for this swap
// to track any future updates to the swap itself.
_, err = swapBucket.CreateBucket(updatesBucketKey)

@ -83,6 +83,13 @@ func TestLoopOutStore(t *testing.T) {
t.Run("two channel outgoing set", func(t *testing.T) {
testLoopOutStore(t, &restrictedSwap)
})
labelledSwap := unrestrictedSwap
labelledSwap.Label = "test label"
t.Run("labelled swap", func(t *testing.T) {
testLoopOutStore(t, &labelledSwap)
})
}
// testLoopOutStore tests the basic functionality of the current bbolt
@ -196,27 +203,6 @@ func testLoopOutStore(t *testing.T, pendingSwap *LoopOutContract) {
// TestLoopInStore tests all the basic functionality of the current bbolt
// swap store.
func TestLoopInStore(t *testing.T) {
tempDirName, err := ioutil.TempDir("", "clientstore")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDirName)
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
if err != nil {
t.Fatal(err)
}
// First, verify that an empty database has no active swaps.
swaps, err := store.FetchLoopInSwaps()
if err != nil {
t.Fatal(err)
}
if len(swaps) != 0 {
t.Fatal("expected empty store")
}
hash := sha256.Sum256(testPreimage[:])
initiationTime := time.Date(2018, 11, 1, 0, 0, 0, 0, time.UTC)
// Next, we'll make a new pending swap that we'll insert into the
@ -243,6 +229,38 @@ func TestLoopInStore(t *testing.T) {
ExternalHtlc: true,
}
t.Run("loop in", func(t *testing.T) {
testLoopInStore(t, pendingSwap)
})
labelledSwap := pendingSwap
labelledSwap.Label = "test label"
t.Run("loop in with label", func(t *testing.T) {
testLoopInStore(t, labelledSwap)
})
}
func testLoopInStore(t *testing.T, pendingSwap LoopInContract) {
tempDirName, err := ioutil.TempDir("", "clientstore")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDirName)
store, err := NewBoltSwapStore(tempDirName, &chaincfg.MainNetParams)
if err != nil {
t.Fatal(err)
}
// First, verify that an empty database has no active swaps.
swaps, err := store.FetchLoopInSwaps()
if err != nil {
t.Fatal(err)
}
if len(swaps) != 0 {
t.Fatal("expected empty store")
}
// checkSwap is a test helper function that'll assert the state of a
// swap.
checkSwap := func(expectedState SwapState) {
@ -269,6 +287,8 @@ func TestLoopInStore(t *testing.T) {
}
}
hash := sha256.Sum256(testPreimage[:])
// If we create a new swap, then it should show up as being initialized
// right after.
if err := store.CreateLoopIn(hash, &pendingSwap); err != nil {

@ -13,6 +13,7 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/loop/labels"
"github.com/lightninglabs/loop/loopdb"
"github.com/lightninglabs/loop/swap"
"github.com/lightningnetwork/lnd/chainntnfs"
@ -77,6 +78,11 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
currentHeight int32, request *LoopInRequest) (*loopInInitResult,
error) {
// Before we start, check that the label is valid.
if err := labels.Validate(request.Label); err != nil {
return nil, err
}
// Request current server loop in terms and use these to calculate the
// swap fee that we should subtract from the swap amount in the payment
// request that we send to the server.
@ -165,6 +171,7 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
CltvExpiry: swapResp.expiry,
MaxMinerFee: request.MaxMinerFee,
MaxSwapFee: request.MaxSwapFee,
Label: request.Label,
},
}

@ -13,6 +13,7 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/loop/labels"
"github.com/lightninglabs/loop/loopdb"
"github.com/lightninglabs/loop/swap"
"github.com/lightninglabs/loop/sweep"
@ -87,6 +88,11 @@ type loopOutInitResult struct {
func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig,
currentHeight int32, request *OutRequest) (*loopOutInitResult, error) {
// Before we start, check that the label is valid.
if err := labels.Validate(request.Label); err != nil {
return nil, err
}
// Generate random preimage.
var swapPreimage [32]byte
if _, err := rand.Read(swapPreimage[:]); err != nil {
@ -154,6 +160,7 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig,
CltvExpiry: request.Expiry,
MaxMinerFee: request.MaxMinerFee,
MaxSwapFee: request.MaxSwapFee,
Label: request.Label,
},
OutgoingChanSet: chanSet,
}

@ -237,10 +237,15 @@ type LoopOutRequest struct {
//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:"-"`
SwapPublicationDeadline uint64 `protobuf:"varint,10,opt,name=swap_publication_deadline,json=swapPublicationDeadline,proto3" json:"swap_publication_deadline,omitempty"`
//
//An optional label for this swap. This field is limited to 500 characters
//and may not start with the prefix [reserved], which is used to tag labels
//produced by the daemon.
Label string `protobuf:"bytes,12,opt,name=label,proto3" json:"label,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *LoopOutRequest) Reset() { *m = LoopOutRequest{} }
@ -346,6 +351,13 @@ func (m *LoopOutRequest) GetSwapPublicationDeadline() uint64 {
return 0
}
func (m *LoopOutRequest) GetLabel() string {
if m != nil {
return m.Label
}
return ""
}
type LoopInRequest struct {
//*
//Requested swap amount in sat. This does not include the swap and miner
@ -374,7 +386,11 @@ type LoopInRequest struct {
ExternalHtlc bool `protobuf:"varint,5,opt,name=external_htlc,json=externalHtlc,proto3" json:"external_htlc,omitempty"`
//*
//The number of blocks that the on chain htlc should confirm within.
HtlcConfTarget int32 `protobuf:"varint,6,opt,name=htlc_conf_target,json=htlcConfTarget,proto3" json:"htlc_conf_target,omitempty"`
HtlcConfTarget int32 `protobuf:"varint,6,opt,name=htlc_conf_target,json=htlcConfTarget,proto3" json:"htlc_conf_target,omitempty"`
//
//An optional label for this swap. This field is limited to 500 characters
//and may not be one of the reserved values in loop/labels Reserved list.
Label string `protobuf:"bytes,7,opt,name=label,proto3" json:"label,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -447,6 +463,13 @@ func (m *LoopInRequest) GetHtlcConfTarget() int32 {
return 0
}
func (m *LoopInRequest) GetLabel() string {
if m != nil {
return m.Label
}
return ""
}
type SwapResponse struct {
//*
//Swap identifier to track status in the update stream that is returned from
@ -631,7 +654,9 @@ type SwapStatus struct {
// On-chain transaction cost
CostOnchain int64 `protobuf:"varint,9,opt,name=cost_onchain,json=costOnchain,proto3" json:"cost_onchain,omitempty"`
// Off-chain routing fees
CostOffchain int64 `protobuf:"varint,10,opt,name=cost_offchain,json=costOffchain,proto3" json:"cost_offchain,omitempty"`
CostOffchain int64 `protobuf:"varint,10,opt,name=cost_offchain,json=costOffchain,proto3" json:"cost_offchain,omitempty"`
// An optional label given to the swap on creation.
Label string `protobuf:"bytes,15,opt,name=label,proto3" json:"label,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -762,6 +787,13 @@ func (m *SwapStatus) GetCostOffchain() int64 {
return 0
}
func (m *SwapStatus) GetLabel() string {
if m != nil {
return m.Label
}
return ""
}
type ListSwapsRequest struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@ -1467,120 +1499,122 @@ func init() {
func init() { proto.RegisterFile("client.proto", fileDescriptor_014de31d7ac8c57c) }
var fileDescriptor_014de31d7ac8c57c = []byte{
// 1803 bytes of a gzipped FileDescriptorProto
// 1827 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xdd, 0x6e, 0x23, 0x49,
0x15, 0x1e, 0xff, 0xc5, 0xf6, 0x71, 0xbb, 0xdd, 0xa9, 0xec, 0x24, 0x8e, 0x19, 0x34, 0x9e, 0xde,
0x15, 0x5e, 0xff, 0xc5, 0xf6, 0x71, 0xbb, 0xdd, 0xa9, 0xcc, 0x24, 0x8e, 0x19, 0x34, 0x9e, 0xde,
0x1d, 0xc8, 0x86, 0xd5, 0x98, 0xcd, 0x5e, 0xb1, 0x02, 0x24, 0x8f, 0xd3, 0xd9, 0x38, 0x4a, 0x6c,
0xd3, 0x76, 0x06, 0x2d, 0x42, 0x6a, 0x55, 0xec, 0x4a, 0xdc, 0xc2, 0xfd, 0xb3, 0x5d, 0xe5, 0x99,
0x44, 0x2b, 0x84, 0xc4, 0x0b, 0x70, 0xc1, 0x3d, 0x17, 0xbc, 0x06, 0x6f, 0x80, 0xb8, 0x01, 0x5e,
0x81, 0x1b, 0x2e, 0x78, 0x05, 0x84, 0xea, 0x54, 0xbb, 0xdd, 0xed, 0xfc, 0x20, 0x2e, 0xb8, 0x4b,
0x7f, 0xe7, 0xab, 0x53, 0xe7, 0xa7, 0xce, 0x8f, 0x03, 0xda, 0x74, 0xe1, 0x32, 0x5f, 0xbc, 0x09,
0xa3, 0x40, 0x04, 0xa4, 0xbc, 0x08, 0x82, 0x30, 0x0a, 0xa7, 0xad, 0x17, 0x37, 0x41, 0x70, 0xb3,
0x60, 0x1d, 0x1a, 0xba, 0x1d, 0xea, 0xfb, 0x81, 0xa0, 0xc2, 0x0d, 0x7c, 0xae, 0x68, 0xe6, 0x9f,
0x0b, 0xa0, 0x9f, 0x07, 0x41, 0x38, 0x5c, 0x0a, 0x9b, 0x7d, 0xb3, 0x64, 0x5c, 0x10, 0x03, 0x0a,
0xd4, 0x13, 0xcd, 0x5c, 0x3b, 0x77, 0x50, 0xb0, 0xe5, 0x9f, 0x84, 0x40, 0x71, 0xc6, 0xb8, 0x68,
0xe6, 0xdb, 0xb9, 0x83, 0xaa, 0x8d, 0x7f, 0x93, 0x0e, 0x7c, 0xe4, 0xd1, 0x5b, 0x87, 0x7f, 0xa0,
0xa1, 0x13, 0x05, 0x4b, 0xe1, 0xfa, 0x37, 0xce, 0x35, 0x63, 0xcd, 0x02, 0x1e, 0xdb, 0xf6, 0xe8,
0xed, 0xf8, 0x03, 0x0d, 0x6d, 0x25, 0x39, 0x61, 0x8c, 0x7c, 0x01, 0xbb, 0xf2, 0x40, 0x18, 0xb1,
0x90, 0xde, 0x65, 0x8e, 0x14, 0xf1, 0xc8, 0x8e, 0x47, 0x6f, 0x47, 0x28, 0x4c, 0x1d, 0x6a, 0x83,
0x96, 0xdc, 0x22, 0xa9, 0x25, 0xa4, 0x42, 0xac, 0x5d, 0x32, 0x3e, 0x01, 0x3d, 0xa5, 0x56, 0x1a,
0xbe, 0x85, 0x1c, 0x2d, 0x51, 0xd7, 0xf5, 0x04, 0x31, 0xa1, 0x2e, 0x59, 0x9e, 0xeb, 0xb3, 0x08,
0x15, 0x95, 0x91, 0x54, 0xf3, 0xe8, 0xed, 0x85, 0xc4, 0xa4, 0xa6, 0xcf, 0xc0, 0x90, 0x31, 0x73,
0x82, 0xa5, 0x70, 0xa6, 0x73, 0xea, 0xfb, 0x6c, 0xd1, 0xac, 0xb4, 0x73, 0x07, 0xc5, 0xb7, 0xf9,
0x66, 0xce, 0xd6, 0x17, 0x2a, 0x4a, 0x3d, 0x25, 0x21, 0x87, 0xb0, 0x1d, 0x2c, 0xc5, 0x4d, 0x20,
0x9d, 0x90, 0x6c, 0x87, 0x33, 0xd1, 0xac, 0xb5, 0x0b, 0x07, 0x45, 0xbb, 0xb1, 0x12, 0x48, 0xee,
0x98, 0x09, 0xc9, 0xe5, 0x1f, 0x18, 0x0b, 0x9d, 0x69, 0xe0, 0x5f, 0x3b, 0x82, 0x46, 0x37, 0x4c,
0x34, 0xab, 0xed, 0xdc, 0x41, 0xc9, 0x6e, 0xa0, 0xa0, 0x17, 0xf8, 0xd7, 0x13, 0x84, 0xc9, 0x97,
0xb0, 0x8f, 0xde, 0x86, 0xcb, 0xab, 0x85, 0x3b, 0xc5, 0x5c, 0x39, 0x33, 0x46, 0x67, 0x0b, 0xd7,
0x67, 0x4d, 0x90, 0xe6, 0xd8, 0x7b, 0x92, 0x30, 0x5a, 0xcb, 0x8f, 0x63, 0xb1, 0xf9, 0xd7, 0x1c,
0xd4, 0x65, 0x32, 0xfb, 0xfe, 0xe3, 0xb9, 0xdc, 0x8c, 0x68, 0xfe, 0x5e, 0x44, 0xef, 0xc5, 0xaa,
0x70, 0x3f, 0x56, 0xfb, 0x50, 0x59, 0x50, 0x2e, 0x9c, 0x79, 0x10, 0x62, 0xfa, 0x34, 0xbb, 0x2c,
0xbf, 0x4f, 0x83, 0x90, 0x7c, 0x0c, 0x75, 0x76, 0x2b, 0x58, 0xe4, 0xd3, 0x85, 0x33, 0x17, 0x8b,
0x29, 0xe6, 0xac, 0x62, 0x6b, 0x2b, 0xf0, 0x54, 0x2c, 0xa6, 0xe4, 0x00, 0x0c, 0x29, 0xcb, 0x04,
0x64, 0x0b, 0x03, 0xa2, 0x4b, 0x7c, 0x1d, 0x0f, 0xf3, 0x9f, 0x39, 0xd0, 0xf0, 0x25, 0x31, 0x1e,
0x06, 0x3e, 0x67, 0x84, 0x40, 0xde, 0x9d, 0xa1, 0x47, 0x55, 0x4c, 0x4c, 0xde, 0x9d, 0x49, 0x73,
0xdc, 0x99, 0x73, 0x75, 0x27, 0x18, 0x47, 0x6b, 0x35, 0xbb, 0xec, 0xce, 0xde, 0xca, 0x4f, 0xf2,
0x1a, 0x34, 0xbc, 0x89, 0xce, 0x66, 0x11, 0xe3, 0x5c, 0xbd, 0x61, 0x3c, 0x58, 0x93, 0x78, 0x57,
0xc1, 0xe4, 0x0d, 0xec, 0xa4, 0x69, 0x8e, 0x1f, 0x1e, 0x7d, 0xe0, 0x73, 0xf4, 0xad, 0x6a, 0x6f,
0xa7, 0x98, 0x03, 0x14, 0x90, 0xcf, 0x80, 0x64, 0xf8, 0x8a, 0x5e, 0x42, 0xba, 0x91, 0xa2, 0x8f,
0x90, 0xfd, 0x1a, 0x74, 0xce, 0xa2, 0xf7, 0x2c, 0x72, 0x3c, 0xc6, 0x39, 0xbd, 0x61, 0xe8, 0x6c,
0xd5, 0xae, 0x2b, 0xf4, 0x42, 0x81, 0xa6, 0x01, 0xfa, 0x45, 0xe0, 0xbb, 0x22, 0x88, 0xe2, 0xfc,
0x99, 0x7f, 0x28, 0x02, 0x48, 0xef, 0xc7, 0x82, 0x8a, 0x25, 0x7f, 0xb0, 0x34, 0x65, 0x34, 0xf2,
0x8f, 0x46, 0xa3, 0xb6, 0x19, 0x8d, 0xa2, 0xb8, 0x0b, 0x55, 0x4a, 0xf5, 0xa3, 0xed, 0x37, 0x71,
0x93, 0x78, 0x23, 0xef, 0x98, 0xdc, 0x85, 0xcc, 0x46, 0x31, 0x39, 0x80, 0x12, 0x17, 0x54, 0xa8,
0xd2, 0xd4, 0x8f, 0x48, 0x86, 0x27, 0x6d, 0x61, 0xb6, 0x22, 0x90, 0x9f, 0x80, 0x7e, 0x4d, 0xdd,
0xc5, 0x32, 0x62, 0x4e, 0xc4, 0x28, 0x0f, 0xfc, 0xa6, 0x8e, 0x47, 0x76, 0x93, 0x23, 0x27, 0x4a,
0x6c, 0xa3, 0xd4, 0xae, 0x5f, 0xa7, 0x3f, 0xc9, 0xf7, 0xa1, 0xe1, 0xfa, 0xae, 0x70, 0xd5, 0x3b,
0x17, 0xae, 0xb7, 0x2a, 0x71, 0x7d, 0x0d, 0x4f, 0x5c, 0x4f, 0x5a, 0x64, 0xe0, 0x83, 0x5b, 0x86,
0x33, 0x2a, 0x98, 0x62, 0xaa, 0x42, 0xd7, 0x25, 0x7e, 0x89, 0x30, 0x32, 0x37, 0x13, 0x5e, 0x7e,
0x38, 0xe1, 0x0f, 0x27, 0x50, 0x7b, 0x24, 0x81, 0x8f, 0x3c, 0x8f, 0xfa, 0x63, 0xcf, 0xe3, 0x25,
0xd4, 0xa6, 0x01, 0x17, 0x8e, 0xca, 0x2f, 0xb6, 0x91, 0x82, 0x0d, 0x12, 0x1a, 0x23, 0x42, 0x5e,
0x81, 0x86, 0x84, 0xc0, 0x9f, 0xce, 0xa9, 0xeb, 0x63, 0x37, 0x28, 0xd8, 0x78, 0x68, 0xa8, 0x20,
0x59, 0x48, 0x8a, 0x72, 0x7d, 0xad, 0x38, 0xa0, 0x1a, 0x1b, 0x72, 0x62, 0xcc, 0x24, 0x60, 0x9c,
0xbb, 0x5c, 0xc8, 0xbc, 0xf0, 0xd5, 0xa3, 0xf9, 0x29, 0x6c, 0xa7, 0xb0, 0xb8, 0x6c, 0x3e, 0x85,
0x92, 0xac, 0x79, 0xde, 0xcc, 0xb5, 0x0b, 0x07, 0xb5, 0xa3, 0x9d, 0x7b, 0x29, 0x5d, 0x72, 0x5b,
0x31, 0xcc, 0x57, 0xd0, 0x90, 0x60, 0xdf, 0xbf, 0x0e, 0x56, 0x7d, 0x44, 0x4f, 0x8a, 0x4e, 0x93,
0x4f, 0xcc, 0xd4, 0x41, 0x9b, 0xb0, 0xc8, 0x4b, 0xae, 0xfc, 0x0d, 0x34, 0xfa, 0x7e, 0x8c, 0xc4,
0x17, 0x7e, 0x0f, 0x1a, 0x9e, 0xeb, 0xab, 0x46, 0x43, 0xbd, 0x60, 0xe9, 0x8b, 0x38, 0xb5, 0x75,
0xcf, 0xf5, 0xa5, 0xfe, 0x2e, 0x82, 0xc8, 0x5b, 0x35, 0xa4, 0x98, 0xb7, 0x15, 0xf3, 0x54, 0x4f,
0x52, 0xbc, 0xb3, 0x62, 0x25, 0x67, 0xe4, 0xcf, 0x8a, 0x95, 0xbc, 0x51, 0x38, 0x2b, 0x56, 0x0a,
0x46, 0xf1, 0xac, 0x58, 0x29, 0x1a, 0xa5, 0xb3, 0x62, 0xa5, 0x6c, 0x54, 0xcc, 0xbf, 0xe4, 0xc0,
0x18, 0x2e, 0xc5, 0xff, 0xd5, 0x04, 0x9c, 0x35, 0xae, 0xef, 0x4c, 0x17, 0xe2, 0xbd, 0x33, 0x63,
0x0b, 0x41, 0x31, 0xb1, 0x25, 0x5b, 0xf3, 0x5c, 0xbf, 0xb7, 0x10, 0xef, 0x8f, 0x25, 0xb6, 0x9a,
0x48, 0x29, 0x56, 0x35, 0x66, 0xd1, 0xdb, 0x84, 0xf5, 0x5f, 0xdc, 0xf9, 0x63, 0x0e, 0xb4, 0x9f,
0x2d, 0x03, 0xc1, 0x1e, 0x6f, 0xe4, 0xf8, 0xc4, 0xd6, 0xdd, 0x33, 0x8f, 0x77, 0xc0, 0x74, 0x3d,
0x49, 0xee, 0x35, 0xe2, 0xc2, 0x03, 0x8d, 0xf8, 0xc9, 0x71, 0x53, 0x7c, 0x7a, 0xdc, 0xfc, 0x2e,
0x27, 0xb3, 0x1e, 0x9b, 0x19, 0x87, 0xbc, 0x0d, 0xda, 0x6a, 0xb4, 0x38, 0x9c, 0xae, 0x0c, 0x06,
0xae, 0x66, 0xcb, 0x98, 0xe2, 0xe2, 0x80, 0xa5, 0x84, 0x37, 0xf2, 0x79, 0xc2, 0x8c, 0x17, 0x07,
0x29, 0x1b, 0x29, 0x51, 0x7c, 0xe0, 0xbb, 0x00, 0xa9, 0x58, 0x96, 0xd0, 0xcf, 0xea, 0x34, 0x15,
0x48, 0x15, 0xc2, 0xa2, 0x51, 0x32, 0xff, 0xa6, 0x5e, 0xc1, 0xff, 0x6a, 0xd2, 0x27, 0xa0, 0xaf,
0xf7, 0x07, 0xe4, 0xa8, 0xa9, 0xa8, 0x85, 0xab, 0x05, 0x42, 0xb2, 0x7e, 0x10, 0x77, 0x0c, 0x35,
0xca, 0xb3, 0x66, 0x37, 0xa4, 0x64, 0x2c, 0x05, 0xb1, 0x4a, 0x1c, 0xf9, 0x32, 0xae, 0xf4, 0xce,
0x63, 0xbe, 0x70, 0x70, 0x7f, 0x52, 0x93, 0xb2, 0x81, 0xf1, 0x54, 0xf8, 0xb1, 0xcc, 0xed, 0xd3,
0x0e, 0x9a, 0x0d, 0xa8, 0x4f, 0x82, 0x5f, 0x31, 0x3f, 0x29, 0xb6, 0x1f, 0x83, 0xbe, 0x02, 0x62,
0x17, 0x0f, 0x61, 0x4b, 0x20, 0x12, 0x57, 0xf7, 0xba, 0x61, 0x9f, 0x73, 0x2a, 0x90, 0x6c, 0xc7,
0x0c, 0xf3, 0x4f, 0x79, 0xa8, 0x26, 0xa8, 0x7c, 0x24, 0x57, 0x94, 0x33, 0xc7, 0xa3, 0x53, 0x1a,
0x05, 0x81, 0x1f, 0xd7, 0xb8, 0x26, 0xc1, 0x8b, 0x18, 0x93, 0xcd, 0x6a, 0xe5, 0xc7, 0x9c, 0xf2,
0x39, 0x46, 0x47, 0xb3, 0x6b, 0x31, 0x76, 0x4a, 0xf9, 0x9c, 0x7c, 0x0a, 0xc6, 0x8a, 0x12, 0x46,
0xcc, 0xf5, 0xe4, 0x8c, 0x53, 0x93, 0xb8, 0x11, 0xe3, 0xa3, 0x18, 0x96, 0xad, 0x5c, 0x15, 0x99,
0x13, 0x52, 0x77, 0xe6, 0x78, 0x32, 0x8a, 0x6a, 0x05, 0xd4, 0x15, 0x3e, 0xa2, 0xee, 0xec, 0x82,
0x53, 0x41, 0x3e, 0x87, 0xe7, 0xa9, 0x3d, 0x31, 0x45, 0x57, 0x55, 0x4c, 0xa2, 0x64, 0x51, 0x4c,
0x8e, 0xbc, 0x02, 0x4d, 0xce, 0x06, 0x67, 0x1a, 0x31, 0x2a, 0xd8, 0x2c, 0xae, 0xe3, 0x9a, 0xc4,
0x7a, 0x0a, 0x22, 0x4d, 0x28, 0xb3, 0xdb, 0xd0, 0x8d, 0xd8, 0x0c, 0x67, 0x43, 0xc5, 0x5e, 0x7d,
0xca, 0xc3, 0x5c, 0x04, 0x11, 0xbd, 0x61, 0x8e, 0x4f, 0x3d, 0x86, 0xd5, 0x5d, 0xb5, 0x6b, 0x31,
0x36, 0xa0, 0x1e, 0x3b, 0x7c, 0x0d, 0x95, 0xd5, 0xac, 0x24, 0x1a, 0x54, 0xce, 0x87, 0xc3, 0x91,
0x33, 0xbc, 0x9c, 0x18, 0xcf, 0x48, 0x0d, 0xca, 0xf8, 0xd5, 0x1f, 0x18, 0xb9, 0x43, 0x0e, 0xd5,
0x64, 0x54, 0x92, 0x3a, 0x54, 0xfb, 0x83, 0xfe, 0xa4, 0xdf, 0x9d, 0x58, 0xc7, 0xc6, 0x33, 0xf2,
0x1c, 0xb6, 0x47, 0xb6, 0xd5, 0xbf, 0xe8, 0x7e, 0x65, 0x39, 0xb6, 0xf5, 0xce, 0xea, 0x9e, 0x5b,
0xc7, 0x46, 0x8e, 0x10, 0xd0, 0x4f, 0x27, 0xe7, 0x3d, 0x67, 0x74, 0xf9, 0xf6, 0xbc, 0x3f, 0x3e,
0xb5, 0x8e, 0x8d, 0xbc, 0xd4, 0x39, 0xbe, 0xec, 0xf5, 0xac, 0xf1, 0xd8, 0x28, 0x10, 0x80, 0xad,
0x93, 0x6e, 0x5f, 0x92, 0x8b, 0x64, 0x07, 0x1a, 0xfd, 0xc1, 0xbb, 0x61, 0xbf, 0x67, 0x39, 0x63,
0x6b, 0x32, 0x91, 0x60, 0xe9, 0xf0, 0x5f, 0x39, 0xa8, 0x67, 0xa6, 0x2d, 0xd9, 0x83, 0x1d, 0x79,
0xe4, 0xd2, 0x96, 0x37, 0x75, 0xc7, 0xc3, 0x81, 0x33, 0x18, 0x0e, 0x2c, 0xe3, 0x19, 0xf9, 0x0e,
0xec, 0x6d, 0x08, 0x86, 0x27, 0x27, 0xbd, 0xd3, 0xae, 0x34, 0x9e, 0xb4, 0x60, 0x77, 0x43, 0x38,
0xe9, 0x5f, 0x58, 0xd2, 0xcb, 0x3c, 0x69, 0xc3, 0x8b, 0x0d, 0xd9, 0xf8, 0xe7, 0x96, 0x35, 0x4a,
0x18, 0x05, 0xf2, 0x1a, 0x5e, 0x6d, 0x30, 0xfa, 0x83, 0xf1, 0xe5, 0xc9, 0x49, 0xbf, 0xd7, 0xb7,
0x06, 0x13, 0xe7, 0x5d, 0xf7, 0xfc, 0xd2, 0x32, 0x8a, 0xe4, 0x05, 0x34, 0x37, 0x2f, 0xb1, 0x2e,
0x46, 0x43, 0xbb, 0x6b, 0x7f, 0x6d, 0x94, 0xc8, 0xc7, 0xf0, 0xf2, 0x9e, 0x92, 0xde, 0xd0, 0xb6,
0xad, 0xde, 0xc4, 0xe9, 0x5e, 0x0c, 0x2f, 0x07, 0x13, 0x63, 0xeb, 0xe8, 0xdf, 0x5b, 0x6a, 0x39,
0xea, 0xe1, 0xef, 0x1e, 0x62, 0x43, 0x39, 0xfe, 0x25, 0x43, 0xf6, 0xd6, 0xef, 0x3f, 0xf3, 0xdb,
0xa6, 0xf5, 0x3c, 0x33, 0xf6, 0x56, 0xf5, 0x63, 0xee, 0xfd, 0xf6, 0xef, 0xff, 0xf8, 0x7d, 0x7e,
0xdb, 0xd4, 0x3a, 0xef, 0x3f, 0xef, 0x48, 0x46, 0x27, 0x58, 0x8a, 0x2f, 0x73, 0x87, 0x64, 0x08,
0x5b, 0x6a, 0xa1, 0x26, 0xbb, 0x19, 0x95, 0xc9, 0x86, 0xfd, 0x98, 0xc6, 0x5d, 0xd4, 0x68, 0x98,
0xb5, 0x44, 0xa3, 0xeb, 0x4b, 0x85, 0x3f, 0x82, 0x72, 0xbc, 0xe2, 0xa5, 0x8c, 0xcc, 0x2e, 0x7d,
0xad, 0x87, 0x66, 0xf3, 0x0f, 0x73, 0xe4, 0x17, 0x50, 0x4d, 0xc6, 0x3a, 0xd9, 0x5f, 0x9b, 0xb3,
0x31, 0xfe, 0x5b, 0xad, 0x87, 0x44, 0x59, 0xb3, 0x88, 0x9e, 0x98, 0x85, 0x23, 0x9f, 0x5c, 0xaa,
0x67, 0x2d, 0x47, 0x3e, 0x69, 0x66, 0xae, 0x4f, 0x6d, 0x01, 0x0f, 0x1a, 0x66, 0xb6, 0x50, 0xe5,
0x47, 0x84, 0x64, 0x54, 0x76, 0xbe, 0x75, 0x67, 0xbf, 0x26, 0xbf, 0x04, 0x2d, 0x4e, 0x00, 0x0e,
0x66, 0xb2, 0x0e, 0x56, 0x7a, 0x7b, 0x68, 0xad, 0x9d, 0xd9, 0x1c, 0xe1, 0x0f, 0x68, 0x0f, 0x96,
0xa2, 0x23, 0x50, 0xdb, 0x55, 0xa2, 0x1d, 0x1b, 0x7e, 0x4a, 0x7b, 0x7a, 0x74, 0x66, 0xb5, 0x67,
0x46, 0x83, 0xd9, 0x46, 0xed, 0x2d, 0xd2, 0xcc, 0x68, 0xff, 0x46, 0x72, 0x3a, 0xdf, 0x52, 0x4f,
0x48, 0x0f, 0xf4, 0xaf, 0x98, 0x50, 0x29, 0x7f, 0xd2, 0x87, 0x75, 0xd4, 0x36, 0x16, 0x21, 0x73,
0x1f, 0x2f, 0xd9, 0x21, 0xdb, 0xa9, 0xa7, 0x90, 0x78, 0xb0, 0xd6, 0xfe, 0xa4, 0x0f, 0x69, 0xed,
0x59, 0x17, 0x5e, 0xa2, 0xf6, 0x7d, 0xb2, 0x97, 0xd6, 0x9e, 0xf6, 0xe0, 0x6b, 0xa8, 0xcb, 0x3b,
0x56, 0x1d, 0x9f, 0xa7, 0x5e, 0x72, 0x66, 0xac, 0xb4, 0xf6, 0xee, 0xe1, 0xd9, 0xea, 0x20, 0x0d,
0xbc, 0x82, 0x53, 0xd1, 0x51, 0xa3, 0xe4, 0x6a, 0x0b, 0xff, 0x87, 0xf0, 0xc5, 0x7f, 0x02, 0x00,
0x00, 0xff, 0xff, 0xbf, 0xed, 0xab, 0x0a, 0x7a, 0x10, 0x00, 0x00,
0x44, 0x2b, 0x84, 0xc4, 0x0b, 0x70, 0xc1, 0x1b, 0xf0, 0x0c, 0xdc, 0xf1, 0x0a, 0x5c, 0xc1, 0x0b,
0x70, 0x81, 0x84, 0xb8, 0xe0, 0x15, 0x10, 0xaa, 0x53, 0xed, 0x76, 0xb7, 0xf3, 0x83, 0xb8, 0xe0,
0x2e, 0xfd, 0x9d, 0xaf, 0x4e, 0x9d, 0x9f, 0x3a, 0x3f, 0x0e, 0x68, 0xd3, 0x85, 0xcb, 0x7c, 0xf1,
0x26, 0x8c, 0x02, 0x11, 0x90, 0xf2, 0x22, 0x08, 0xc2, 0x28, 0x9c, 0xb6, 0x5e, 0xdc, 0x04, 0xc1,
0xcd, 0x82, 0x75, 0x68, 0xe8, 0x76, 0xa8, 0xef, 0x07, 0x82, 0x0a, 0x37, 0xf0, 0xb9, 0xa2, 0x99,
0x7f, 0x2b, 0x80, 0x7e, 0x1e, 0x04, 0xe1, 0x70, 0x29, 0x6c, 0xf6, 0xcd, 0x92, 0x71, 0x41, 0x0c,
0x28, 0x50, 0x4f, 0x34, 0x73, 0xed, 0xdc, 0x41, 0xc1, 0x96, 0x7f, 0x12, 0x02, 0xc5, 0x19, 0xe3,
0xa2, 0x99, 0x6f, 0xe7, 0x0e, 0xaa, 0x36, 0xfe, 0x4d, 0x3a, 0xf0, 0xcc, 0xa3, 0xb7, 0x0e, 0xff,
0x40, 0x43, 0x27, 0x0a, 0x96, 0xc2, 0xf5, 0x6f, 0x9c, 0x6b, 0xc6, 0x9a, 0x05, 0x3c, 0xb6, 0xed,
0xd1, 0xdb, 0xf1, 0x07, 0x1a, 0xda, 0x4a, 0x72, 0xc2, 0x18, 0xf9, 0x02, 0x76, 0xe5, 0x81, 0x30,
0x62, 0x21, 0xbd, 0xcb, 0x1c, 0x29, 0xe2, 0x91, 0x1d, 0x8f, 0xde, 0x8e, 0x50, 0x98, 0x3a, 0xd4,
0x06, 0x2d, 0xb9, 0x45, 0x52, 0x4b, 0x48, 0x85, 0x58, 0xbb, 0x64, 0x7c, 0x02, 0x7a, 0x4a, 0xad,
0x34, 0x7c, 0x0b, 0x39, 0x5a, 0xa2, 0xae, 0xeb, 0x09, 0x62, 0x42, 0x5d, 0xb2, 0x3c, 0xd7, 0x67,
0x11, 0x2a, 0x2a, 0x23, 0xa9, 0xe6, 0xd1, 0xdb, 0x0b, 0x89, 0x49, 0x4d, 0x9f, 0x81, 0x21, 0x63,
0xe6, 0x04, 0x4b, 0xe1, 0x4c, 0xe7, 0xd4, 0xf7, 0xd9, 0xa2, 0x59, 0x69, 0xe7, 0x0e, 0x8a, 0x6f,
0xf3, 0xcd, 0x9c, 0xad, 0x2f, 0x54, 0x94, 0x7a, 0x4a, 0x42, 0x0e, 0x61, 0x3b, 0x58, 0x8a, 0x9b,
0x40, 0x3a, 0x21, 0xd9, 0x0e, 0x67, 0xa2, 0x59, 0x6b, 0x17, 0x0e, 0x8a, 0x76, 0x63, 0x25, 0x90,
0xdc, 0x31, 0x13, 0x92, 0xcb, 0x3f, 0x30, 0x16, 0x3a, 0xd3, 0xc0, 0xbf, 0x76, 0x04, 0x8d, 0x6e,
0x98, 0x68, 0x56, 0xdb, 0xb9, 0x83, 0x92, 0xdd, 0x40, 0x41, 0x2f, 0xf0, 0xaf, 0x27, 0x08, 0x93,
0x2f, 0x61, 0x1f, 0xbd, 0x0d, 0x97, 0x57, 0x0b, 0x77, 0x8a, 0xb9, 0x72, 0x66, 0x8c, 0xce, 0x16,
0xae, 0xcf, 0x9a, 0x20, 0xcd, 0xb1, 0xf7, 0x24, 0x61, 0xb4, 0x96, 0x1f, 0xc7, 0x62, 0xf2, 0x0c,
0x4a, 0x0b, 0x7a, 0xc5, 0x16, 0x4d, 0x0d, 0x13, 0xa5, 0x3e, 0xcc, 0x7f, 0xe4, 0xa0, 0x2e, 0x53,
0xdc, 0xf7, 0x1f, 0xcf, 0xf0, 0x66, 0x9c, 0xf3, 0xf7, 0xe2, 0x7c, 0x2f, 0x82, 0x85, 0xfb, 0x11,
0xdc, 0x87, 0xca, 0x82, 0x72, 0xe1, 0xcc, 0x83, 0x10, 0x93, 0xaa, 0xd9, 0x65, 0xf9, 0x7d, 0x1a,
0x84, 0xe4, 0x63, 0xa8, 0xb3, 0x5b, 0xc1, 0x22, 0x9f, 0x2e, 0x9c, 0xb9, 0x58, 0x4c, 0x31, 0x93,
0x15, 0x5b, 0x5b, 0x81, 0xa7, 0x62, 0x31, 0x25, 0x07, 0x60, 0x48, 0x59, 0x26, 0x4c, 0x5b, 0x18,
0x26, 0x5d, 0xe2, 0xa9, 0x28, 0x25, 0x9e, 0x96, 0xd3, 0x9e, 0xfe, 0x33, 0x07, 0x1a, 0xbe, 0x3a,
0xc6, 0xc3, 0xc0, 0xe7, 0x8c, 0x10, 0xc8, 0xbb, 0x33, 0xf4, 0xb3, 0x8a, 0x49, 0xcc, 0xbb, 0x33,
0x69, 0xa4, 0x3b, 0x73, 0xae, 0xee, 0x04, 0xe3, 0xe8, 0x83, 0x66, 0x97, 0xdd, 0xd9, 0x5b, 0xf9,
0x49, 0x5e, 0x83, 0x86, 0xf7, 0xd3, 0xd9, 0x2c, 0x62, 0x9c, 0xab, 0xf7, 0x8e, 0x07, 0x6b, 0x12,
0xef, 0x2a, 0x98, 0xbc, 0x81, 0x9d, 0x34, 0xcd, 0xf1, 0xc3, 0xa3, 0x0f, 0x7c, 0x8e, 0x1e, 0x57,
0xed, 0xed, 0x14, 0x73, 0x80, 0x02, 0xf2, 0x19, 0x90, 0x0c, 0x5f, 0xd1, 0x4b, 0x48, 0x37, 0x52,
0xf4, 0x11, 0xb2, 0x5f, 0x83, 0xce, 0x59, 0xf4, 0x9e, 0x45, 0x8e, 0xc7, 0x38, 0xa7, 0x37, 0x0c,
0x43, 0x50, 0xb5, 0xeb, 0x0a, 0xbd, 0x50, 0xa0, 0x69, 0x80, 0x7e, 0x11, 0xf8, 0xae, 0x08, 0xa2,
0x38, 0xab, 0xe6, 0x1f, 0x8b, 0x00, 0xd2, 0xfb, 0xb1, 0xa0, 0x62, 0xc9, 0x1f, 0x2c, 0x63, 0x19,
0x8d, 0xfc, 0xa3, 0xd1, 0xa8, 0x6d, 0x46, 0xa3, 0x28, 0xee, 0x42, 0x95, 0x68, 0xfd, 0x68, 0xfb,
0x4d, 0xdc, 0x50, 0xde, 0xc8, 0x3b, 0x26, 0x77, 0x21, 0xb3, 0x51, 0x4c, 0x0e, 0xa0, 0xc4, 0x05,
0x15, 0xaa, 0x8c, 0xf5, 0x23, 0x92, 0xe1, 0x49, 0x5b, 0x98, 0xad, 0x08, 0xe4, 0x27, 0xa0, 0x5f,
0x53, 0x77, 0xb1, 0x8c, 0x98, 0x13, 0x31, 0xca, 0x03, 0xbf, 0xa9, 0xe3, 0x91, 0xdd, 0xe4, 0xc8,
0x89, 0x12, 0xdb, 0x28, 0xb5, 0xeb, 0xd7, 0xe9, 0x4f, 0xf2, 0x7d, 0x68, 0xb8, 0xbe, 0x2b, 0x5c,
0x55, 0x13, 0xc2, 0xf5, 0x56, 0xed, 0x40, 0x5f, 0xc3, 0x13, 0xd7, 0x93, 0x16, 0x19, 0xf8, 0x0c,
0x97, 0xe1, 0x8c, 0x0a, 0xa6, 0x98, 0xaa, 0x29, 0xe8, 0x12, 0xbf, 0x44, 0x18, 0x99, 0x9b, 0x09,
0x2f, 0x3f, 0x9c, 0xf0, 0x87, 0x13, 0xa8, 0x3d, 0x92, 0xc0, 0x47, 0x9e, 0x47, 0xfd, 0xb1, 0xe7,
0xf1, 0x12, 0x6a, 0xd3, 0x80, 0x0b, 0x47, 0xe5, 0x17, 0x5b, 0x4e, 0xc1, 0x06, 0x09, 0x8d, 0x11,
0x21, 0xaf, 0x40, 0x43, 0x42, 0xe0, 0x4f, 0xe7, 0xd4, 0xf5, 0xb1, 0x73, 0x14, 0x6c, 0x3c, 0x34,
0x54, 0x90, 0x2c, 0x2f, 0x45, 0xb9, 0xbe, 0x56, 0x1c, 0x50, 0x4d, 0x10, 0x39, 0x31, 0xb6, 0x2e,
0x9a, 0x46, 0xba, 0x68, 0x08, 0x18, 0xe7, 0x2e, 0x17, 0x32, 0x5b, 0x7c, 0xf5, 0x94, 0x7e, 0x0a,
0xdb, 0x29, 0x2c, 0x2e, 0xa6, 0x4f, 0xa1, 0x24, 0xfb, 0x03, 0x6f, 0xe6, 0xda, 0x85, 0x83, 0xda,
0xd1, 0xce, 0xbd, 0x44, 0x2f, 0xb9, 0xad, 0x18, 0xe6, 0x2b, 0x68, 0x48, 0xb0, 0xef, 0x5f, 0x07,
0xab, 0x9e, 0xa3, 0x27, 0xa5, 0xa8, 0xc9, 0x87, 0x67, 0xea, 0xa0, 0x4d, 0x58, 0xe4, 0x25, 0x57,
0xfe, 0x06, 0x1a, 0x7d, 0x3f, 0x46, 0xe2, 0x0b, 0xbf, 0x07, 0x0d, 0xcf, 0xf5, 0x55, 0x53, 0xa2,
0x5e, 0xb0, 0xf4, 0x45, 0x9c, 0xf0, 0xba, 0xe7, 0xfa, 0x52, 0x7f, 0x17, 0x41, 0xe4, 0xad, 0x9a,
0x57, 0xcc, 0xdb, 0x8a, 0x79, 0xaa, 0x7f, 0x29, 0xde, 0x59, 0xb1, 0x92, 0x33, 0xf2, 0x67, 0xc5,
0x4a, 0xde, 0x28, 0x9c, 0x15, 0x2b, 0x05, 0xa3, 0x78, 0x56, 0xac, 0x14, 0x8d, 0xd2, 0x59, 0xb1,
0x52, 0x36, 0x2a, 0xe6, 0x9f, 0x73, 0x60, 0x0c, 0x97, 0xe2, 0xff, 0x6a, 0x02, 0x4e, 0x2b, 0xd7,
0x77, 0xa6, 0x0b, 0xf1, 0xde, 0x99, 0xb1, 0x85, 0xa0, 0x98, 0xee, 0x92, 0xad, 0x79, 0xae, 0xdf,
0x5b, 0x88, 0xf7, 0xc7, 0x12, 0x5b, 0xcd, 0xb4, 0x14, 0xab, 0x1a, 0xb3, 0xe8, 0x6d, 0xc2, 0xfa,
0x2f, 0xee, 0xfc, 0x21, 0x07, 0xda, 0xcf, 0x96, 0x81, 0x60, 0x8f, 0x37, 0x7d, 0x7c, 0x78, 0xeb,
0x4e, 0x9b, 0xc7, 0x3b, 0x60, 0xba, 0xee, 0xb2, 0xf7, 0x9a, 0x76, 0xe1, 0x81, 0xa6, 0xfd, 0xe4,
0xc0, 0x2a, 0x3e, 0x39, 0xb0, 0xcc, 0xdf, 0xe5, 0x64, 0xd6, 0x63, 0x33, 0xe3, 0x90, 0xb7, 0x41,
0x5b, 0x8d, 0x21, 0x87, 0xd3, 0x95, 0xc1, 0xc0, 0xd5, 0x1c, 0x1a, 0x53, 0x5c, 0x3d, 0xb0, 0xc0,
0xf0, 0x46, 0x3e, 0x4f, 0x98, 0xf1, 0xea, 0x21, 0x65, 0x23, 0x25, 0x8a, 0x0f, 0x7c, 0x17, 0x20,
0x15, 0xcb, 0x12, 0xfa, 0x59, 0x9d, 0xa6, 0x02, 0xa9, 0x42, 0x58, 0x34, 0x4a, 0xe6, 0x5f, 0xd4,
0x2b, 0xf8, 0x5f, 0x4d, 0xfa, 0x04, 0xf4, 0xf5, 0x06, 0x82, 0x1c, 0x35, 0x41, 0xb5, 0x70, 0xb5,
0x82, 0x48, 0xd6, 0x0f, 0xe2, 0x3e, 0xa2, 0x96, 0x81, 0xac, 0xd9, 0x0d, 0x29, 0x19, 0x4b, 0x41,
0xac, 0x12, 0x97, 0x06, 0x19, 0x57, 0x7a, 0xe7, 0x31, 0x5f, 0x38, 0xb8, 0x81, 0xa9, 0xa9, 0xda,
0xc0, 0x78, 0x2a, 0xfc, 0x58, 0xe6, 0xf6, 0x69, 0x07, 0xcd, 0x06, 0xd4, 0x27, 0xc1, 0xaf, 0x98,
0x9f, 0x14, 0xdb, 0x8f, 0x41, 0x5f, 0x01, 0xb1, 0x8b, 0x87, 0xb0, 0x25, 0x10, 0x89, 0xab, 0x7b,
0xdd, 0xc6, 0xcf, 0x39, 0x15, 0x48, 0xb6, 0x63, 0x86, 0xf9, 0xa7, 0x3c, 0x54, 0x13, 0x54, 0x3e,
0x92, 0x2b, 0xca, 0x99, 0xe3, 0xd1, 0x29, 0x8d, 0x82, 0xc0, 0x8f, 0x6b, 0x5c, 0x93, 0xe0, 0x45,
0x8c, 0xc9, 0x16, 0xb6, 0xf2, 0x63, 0x4e, 0xf9, 0x1c, 0xa3, 0xa3, 0xd9, 0xb5, 0x18, 0x3b, 0xa5,
0x7c, 0x4e, 0x3e, 0x05, 0x63, 0x45, 0x09, 0x23, 0xe6, 0x7a, 0x72, 0xf2, 0xa9, 0xf9, 0xdc, 0x88,
0xf1, 0x51, 0x0c, 0xcb, 0x06, 0xaf, 0x8a, 0xcc, 0x09, 0xa9, 0x3b, 0x73, 0x3c, 0x19, 0x45, 0xb5,
0x44, 0xea, 0x0a, 0x1f, 0x51, 0x77, 0x76, 0xc1, 0xa9, 0x20, 0x9f, 0xc3, 0xf3, 0xd4, 0xa6, 0x99,
0xa2, 0xab, 0x2a, 0x26, 0x51, 0xb2, 0x6a, 0x26, 0x47, 0x5e, 0x81, 0x26, 0x27, 0x86, 0x33, 0x8d,
0x18, 0x15, 0x6c, 0x16, 0xd7, 0x71, 0x4d, 0x62, 0x3d, 0x05, 0x91, 0x26, 0x94, 0xd9, 0x6d, 0xe8,
0x46, 0x6c, 0x86, 0x13, 0xa3, 0x62, 0xaf, 0x3e, 0xe5, 0x61, 0x2e, 0x82, 0x88, 0xde, 0x30, 0xc7,
0xa7, 0x1e, 0xc3, 0xea, 0xae, 0xda, 0xb5, 0x18, 0x1b, 0x50, 0x8f, 0x1d, 0xbe, 0x86, 0xca, 0x6a,
0x82, 0x12, 0x0d, 0x2a, 0xe7, 0xc3, 0xe1, 0xc8, 0x19, 0x5e, 0x4e, 0x8c, 0x8f, 0x48, 0x0d, 0xca,
0xf8, 0xd5, 0x1f, 0x18, 0xb9, 0x43, 0x0e, 0xd5, 0x64, 0x80, 0x92, 0x3a, 0x54, 0xfb, 0x83, 0xfe,
0xa4, 0xdf, 0x9d, 0x58, 0xc7, 0xc6, 0x47, 0xe4, 0x39, 0x6c, 0x8f, 0x6c, 0xab, 0x7f, 0xd1, 0xfd,
0xca, 0x72, 0x6c, 0xeb, 0x9d, 0xd5, 0x3d, 0xb7, 0x8e, 0x8d, 0x1c, 0x21, 0xa0, 0x9f, 0x4e, 0xce,
0x7b, 0xce, 0xe8, 0xf2, 0xed, 0x79, 0x7f, 0x7c, 0x6a, 0x1d, 0x1b, 0x79, 0xa9, 0x73, 0x7c, 0xd9,
0xeb, 0x59, 0xe3, 0xb1, 0x51, 0x20, 0x00, 0x5b, 0x27, 0xdd, 0xbe, 0x24, 0x17, 0xc9, 0x0e, 0x34,
0xfa, 0x83, 0x77, 0xc3, 0x7e, 0xcf, 0x72, 0xc6, 0xd6, 0x64, 0x22, 0xc1, 0xd2, 0xe1, 0xbf, 0x72,
0x50, 0xcf, 0xcc, 0x60, 0xb2, 0x07, 0x3b, 0xf2, 0xc8, 0xa5, 0x2d, 0x6f, 0xea, 0x8e, 0x87, 0x03,
0x67, 0x30, 0x1c, 0x58, 0xc6, 0x47, 0xe4, 0x3b, 0xb0, 0xb7, 0x21, 0x18, 0x9e, 0x9c, 0xf4, 0x4e,
0xbb, 0xd2, 0x78, 0xd2, 0x82, 0xdd, 0x0d, 0xe1, 0xa4, 0x7f, 0x61, 0x49, 0x2f, 0xf3, 0xa4, 0x0d,
0x2f, 0x36, 0x64, 0xe3, 0x9f, 0x5b, 0xd6, 0x28, 0x61, 0x14, 0xc8, 0x6b, 0x78, 0xb5, 0xc1, 0xe8,
0x0f, 0xc6, 0x97, 0x27, 0x27, 0xfd, 0x5e, 0xdf, 0x1a, 0x4c, 0x9c, 0x77, 0xdd, 0xf3, 0x4b, 0xcb,
0x28, 0x92, 0x17, 0xd0, 0xdc, 0xbc, 0xc4, 0xba, 0x18, 0x0d, 0xed, 0xae, 0xfd, 0xb5, 0x51, 0x22,
0x1f, 0xc3, 0xcb, 0x7b, 0x4a, 0x7a, 0x43, 0xdb, 0xb6, 0x7a, 0x13, 0xa7, 0x7b, 0x31, 0xbc, 0x1c,
0x4c, 0x8c, 0xad, 0xa3, 0x7f, 0x6f, 0xa9, 0x95, 0xa9, 0x87, 0xbf, 0x9c, 0x88, 0x0d, 0xe5, 0xf8,
0xb7, 0x10, 0xd9, 0x5b, 0xbf, 0xff, 0xcc, 0xaf, 0xa3, 0xd6, 0xf3, 0xcc, 0xd8, 0x5b, 0xd5, 0x8f,
0xb9, 0xf7, 0xdb, 0xbf, 0xfe, 0xfd, 0xf7, 0xf9, 0x6d, 0x53, 0xeb, 0xbc, 0xff, 0xbc, 0x23, 0x19,
0x9d, 0x60, 0x29, 0xbe, 0xcc, 0x1d, 0x92, 0x21, 0x6c, 0xa9, 0xe5, 0x9b, 0xec, 0x66, 0x54, 0x26,
0xdb, 0xf8, 0x63, 0x1a, 0x77, 0x51, 0xa3, 0x61, 0xd6, 0x12, 0x8d, 0xae, 0x2f, 0x15, 0xfe, 0x08,
0xca, 0xf1, 0xe2, 0x97, 0x32, 0x32, 0xbb, 0x0a, 0xb6, 0x1e, 0x9a, 0xcd, 0x3f, 0xcc, 0x91, 0x5f,
0x40, 0x35, 0x19, 0xeb, 0x64, 0x7f, 0x6d, 0xce, 0xc6, 0xf8, 0x6f, 0xb5, 0x1e, 0x12, 0x65, 0xcd,
0x22, 0x7a, 0x62, 0x16, 0x8e, 0x7c, 0x72, 0xa9, 0x9e, 0xb5, 0x1c, 0xf9, 0xa4, 0x99, 0xb9, 0x3e,
0xb5, 0x05, 0x3c, 0x68, 0x98, 0xd9, 0x42, 0x95, 0xcf, 0x08, 0xc9, 0xa8, 0xec, 0x7c, 0xeb, 0xce,
0x7e, 0x4d, 0x7e, 0x09, 0x5a, 0x9c, 0x00, 0x1c, 0xcc, 0x64, 0x1d, 0xac, 0xf4, 0xf6, 0xd0, 0x5a,
0x3b, 0xb3, 0x39, 0xc2, 0x1f, 0xd0, 0x1e, 0x2c, 0x45, 0x47, 0xa0, 0xb6, 0xab, 0x44, 0x3b, 0x36,
0xfc, 0x94, 0xf6, 0xf4, 0xe8, 0xcc, 0x6a, 0xcf, 0x8c, 0x06, 0xb3, 0x8d, 0xda, 0x5b, 0xa4, 0x99,
0xd1, 0xfe, 0x8d, 0xe4, 0x74, 0xbe, 0xa5, 0x9e, 0x90, 0x1e, 0xe8, 0x5f, 0x31, 0xa1, 0x52, 0xfe,
0xa4, 0x0f, 0xeb, 0xa8, 0x6d, 0x2c, 0x42, 0xe6, 0x3e, 0x5e, 0xb2, 0x43, 0xb6, 0x53, 0x4f, 0x21,
0xf1, 0x60, 0xad, 0xfd, 0x49, 0x1f, 0xd2, 0xda, 0xb3, 0x2e, 0xbc, 0x44, 0xed, 0xfb, 0x64, 0x2f,
0xad, 0x3d, 0xed, 0xc1, 0xd7, 0x50, 0x97, 0x77, 0xac, 0x3a, 0x3e, 0x4f, 0xbd, 0xe4, 0xcc, 0x58,
0x69, 0xed, 0xdd, 0xc3, 0xb3, 0xd5, 0x41, 0x1a, 0x78, 0x05, 0xa7, 0xa2, 0xa3, 0x46, 0xc9, 0xd5,
0x16, 0xfe, 0x17, 0xe2, 0x8b, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x34, 0x6b, 0xfd, 0xc4, 0xbc,
0x10, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

@ -190,6 +190,13 @@ message LoopOutRequest {
lower total swap fee.
*/
uint64 swap_publication_deadline = 10;
/*
An optional label for this swap. This field is limited to 500 characters
and may not start with the prefix [reserved], which is used to tag labels
produced by the daemon.
*/
string label = 12;
}
message LoopInRequest {
@ -232,6 +239,12 @@ message LoopInRequest {
The number of blocks that the on chain htlc should confirm within.
*/
int32 htlc_conf_target = 6;
/*
An optional label for this swap. This field is limited to 500 characters
and may not be one of the reserved values in loop/labels Reserved list.
*/
string label = 7;
}
message SwapResponse {
@ -351,6 +364,9 @@ message SwapStatus {
// Off-chain routing fees
int64 cost_offchain = 10;
// An optional label given to the swap on creation.
string label = 15;
}
enum SwapType {

@ -411,6 +411,10 @@
"type": "integer",
"format": "int32",
"description": "*\nThe number of blocks that the on chain htlc should confirm within."
},
"label": {
"type": "string",
"description": "An optional label for this swap. This field is limited to 500 characters\nand may not be one of the reserved values in loop/labels Reserved list."
}
}
},
@ -473,6 +477,10 @@
"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."
},
"label": {
"type": "string",
"description": "An optional label for this swap. This field is limited to 500 characters\nand may not start with the prefix [reserved], which is used to tag labels\nproduced by the daemon."
}
}
},
@ -683,6 +691,10 @@
"type": "string",
"format": "int64",
"title": "Off-chain routing fees"
},
"label": {
"type": "string",
"description": "An optional label given to the swap on creation."
}
}
},

Loading…
Cancel
Save