loopin: mpp pre-swap probe

pull/210/head
Joost Jager 4 years ago
parent 456a29c523
commit c8666caf20
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7

@ -35,16 +35,20 @@ const (
// HTLC v2 scrips for swaps. // HTLC v2 scrips for swaps.
ProtocolVersionHtlcV2 ProtocolVersion = 5 ProtocolVersionHtlcV2 ProtocolVersion = 5
// ProtocolVersionMultiLoopIn indicates that the client creates a probe
// invoice so that the server can perform a multi-path probe.
ProtocolVersionMultiLoopIn ProtocolVersion = 6
// ProtocolVersionUnrecorded is set for swaps were created before we // ProtocolVersionUnrecorded is set for swaps were created before we
// started saving protocol version with swaps. // started saving protocol version with swaps.
ProtocolVersionUnrecorded ProtocolVersion = math.MaxUint32 ProtocolVersionUnrecorded ProtocolVersion = math.MaxUint32
// CurrentRpcProtocolVersion defines the version of the RPC protocol // CurrentRPCProtocolVersion defines the version of the RPC protocol
// that is currently supported by the loop client. // that is currently supported by the loop client.
CurrentRPCProtocolVersion = looprpc.ProtocolVersion_HTLC_V2 CurrentRPCProtocolVersion = looprpc.ProtocolVersion_MULTI_LOOP_IN
// CurrentInteranlProtocolVersionInternal defines the RPC current // CurrentInternalProtocolVersion defines the RPC current protocol in
// protocol in the internal representation. // the internal representation.
CurrentInternalProtocolVersion = ProtocolVersion(CurrentRPCProtocolVersion) CurrentInternalProtocolVersion = ProtocolVersion(CurrentRPCProtocolVersion)
) )

@ -20,6 +20,7 @@ func TestProtocolVersionSanity(t *testing.T) {
ProtocolVersionPreimagePush, ProtocolVersionPreimagePush,
ProtocolVersionUserExpiryLoopOut, ProtocolVersionUserExpiryLoopOut,
ProtocolVersionHtlcV2, ProtocolVersionHtlcV2,
ProtocolVersionMultiLoopIn,
} }
rpcVersions := [...]looprpc.ProtocolVersion{ rpcVersions := [...]looprpc.ProtocolVersion{
@ -29,6 +30,7 @@ func TestProtocolVersionSanity(t *testing.T) {
looprpc.ProtocolVersion_PREIMAGE_PUSH_LOOP_OUT, looprpc.ProtocolVersion_PREIMAGE_PUSH_LOOP_OUT,
looprpc.ProtocolVersion_USER_EXPIRY_LOOP_OUT, looprpc.ProtocolVersion_USER_EXPIRY_LOOP_OUT,
looprpc.ProtocolVersion_HTLC_V2, looprpc.ProtocolVersion_HTLC_V2,
looprpc.ProtocolVersion_MULTI_LOOP_IN,
} }
require.Equal(t, len(versions), len(rpcVersions)) require.Equal(t, len(versions), len(rpcVersions))

@ -4,6 +4,7 @@ import (
"context" "context"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"errors"
"fmt" "fmt"
"sync" "sync"
"time" "time"
@ -135,17 +136,55 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
return nil, err return nil, err
} }
// Create the probe invoice in lnd. Derive the payment hash
// deterministically from the swap hash in such a way that the server
// can be sure that we don't know the preimage.
probeHash := lntypes.Hash(sha256.Sum256(swapHash[:]))
probeHash[0] ^= 1
log.Infof("Creating probe invoice %v", probeHash)
probeInvoice, err := cfg.lnd.Invoices.AddHoldInvoice(
globalCtx, &invoicesrpc.AddInvoiceData{
Hash: &probeHash,
Value: lnwire.NewMSatFromSatoshis(swapInvoiceAmt),
Memo: "loop in probe",
Expiry: 3600,
},
)
if err != nil {
return nil, err
}
// Create a cancellable context that is used for monitoring the probe.
probeWaitCtx, probeWaitCancel := context.WithCancel(globalCtx)
// Launch a goroutine to monitor the probe.
probeResult, err := awaitProbe(probeWaitCtx, *cfg.lnd, probeHash)
if err != nil {
probeWaitCancel()
return nil, fmt.Errorf("probe failed: %v", err)
}
// Post the swap parameters to the swap server. The response contains // Post the swap parameters to the swap server. The response contains
// the server success key and the expiry height of the on-chain swap // the server success key and the expiry height of the on-chain swap
// htlc. // htlc.
log.Infof("Initiating swap request at height %v", currentHeight) log.Infof("Initiating swap request at height %v", currentHeight)
swapResp, err := cfg.server.NewLoopInSwap(globalCtx, swapHash, swapResp, err := cfg.server.NewLoopInSwap(globalCtx, swapHash,
request.Amount, senderKey, swapInvoice, request.LastHop, request.Amount, senderKey, swapInvoice, probeInvoice,
request.LastHop,
) )
probeWaitCancel()
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot initiate swap: %v", err) return nil, fmt.Errorf("cannot initiate swap: %v", err)
} }
// Because the context is cancelled, it is guaranteed that we will be
// able to read from the probeResult channel.
err = <-probeResult
if err != nil {
return nil, fmt.Errorf("probe error: %v", err)
}
// Validate the response parameters the prevent us continuing with a // Validate the response parameters the prevent us continuing with a
// swap that is based on parameters outside our allowed range. // swap that is based on parameters outside our allowed range.
err = validateLoopInContract(cfg.lnd, currentHeight, request, swapResp) err = validateLoopInContract(cfg.lnd, currentHeight, request, swapResp)
@ -209,6 +248,72 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
}, nil }, nil
} }
// awaitProbe waits for a probe payment to arrive and cancels it. This is a
// workaround for the current lack of multi-path probing.
func awaitProbe(ctx context.Context, lnd lndclient.LndServices,
probeHash lntypes.Hash) (chan error, error) {
// Subscribe to the probe invoice.
updateChan, errChan, err := lnd.Invoices.SubscribeSingleInvoice(
ctx, probeHash,
)
if err != nil {
return nil, err
}
// Wait in the background for the probe to arrive.
probeResult := make(chan error, 1)
go func() {
for {
select {
case update := <-updateChan:
switch update.State {
case channeldb.ContractAccepted:
log.Infof("Server probe successful")
probeResult <- nil
// Cancel probe invoice so that the
// server will know that its probe was
// successful.
err := lnd.Invoices.CancelInvoice(
ctx, probeHash,
)
if err != nil {
log.Errorf("Cancel probe "+
"invoice: %v", err)
}
return
case channeldb.ContractCanceled:
probeResult <- errors.New(
"probe invoice expired")
return
case channeldb.ContractSettled:
probeResult <- errors.New(
"impossible that probe " +
"invoice was settled")
return
}
case err := <-errChan:
probeResult <- err
return
case <-ctx.Done():
probeResult <- ctx.Err()
return
}
}
}()
return probeResult, nil
}
// resumeLoopInSwap returns a swap object representing a pending swap that has // resumeLoopInSwap returns a swap object representing a pending swap that has
// been restored from the database. // been restored from the database.
func resumeLoopInSwap(reqContext context.Context, cfg *swapConfig, func resumeLoopInSwap(reqContext context.Context, cfg *swapConfig,

@ -22,7 +22,7 @@ type loopInTestContext struct {
func newLoopInTestContext(t *testing.T) *loopInTestContext { func newLoopInTestContext(t *testing.T) *loopInTestContext {
lnd := test.NewMockLnd() lnd := test.NewMockLnd()
server := newServerMock() server := newServerMock(lnd)
store := newStoreMock(t) store := newStoreMock(t)
sweeper := sweep.Sweeper{Lnd: &lnd.LndServices} sweeper := sweep.Sweeper{Lnd: &lnd.LndServices}

@ -27,7 +27,7 @@ func TestLoopOutPaymentParameters(t *testing.T) {
// Set up test context objects. // Set up test context objects.
lnd := test.NewMockLnd() lnd := test.NewMockLnd()
ctx := test.NewContext(t, lnd) ctx := test.NewContext(t, lnd)
server := newServerMock() server := newServerMock(lnd)
store := newStoreMock(t) store := newStoreMock(t)
expiryChan := make(chan time.Time) expiryChan := make(chan time.Time)
@ -138,7 +138,7 @@ func TestLateHtlcPublish(t *testing.T) {
ctx := test.NewContext(t, lnd) ctx := test.NewContext(t, lnd)
server := newServerMock() server := newServerMock(lnd)
store := newStoreMock(t) store := newStoreMock(t)
@ -223,7 +223,7 @@ func TestCustomSweepConfTarget(t *testing.T) {
lnd := test.NewMockLnd() lnd := test.NewMockLnd()
ctx := test.NewContext(t, lnd) ctx := test.NewContext(t, lnd)
server := newServerMock() server := newServerMock(lnd)
// Use the highest sweep confirmation target before we attempt to use // Use the highest sweep confirmation target before we attempt to use
// the default. // the default.
@ -424,7 +424,7 @@ func TestPreimagePush(t *testing.T) {
lnd := test.NewMockLnd() lnd := test.NewMockLnd()
ctx := test.NewContext(t, lnd) ctx := test.NewContext(t, lnd)
server := newServerMock() server := newServerMock(lnd)
// Start with a high confirmation delta which will have a very high fee // Start with a high confirmation delta which will have a very high fee
// attached to it. // attached to it.

@ -51,6 +51,9 @@ const (
ProtocolVersion_USER_EXPIRY_LOOP_OUT ProtocolVersion = 4 ProtocolVersion_USER_EXPIRY_LOOP_OUT ProtocolVersion = 4
// The client will use the new v2 HTLC scripts. // The client will use the new v2 HTLC scripts.
ProtocolVersion_HTLC_V2 ProtocolVersion = 5 ProtocolVersion_HTLC_V2 ProtocolVersion = 5
// The client creates a probe invoice so that the server can perform a
// multi-path probe.
ProtocolVersion_MULTI_LOOP_IN ProtocolVersion = 6
) )
var ProtocolVersion_name = map[int32]string{ var ProtocolVersion_name = map[int32]string{
@ -60,6 +63,7 @@ var ProtocolVersion_name = map[int32]string{
3: "PREIMAGE_PUSH_LOOP_OUT", 3: "PREIMAGE_PUSH_LOOP_OUT",
4: "USER_EXPIRY_LOOP_OUT", 4: "USER_EXPIRY_LOOP_OUT",
5: "HTLC_V2", 5: "HTLC_V2",
6: "MULTI_LOOP_IN",
} }
var ProtocolVersion_value = map[string]int32{ var ProtocolVersion_value = map[string]int32{
@ -69,6 +73,7 @@ var ProtocolVersion_value = map[string]int32{
"PREIMAGE_PUSH_LOOP_OUT": 3, "PREIMAGE_PUSH_LOOP_OUT": 3,
"USER_EXPIRY_LOOP_OUT": 4, "USER_EXPIRY_LOOP_OUT": 4,
"HTLC_V2": 5, "HTLC_V2": 5,
"MULTI_LOOP_IN": 6,
} }
func (x ProtocolVersion) String() string { func (x ProtocolVersion) String() string {
@ -594,6 +599,7 @@ type ServerLoopInRequest struct {
LastHop []byte `protobuf:"bytes,5,opt,name=last_hop,json=lastHop,proto3" json:"last_hop,omitempty"` LastHop []byte `protobuf:"bytes,5,opt,name=last_hop,json=lastHop,proto3" json:"last_hop,omitempty"`
/// The protocol version that the client adheres to. /// The protocol version that the client adheres to.
ProtocolVersion ProtocolVersion `protobuf:"varint,6,opt,name=protocol_version,json=protocolVersion,proto3,enum=looprpc.ProtocolVersion" json:"protocol_version,omitempty"` ProtocolVersion ProtocolVersion `protobuf:"varint,6,opt,name=protocol_version,json=protocolVersion,proto3,enum=looprpc.ProtocolVersion" json:"protocol_version,omitempty"`
ProbeInvoice string `protobuf:"bytes,7,opt,name=probe_invoice,json=probeInvoice,proto3" json:"probe_invoice,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -666,6 +672,13 @@ func (m *ServerLoopInRequest) GetProtocolVersion() ProtocolVersion {
return ProtocolVersion_LEGACY return ProtocolVersion_LEGACY
} }
func (m *ServerLoopInRequest) GetProbeInvoice() string {
if m != nil {
return m.ProbeInvoice
}
return ""
}
type ServerLoopInResponse struct { type ServerLoopInResponse 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"`
Expiry int32 `protobuf:"varint,2,opt,name=expiry,proto3" json:"expiry,omitempty"` Expiry int32 `protobuf:"varint,2,opt,name=expiry,proto3" json:"expiry,omitempty"`
@ -1189,88 +1202,89 @@ 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{
// 1285 bytes of a gzipped FileDescriptorProto // 1309 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xdd, 0x72, 0xdb, 0x44, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcd, 0x52, 0xdb, 0xd6,
0x14, 0x46, 0xf2, 0x4f, 0xe2, 0x63, 0x27, 0x51, 0xb7, 0x6d, 0xea, 0xb8, 0x4d, 0x71, 0x04, 0x94, 0x17, 0xff, 0x4b, 0xfe, 0xc2, 0xc7, 0x36, 0x88, 0x9b, 0x84, 0x18, 0x27, 0xe4, 0x6f, 0x94, 0x36,
0x90, 0x8b, 0xb4, 0x53, 0xee, 0xb8, 0x53, 0x6d, 0xa5, 0xd1, 0xd4, 0x91, 0x8d, 0x2c, 0xa7, 0xed, 0xa5, 0x2c, 0x48, 0x26, 0xdd, 0x75, 0xa7, 0xd8, 0x22, 0x68, 0x62, 0x64, 0x57, 0x96, 0x49, 0xb2,
0xd5, 0xb2, 0x71, 0x96, 0x44, 0x83, 0x2d, 0xa9, 0x92, 0x9c, 0x26, 0xc3, 0x15, 0xc3, 0x03, 0xf0, 0xba, 0x15, 0xe6, 0x16, 0x34, 0xb5, 0x3e, 0x22, 0xc9, 0x04, 0xa6, 0xab, 0x4e, 0x97, 0x7d, 0x86,
0x04, 0x3c, 0x03, 0xdc, 0xf0, 0x04, 0xcc, 0xf0, 0x06, 0xbc, 0x02, 0xcf, 0xc1, 0xec, 0x6a, 0x65, 0x6e, 0xfa, 0x02, 0xed, 0xa6, 0x4f, 0xd0, 0x99, 0xbe, 0x41, 0xdf, 0xa7, 0x73, 0xaf, 0xae, 0x6c,
0x4b, 0xb6, 0x92, 0xd6, 0x4c, 0xb8, 0xb3, 0xce, 0xf9, 0xb4, 0xe7, 0x7c, 0xdf, 0xd9, 0xf3, 0xc9, 0xc9, 0x16, 0x04, 0x3a, 0x74, 0x67, 0x9d, 0xf3, 0xd3, 0xf9, 0xf8, 0x9d, 0x73, 0x7e, 0x32, 0xd4,
0x50, 0x0b, 0x69, 0x70, 0x41, 0x83, 0x7d, 0x3f, 0xf0, 0x22, 0x0f, 0xad, 0x8c, 0x3c, 0xcf, 0x0f, 0x43, 0x12, 0x9c, 0x93, 0x60, 0xcf, 0x0f, 0xbc, 0xc8, 0x43, 0x95, 0x89, 0xe7, 0xf9, 0x81, 0x3f,
0xfc, 0x61, 0xe3, 0xd1, 0x99, 0xe7, 0x9d, 0x8d, 0xe8, 0x53, 0xe2, 0x3b, 0x4f, 0x89, 0xeb, 0x7a, 0x6e, 0x3d, 0x3e, 0xf5, 0xbc, 0xd3, 0x09, 0x79, 0x6e, 0xf9, 0xf6, 0x73, 0xcb, 0x75, 0xbd, 0xc8,
0x11, 0x89, 0x1c, 0xcf, 0x0d, 0x63, 0x98, 0xfa, 0x93, 0x0c, 0xf7, 0xfa, 0xfc, 0xbd, 0x8e, 0xe7, 0x8a, 0x6c, 0xcf, 0x0d, 0x63, 0x98, 0xfc, 0xa3, 0x08, 0xf7, 0x87, 0xec, 0xbd, 0x9e, 0xe7, 0xf9,
0xf9, 0xdd, 0x49, 0x64, 0xd1, 0x77, 0x13, 0x1a, 0x46, 0x68, 0x07, 0x6a, 0x01, 0x1d, 0x52, 0xe7, 0xfd, 0x69, 0x64, 0x90, 0x0f, 0x53, 0x12, 0x46, 0x68, 0x1b, 0xea, 0x01, 0x19, 0x13, 0xfb, 0x9c,
0x82, 0x06, 0xf8, 0x07, 0x7a, 0x55, 0x97, 0x9a, 0xd2, 0x6e, 0xcd, 0xaa, 0x26, 0xb1, 0x57, 0xf4, 0x04, 0xf8, 0x7b, 0x72, 0xd9, 0x14, 0xda, 0xc2, 0x4e, 0xdd, 0xa8, 0x25, 0xb6, 0x37, 0xe4, 0x12,
0x0a, 0x3d, 0x84, 0x4a, 0xf8, 0x9e, 0xf8, 0xf8, 0x9c, 0x84, 0xe7, 0x75, 0x99, 0xe7, 0x57, 0x59, 0x3d, 0x82, 0x6a, 0xf8, 0xd1, 0xf2, 0xf1, 0x99, 0x15, 0x9e, 0x35, 0x45, 0xe6, 0x5f, 0xa1, 0x86,
0xe0, 0x90, 0x84, 0xe7, 0x48, 0x81, 0x02, 0x19, 0x47, 0xf5, 0x42, 0x53, 0xda, 0x2d, 0x5a, 0xec, 0x03, 0x2b, 0x3c, 0x43, 0x12, 0x14, 0x2c, 0x27, 0x6a, 0x16, 0xda, 0xc2, 0x4e, 0xd1, 0xa0, 0x3f,
0x27, 0xfa, 0x06, 0xb6, 0x38, 0xdc, 0x9f, 0x9c, 0x8c, 0x9c, 0x21, 0xef, 0x02, 0x9f, 0x52, 0x72, 0xd1, 0xd7, 0xb0, 0xc9, 0xe0, 0xfe, 0xf4, 0x78, 0x62, 0x8f, 0x59, 0x15, 0xf8, 0x84, 0x58, 0x27,
0x3a, 0x72, 0x5c, 0x5a, 0x2f, 0x36, 0xa5, 0xdd, 0x82, 0xf5, 0x80, 0x01, 0x7a, 0xb3, 0x7c, 0x5b, 0x13, 0xdb, 0x25, 0xcd, 0x62, 0x5b, 0xd8, 0x29, 0x18, 0x0f, 0x29, 0x60, 0x30, 0xf7, 0x77, 0xb9,
0xa4, 0x51, 0x0b, 0x14, 0xde, 0xef, 0xd0, 0x1b, 0xe1, 0x0b, 0x1a, 0x84, 0x8e, 0xe7, 0xd6, 0x4b, 0x1b, 0x75, 0x40, 0x62, 0xf5, 0x8e, 0xbd, 0x09, 0x3e, 0x27, 0x41, 0x68, 0x7b, 0x6e, 0xb3, 0xd4,
0x4d, 0x69, 0x77, 0xfd, 0x79, 0x7d, 0x5f, 0x10, 0xdd, 0xef, 0x09, 0xc0, 0x71, 0x9c, 0xb7, 0x36, 0x16, 0x76, 0x56, 0x5f, 0x36, 0xf7, 0x78, 0xa3, 0x7b, 0x03, 0x0e, 0x38, 0x8a, 0xfd, 0xc6, 0x9a,
0xfc, 0x6c, 0x00, 0x6d, 0x42, 0x99, 0x5e, 0xfa, 0x4e, 0x70, 0x55, 0x2f, 0x37, 0xa5, 0xdd, 0x92, 0x9f, 0x35, 0xa0, 0x0d, 0x28, 0x93, 0x0b, 0xdf, 0x0e, 0x2e, 0x9b, 0xe5, 0xb6, 0xb0, 0x53, 0x32,
0x25, 0x9e, 0xd4, 0x3f, 0x25, 0xb8, 0x3f, 0xa7, 0x41, 0xe8, 0x7b, 0x6e, 0x48, 0x99, 0x08, 0xbc, 0xf8, 0x93, 0xfc, 0xa7, 0x00, 0x0f, 0x16, 0x38, 0x08, 0x7d, 0xcf, 0x0d, 0x09, 0x25, 0x81, 0x95,
0x65, 0xc7, 0xbd, 0xf0, 0x9c, 0x21, 0xe5, 0x22, 0x54, 0xac, 0x2a, 0x8b, 0x19, 0x71, 0x08, 0x7d, 0x6c, 0xbb, 0xe7, 0x9e, 0x3d, 0x26, 0x8c, 0x84, 0xaa, 0x51, 0xa3, 0x36, 0x2d, 0x36, 0xa1, 0xcf,
0x01, 0xeb, 0x7e, 0x40, 0x7d, 0x72, 0x35, 0x05, 0xc9, 0x1c, 0xb4, 0x16, 0x47, 0x13, 0xd8, 0x36, 0x61, 0xd5, 0x0f, 0x88, 0x6f, 0x5d, 0xce, 0x40, 0x22, 0x03, 0x35, 0x62, 0x6b, 0x02, 0xdb, 0x02,
0x40, 0x48, 0xdd, 0x53, 0x21, 0x66, 0x81, 0x8b, 0x55, 0x89, 0x23, 0x4c, 0xca, 0xc6, 0xb4, 0x35, 0x08, 0x89, 0x7b, 0xc2, 0xc9, 0x2c, 0x30, 0xb2, 0xaa, 0xb1, 0x85, 0x52, 0xd9, 0x9a, 0x95, 0x46,
0x26, 0x44, 0xe9, 0x85, 0x5c, 0x97, 0x92, 0xf6, 0x58, 0x85, 0x78, 0xb2, 0x78, 0x4c, 0xc3, 0x90, 0x89, 0x28, 0xbd, 0x12, 0x9b, 0x42, 0x52, 0x1e, 0xcd, 0x10, 0x4f, 0x16, 0x3b, 0x24, 0x0c, 0xad,
0x9c, 0x51, 0xce, 0xbc, 0x62, 0xad, 0xc5, 0xd1, 0xa3, 0x38, 0xa8, 0xfe, 0x25, 0xc1, 0x56, 0x86, 0x53, 0xc2, 0x3a, 0xaf, 0x1a, 0x8d, 0xd8, 0x7a, 0x18, 0x1b, 0xe5, 0xbf, 0x04, 0xd8, 0xcc, 0x74,
0xc5, 0xb7, 0x13, 0x2f, 0xa2, 0xc9, 0x38, 0xc5, 0x38, 0xa4, 0x8f, 0x1c, 0x87, 0xbc, 0xfc, 0x38, 0xf1, 0xcd, 0xd4, 0x8b, 0x48, 0x32, 0x4e, 0x3e, 0x0e, 0xe1, 0x86, 0xe3, 0x10, 0x6f, 0x3f, 0x8e,
0x0a, 0xff, 0x7d, 0x1c, 0xc5, 0xcc, 0x38, 0x7e, 0x95, 0x01, 0x2d, 0x12, 0x41, 0x7b, 0x70, 0x27, 0xc2, 0xbf, 0x1f, 0x47, 0x31, 0x33, 0x8e, 0x5f, 0x44, 0x40, 0xcb, 0x8d, 0xa0, 0x5d, 0x58, 0x8f,
0xee, 0x97, 0x5c, 0x8d, 0xa9, 0x1b, 0xe1, 0x53, 0x1a, 0x46, 0x62, 0x20, 0x1b, 0xbc, 0xcf, 0x38, 0xeb, 0xb5, 0x2e, 0x1d, 0xe2, 0x46, 0xf8, 0x84, 0x84, 0x11, 0x1f, 0xc8, 0x1a, 0xab, 0x33, 0xb6,
0xde, 0x66, 0x6c, 0xb7, 0x80, 0x5f, 0x44, 0xfc, 0x3d, 0x4d, 0xa8, 0xac, 0xb0, 0xe7, 0x03, 0x4a, 0x77, 0x69, 0xb7, 0x9b, 0xc0, 0x16, 0x11, 0x7f, 0x47, 0x92, 0x56, 0x2a, 0xf4, 0x79, 0x9f, 0x10,
0xd1, 0x13, 0x58, 0x4b, 0x52, 0x38, 0x20, 0x11, 0xe5, 0x7d, 0x17, 0xb8, 0xe0, 0x55, 0x81, 0xb1, 0xf4, 0x0c, 0x1a, 0x89, 0x0b, 0x07, 0x56, 0x44, 0x58, 0xdd, 0x05, 0x46, 0x78, 0x8d, 0x63, 0x0c,
0x48, 0xc4, 0x07, 0x26, 0xe6, 0xca, 0x74, 0x2b, 0x72, 0xdd, 0x2a, 0x71, 0x44, 0x1b, 0x47, 0x68, 0x2b, 0x62, 0x03, 0xe3, 0x73, 0xa5, 0xbc, 0x15, 0x19, 0x6f, 0xd5, 0xd8, 0xa2, 0x38, 0x11, 0xda,
0x0f, 0x36, 0xc6, 0x8e, 0x8b, 0xf9, 0x51, 0x64, 0xec, 0x4d, 0xdc, 0x88, 0x4f, 0xa5, 0xc8, 0x0f, 0x85, 0x35, 0xc7, 0x76, 0x31, 0x0b, 0x65, 0x39, 0xde, 0xd4, 0x8d, 0xd8, 0x54, 0x8a, 0x2c, 0x50,
0x5a, 0x1b, 0x3b, 0x6e, 0xff, 0x3d, 0xf1, 0x35, 0x9e, 0xe0, 0x58, 0x72, 0x99, 0xc1, 0x96, 0x53, 0xc3, 0xb1, 0xdd, 0xe1, 0x47, 0xcb, 0x57, 0x98, 0x83, 0x61, 0xad, 0x8b, 0x0c, 0xb6, 0x9c, 0xc2,
0x58, 0x72, 0x99, 0xc2, 0xee, 0x00, 0x0c, 0x47, 0xd1, 0x05, 0x3e, 0xa5, 0xa3, 0x88, 0xd4, 0x57, 0x5a, 0x17, 0x29, 0xec, 0x36, 0xc0, 0x78, 0x12, 0x9d, 0xe3, 0x13, 0x32, 0x89, 0xac, 0x66, 0x65,
0xa6, 0x97, 0xa1, 0xc2, 0xa2, 0x6d, 0x16, 0x54, 0xbf, 0x9b, 0x9b, 0xb3, 0x4d, 0x83, 0x71, 0x98, 0xb6, 0x0c, 0x55, 0x6a, 0xed, 0x52, 0xa3, 0xfc, 0xed, 0xc2, 0x9c, 0x4d, 0x12, 0x38, 0x61, 0x32,
0xcc, 0x39, 0x6f, 0x32, 0xd2, 0x92, 0x93, 0x51, 0x7f, 0x97, 0xe6, 0x26, 0xc0, 0x4b, 0xa0, 0x27, 0xe7, 0xbc, 0xc9, 0x08, 0xb7, 0x9c, 0x8c, 0xfc, 0xbb, 0xb0, 0x30, 0x01, 0x96, 0x02, 0x3d, 0x5b,
0x8b, 0x9c, 0xe3, 0xfb, 0x34, 0xc7, 0xf7, 0xc9, 0x22, 0x5f, 0x59, 0xe0, 0x32, 0x5c, 0x3f, 0x87, 0xee, 0x39, 0xde, 0xa7, 0x85, 0x7e, 0x9f, 0x2d, 0xf7, 0x2b, 0x72, 0x5c, 0xa6, 0xd7, 0xcf, 0x60,
0x75, 0x76, 0x5e, 0x8a, 0x6f, 0x81, 0x5f, 0x84, 0xda, 0xd8, 0x71, 0x5b, 0x09, 0x5d, 0x8e, 0x22, 0x95, 0xc6, 0x4b, 0xf5, 0x5b, 0x60, 0x8b, 0x50, 0x77, 0x6c, 0xb7, 0x93, 0xb4, 0xcb, 0x50, 0xd6,
0x97, 0x69, 0x54, 0x51, 0xa0, 0xc8, 0xe5, 0x14, 0xa5, 0xfe, 0x23, 0xc1, 0xdd, 0x59, 0xcb, 0x86, 0x45, 0x1a, 0x55, 0xe4, 0x28, 0xeb, 0x62, 0x86, 0x92, 0x7f, 0x16, 0xe1, 0xde, 0xbc, 0x64, 0xcd,
0x9b, 0xe8, 0x91, 0xdd, 0x3b, 0x69, 0x7e, 0xef, 0x96, 0xb4, 0xb0, 0x79, 0x3f, 0x28, 0x2e, 0xfa, 0x4d, 0xf8, 0xc8, 0xde, 0x9d, 0xb0, 0x78, 0x77, 0xb7, 0x94, 0xb0, 0x45, 0x3d, 0x28, 0x2e, 0xeb,
0xc1, 0x16, 0xac, 0x8e, 0x48, 0x18, 0xe1, 0x73, 0xcf, 0xe7, 0x37, 0xa2, 0x66, 0xad, 0xb0, 0xe7, 0xc1, 0x26, 0xac, 0x4c, 0xac, 0x30, 0xc2, 0x67, 0x9e, 0xcf, 0x36, 0xa2, 0x6e, 0x54, 0xe8, 0xf3,
0x43, 0xcf, 0xcf, 0x9d, 0x4d, 0x79, 0xd9, 0xd9, 0x5c, 0xa6, 0xfd, 0x9a, 0xf1, 0x9c, 0x59, 0xd5, 0x81, 0xe7, 0xe7, 0xce, 0xa6, 0x7c, 0xdb, 0xab, 0x79, 0x0a, 0x0d, 0x3f, 0xf0, 0x8e, 0xc9, 0xac,
0x87, 0xfc, 0x7a, 0xb6, 0x70, 0x72, 0x7a, 0xe1, 0x72, 0x0c, 0xa6, 0x90, 0x67, 0x30, 0xef, 0xa0, 0x86, 0x0a, 0xab, 0xa1, 0xce, 0x8c, 0xbc, 0x08, 0xf9, 0x22, 0x2d, 0xea, 0x94, 0x8c, 0xb9, 0x9e,
0x9e, 0xae, 0xfc, 0x01, 0x7b, 0xc9, 0x23, 0x2b, 0x2f, 0x4b, 0xf6, 0xef, 0x8c, 0xa7, 0x4d, 0x6b, 0x7d, 0x4a, 0xd4, 0xe7, 0x57, 0x29, 0xa6, 0xaf, 0x32, 0x47, 0x85, 0x0a, 0x79, 0x2a, 0xf4, 0x01,
0x0a, 0xca, 0xe9, 0x2d, 0x97, 0x3e, 0xb0, 0xe5, 0x72, 0xfe, 0x96, 0xe7, 0xac, 0x71, 0x71, 0x89, 0x9a, 0xe9, 0xcc, 0x9f, 0xd0, 0xa0, 0x3c, 0x46, 0xc4, 0xdb, 0x6e, 0xeb, 0xdf, 0x19, 0xe1, 0x9b,
0x35, 0x2e, 0x5d, 0xb7, 0xc6, 0xdb, 0x99, 0x35, 0x8e, 0x3f, 0x37, 0xa9, 0x15, 0xc6, 0x59, 0x29, 0xe5, 0xe4, 0x2d, 0xa7, 0xa5, 0x40, 0xf8, 0x84, 0x14, 0x88, 0xf9, 0x52, 0x90, 0x73, 0xeb, 0xc5,
0x6f, 0x7f, 0x83, 0x87, 0x70, 0x67, 0xa1, 0xc0, 0x6d, 0xef, 0xaf, 0xfa, 0xb3, 0x04, 0xcd, 0x8c, 0x5b, 0xdc, 0x7a, 0xe9, 0xaa, 0x5b, 0xdf, 0xca, 0xdc, 0x7a, 0xfc, 0x4d, 0x4a, 0xdd, 0x39, 0xce,
0x4d, 0xf4, 0x26, 0xe1, 0x79, 0x2f, 0xa0, 0xce, 0x98, 0x9c, 0xd1, 0xdb, 0xa4, 0x83, 0x1a, 0xb0, 0x52, 0x79, 0xf7, 0x67, 0x3e, 0x86, 0xf5, 0xa5, 0x04, 0x77, 0x7d, 0xe4, 0xf2, 0x4f, 0x02, 0xb4,
0xea, 0x8b, 0x73, 0x93, 0x2d, 0x4d, 0x9e, 0xd5, 0xcf, 0x60, 0xe7, 0x86, 0x26, 0xe2, 0xab, 0xa2, 0x33, 0x5a, 0x32, 0x98, 0x86, 0x67, 0x83, 0x80, 0xd8, 0x8e, 0x75, 0x4a, 0xee, 0xb2, 0x1d, 0xd4,
0xfe, 0x08, 0x0f, 0xfa, 0x93, 0x93, 0x70, 0x18, 0x38, 0x27, 0x74, 0xe0, 0x9f, 0x92, 0x88, 0xde, 0x82, 0x15, 0x9f, 0xc7, 0x4d, 0x4e, 0x39, 0x79, 0x96, 0x9f, 0xc2, 0xf6, 0x35, 0x45, 0xc4, 0xab,
0xaa, 0xde, 0x37, 0xfa, 0x88, 0x1a, 0xc1, 0xa7, 0xd3, 0xe2, 0xa2, 0xc9, 0x69, 0x0f, 0xb3, 0xed, 0x22, 0xff, 0x00, 0x0f, 0x87, 0xd3, 0xe3, 0x70, 0x1c, 0xd8, 0xc7, 0x64, 0xe4, 0x9f, 0x58, 0x11,
0x8d, 0x9c, 0x31, 0x0d, 0x23, 0x32, 0xf6, 0xb1, 0x1b, 0x8a, 0xeb, 0x5c, 0x9d, 0xc6, 0xcc, 0x10, 0xb9, 0x53, 0xbe, 0xaf, 0x15, 0x1b, 0x39, 0x82, 0xff, 0xcf, 0x92, 0xf3, 0x22, 0x67, 0x35, 0xcc,
0xed, 0x43, 0x29, 0x8c, 0x92, 0xab, 0x9c, 0x6e, 0x2e, 0x66, 0xcf, 0xe6, 0xd2, 0x67, 0x79, 0x2b, 0xaf, 0x37, 0xb2, 0x1d, 0x12, 0x46, 0x96, 0xe3, 0x63, 0x37, 0xe4, 0xeb, 0x5c, 0x9b, 0xd9, 0xf4,
0x86, 0xa9, 0x21, 0x3c, 0xce, 0x54, 0x35, 0xdc, 0xff, 0xbf, 0xe8, 0xde, 0x2f, 0x12, 0x6c, 0xcc, 0x10, 0xed, 0x41, 0x29, 0x8c, 0x92, 0x55, 0x4e, 0x17, 0x17, 0x77, 0x4f, 0xe7, 0x32, 0xa4, 0x7e,
0x89, 0x85, 0x00, 0xca, 0x1d, 0xfd, 0xa5, 0xd6, 0x7a, 0xab, 0x7c, 0x82, 0x10, 0xac, 0x1f, 0x0d, 0x23, 0x86, 0xc9, 0x21, 0x3c, 0xc9, 0x64, 0xd5, 0xdc, 0xff, 0x3e, 0xe9, 0xee, 0xaf, 0x02, 0xac,
0x3a, 0xb6, 0x81, 0x3b, 0xdd, 0x6e, 0x0f, 0x77, 0x07, 0xb6, 0x22, 0xa1, 0x2d, 0xb8, 0x6f, 0x6a, 0x2d, 0x90, 0x85, 0x00, 0xca, 0x3d, 0xf5, 0xb5, 0xd2, 0x79, 0x2f, 0xfd, 0x0f, 0x21, 0x58, 0x3d,
0xb6, 0x71, 0xac, 0xe3, 0xbe, 0xfe, 0xf2, 0xb5, 0x61, 0xc7, 0x39, 0xc3, 0x54, 0x64, 0xd4, 0x80, 0x1c, 0xf5, 0x4c, 0x0d, 0xf7, 0xfa, 0xfd, 0x01, 0xee, 0x8f, 0x4c, 0x49, 0x40, 0x9b, 0xf0, 0x40,
0xcd, 0x9e, 0xa5, 0x1b, 0x47, 0xda, 0x4b, 0x1d, 0xf7, 0x06, 0xfd, 0xc3, 0xd9, 0x6b, 0x05, 0x54, 0x57, 0x4c, 0xed, 0x48, 0xc5, 0x43, 0xf5, 0xf5, 0x5b, 0xcd, 0x8c, 0x7d, 0x9a, 0x2e, 0x89, 0xa8,
0x87, 0x7b, 0x83, 0xbe, 0x6e, 0x61, 0xfd, 0x4d, 0xcf, 0xb0, 0xde, 0xce, 0x32, 0x45, 0x54, 0x85, 0x05, 0x1b, 0x03, 0x43, 0xd5, 0x0e, 0x95, 0xd7, 0x2a, 0x1e, 0x8c, 0x86, 0x07, 0xf3, 0xd7, 0x0a,
0x95, 0x43, 0xbb, 0xd3, 0xc2, 0xc7, 0xcf, 0x95, 0xd2, 0xde, 0x1f, 0x32, 0x6c, 0xcc, 0x35, 0x8b, 0xa8, 0x09, 0xf7, 0x47, 0x43, 0xd5, 0xc0, 0xea, 0xbb, 0x81, 0x66, 0xbc, 0x9f, 0x7b, 0x8a, 0xa8,
0xd6, 0xa0, 0x62, 0x98, 0x86, 0x6d, 0x68, 0xb6, 0xde, 0x8e, 0x9b, 0xe2, 0xf8, 0xde, 0xe0, 0x45, 0x06, 0x95, 0x03, 0xb3, 0xd7, 0xc1, 0x47, 0x2f, 0xa5, 0x12, 0x5a, 0x87, 0x46, 0x2a, 0xa3, 0xa6,
0xc7, 0xe8, 0x1f, 0xea, 0x6d, 0x45, 0x62, 0x67, 0xf4, 0x07, 0xad, 0x96, 0xde, 0xef, 0x2b, 0x32, 0x4b, 0xe5, 0xdd, 0x3f, 0x44, 0x58, 0x5b, 0xa8, 0x1f, 0x35, 0xa0, 0xaa, 0xe9, 0x9a, 0xa9, 0x29,
0x03, 0x1c, 0x68, 0x46, 0x47, 0x6f, 0xe3, 0x81, 0xf9, 0xca, 0xec, 0xbe, 0x36, 0x95, 0x42, 0x2a, 0xa6, 0xda, 0x8d, 0xeb, 0x64, 0x21, 0x06, 0xa3, 0x57, 0x3d, 0x6d, 0x78, 0xa0, 0x76, 0x25, 0x81,
0x66, 0x76, 0x31, 0x7b, 0x5d, 0x29, 0xa2, 0xc7, 0xd0, 0x10, 0x31, 0xc3, 0x3c, 0xd6, 0x3a, 0x46, 0x86, 0x1d, 0x8e, 0x3a, 0x1d, 0x75, 0x38, 0x94, 0x44, 0x0a, 0xd8, 0x57, 0xb4, 0x9e, 0xda, 0xc5,
0x9b, 0x27, 0xb0, 0x76, 0xd4, 0x1d, 0x98, 0xb6, 0x52, 0x42, 0x8f, 0xa0, 0x2e, 0xf2, 0xdd, 0x83, 0x23, 0xfd, 0x8d, 0xde, 0x7f, 0xab, 0x4b, 0x85, 0x94, 0x4d, 0xef, 0x63, 0xfa, 0xba, 0x54, 0x44,
0x03, 0xdc, 0x3a, 0xd4, 0x0c, 0x13, 0xdb, 0xc6, 0x91, 0xce, 0xda, 0x2e, 0xa7, 0x4e, 0x4c, 0x62, 0x4f, 0xa0, 0xc5, 0x6d, 0x9a, 0x7e, 0xa4, 0xf4, 0xb4, 0x2e, 0x73, 0x60, 0xe5, 0xb0, 0x3f, 0xd2,
0x2b, 0x8c, 0xa4, 0x88, 0xf5, 0x5f, 0x6b, 0x3d, 0xdc, 0xd6, 0xb5, 0x76, 0xc7, 0x30, 0x75, 0x65, 0x4d, 0xa9, 0x84, 0x1e, 0x43, 0x93, 0xfb, 0xfb, 0xfb, 0xfb, 0xb8, 0x73, 0xa0, 0x68, 0x3a, 0x36,
0x15, 0x3d, 0x84, 0x07, 0x22, 0x33, 0xeb, 0xbd, 0xa5, 0xd9, 0x46, 0xd7, 0x54, 0x2a, 0xe8, 0x3e, 0xb5, 0x43, 0x95, 0x76, 0x52, 0x4e, 0x45, 0x4c, 0x6c, 0x15, 0xda, 0x37, 0xb7, 0x0d, 0xdf, 0x2a,
0xdc, 0x11, 0x67, 0xa4, 0x48, 0x01, 0xda, 0x04, 0x34, 0x30, 0xf5, 0x37, 0x3d, 0xbd, 0x65, 0xeb, 0x03, 0xdc, 0x55, 0x95, 0x6e, 0x4f, 0xd3, 0x55, 0x69, 0x05, 0x3d, 0x82, 0x87, 0xdc, 0x33, 0xaf,
0x6d, 0xcc, 0x5e, 0x1f, 0x58, 0xba, 0x52, 0x9d, 0x0a, 0xd0, 0xea, 0x9a, 0x07, 0x86, 0x75, 0xa4, 0xbd, 0xa3, 0x98, 0x5a, 0x5f, 0x97, 0xaa, 0xe8, 0x01, 0xac, 0xf3, 0x18, 0xa9, 0xa6, 0x00, 0x6d,
0xb7, 0x95, 0xda, 0xf3, 0xdf, 0xca, 0x00, 0x5c, 0x31, 0xae, 0x1d, 0xea, 0x42, 0x2d, 0xf3, 0x5f, 0x00, 0x1a, 0xe9, 0xea, 0xbb, 0x81, 0xda, 0x31, 0xd5, 0x2e, 0xa6, 0xaf, 0x8f, 0x0c, 0x55, 0xaa,
0x40, 0x9d, 0xbb, 0x09, 0x39, 0xff, 0x45, 0x1a, 0x0f, 0x6f, 0xc0, 0xa0, 0x2e, 0xac, 0x9b, 0xf4, 0xcd, 0x08, 0xe8, 0xf4, 0xf5, 0x7d, 0xcd, 0x38, 0x54, 0xbb, 0x52, 0xfd, 0xe5, 0x6f, 0x65, 0x00,
0xbd, 0x08, 0xb1, 0x42, 0x68, 0x3b, 0x1f, 0x9e, 0x9c, 0xf6, 0xf8, 0xba, 0xb4, 0xb8, 0xcd, 0x23, 0xc6, 0x18, 0xe3, 0x0e, 0xf5, 0xa1, 0x9e, 0xf9, 0x0f, 0x21, 0x2f, 0x2c, 0x47, 0xce, 0x7f, 0x98,
0xb8, 0x9b, 0xe3, 0x00, 0xe8, 0xab, 0xfc, 0xd7, 0x72, 0xac, 0xaa, 0xb1, 0xf7, 0x31, 0x50, 0x51, 0xd6, 0xa3, 0x6b, 0x30, 0xa8, 0x0f, 0xab, 0x3a, 0xf9, 0xc8, 0x4d, 0x34, 0x11, 0xda, 0xca, 0x87,
0x6d, 0xa6, 0x47, 0xfc, 0xef, 0xf4, 0x1a, 0x3d, 0xd2, 0x1f, 0xc9, 0xeb, 0xf4, 0x88, 0x0f, 0xe8, 0x27, 0xd1, 0x9e, 0x5c, 0xe5, 0xe6, 0x0b, 0x3e, 0x81, 0x7b, 0x39, 0xa2, 0x80, 0xbe, 0xcc, 0x7f,
0x40, 0x35, 0xed, 0xd5, 0x3b, 0x39, 0xd8, 0xec, 0x87, 0xa2, 0xd1, 0xb8, 0x1e, 0x82, 0x3a, 0xb0, 0x2d, 0x47, 0xbd, 0x5a, 0xbb, 0x37, 0x81, 0xf2, 0x6c, 0x73, 0x3e, 0xe2, 0x7f, 0xb5, 0x57, 0xf0,
0x26, 0xd4, 0x35, 0xb8, 0xb3, 0xa3, 0x47, 0xb9, 0xe0, 0xe4, 0xa8, 0xed, 0x6b, 0xb2, 0x82, 0xac, 0x91, 0xfe, 0x6e, 0x5e, 0xc5, 0x47, 0x1c, 0xa0, 0x07, 0xb5, 0xb4, 0x7c, 0x6f, 0xe7, 0x60, 0xb3,
0x9d, 0xf4, 0x16, 0xb7, 0x9a, 0xdf, 0x5b, 0x86, 0xaa, 0x7a, 0x13, 0x44, 0x9c, 0x7a, 0x96, 0xf2, 0xdf, 0x8e, 0x56, 0xeb, 0x6a, 0x08, 0xea, 0x41, 0x83, 0xb3, 0xab, 0x31, 0xb1, 0x47, 0x8f, 0x73,
0xe4, 0xac, 0x2d, 0xa2, 0xe6, 0xec, 0xf5, 0x7c, 0xd7, 0x6e, 0xec, 0x2e, 0x22, 0xf2, 0xad, 0xf5, 0xc1, 0x49, 0xa8, 0xad, 0x2b, 0xbc, 0xbc, 0x59, 0x33, 0xa9, 0x2d, 0x2e, 0x35, 0xbf, 0xb6, 0x4c,
0x99, 0x84, 0x28, 0x6c, 0xe6, 0x3b, 0xe1, 0x47, 0xd4, 0xf9, 0x32, 0xbf, 0xce, 0x82, 0x99, 0x3e, 0xab, 0xf2, 0x75, 0x10, 0x1e, 0xf5, 0x34, 0x25, 0xd3, 0x59, 0xa5, 0x44, 0xed, 0xf9, 0xeb, 0xf9,
0x93, 0x4e, 0xca, 0xfc, 0xa3, 0xf0, 0xf5, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbf, 0xd7, 0x01, 0x42, 0xde, 0xda, 0x59, 0x46, 0xe4, 0xab, 0xed, 0x0b, 0x01, 0x11, 0xd8, 0xc8, 0x17, 0xc7, 0x1b,
0x1e, 0x88, 0x0f, 0x00, 0x00, 0xe4, 0xf9, 0x22, 0x3f, 0xcf, 0x92, 0xbe, 0xbe, 0x10, 0x8e, 0xcb, 0xec, 0x3b, 0xf1, 0xd5, 0x3f,
0x01, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x77, 0x98, 0xf6, 0xc0, 0x0f, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.

@ -21,10 +21,10 @@ service SwapServer {
rpc LoopInQuote (ServerLoopInQuoteRequest) rpc LoopInQuote (ServerLoopInQuoteRequest)
returns (ServerLoopInQuoteResponse); returns (ServerLoopInQuoteResponse);
rpc SubscribeLoopOutUpdates(SubscribeUpdatesRequest) rpc SubscribeLoopOutUpdates (SubscribeUpdatesRequest)
returns (stream SubscribeLoopOutUpdatesResponse); returns (stream SubscribeLoopOutUpdatesResponse);
rpc SubscribeLoopInUpdates(SubscribeUpdatesRequest) rpc SubscribeLoopInUpdates (SubscribeUpdatesRequest)
returns (stream SubscribeLoopInUpdatesResponse); returns (stream SubscribeLoopInUpdatesResponse);
} }
@ -60,6 +60,10 @@ enum ProtocolVersion {
// The client will use the new v2 HTLC scripts. // The client will use the new v2 HTLC scripts.
HTLC_V2 = 5; HTLC_V2 = 5;
// The client creates a probe invoice so that the server can perform a
// multi-path probe.
MULTI_LOOP_IN = 6;
} }
message ServerLoopOutRequest { message ServerLoopOutRequest {
@ -157,6 +161,8 @@ message ServerLoopInRequest {
/// The protocol version that the client adheres to. /// The protocol version that the client adheres to.
ProtocolVersion protocol_version = 6; ProtocolVersion protocol_version = 6;
string probe_invoice = 7;
} }
message ServerLoopInResponse { message ServerLoopInResponse {
@ -270,7 +276,7 @@ enum ServerSwapState {
HTLC_CONFIRMED = 12; HTLC_CONFIRMED = 12;
} }
message SubscribeLoopOutUpdatesResponse { message SubscribeLoopOutUpdatesResponse{
// The unix timestamp in nanoseconds when the swap was updated. // The unix timestamp in nanoseconds when the swap was updated.
int64 timestamp_ns = 1; int64 timestamp_ns = 1;
@ -278,7 +284,7 @@ message SubscribeLoopOutUpdatesResponse {
ServerSwapState state = 2; ServerSwapState state = 2;
} }
message SubscribeLoopInUpdatesResponse { message SubscribeLoopInUpdatesResponse{
// The unix timestamp in nanoseconds when the swap was updated. // The unix timestamp in nanoseconds when the swap was updated.
int64 timestamp_ns = 1; int64 timestamp_ns = 1;

@ -13,6 +13,11 @@ This file tracks release notes for the loop client.
#### New Features #### New Features
* Multi-path payment has been enabled for Loop In. This means that it is now possible
to replenish multiple channels via a single Loop In request and a single on-chain htlc.
This has to potential to greatly reduce chain fee costs. Note that it is not yet possible
to select specific peers to loop in through.
#### Breaking Changes #### Breaking Changes
* Macaroon authentication has been enabled for the `loopd` gRPC and REST * Macaroon authentication has been enabled for the `loopd` gRPC and REST

@ -8,7 +8,9 @@ import (
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/loop/test" "github.com/lightninglabs/loop/test"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/routing/route"
@ -40,11 +42,13 @@ type serverMock struct {
// preimagePush is a channel that preimage pushes are sent into. // preimagePush is a channel that preimage pushes are sent into.
preimagePush chan lntypes.Preimage preimagePush chan lntypes.Preimage
lnd *test.LndMockServices
} }
var _ swapServerClient = (*serverMock)(nil) var _ swapServerClient = (*serverMock)(nil)
func newServerMock() *serverMock { func newServerMock(lnd *test.LndMockServices) *serverMock {
return &serverMock{ return &serverMock{
expectedSwapAmt: 50000, expectedSwapAmt: 50000,
@ -55,6 +59,8 @@ func newServerMock() *serverMock {
height: 600, height: 600,
preimagePush: make(chan lntypes.Preimage), preimagePush: make(chan lntypes.Preimage),
lnd: lnd,
} }
} }
@ -134,8 +140,8 @@ func getInvoice(hash lntypes.Hash, amt btcutil.Amount, memo string) (string, err
func (s *serverMock) NewLoopInSwap(ctx context.Context, func (s *serverMock) NewLoopInSwap(ctx context.Context,
swapHash lntypes.Hash, amount btcutil.Amount, swapHash lntypes.Hash, amount btcutil.Amount,
senderKey [33]byte, swapInvoice string, lastHop *route.Vertex) ( senderKey [33]byte, swapInvoice, probeInvoice string,
*newLoopInResponse, error) { lastHop *route.Vertex) (*newLoopInResponse, error) {
_, receiverKey := test.CreateKey(101) _, receiverKey := test.CreateKey(101)
@ -149,6 +155,14 @@ func (s *serverMock) NewLoopInSwap(ctx context.Context,
s.swapInvoice = swapInvoice s.swapInvoice = swapInvoice
s.swapHash = swapHash s.swapHash = swapHash
// Simulate the server paying the probe invoice and expect the client to
// cancel the probe payment.
probeSub := <-s.lnd.SingleInvoiceSubcribeChannel
probeSub.Update <- lndclient.InvoiceUpdate{
State: channeldb.ContractAccepted,
}
<-s.lnd.FailInvoiceChannel
resp := &newLoopInResponse{ resp := &newLoopInResponse{
expiry: s.height + testChargeOnChainCltvDelta, expiry: s.height + testChargeOnChainCltvDelta,
receiverKey: receiverKeyArray, receiverKey: receiverKeyArray,

@ -64,8 +64,8 @@ type swapServerClient interface {
NewLoopInSwap(ctx context.Context, NewLoopInSwap(ctx context.Context,
swapHash lntypes.Hash, amount btcutil.Amount, swapHash lntypes.Hash, amount btcutil.Amount,
senderKey [33]byte, swapInvoice string, lastHop *route.Vertex) ( senderKey [33]byte, swapInvoice, probeInvoice string,
*newLoopInResponse, error) lastHop *route.Vertex) (*newLoopInResponse, error)
// SubscribeLoopOutUpdates subscribes to loop out server state. // SubscribeLoopOutUpdates subscribes to loop out server state.
SubscribeLoopOutUpdates(ctx context.Context, SubscribeLoopOutUpdates(ctx context.Context,
@ -275,7 +275,7 @@ func (s *grpcSwapServerClient) PushLoopOutPreimage(ctx context.Context,
func (s *grpcSwapServerClient) NewLoopInSwap(ctx context.Context, func (s *grpcSwapServerClient) NewLoopInSwap(ctx context.Context,
swapHash lntypes.Hash, amount btcutil.Amount, senderKey [33]byte, swapHash lntypes.Hash, amount btcutil.Amount, senderKey [33]byte,
swapInvoice string, lastHop *route.Vertex) (*newLoopInResponse, error) { swapInvoice, probeInvoice string, lastHop *route.Vertex) (*newLoopInResponse, error) {
rpcCtx, rpcCancel := context.WithTimeout(ctx, globalCallTimeout) rpcCtx, rpcCancel := context.WithTimeout(ctx, globalCallTimeout)
defer rpcCancel() defer rpcCancel()
@ -286,6 +286,7 @@ func (s *grpcSwapServerClient) NewLoopInSwap(ctx context.Context,
SenderKey: senderKey[:], SenderKey: senderKey[:],
SwapInvoice: swapInvoice, SwapInvoice: swapInvoice,
ProtocolVersion: loopdb.CurrentRPCProtocolVersion, ProtocolVersion: loopdb.CurrentRPCProtocolVersion,
ProbeInvoice: probeInvoice,
} }
if lastHop != nil { if lastHop != nil {
req.LastHop = lastHop[:] req.LastHop = lastHop[:]

@ -55,7 +55,7 @@ func NewMockLnd() *LndMockServices {
TxPublishChannel: make(chan *wire.MsgTx), TxPublishChannel: make(chan *wire.MsgTx),
SendOutputsChannel: make(chan wire.MsgTx), SendOutputsChannel: make(chan wire.MsgTx),
SettleInvoiceChannel: make(chan lntypes.Preimage), SettleInvoiceChannel: make(chan lntypes.Preimage),
SingleInvoiceSubcribeChannel: make(chan *SingleInvoiceSubscription), SingleInvoiceSubcribeChannel: make(chan *SingleInvoiceSubscription, 1),
RouterSendPaymentChannel: make(chan RouterPaymentChannelMessage), RouterSendPaymentChannel: make(chan RouterPaymentChannelMessage),
TrackPaymentChannel: make(chan TrackPaymentMessage), TrackPaymentChannel: make(chan TrackPaymentMessage),

@ -67,9 +67,8 @@ func newSwapClient(config *clientConfig) *Client {
func createClientTestContext(t *testing.T, func createClientTestContext(t *testing.T,
pendingSwaps []*loopdb.LoopOut) *testContext { pendingSwaps []*loopdb.LoopOut) *testContext {
serverMock := newServerMock()
clientLnd := test.NewMockLnd() clientLnd := test.NewMockLnd()
serverMock := newServerMock(clientLnd)
store := newStoreMock(t) store := newStoreMock(t)
for _, s := range pendingSwaps { for _, s := range pendingSwaps {

Loading…
Cancel
Save