diff --git a/cmd/loop/staticaddr.go b/cmd/loop/staticaddr.go index 4de4e7c280..a404c5bd28 100644 --- a/cmd/loop/staticaddr.go +++ b/cmd/loop/staticaddr.go @@ -9,7 +9,10 @@ import ( "strings" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/lightninglabs/loop/labels" "github.com/lightninglabs/loop/looprpc" + "github.com/lightninglabs/loop/swapserverrpc" + "github.com/lightningnetwork/lnd/routing/route" "github.com/urfave/cli" ) @@ -24,6 +27,46 @@ var staticAddressCommands = cli.Command{ withdrawalCommand, summaryCommand, }, + Description: ` + TODO . + `, + Flags: []cli.Flag{ + cli.StringSliceFlag{ + Name: "utxo", + Usage: "specify the utxos of deposits as " + + "outpoints(tx:idx) that should be looped in.", + }, + cli.StringFlag{ + Name: "last_hop", + Usage: "the pubkey of the last hop to use for this " + + "swap", + }, + 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), + }, + cli.StringSliceFlag{ + Name: "route_hints", + Usage: "route hints that can each be individually " + + "used to assist in reaching the invoice's " + + "destination", + }, + cli.BoolFlag{ + Name: "private", + Usage: "generates and passes routehints. Should be " + + "used if the connected node is only " + + "reachable via private channels", + }, + cli.BoolFlag{ + Name: "force, f", + Usage: "Assumes yes during confirmation. Using this " + + "option will result in an immediate swap", + }, + }, + Action: staticAddressLoopIn, } var newStaticAddressCommand = cli.Command{ @@ -196,7 +239,7 @@ var summaryCommand = cli.Command{ Usage: "specify a filter to only display deposits in " + "the specified state. The state can be one " + "of [deposited|withdrawing|withdrawn|" + - "publish_expired_deposit|" + + "loopingin|loopedin|publish_expired_deposit|" + "wait_for_expiry_sweep|expired|failed].", }, }, @@ -229,6 +272,12 @@ func summary(ctx *cli.Context) error { case "withdrawn": filterState = looprpc.DepositState_WITHDRAWN + case "loopingin": + filterState = looprpc.DepositState_LOOPING_IN + + case "loopedin": + filterState = looprpc.DepositState_LOOPED_IN + case "publish_expired_deposit": filterState = looprpc.DepositState_PUBLISH_EXPIRED @@ -297,3 +346,130 @@ func NewProtoOutPoint(op string) (*looprpc.OutPoint, error) { OutputIndex: uint32(outputIndex), }, nil } + +func staticAddressLoopIn(ctx *cli.Context) error { + if ctx.NArg() > 0 { + return cli.ShowCommandHelp(ctx, "static") + } + + client, cleanup, err := getClient(ctx) + if err != nil { + return err + } + defer cleanup() + + var ( + ctxb = context.Background() + isAllSelected = ctx.IsSet("all") + isUtxoSelected = ctx.IsSet("utxo") + label = ctx.String("static-loop-in") + hints []*swapserverrpc.RouteHint + lastHop []byte + ) + + // Validate our label early so that we can fail before getting a quote. + if err := labels.Validate(label); err != nil { + return err + } + + // Private and route hints are mutually exclusive as setting private + // means we retrieve our own route hints from the connected node. + hints, err = validateRouteHints(ctx) + if err != nil { + return err + } + + if ctx.IsSet(lastHopFlag.Name) { + lastHopVertex, err := route.NewVertexFromStr( + ctx.String(lastHopFlag.Name), + ) + if err != nil { + return err + } + + lastHop = lastHopVertex[:] + } + + // Get the amount we need to quote for. + summaryResp, err := client.GetStaticAddressSummary( + ctxb, &looprpc.StaticAddressSummaryRequest{ + StateFilter: looprpc.DepositState_DEPOSITED, + }, + ) + if err != nil { + return err + } + + var depositOutpoints []string + switch { + case isAllSelected == isUtxoSelected: + return errors.New("must select either all or some utxos") + + case isAllSelected: + depositOutpoints = depositsToOutpoints( + summaryResp.FilteredDeposits, + ) + + case isUtxoSelected: + depositOutpoints = ctx.StringSlice("utxo") + + default: + return fmt.Errorf("unknown quote request") + } + + quote, err := client.GetLoopInQuote( + ctxb, &looprpc.QuoteRequest{ + LoopInRouteHints: hints, + LoopInLastHop: lastHop, + Private: ctx.Bool(privateFlag.Name), + DepositOutpoints: depositOutpoints, + }, + ) + if err != nil { + return err + } + + limits := getInLimits(quote) + + req := &looprpc.StaticAddressLoopInRequest{ + Outpoints: depositOutpoints, + MaxSwapFee: int64(limits.maxSwapFee), + LastHop: lastHop, + Label: label, + Initiator: defaultInitiator, + RouteHints: hints, + Private: ctx.Bool("private"), + } + + resp, err := client.StaticAddressLoopIn(ctxb, req) + if err != nil { + return err + } + + fmt.Printf("Static loop-in response from the server: %v\n", resp) + + return nil +} + +func sumOutpointValues(outpoints []string, deposits []*looprpc.Deposit) int64 { + var total int64 + for _, outpoint := range outpoints { + for _, deposit := range deposits { + if deposit.Outpoint == outpoint { + total += deposit.Value + break + } + } + } + + return total +} + +func depositsToOutpoints(deposits []*looprpc.Deposit) []string { + outpoints := make([]string, 0, len(deposits)) + for _, deposit := range deposits { + outpoints = append(outpoints, deposit.Outpoint) + } + + return outpoints +} diff --git a/interface.go b/interface.go index 3905159699..65af44f2b3 100644 --- a/interface.go +++ b/interface.go @@ -234,6 +234,44 @@ type LoopInRequest struct { RouteHints [][]zpay32.HopHint } +// StaticAddressLoopInRequest contains the required parameters for the swap. +type StaticAddressLoopInRequest struct { + DepositOutpoints []string + + // 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 + // the server asks for a higher fee, we abort the swap. Typically this + // value is taken from the response of the LoopInQuote call. It + // includes the pre-pay amount. + MaxSwapFee btcutil.Amount + + // LastHop optionally specifies the last hop to use for the loop in + // payment. + LastHop *route.Vertex + + // Label contains an optional label for the swap. + Label string + + // Initiator is an optional string that identifies what software + // initiated the swap (loop CLI, autolooper, LiT UI and so on) and is + // appended to the user agent string. + Initiator string + + // Private indicates whether the destination node should be considered + // private. In which case, loop will generate hophints to assist with + // probing and payment. + Private bool + + // RouteHints are optional route hints to reach the destination through + // private channels. + RouteHints [][]zpay32.HopHint +} + +// StaticAddressLoopInResponse contains the parameters for the static address +// loop-in. +type StaticAddressLoopInResponse struct { +} + // LoopInTerms are the server terms on which it executes loop in swaps. type LoopInTerms struct { // MinSwapAmount is the minimum amount that the server requires for a diff --git a/loopd/daemon.go b/loopd/daemon.go index 0a31e7fabc..cc2390a3f8 100644 --- a/loopd/daemon.go +++ b/loopd/daemon.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "errors" "fmt" + "github.com/lightninglabs/loop/staticaddr/loopin" "net" "net/http" "strings" @@ -513,6 +514,7 @@ func (d *Daemon) initialize(withMacaroonService bool) error { staticAddressManager *address.Manager depositManager *deposit.Manager withdrawalManager *withdraw.Manager + staticLoopInManager *loopin.Manager ) // Create the reservation and instantout managers. if d.cfg.EnableExperimental { @@ -589,6 +591,30 @@ func (d *Daemon) initialize(withMacaroonService bool) error { Signer: d.lnd.Signer, } withdrawalManager = withdraw.NewManager(withdrawalCfg) + + // Static address loop-in manager setup. + staticAddressLoopInStore := loopin.NewSqlStore( + loopdb.NewTypedStore[loopin.Querier](baseDb), + clock.NewDefaultClock(), depositStore, + d.lnd.ChainParams, + ) + + loopinCfg := &loopin.Config{ + StaticAddressServerClient: staticAddressClient, + SwapClient: swapClient, + LndClient: d.lnd.Client, + InvoicesClient: d.lnd.Invoices, + NodePubkey: d.lnd.NodePubkey, + AddressManager: staticAddressManager, + DepositManager: depositManager, + WithdrawalManager: withdrawalManager, + Store: staticAddressLoopInStore, + WalletKit: d.lnd.WalletKit, + ChainNotifier: d.lnd.ChainNotifier, + ChainParams: d.lnd.ChainParams, + Signer: d.lnd.Signer, + } + staticLoopInManager = loopin.NewManager(loopinCfg) } // Now finally fully initialize the swap client RPC server instance. @@ -607,6 +633,7 @@ func (d *Daemon) initialize(withMacaroonService bool) error { staticAddressManager: staticAddressManager, depositManager: depositManager, withdrawalManager: withdrawalManager, + staticLoopInManager: staticLoopInManager, } // Retrieve all currently existing swaps from the database. @@ -764,6 +791,33 @@ func (d *Daemon) initialize(withMacaroonService bool) error { withdrawalManager.WaitInitComplete() } + // Start the static address loop-in manager. + if staticLoopInManager != nil { + d.wg.Add(1) + go func() { + defer d.wg.Done() + + // Lnd's GetInfo call supplies us with the current block + // height. + info, err := d.lnd.Client.GetInfo(d.mainCtx) + if err != nil { + d.internalErrChan <- err + return + } + + log.Info("Starting static address loop-in manager...") + err = staticLoopInManager.Run( + d.mainCtx, info.BlockHeight, + ) + if err != nil && !errors.Is(context.Canceled, err) { + d.internalErrChan <- err + } + log.Info("Starting static address loop-in manager " + + "stopped") + }() + staticLoopInManager.WaitInitComplete() + } + // Last, start our internal error handler. This will return exactly one // error or nil on the main error channel to inform the caller that // something went wrong or that shutdown is complete. We don't add to diff --git a/loopd/perms/perms.go b/loopd/perms/perms.go index e04762f8cb..663fd2e722 100644 --- a/loopd/perms/perms.go +++ b/loopd/perms/perms.go @@ -101,6 +101,13 @@ var RequiredPermissions = map[string][]bakery.Op{ Entity: "loop", Action: "in", }}, + "/looprpc.SwapClient/StaticAddressLoopIn": {{ + Entity: "swap", + Action: "read", + }, { + Entity: "loop", + Action: "in", + }}, "/looprpc.SwapClient/GetLsatTokens": {{ Entity: "auth", Action: "read", diff --git a/loopd/swapclient_server.go b/loopd/swapclient_server.go index 7d511969a6..1b1080a92d 100644 --- a/loopd/swapclient_server.go +++ b/loopd/swapclient_server.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "errors" "fmt" + "github.com/lightninglabs/loop/staticaddr/loopin" "reflect" "sort" "strings" @@ -91,6 +92,7 @@ type swapClientServer struct { staticAddressManager *address.Manager depositManager *deposit.Manager withdrawalManager *withdraw.Manager + staticLoopInManager *loopin.Manager swaps map[lntypes.Hash]loop.SwapInfo subscribers map[int]chan<- interface{} statusChan chan loop.SwapInfo @@ -1461,6 +1463,47 @@ func (s *swapClientServer) GetStaticAddressSummary(ctx context.Context, ) } +type LoopInRequest struct { +} + +// StaticAddressLoopIn ... +func (s *swapClientServer) StaticAddressLoopIn(_ context.Context, + in *clientrpc.StaticAddressLoopInRequest) ( + *clientrpc.StaticAddressLoopInResponse, error) { + + log.Infof("Static loop in request received") + + routeHints, err := unmarshallRouteHints(in.RouteHints) + if err != nil { + return nil, err + } + + var lastHop route.Vertex + if in.LastHop != nil { + lastHop, err = route.NewVertexFromBytes(in.LastHop) + if err != nil { + return nil, err + } + } + + req := &loop.StaticAddressLoopInRequest{ + DepositOutpoints: in.Outpoints, + MaxSwapFee: btcutil.Amount(in.MaxSwapFee), + LastHop: &lastHop, + Label: in.Label, + Initiator: in.Initiator, + Private: in.Private, + RouteHints: routeHints, + } + + err = s.staticLoopInManager.InitiateLoopIn(req) + if err != nil { + return nil, err + } + + return &clientrpc.StaticAddressLoopInResponse{}, nil +} + func (s *swapClientServer) depositSummary(ctx context.Context, deposits []*deposit.Deposit, stateFilter clientrpc.DepositState, outpointsFilter []string) (*clientrpc.StaticAddressSummaryResponse, @@ -1472,6 +1515,7 @@ func (s *swapClientServer) depositSummary(ctx context.Context, valueDeposited int64 valueExpired int64 valueWithdrawn int64 + valueLoopedIn int64 ) // Value unconfirmed. @@ -1497,6 +1541,9 @@ func (s *swapClientServer) depositSummary(ctx context.Context, case deposit.Withdrawn: valueWithdrawn += value + + case deposit.LoopedIn: + valueLoopedIn += value } } @@ -1549,6 +1596,7 @@ func (s *swapClientServer) depositSummary(ctx context.Context, ValueDeposited: valueDeposited, ValueExpired: valueExpired, ValueWithdrawn: valueWithdrawn, + ValueLoopedIn: valueLoopedIn, FilteredDeposits: clientDeposits, }, nil } @@ -1592,6 +1640,12 @@ func toClientState(state fsm.StateType) clientrpc.DepositState { case deposit.PublishExpiredDeposit: return clientrpc.DepositState_PUBLISH_EXPIRED + case deposit.LoopingIn: + return clientrpc.DepositState_LOOPING_IN + + case deposit.LoopedIn: + return clientrpc.DepositState_LOOPED_IN + case deposit.WaitForExpirySweep: return clientrpc.DepositState_WAIT_FOR_EXPIRY_SWEEP @@ -1617,6 +1671,12 @@ func toServerState(state clientrpc.DepositState) fsm.StateType { case clientrpc.DepositState_WITHDRAWN: return deposit.Withdrawn + case clientrpc.DepositState_LOOPING_IN: + return deposit.LoopingIn + + case clientrpc.DepositState_LOOPED_IN: + return deposit.LoopedIn + case clientrpc.DepositState_PUBLISH_EXPIRED: return deposit.PublishExpiredDeposit diff --git a/loopdb/sqlc/migrations/000011_static_address_loop_in.down.sql b/loopdb/sqlc/migrations/000011_static_address_loop_in.down.sql new file mode 100644 index 0000000000..535f54c5e8 --- /dev/null +++ b/loopdb/sqlc/migrations/000011_static_address_loop_in.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS static_address_swaps; diff --git a/loopdb/sqlc/migrations/000011_static_address_loop_in.up.sql b/loopdb/sqlc/migrations/000011_static_address_loop_in.up.sql new file mode 100644 index 0000000000..1bcce667a8 --- /dev/null +++ b/loopdb/sqlc/migrations/000011_static_address_loop_in.up.sql @@ -0,0 +1,47 @@ +-- static_address_swaps... +CREATE TABLE IF NOT EXISTS static_address_swaps ( + -- swap_hash is the primary identifier of the swap + swap_hash BLOB PRIMARY KEY, + + -- swap_invoice is the invoice that needs to be paid by the server to + -- complete the loop-in swap. + swap_invoice TEXT NOT NULL, + + -- last_hop is an optional parameter that specifies the last hop to be + -- used for a loop in swap. + last_hop BLOB, + + -- quoted_swap_fee is the swap fee in sats that the server returned in + -- the swap quote. + quoted_swap_fee BIGINT NOT NULL, + + -- deposit_outpoints is a list of outpoints in the format txid:idx that are + -- used for this swap. + deposit_outpoints BLOB NOT NULL, + + + -- htlc_tx contains the htlc transaction without signatures. + htlc_tx BLOB, + -- htlc_tx_fee_rate is the fee rate in sat/kw that is used for the htlc transaction. + htlc_tx_fee_rate BIGINT NOT NULL, + htlc_timeout_sweep_tx BLOB, + htlc_timeout_sweep_address TEXT +); + + +-- static_address_swap_updates contains all the updates to a loop-in swap. +CREATE TABLE IF NOT EXISTS static_address_swap_updates ( + -- id is the auto incrementing primary key. + id INTEGER PRIMARY KEY, + + -- deposit_id is the unique identifier for the deposit. + swap_hash BLOB NOT NULL REFERENCES static_address_swaps(swap_hash), + + -- update_state is the state of the loop-in at the time of the update. + update_state TEXT NOT NULL, + + -- update_timestamp is the timestamp of the update. + update_timestamp TIMESTAMP NOT NULL +); + +CREATE INDEX IF NOT EXISTS static_address_swap_hash_idx ON static_address_swap_updates(swap_hash); diff --git a/loopdb/sqlc/models.go b/loopdb/sqlc/models.go index b369334895..deeee9a2e7 100644 --- a/loopdb/sqlc/models.go +++ b/loopdb/sqlc/models.go @@ -124,6 +124,25 @@ type StaticAddress struct { ProtocolVersion int32 } +type StaticAddressSwap struct { + SwapHash []byte + SwapInvoice string + LastHop []byte + QuotedSwapFee int64 + DepositOutpoints []byte + HtlcTx []byte + HtlcTxFeeRate int64 + HtlcTimeoutSweepTx []byte + HtlcTimeoutSweepAddress sql.NullString +} + +type StaticAddressSwapUpdate struct { + ID int32 + SwapHash []byte + UpdateState string + UpdateTimestamp time.Time +} + type Swap struct { ID int32 SwapHash []byte diff --git a/loopdb/sqlc/querier.go b/loopdb/sqlc/querier.go index a942562c22..31c81ae421 100644 --- a/loopdb/sqlc/querier.go +++ b/loopdb/sqlc/querier.go @@ -26,6 +26,7 @@ type Querier interface { GetLastUpdateID(ctx context.Context, swapHash []byte) (int32, error) GetLatestDepositUpdate(ctx context.Context, depositID []byte) (DepositUpdate, error) GetLoopInSwap(ctx context.Context, swapHash []byte) (GetLoopInSwapRow, error) + GetLoopInSwapUpdates(ctx context.Context, swapHash []byte) ([]StaticAddressSwapUpdate, error) GetLoopInSwaps(ctx context.Context) ([]GetLoopInSwapsRow, error) GetLoopOutSwap(ctx context.Context, swapHash []byte) (GetLoopOutSwapRow, error) GetLoopOutSwaps(ctx context.Context) ([]GetLoopOutSwapsRow, error) @@ -35,6 +36,8 @@ type Querier interface { GetReservationUpdates(ctx context.Context, reservationID []byte) ([]ReservationUpdate, error) GetReservations(ctx context.Context) ([]Reservation, error) GetStaticAddress(ctx context.Context, pkscript []byte) (StaticAddress, error) + GetStaticAddressLoopInSwap(ctx context.Context, swapHash []byte) (GetStaticAddressLoopInSwapRow, error) + GetStaticAddressLoopInSwaps(ctx context.Context) ([]GetStaticAddressLoopInSwapsRow, error) GetSwapUpdates(ctx context.Context, swapHash []byte) ([]SwapUpdate, error) GetSweepStatus(ctx context.Context, swapHash []byte) (bool, error) GetUnconfirmedBatches(ctx context.Context) ([]SweepBatch, error) @@ -47,6 +50,8 @@ type Querier interface { InsertLoopOut(ctx context.Context, arg InsertLoopOutParams) error InsertMigration(ctx context.Context, arg InsertMigrationParams) error InsertReservationUpdate(ctx context.Context, arg InsertReservationUpdateParams) error + InsertStaticAddressLoopIn(ctx context.Context, arg InsertStaticAddressLoopInParams) error + InsertStaticAddressMetaUpdate(ctx context.Context, arg InsertStaticAddressMetaUpdateParams) error InsertSwap(ctx context.Context, arg InsertSwapParams) error InsertSwapUpdate(ctx context.Context, arg InsertSwapUpdateParams) error OverrideSwapCosts(ctx context.Context, arg OverrideSwapCostsParams) error @@ -54,6 +59,7 @@ type Querier interface { UpdateDeposit(ctx context.Context, arg UpdateDepositParams) error UpdateInstantOut(ctx context.Context, arg UpdateInstantOutParams) error UpdateReservation(ctx context.Context, arg UpdateReservationParams) error + UpdateStaticAddressLoopIn(ctx context.Context, arg UpdateStaticAddressLoopInParams) error UpsertLiquidityParams(ctx context.Context, params []byte) error UpsertSweep(ctx context.Context, arg UpsertSweepParams) error } diff --git a/loopdb/sqlc/queries/static_address_loopin.sql b/loopdb/sqlc/queries/static_address_loopin.sql new file mode 100644 index 0000000000..3ade525287 --- /dev/null +++ b/loopdb/sqlc/queries/static_address_loopin.sql @@ -0,0 +1,79 @@ +-- name: InsertStaticAddressLoopIn :exec +INSERT INTO static_address_swaps ( + swap_hash, + swap_invoice, + last_hop, + quoted_swap_fee, + deposit_outpoints, + htlc_tx, + htlc_tx_fee_rate, + htlc_timeout_sweep_tx, + htlc_timeout_sweep_address +) VALUES ( + $1, + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9 +); + +-- name: UpdateStaticAddressLoopIn :exec +UPDATE static_address_swaps +SET + htlc_tx = $2, + htlc_tx_fee_rate = $3, + htlc_timeout_sweep_tx = $4, + htlc_timeout_sweep_address = $5 +WHERE + static_address_swaps.swap_hash = $1; + +-- name: InsertStaticAddressMetaUpdate :exec +INSERT INTO static_address_swap_updates ( + swap_hash, + update_state, + update_timestamp +) VALUES ( + $1, + $2, + $3 + ); + +-- name: GetStaticAddressLoopInSwap :one +SELECT + swaps.*, + static_address_swaps.*, + htlc_keys.* +FROM + swaps + JOIN + static_address_swaps ON swaps.swap_hash = static_address_swaps.swap_hash + JOIN + htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash +WHERE + swaps.swap_hash = $1; + +-- name: GetStaticAddressLoopInSwaps :many +SELECT + swaps.*, + static_address_swaps.*, + htlc_keys.* +FROM + swaps + JOIN + static_address_swaps ON swaps.swap_hash = static_address_swaps.swap_hash + JOIN + htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash +ORDER BY + swaps.id; + +-- name: GetLoopInSwapUpdates :many +SELECT + static_address_swap_updates.* +FROM + static_address_swap_updates +WHERE + static_address_swap_updates.swap_hash = $1; \ No newline at end of file diff --git a/loopdb/sqlc/static_address_loopin.sql.go b/loopdb/sqlc/static_address_loopin.sql.go new file mode 100644 index 0000000000..9295fffd05 --- /dev/null +++ b/loopdb/sqlc/static_address_loopin.sql.go @@ -0,0 +1,329 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.25.0 +// source: static_address_loopin.sql + +package sqlc + +import ( + "context" + "database/sql" + "time" +) + +const getLoopInSwapUpdates = `-- name: GetLoopInSwapUpdates :many +SELECT + static_address_swap_updates.id, static_address_swap_updates.swap_hash, static_address_swap_updates.update_state, static_address_swap_updates.update_timestamp +FROM + static_address_swap_updates +WHERE + static_address_swap_updates.swap_hash = $1 +` + +func (q *Queries) GetLoopInSwapUpdates(ctx context.Context, swapHash []byte) ([]StaticAddressSwapUpdate, error) { + rows, err := q.db.QueryContext(ctx, getLoopInSwapUpdates, swapHash) + if err != nil { + return nil, err + } + defer rows.Close() + var items []StaticAddressSwapUpdate + for rows.Next() { + var i StaticAddressSwapUpdate + if err := rows.Scan( + &i.ID, + &i.SwapHash, + &i.UpdateState, + &i.UpdateTimestamp, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getStaticAddressLoopInSwap = `-- name: GetStaticAddressLoopInSwap :one +SELECT + swaps.id, swaps.swap_hash, swaps.preimage, swaps.initiation_time, swaps.amount_requested, swaps.cltv_expiry, swaps.max_miner_fee, swaps.max_swap_fee, swaps.initiation_height, swaps.protocol_version, swaps.label, + static_address_swaps.swap_hash, static_address_swaps.swap_invoice, static_address_swaps.last_hop, static_address_swaps.quoted_swap_fee, static_address_swaps.deposit_outpoints, static_address_swaps.htlc_tx, static_address_swaps.htlc_tx_fee_rate, static_address_swaps.htlc_timeout_sweep_tx, static_address_swaps.htlc_timeout_sweep_address, + htlc_keys.swap_hash, htlc_keys.sender_script_pubkey, htlc_keys.receiver_script_pubkey, htlc_keys.sender_internal_pubkey, htlc_keys.receiver_internal_pubkey, htlc_keys.client_key_family, htlc_keys.client_key_index +FROM + swaps + JOIN + static_address_swaps ON swaps.swap_hash = static_address_swaps.swap_hash + JOIN + htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash +WHERE + swaps.swap_hash = $1 +` + +type GetStaticAddressLoopInSwapRow struct { + ID int32 + SwapHash []byte + Preimage []byte + InitiationTime time.Time + AmountRequested int64 + CltvExpiry int32 + MaxMinerFee int64 + MaxSwapFee int64 + InitiationHeight int32 + ProtocolVersion int32 + Label string + SwapHash_2 []byte + SwapInvoice string + LastHop []byte + QuotedSwapFee int64 + DepositOutpoints []byte + HtlcTx []byte + HtlcTxFeeRate int64 + HtlcTimeoutSweepTx []byte + HtlcTimeoutSweepAddress sql.NullString + SwapHash_3 []byte + SenderScriptPubkey []byte + ReceiverScriptPubkey []byte + SenderInternalPubkey []byte + ReceiverInternalPubkey []byte + ClientKeyFamily int32 + ClientKeyIndex int32 +} + +func (q *Queries) GetStaticAddressLoopInSwap(ctx context.Context, swapHash []byte) (GetStaticAddressLoopInSwapRow, error) { + row := q.db.QueryRowContext(ctx, getStaticAddressLoopInSwap, swapHash) + var i GetStaticAddressLoopInSwapRow + err := row.Scan( + &i.ID, + &i.SwapHash, + &i.Preimage, + &i.InitiationTime, + &i.AmountRequested, + &i.CltvExpiry, + &i.MaxMinerFee, + &i.MaxSwapFee, + &i.InitiationHeight, + &i.ProtocolVersion, + &i.Label, + &i.SwapHash_2, + &i.SwapInvoice, + &i.LastHop, + &i.QuotedSwapFee, + &i.DepositOutpoints, + &i.HtlcTx, + &i.HtlcTxFeeRate, + &i.HtlcTimeoutSweepTx, + &i.HtlcTimeoutSweepAddress, + &i.SwapHash_3, + &i.SenderScriptPubkey, + &i.ReceiverScriptPubkey, + &i.SenderInternalPubkey, + &i.ReceiverInternalPubkey, + &i.ClientKeyFamily, + &i.ClientKeyIndex, + ) + return i, err +} + +const getStaticAddressLoopInSwaps = `-- name: GetStaticAddressLoopInSwaps :many +SELECT + swaps.id, swaps.swap_hash, swaps.preimage, swaps.initiation_time, swaps.amount_requested, swaps.cltv_expiry, swaps.max_miner_fee, swaps.max_swap_fee, swaps.initiation_height, swaps.protocol_version, swaps.label, + static_address_swaps.swap_hash, static_address_swaps.swap_invoice, static_address_swaps.last_hop, static_address_swaps.quoted_swap_fee, static_address_swaps.deposit_outpoints, static_address_swaps.htlc_tx, static_address_swaps.htlc_tx_fee_rate, static_address_swaps.htlc_timeout_sweep_tx, static_address_swaps.htlc_timeout_sweep_address, + htlc_keys.swap_hash, htlc_keys.sender_script_pubkey, htlc_keys.receiver_script_pubkey, htlc_keys.sender_internal_pubkey, htlc_keys.receiver_internal_pubkey, htlc_keys.client_key_family, htlc_keys.client_key_index +FROM + swaps + JOIN + static_address_swaps ON swaps.swap_hash = static_address_swaps.swap_hash + JOIN + htlc_keys ON swaps.swap_hash = htlc_keys.swap_hash +ORDER BY + swaps.id +` + +type GetStaticAddressLoopInSwapsRow struct { + ID int32 + SwapHash []byte + Preimage []byte + InitiationTime time.Time + AmountRequested int64 + CltvExpiry int32 + MaxMinerFee int64 + MaxSwapFee int64 + InitiationHeight int32 + ProtocolVersion int32 + Label string + SwapHash_2 []byte + SwapInvoice string + LastHop []byte + QuotedSwapFee int64 + DepositOutpoints []byte + HtlcTx []byte + HtlcTxFeeRate int64 + HtlcTimeoutSweepTx []byte + HtlcTimeoutSweepAddress sql.NullString + SwapHash_3 []byte + SenderScriptPubkey []byte + ReceiverScriptPubkey []byte + SenderInternalPubkey []byte + ReceiverInternalPubkey []byte + ClientKeyFamily int32 + ClientKeyIndex int32 +} + +func (q *Queries) GetStaticAddressLoopInSwaps(ctx context.Context) ([]GetStaticAddressLoopInSwapsRow, error) { + rows, err := q.db.QueryContext(ctx, getStaticAddressLoopInSwaps) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetStaticAddressLoopInSwapsRow + for rows.Next() { + var i GetStaticAddressLoopInSwapsRow + if err := rows.Scan( + &i.ID, + &i.SwapHash, + &i.Preimage, + &i.InitiationTime, + &i.AmountRequested, + &i.CltvExpiry, + &i.MaxMinerFee, + &i.MaxSwapFee, + &i.InitiationHeight, + &i.ProtocolVersion, + &i.Label, + &i.SwapHash_2, + &i.SwapInvoice, + &i.LastHop, + &i.QuotedSwapFee, + &i.DepositOutpoints, + &i.HtlcTx, + &i.HtlcTxFeeRate, + &i.HtlcTimeoutSweepTx, + &i.HtlcTimeoutSweepAddress, + &i.SwapHash_3, + &i.SenderScriptPubkey, + &i.ReceiverScriptPubkey, + &i.SenderInternalPubkey, + &i.ReceiverInternalPubkey, + &i.ClientKeyFamily, + &i.ClientKeyIndex, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const insertStaticAddressLoopIn = `-- name: InsertStaticAddressLoopIn :exec +INSERT INTO static_address_swaps ( + swap_hash, + swap_invoice, + last_hop, + quoted_swap_fee, + deposit_outpoints, + htlc_tx, + htlc_tx_fee_rate, + htlc_timeout_sweep_tx, + htlc_timeout_sweep_address +) VALUES ( + $1, + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9 +) +` + +type InsertStaticAddressLoopInParams struct { + SwapHash []byte + SwapInvoice string + LastHop []byte + QuotedSwapFee int64 + DepositOutpoints []byte + HtlcTx []byte + HtlcTxFeeRate int64 + HtlcTimeoutSweepTx []byte + HtlcTimeoutSweepAddress sql.NullString +} + +func (q *Queries) InsertStaticAddressLoopIn(ctx context.Context, arg InsertStaticAddressLoopInParams) error { + _, err := q.db.ExecContext(ctx, insertStaticAddressLoopIn, + arg.SwapHash, + arg.SwapInvoice, + arg.LastHop, + arg.QuotedSwapFee, + arg.DepositOutpoints, + arg.HtlcTx, + arg.HtlcTxFeeRate, + arg.HtlcTimeoutSweepTx, + arg.HtlcTimeoutSweepAddress, + ) + return err +} + +const insertStaticAddressMetaUpdate = `-- name: InsertStaticAddressMetaUpdate :exec +INSERT INTO static_address_swap_updates ( + swap_hash, + update_state, + update_timestamp +) VALUES ( + $1, + $2, + $3 + ) +` + +type InsertStaticAddressMetaUpdateParams struct { + SwapHash []byte + UpdateState string + UpdateTimestamp time.Time +} + +func (q *Queries) InsertStaticAddressMetaUpdate(ctx context.Context, arg InsertStaticAddressMetaUpdateParams) error { + _, err := q.db.ExecContext(ctx, insertStaticAddressMetaUpdate, arg.SwapHash, arg.UpdateState, arg.UpdateTimestamp) + return err +} + +const updateStaticAddressLoopIn = `-- name: UpdateStaticAddressLoopIn :exec +UPDATE static_address_swaps +SET + htlc_tx = $2, + htlc_tx_fee_rate = $3, + htlc_timeout_sweep_tx = $4, + htlc_timeout_sweep_address = $5 +WHERE + static_address_swaps.swap_hash = $1 +` + +type UpdateStaticAddressLoopInParams struct { + SwapHash []byte + HtlcTx []byte + HtlcTxFeeRate int64 + HtlcTimeoutSweepTx []byte + HtlcTimeoutSweepAddress sql.NullString +} + +func (q *Queries) UpdateStaticAddressLoopIn(ctx context.Context, arg UpdateStaticAddressLoopInParams) error { + _, err := q.db.ExecContext(ctx, updateStaticAddressLoopIn, + arg.SwapHash, + arg.HtlcTx, + arg.HtlcTxFeeRate, + arg.HtlcTimeoutSweepTx, + arg.HtlcTimeoutSweepAddress, + ) + return err +} diff --git a/looprpc/client.pb.go b/looprpc/client.pb.go index 3e781c5e35..45d11489c1 100644 --- a/looprpc/client.pb.go +++ b/looprpc/client.pb.go @@ -453,17 +453,23 @@ const ( DepositState_WITHDRAWING DepositState = 2 // WITHDRAWN indicates that the deposit has been withdrawn. DepositState_WITHDRAWN DepositState = 3 + // LOOPING_IN indicates that the deposit is currently being used in a static + // address loop-in swap. + DepositState_LOOPING_IN DepositState = 4 + // LOOPED_IN indicates that the deposit was used in a static address loop-in + // swap. + DepositState_LOOPED_IN DepositState = 5 // PUBLISH_EXPIRED indicates that the deposit has expired and the sweep // transaction has been published. - DepositState_PUBLISH_EXPIRED DepositState = 4 + DepositState_PUBLISH_EXPIRED DepositState = 6 // WAIT_FOR_EXPIRY_SWEEP indicates that the deposit has expired and the sweep // transaction has not yet been sufficiently confirmed. - DepositState_WAIT_FOR_EXPIRY_SWEEP DepositState = 5 + DepositState_WAIT_FOR_EXPIRY_SWEEP DepositState = 7 // EXPIRED indicates that the deposit has expired and the sweep transaction // has been sufficiently confirmed. - DepositState_EXPIRED DepositState = 6 + DepositState_EXPIRED DepositState = 8 // FAILED_STATE indicates that the deposit has failed. - DepositState_FAILED_STATE DepositState = 7 + DepositState_FAILED_STATE DepositState = 9 ) // Enum value maps for DepositState. @@ -473,20 +479,24 @@ var ( 1: "DEPOSITED", 2: "WITHDRAWING", 3: "WITHDRAWN", - 4: "PUBLISH_EXPIRED", - 5: "WAIT_FOR_EXPIRY_SWEEP", - 6: "EXPIRED", - 7: "FAILED_STATE", + 4: "LOOPING_IN", + 5: "LOOPED_IN", + 6: "PUBLISH_EXPIRED", + 7: "WAIT_FOR_EXPIRY_SWEEP", + 8: "EXPIRED", + 9: "FAILED_STATE", } DepositState_value = map[string]int32{ "UNKNOWN_STATE": 0, "DEPOSITED": 1, "WITHDRAWING": 2, "WITHDRAWN": 3, - "PUBLISH_EXPIRED": 4, - "WAIT_FOR_EXPIRY_SWEEP": 5, - "EXPIRED": 6, - "FAILED_STATE": 7, + "LOOPING_IN": 4, + "LOOPED_IN": 5, + "PUBLISH_EXPIRED": 6, + "WAIT_FOR_EXPIRY_SWEEP": 7, + "EXPIRED": 8, + "FAILED_STATE": 9, } ) @@ -4483,8 +4493,10 @@ type StaticAddressSummaryResponse struct { ValueExpired int64 `protobuf:"varint,5,opt,name=value_expired,json=valueExpired,proto3" json:"value_expired,omitempty"` // The total value of all deposits that have been withdrawn. ValueWithdrawn int64 `protobuf:"varint,6,opt,name=value_withdrawn,json=valueWithdrawn,proto3" json:"value_withdrawn,omitempty"` + // The total value of all loop-ins that have been finalized. + ValueLoopedIn int64 `protobuf:"varint,7,opt,name=value_looped_in,json=valueLoopedIn,proto3" json:"value_looped_in,omitempty"` // A list of all deposits that match the filtered state. - FilteredDeposits []*Deposit `protobuf:"bytes,7,rep,name=filtered_deposits,json=filteredDeposits,proto3" json:"filtered_deposits,omitempty"` + FilteredDeposits []*Deposit `protobuf:"bytes,8,rep,name=filtered_deposits,json=filteredDeposits,proto3" json:"filtered_deposits,omitempty"` } func (x *StaticAddressSummaryResponse) Reset() { @@ -4561,6 +4573,13 @@ func (x *StaticAddressSummaryResponse) GetValueWithdrawn() int64 { return 0 } +func (x *StaticAddressSummaryResponse) GetValueLoopedIn() int64 { + if x != nil { + return x.ValueLoopedIn + } + return 0 +} + func (x *StaticAddressSummaryResponse) GetFilteredDeposits() []*Deposit { if x != nil { return x.FilteredDeposits @@ -4652,6 +4671,158 @@ func (x *Deposit) GetConfirmationHeight() int64 { return 0 } +type StaticAddressLoopInRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The outpoints of the deposits to loop-in. + Outpoints []string `protobuf:"bytes,1,rep,name=outpoints,proto3" json:"outpoints,omitempty"` + // Maximum we are willing to pay the server for the 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 value is taken from the response of + // the GetQuote call. + MaxSwapFee int64 `protobuf:"varint,2,opt,name=max_swap_fee,json=maxSwapFee,proto3" json:"max_swap_fee,omitempty"` + // Optionally the client can specify the last hop pubkey when requesting a + // loop-in quote. This is useful to get better off-chain routing fee from the + // server. + LastHop []byte `protobuf:"bytes,3,opt,name=last_hop,json=lastHop,proto3" json:"last_hop,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,4,opt,name=label,proto3" json:"label,omitempty"` + // An optional identification string that will be appended to the user agent + // string sent to the server to give information about the usage of loop. This + // initiator part is meant for user interfaces to add their name to give the + // full picture of the binary used (loopd, LiT) and the method used for + // triggering the swap (loop CLI, autolooper, LiT UI, other 3rd party UI). + Initiator string `protobuf:"bytes,5,opt,name=initiator,proto3" json:"initiator,omitempty"` + // Optional route hints to reach the destination through private channels. + RouteHints []*swapserverrpc.RouteHint `protobuf:"bytes,6,rep,name=route_hints,json=routeHints,proto3" json:"route_hints,omitempty"` + // Private indicates whether the destination node should be considered private. + // In which case, loop will generate hop hints to assist with probing and + // payment. + Private bool `protobuf:"varint,7,opt,name=private,proto3" json:"private,omitempty"` +} + +func (x *StaticAddressLoopInRequest) Reset() { + *x = StaticAddressLoopInRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_client_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StaticAddressLoopInRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StaticAddressLoopInRequest) ProtoMessage() {} + +func (x *StaticAddressLoopInRequest) ProtoReflect() protoreflect.Message { + mi := &file_client_proto_msgTypes[54] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StaticAddressLoopInRequest.ProtoReflect.Descriptor instead. +func (*StaticAddressLoopInRequest) Descriptor() ([]byte, []int) { + return file_client_proto_rawDescGZIP(), []int{54} +} + +func (x *StaticAddressLoopInRequest) GetOutpoints() []string { + if x != nil { + return x.Outpoints + } + return nil +} + +func (x *StaticAddressLoopInRequest) GetMaxSwapFee() int64 { + if x != nil { + return x.MaxSwapFee + } + return 0 +} + +func (x *StaticAddressLoopInRequest) GetLastHop() []byte { + if x != nil { + return x.LastHop + } + return nil +} + +func (x *StaticAddressLoopInRequest) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +func (x *StaticAddressLoopInRequest) GetInitiator() string { + if x != nil { + return x.Initiator + } + return "" +} + +func (x *StaticAddressLoopInRequest) GetRouteHints() []*swapserverrpc.RouteHint { + if x != nil { + return x.RouteHints + } + return nil +} + +func (x *StaticAddressLoopInRequest) GetPrivate() bool { + if x != nil { + return x.Private + } + return false +} + +type StaticAddressLoopInResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StaticAddressLoopInResponse) Reset() { + *x = StaticAddressLoopInResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_client_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StaticAddressLoopInResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StaticAddressLoopInResponse) ProtoMessage() {} + +func (x *StaticAddressLoopInResponse) ProtoReflect() protoreflect.Message { + mi := &file_client_proto_msgTypes[55] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StaticAddressLoopInResponse.ProtoReflect.Descriptor instead. +func (*StaticAddressLoopInResponse) Descriptor() ([]byte, []int) { + return file_client_proto_rawDescGZIP(), []int{55} +} + var File_client_proto protoreflect.FileDescriptor var file_client_proto_rawDesc = []byte{ @@ -5189,7 +5360,7 @@ var file_client_proto_rawDesc = []byte{ 0x74, 0x61, 0x74, 0x65, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, - 0xd6, 0x02, 0x0a, 0x1c, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0xfe, 0x02, 0x0a, 0x1c, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, @@ -5206,218 +5377,247 @@ var file_client_proto_rawDesc = []byte{ 0x28, 0x03, 0x52, 0x0c, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x6e, 0x12, 0x3d, 0x0a, 0x11, 0x66, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x18, 0x07, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, - 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x52, 0x10, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, - 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x22, 0xa9, 0x01, 0x0a, 0x07, 0x44, 0x65, 0x70, - 0x6f, 0x73, 0x69, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x2b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, - 0x70, 0x6f, 0x73, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, - 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x12, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x2a, 0x3b, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x12, 0x0a, - 0x0e, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x4b, 0x45, 0x59, 0x10, - 0x01, 0x2a, 0x25, 0x0a, 0x08, 0x53, 0x77, 0x61, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0c, 0x0a, - 0x08, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x4c, - 0x4f, 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x01, 0x2a, 0x73, 0x0a, 0x09, 0x53, 0x77, 0x61, 0x70, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x50, 0x52, 0x45, 0x49, 0x4d, 0x41, 0x47, 0x45, - 0x5f, 0x52, 0x45, 0x56, 0x45, 0x41, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x48, - 0x54, 0x4c, 0x43, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x02, 0x12, - 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, - 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x56, 0x4f, - 0x49, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x44, 0x10, 0x05, 0x2a, 0xeb, 0x02, - 0x0a, 0x0d, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, - 0x17, 0x0a, 0x13, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, - 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x41, 0x49, 0x4c, - 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4f, 0x46, 0x46, 0x43, 0x48, - 0x41, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, - 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, - 0x02, 0x12, 0x20, 0x0a, 0x1c, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x57, 0x45, 0x45, 0x50, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, - 0x54, 0x10, 0x03, 0x12, 0x25, 0x0a, 0x21, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, - 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, - 0x4e, 0x54, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x04, 0x12, 0x1c, 0x0a, 0x18, 0x46, 0x41, - 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x45, 0x4d, - 0x50, 0x4f, 0x52, 0x41, 0x52, 0x59, 0x10, 0x05, 0x12, 0x23, 0x0a, 0x1f, 0x46, 0x41, 0x49, 0x4c, - 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, - 0x52, 0x45, 0x43, 0x54, 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x06, 0x12, 0x1c, 0x0a, - 0x18, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, - 0x41, 0x42, 0x41, 0x4e, 0x44, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x07, 0x12, 0x31, 0x0a, 0x2d, 0x46, - 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, - 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, - 0x52, 0x4d, 0x45, 0x44, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x08, 0x12, 0x2b, - 0x0a, 0x27, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, - 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, - 0x41, 0x4d, 0x54, 0x5f, 0x53, 0x57, 0x45, 0x50, 0x54, 0x10, 0x09, 0x2a, 0x2f, 0x0a, 0x11, 0x4c, - 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0d, 0x0a, - 0x09, 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, 0x10, 0x01, 0x2a, 0xa6, 0x03, 0x0a, - 0x0a, 0x41, 0x75, 0x74, 0x6f, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x41, - 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, - 0x57, 0x4e, 0x10, 0x00, 0x12, 0x22, 0x0a, 0x1e, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x42, 0x55, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x53, - 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x55, 0x54, 0x4f, - 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x57, 0x45, 0x45, 0x50, 0x5f, 0x46, 0x45, - 0x45, 0x53, 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x42, 0x55, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x45, 0x4c, 0x41, 0x50, 0x53, - 0x45, 0x44, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x5f, 0x46, 0x4c, 0x49, 0x47, 0x48, 0x54, 0x10, 0x04, 0x12, - 0x18, 0x0a, 0x14, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x53, - 0x57, 0x41, 0x50, 0x5f, 0x46, 0x45, 0x45, 0x10, 0x05, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x55, 0x54, - 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x49, 0x4e, 0x45, 0x52, 0x5f, 0x46, - 0x45, 0x45, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x50, 0x52, 0x45, 0x50, 0x41, 0x59, 0x10, 0x07, 0x12, 0x1f, 0x0a, 0x1b, - 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, - 0x55, 0x52, 0x45, 0x5f, 0x42, 0x41, 0x43, 0x4b, 0x4f, 0x46, 0x46, 0x10, 0x08, 0x12, 0x18, 0x0a, - 0x14, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4c, 0x4f, 0x4f, - 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x09, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x55, 0x54, 0x4f, 0x5f, - 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x0a, - 0x12, 0x1c, 0x0a, 0x18, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, - 0x4c, 0x49, 0x51, 0x55, 0x49, 0x44, 0x49, 0x54, 0x59, 0x5f, 0x4f, 0x4b, 0x10, 0x0b, 0x12, 0x23, - 0x0a, 0x1f, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x42, 0x55, - 0x44, 0x47, 0x45, 0x54, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, - 0x54, 0x10, 0x0c, 0x12, 0x20, 0x0a, 0x1c, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, - 0x4f, 0x4e, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, - 0x45, 0x4e, 0x54, 0x10, 0x0d, 0x2a, 0x9f, 0x01, 0x0a, 0x0c, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, - 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, - 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x45, 0x50, - 0x4f, 0x53, 0x49, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x57, 0x49, 0x54, 0x48, - 0x44, 0x52, 0x41, 0x57, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x57, 0x49, 0x54, - 0x48, 0x44, 0x52, 0x41, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x55, 0x42, 0x4c, - 0x49, 0x53, 0x48, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x04, 0x12, 0x19, 0x0a, - 0x15, 0x57, 0x41, 0x49, 0x54, 0x5f, 0x46, 0x4f, 0x52, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59, - 0x5f, 0x53, 0x57, 0x45, 0x45, 0x50, 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x58, 0x50, 0x49, - 0x52, 0x45, 0x44, 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, - 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x07, 0x32, 0xd4, 0x0e, 0x0a, 0x0a, 0x53, 0x77, 0x61, 0x70, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x07, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, - 0x74, 0x12, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x70, - 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x37, 0x0a, 0x06, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x12, 0x16, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, - 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x07, 0x4d, 0x6f, - 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x12, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x61, - 0x70, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, - 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x08, 0x53, 0x77, 0x61, - 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x53, 0x77, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x48, 0x0a, 0x0b, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x53, - 0x77, 0x61, 0x70, 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, - 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, - 0x6f, 0x6e, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, - 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x15, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x40, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, - 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, - 0x65, 0x72, 0x6d, 0x73, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, - 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x73, + 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x6e, 0x12, 0x26, 0x0a, 0x0f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x5f, 0x6c, 0x6f, 0x6f, 0x70, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x65, 0x64, 0x49, + 0x6e, 0x12, 0x3d, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x64, 0x65, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x52, 0x10, + 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, + 0x22, 0xa9, 0x01, 0x0a, 0x07, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2b, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, + 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0xfa, 0x01, 0x0a, + 0x1a, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x6f, + 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6f, + 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, + 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x6d, 0x61, 0x78, + 0x5f, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x66, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x6d, 0x61, 0x78, 0x53, 0x77, 0x61, 0x70, 0x46, 0x65, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6c, + 0x61, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6c, + 0x61, 0x73, 0x74, 0x48, 0x6f, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x09, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x0b, 0x72, 0x6f, + 0x75, 0x74, 0x65, 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x12, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, + 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x69, 0x6e, 0x74, 0x73, 0x12, + 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x22, 0x1d, 0x0a, 0x1b, 0x53, 0x74, 0x61, + 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x3b, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x44, 0x44, 0x52, 0x45, + 0x53, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, + 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x41, 0x50, 0x52, 0x4f, 0x4f, 0x54, 0x5f, 0x50, 0x55, 0x42, + 0x4b, 0x45, 0x59, 0x10, 0x01, 0x2a, 0x25, 0x0a, 0x08, 0x53, 0x77, 0x61, 0x70, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x00, 0x12, + 0x0b, 0x0a, 0x07, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x01, 0x2a, 0x73, 0x0a, 0x09, + 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4e, 0x49, + 0x54, 0x49, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x50, 0x52, 0x45, 0x49, + 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x45, 0x56, 0x45, 0x41, 0x4c, 0x45, 0x44, 0x10, 0x01, 0x12, + 0x12, 0x0a, 0x0e, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, + 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x03, + 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, + 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x44, 0x10, + 0x05, 0x2a, 0xeb, 0x02, 0x0a, 0x0d, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, + 0x73, 0x6f, 0x6e, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, + 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, + 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4f, + 0x46, 0x46, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x41, 0x49, + 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, + 0x4f, 0x55, 0x54, 0x10, 0x02, 0x12, 0x20, 0x0a, 0x1c, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, + 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x57, 0x45, 0x45, 0x50, 0x5f, 0x54, 0x49, + 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x03, 0x12, 0x25, 0x0a, 0x21, 0x46, 0x41, 0x49, 0x4c, 0x55, + 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, + 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x10, 0x04, 0x12, 0x1c, + 0x0a, 0x18, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, + 0x5f, 0x54, 0x45, 0x4d, 0x50, 0x4f, 0x52, 0x41, 0x52, 0x59, 0x10, 0x05, 0x12, 0x23, 0x0a, 0x1f, + 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, + 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x10, + 0x06, 0x12, 0x1c, 0x0a, 0x18, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, + 0x53, 0x4f, 0x4e, 0x5f, 0x41, 0x42, 0x41, 0x4e, 0x44, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x07, 0x12, + 0x31, 0x0a, 0x2d, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, + 0x4e, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x43, + 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, + 0x10, 0x08, 0x12, 0x2b, 0x0a, 0x27, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, + 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x48, + 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x4d, 0x54, 0x5f, 0x53, 0x57, 0x45, 0x50, 0x54, 0x10, 0x09, 0x2a, + 0x2f, 0x0a, 0x11, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x52, 0x75, 0x6c, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, + 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, 0x10, 0x01, + 0x2a, 0xa6, 0x03, 0x0a, 0x0a, 0x41, 0x75, 0x74, 0x6f, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, + 0x17, 0x0a, 0x13, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x55, + 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x22, 0x0a, 0x1e, 0x41, 0x55, 0x54, 0x4f, + 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x42, 0x55, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x4e, + 0x4f, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, + 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x53, 0x57, 0x45, 0x45, + 0x50, 0x5f, 0x46, 0x45, 0x45, 0x53, 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, 0x41, 0x55, 0x54, 0x4f, + 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x42, 0x55, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x45, + 0x4c, 0x41, 0x50, 0x53, 0x45, 0x44, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x55, 0x54, 0x4f, + 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x5f, 0x46, 0x4c, 0x49, 0x47, 0x48, + 0x54, 0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, + 0x4f, 0x4e, 0x5f, 0x53, 0x57, 0x41, 0x50, 0x5f, 0x46, 0x45, 0x45, 0x10, 0x05, 0x12, 0x19, 0x0a, + 0x15, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4d, 0x49, 0x4e, + 0x45, 0x52, 0x5f, 0x46, 0x45, 0x45, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x55, 0x54, 0x4f, + 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x50, 0x52, 0x45, 0x50, 0x41, 0x59, 0x10, 0x07, + 0x12, 0x1f, 0x0a, 0x1b, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, + 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x42, 0x41, 0x43, 0x4b, 0x4f, 0x46, 0x46, 0x10, + 0x08, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, + 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x09, 0x12, 0x17, 0x0a, 0x13, 0x41, + 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, + 0x49, 0x4e, 0x10, 0x0a, 0x12, 0x1c, 0x0a, 0x18, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, + 0x53, 0x4f, 0x4e, 0x5f, 0x4c, 0x49, 0x51, 0x55, 0x49, 0x44, 0x49, 0x54, 0x59, 0x5f, 0x4f, 0x4b, + 0x10, 0x0b, 0x12, 0x23, 0x0a, 0x1f, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, + 0x4e, 0x5f, 0x42, 0x55, 0x44, 0x47, 0x45, 0x54, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, + 0x43, 0x49, 0x45, 0x4e, 0x54, 0x10, 0x0c, 0x12, 0x20, 0x0a, 0x1c, 0x41, 0x55, 0x54, 0x4f, 0x5f, + 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x46, 0x45, 0x45, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, + 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x10, 0x0d, 0x2a, 0xbe, 0x01, 0x0a, 0x0c, 0x44, 0x65, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x0d, 0x0a, + 0x09, 0x44, 0x45, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, + 0x57, 0x49, 0x54, 0x48, 0x44, 0x52, 0x41, 0x57, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0d, 0x0a, + 0x09, 0x57, 0x49, 0x54, 0x48, 0x44, 0x52, 0x41, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, + 0x4c, 0x4f, 0x4f, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x49, 0x4e, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, + 0x4c, 0x4f, 0x4f, 0x50, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x10, 0x05, 0x12, 0x13, 0x0a, 0x0f, 0x50, + 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x06, + 0x12, 0x19, 0x0a, 0x15, 0x57, 0x41, 0x49, 0x54, 0x5f, 0x46, 0x4f, 0x52, 0x5f, 0x45, 0x58, 0x50, + 0x49, 0x52, 0x59, 0x5f, 0x53, 0x57, 0x45, 0x45, 0x50, 0x10, 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x45, + 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x08, 0x12, 0x10, 0x0a, 0x0c, 0x46, 0x41, 0x49, 0x4c, + 0x45, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x09, 0x32, 0xb6, 0x0f, 0x0a, 0x0a, 0x53, + 0x77, 0x61, 0x70, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x07, 0x4c, 0x6f, 0x6f, + 0x70, 0x4f, 0x75, 0x74, 0x12, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x12, 0x16, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, + 0x07, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x12, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, + 0x53, 0x77, 0x61, 0x70, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, + 0x77, 0x61, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x08, + 0x53, 0x77, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x77, 0x61, + 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x48, 0x0a, 0x0b, 0x41, 0x62, 0x61, 0x6e, 0x64, + 0x6f, 0x6e, 0x53, 0x77, 0x61, 0x70, 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x62, + 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x40, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, + 0x73, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x65, 0x72, 0x6d, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, + 0x6f, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, + 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x6f, 0x70, - 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x62, - 0x65, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x62, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x40, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4c, 0x34, 0x30, 0x32, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x73, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4c, 0x73, 0x61, 0x74, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x56, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, - 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x5d, 0x0a, 0x12, 0x53, 0x65, + 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, + 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x51, 0x75, + 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x50, + 0x72, 0x6f, 0x62, 0x65, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, + 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4c, 0x34, 0x30, 0x32, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4c, 0x73, 0x61, 0x74, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, + 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x17, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, + 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x22, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, + 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, + 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x5d, 0x0a, + 0x12, 0x53, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x69, - 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0c, 0x53, 0x75, 0x67, - 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x12, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x45, 0x0a, 0x0a, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x12, 0x1a, 0x2e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x69, 0x74, 0x79, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0c, + 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, 0x73, 0x12, 0x1c, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, + 0x61, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x53, 0x77, 0x61, 0x70, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x10, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x65, + 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0a, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, 0x74, + 0x12, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0f, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, + 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, - 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x74, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x51, 0x75, - 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x51, - 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0f, - 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x12, - 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, - 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x57, 0x0a, 0x10, 0x4e, 0x65, 0x77, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, - 0x2e, 0x4e, 0x65, 0x77, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x13, 0x4c, - 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, - 0x74, 0x73, 0x12, 0x23, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x70, - 0x6f, 0x73, 0x69, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, - 0x10, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, - 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, 0x74, 0x68, - 0x64, 0x72, 0x61, 0x77, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x57, 0x69, - 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, - 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, - 0x79, 0x12, 0x24, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, - 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, - 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, - 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, - 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x54, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, + 0x74, 0x73, 0x12, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x10, 0x4e, 0x65, 0x77, 0x53, 0x74, 0x61, 0x74, + 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, + 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x73, 0x12, 0x23, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x6e, 0x74, + 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x57, 0x0a, 0x10, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x44, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x57, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x17, 0x47, 0x65, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x75, 0x6d, + 0x6d, 0x61, 0x72, 0x79, 0x12, 0x24, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x75, 0x6d, 0x6d, + 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x60, 0x0a, 0x13, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x12, 0x23, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, + 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -5433,7 +5633,7 @@ func file_client_proto_rawDescGZIP() []byte { } var file_client_proto_enumTypes = make([]protoimpl.EnumInfo, 8) -var file_client_proto_msgTypes = make([]protoimpl.MessageInfo, 54) +var file_client_proto_msgTypes = make([]protoimpl.MessageInfo, 56) var file_client_proto_goTypes = []interface{}{ (AddressType)(0), // 0: looprpc.AddressType (SwapType)(0), // 1: looprpc.SwapType @@ -5497,19 +5697,21 @@ var file_client_proto_goTypes = []interface{}{ (*StaticAddressSummaryRequest)(nil), // 59: looprpc.StaticAddressSummaryRequest (*StaticAddressSummaryResponse)(nil), // 60: looprpc.StaticAddressSummaryResponse (*Deposit)(nil), // 61: looprpc.Deposit - (*swapserverrpc.RouteHint)(nil), // 62: looprpc.RouteHint + (*StaticAddressLoopInRequest)(nil), // 62: looprpc.StaticAddressLoopInRequest + (*StaticAddressLoopInResponse)(nil), // 63: looprpc.StaticAddressLoopInResponse + (*swapserverrpc.RouteHint)(nil), // 64: looprpc.RouteHint } var file_client_proto_depIdxs = []int32{ 0, // 0: looprpc.LoopOutRequest.account_addr_type:type_name -> looprpc.AddressType - 62, // 1: looprpc.LoopInRequest.route_hints:type_name -> looprpc.RouteHint + 64, // 1: looprpc.LoopInRequest.route_hints:type_name -> looprpc.RouteHint 1, // 2: looprpc.SwapStatus.type:type_name -> looprpc.SwapType 2, // 3: looprpc.SwapStatus.state:type_name -> looprpc.SwapState 3, // 4: looprpc.SwapStatus.failure_reason:type_name -> looprpc.FailureReason 14, // 5: looprpc.ListSwapsRequest.list_swap_filter:type_name -> looprpc.ListSwapsFilter 7, // 6: looprpc.ListSwapsFilter.swap_type:type_name -> looprpc.ListSwapsFilter.SwapTypeFilter 12, // 7: looprpc.ListSwapsResponse.swaps:type_name -> looprpc.SwapStatus - 62, // 8: looprpc.QuoteRequest.loop_in_route_hints:type_name -> looprpc.RouteHint - 62, // 9: looprpc.ProbeRequest.route_hints:type_name -> looprpc.RouteHint + 64, // 8: looprpc.QuoteRequest.loop_in_route_hints:type_name -> looprpc.RouteHint + 64, // 9: looprpc.ProbeRequest.route_hints:type_name -> looprpc.RouteHint 27, // 10: looprpc.TokensResponse.tokens:type_name -> looprpc.L402Token 28, // 11: looprpc.GetInfoResponse.loop_out_stats:type_name -> looprpc.LoopStats 28, // 12: looprpc.GetInfoResponse.loop_in_stats:type_name -> looprpc.LoopStats @@ -5529,61 +5731,64 @@ var file_client_proto_depIdxs = []int32{ 6, // 26: looprpc.StaticAddressSummaryRequest.state_filter:type_name -> looprpc.DepositState 61, // 27: looprpc.StaticAddressSummaryResponse.filtered_deposits:type_name -> looprpc.Deposit 6, // 28: looprpc.Deposit.state:type_name -> looprpc.DepositState - 8, // 29: looprpc.SwapClient.LoopOut:input_type -> looprpc.LoopOutRequest - 9, // 30: looprpc.SwapClient.LoopIn:input_type -> looprpc.LoopInRequest - 11, // 31: looprpc.SwapClient.Monitor:input_type -> looprpc.MonitorRequest - 13, // 32: looprpc.SwapClient.ListSwaps:input_type -> looprpc.ListSwapsRequest - 16, // 33: looprpc.SwapClient.SwapInfo:input_type -> looprpc.SwapInfoRequest - 39, // 34: looprpc.SwapClient.AbandonSwap:input_type -> looprpc.AbandonSwapRequest - 17, // 35: looprpc.SwapClient.LoopOutTerms:input_type -> looprpc.TermsRequest - 20, // 36: looprpc.SwapClient.LoopOutQuote:input_type -> looprpc.QuoteRequest - 17, // 37: looprpc.SwapClient.GetLoopInTerms:input_type -> looprpc.TermsRequest - 20, // 38: looprpc.SwapClient.GetLoopInQuote:input_type -> looprpc.QuoteRequest - 23, // 39: looprpc.SwapClient.Probe:input_type -> looprpc.ProbeRequest - 25, // 40: looprpc.SwapClient.GetL402Tokens:input_type -> looprpc.TokensRequest - 25, // 41: looprpc.SwapClient.GetLsatTokens:input_type -> looprpc.TokensRequest - 29, // 42: looprpc.SwapClient.GetInfo:input_type -> looprpc.GetInfoRequest - 31, // 43: looprpc.SwapClient.GetLiquidityParams:input_type -> looprpc.GetLiquidityParamsRequest - 34, // 44: looprpc.SwapClient.SetLiquidityParams:input_type -> looprpc.SetLiquidityParamsRequest - 36, // 45: looprpc.SwapClient.SuggestSwaps:input_type -> looprpc.SuggestSwapsRequest - 41, // 46: looprpc.SwapClient.ListReservations:input_type -> looprpc.ListReservationsRequest - 44, // 47: looprpc.SwapClient.InstantOut:input_type -> looprpc.InstantOutRequest - 46, // 48: looprpc.SwapClient.InstantOutQuote:input_type -> looprpc.InstantOutQuoteRequest - 48, // 49: looprpc.SwapClient.ListInstantOuts:input_type -> looprpc.ListInstantOutsRequest - 51, // 50: looprpc.SwapClient.NewStaticAddress:input_type -> looprpc.NewStaticAddressRequest - 53, // 51: looprpc.SwapClient.ListUnspentDeposits:input_type -> looprpc.ListUnspentDepositsRequest - 56, // 52: looprpc.SwapClient.WithdrawDeposits:input_type -> looprpc.WithdrawDepositsRequest - 59, // 53: looprpc.SwapClient.GetStaticAddressSummary:input_type -> looprpc.StaticAddressSummaryRequest - 10, // 54: looprpc.SwapClient.LoopOut:output_type -> looprpc.SwapResponse - 10, // 55: looprpc.SwapClient.LoopIn:output_type -> looprpc.SwapResponse - 12, // 56: looprpc.SwapClient.Monitor:output_type -> looprpc.SwapStatus - 15, // 57: looprpc.SwapClient.ListSwaps:output_type -> looprpc.ListSwapsResponse - 12, // 58: looprpc.SwapClient.SwapInfo:output_type -> looprpc.SwapStatus - 40, // 59: looprpc.SwapClient.AbandonSwap:output_type -> looprpc.AbandonSwapResponse - 19, // 60: looprpc.SwapClient.LoopOutTerms:output_type -> looprpc.OutTermsResponse - 22, // 61: looprpc.SwapClient.LoopOutQuote:output_type -> looprpc.OutQuoteResponse - 18, // 62: looprpc.SwapClient.GetLoopInTerms:output_type -> looprpc.InTermsResponse - 21, // 63: looprpc.SwapClient.GetLoopInQuote:output_type -> looprpc.InQuoteResponse - 24, // 64: looprpc.SwapClient.Probe:output_type -> looprpc.ProbeResponse - 26, // 65: looprpc.SwapClient.GetL402Tokens:output_type -> looprpc.TokensResponse - 26, // 66: looprpc.SwapClient.GetLsatTokens:output_type -> looprpc.TokensResponse - 30, // 67: looprpc.SwapClient.GetInfo:output_type -> looprpc.GetInfoResponse - 32, // 68: looprpc.SwapClient.GetLiquidityParams:output_type -> looprpc.LiquidityParameters - 35, // 69: looprpc.SwapClient.SetLiquidityParams:output_type -> looprpc.SetLiquidityParamsResponse - 38, // 70: looprpc.SwapClient.SuggestSwaps:output_type -> looprpc.SuggestSwapsResponse - 42, // 71: looprpc.SwapClient.ListReservations:output_type -> looprpc.ListReservationsResponse - 45, // 72: looprpc.SwapClient.InstantOut:output_type -> looprpc.InstantOutResponse - 47, // 73: looprpc.SwapClient.InstantOutQuote:output_type -> looprpc.InstantOutQuoteResponse - 49, // 74: looprpc.SwapClient.ListInstantOuts:output_type -> looprpc.ListInstantOutsResponse - 52, // 75: looprpc.SwapClient.NewStaticAddress:output_type -> looprpc.NewStaticAddressResponse - 54, // 76: looprpc.SwapClient.ListUnspentDeposits:output_type -> looprpc.ListUnspentDepositsResponse - 57, // 77: looprpc.SwapClient.WithdrawDeposits:output_type -> looprpc.WithdrawDepositsResponse - 60, // 78: looprpc.SwapClient.GetStaticAddressSummary:output_type -> looprpc.StaticAddressSummaryResponse - 54, // [54:79] is the sub-list for method output_type - 29, // [29:54] is the sub-list for method input_type - 29, // [29:29] is the sub-list for extension type_name - 29, // [29:29] is the sub-list for extension extendee - 0, // [0:29] is the sub-list for field type_name + 64, // 29: looprpc.StaticAddressLoopInRequest.route_hints:type_name -> looprpc.RouteHint + 8, // 30: looprpc.SwapClient.LoopOut:input_type -> looprpc.LoopOutRequest + 9, // 31: looprpc.SwapClient.LoopIn:input_type -> looprpc.LoopInRequest + 11, // 32: looprpc.SwapClient.Monitor:input_type -> looprpc.MonitorRequest + 13, // 33: looprpc.SwapClient.ListSwaps:input_type -> looprpc.ListSwapsRequest + 16, // 34: looprpc.SwapClient.SwapInfo:input_type -> looprpc.SwapInfoRequest + 39, // 35: looprpc.SwapClient.AbandonSwap:input_type -> looprpc.AbandonSwapRequest + 17, // 36: looprpc.SwapClient.LoopOutTerms:input_type -> looprpc.TermsRequest + 20, // 37: looprpc.SwapClient.LoopOutQuote:input_type -> looprpc.QuoteRequest + 17, // 38: looprpc.SwapClient.GetLoopInTerms:input_type -> looprpc.TermsRequest + 20, // 39: looprpc.SwapClient.GetLoopInQuote:input_type -> looprpc.QuoteRequest + 23, // 40: looprpc.SwapClient.Probe:input_type -> looprpc.ProbeRequest + 25, // 41: looprpc.SwapClient.GetL402Tokens:input_type -> looprpc.TokensRequest + 25, // 42: looprpc.SwapClient.GetLsatTokens:input_type -> looprpc.TokensRequest + 29, // 43: looprpc.SwapClient.GetInfo:input_type -> looprpc.GetInfoRequest + 31, // 44: looprpc.SwapClient.GetLiquidityParams:input_type -> looprpc.GetLiquidityParamsRequest + 34, // 45: looprpc.SwapClient.SetLiquidityParams:input_type -> looprpc.SetLiquidityParamsRequest + 36, // 46: looprpc.SwapClient.SuggestSwaps:input_type -> looprpc.SuggestSwapsRequest + 41, // 47: looprpc.SwapClient.ListReservations:input_type -> looprpc.ListReservationsRequest + 44, // 48: looprpc.SwapClient.InstantOut:input_type -> looprpc.InstantOutRequest + 46, // 49: looprpc.SwapClient.InstantOutQuote:input_type -> looprpc.InstantOutQuoteRequest + 48, // 50: looprpc.SwapClient.ListInstantOuts:input_type -> looprpc.ListInstantOutsRequest + 51, // 51: looprpc.SwapClient.NewStaticAddress:input_type -> looprpc.NewStaticAddressRequest + 53, // 52: looprpc.SwapClient.ListUnspentDeposits:input_type -> looprpc.ListUnspentDepositsRequest + 56, // 53: looprpc.SwapClient.WithdrawDeposits:input_type -> looprpc.WithdrawDepositsRequest + 59, // 54: looprpc.SwapClient.GetStaticAddressSummary:input_type -> looprpc.StaticAddressSummaryRequest + 62, // 55: looprpc.SwapClient.StaticAddressLoopIn:input_type -> looprpc.StaticAddressLoopInRequest + 10, // 56: looprpc.SwapClient.LoopOut:output_type -> looprpc.SwapResponse + 10, // 57: looprpc.SwapClient.LoopIn:output_type -> looprpc.SwapResponse + 12, // 58: looprpc.SwapClient.Monitor:output_type -> looprpc.SwapStatus + 15, // 59: looprpc.SwapClient.ListSwaps:output_type -> looprpc.ListSwapsResponse + 12, // 60: looprpc.SwapClient.SwapInfo:output_type -> looprpc.SwapStatus + 40, // 61: looprpc.SwapClient.AbandonSwap:output_type -> looprpc.AbandonSwapResponse + 19, // 62: looprpc.SwapClient.LoopOutTerms:output_type -> looprpc.OutTermsResponse + 22, // 63: looprpc.SwapClient.LoopOutQuote:output_type -> looprpc.OutQuoteResponse + 18, // 64: looprpc.SwapClient.GetLoopInTerms:output_type -> looprpc.InTermsResponse + 21, // 65: looprpc.SwapClient.GetLoopInQuote:output_type -> looprpc.InQuoteResponse + 24, // 66: looprpc.SwapClient.Probe:output_type -> looprpc.ProbeResponse + 26, // 67: looprpc.SwapClient.GetL402Tokens:output_type -> looprpc.TokensResponse + 26, // 68: looprpc.SwapClient.GetLsatTokens:output_type -> looprpc.TokensResponse + 30, // 69: looprpc.SwapClient.GetInfo:output_type -> looprpc.GetInfoResponse + 32, // 70: looprpc.SwapClient.GetLiquidityParams:output_type -> looprpc.LiquidityParameters + 35, // 71: looprpc.SwapClient.SetLiquidityParams:output_type -> looprpc.SetLiquidityParamsResponse + 38, // 72: looprpc.SwapClient.SuggestSwaps:output_type -> looprpc.SuggestSwapsResponse + 42, // 73: looprpc.SwapClient.ListReservations:output_type -> looprpc.ListReservationsResponse + 45, // 74: looprpc.SwapClient.InstantOut:output_type -> looprpc.InstantOutResponse + 47, // 75: looprpc.SwapClient.InstantOutQuote:output_type -> looprpc.InstantOutQuoteResponse + 49, // 76: looprpc.SwapClient.ListInstantOuts:output_type -> looprpc.ListInstantOutsResponse + 52, // 77: looprpc.SwapClient.NewStaticAddress:output_type -> looprpc.NewStaticAddressResponse + 54, // 78: looprpc.SwapClient.ListUnspentDeposits:output_type -> looprpc.ListUnspentDepositsResponse + 57, // 79: looprpc.SwapClient.WithdrawDeposits:output_type -> looprpc.WithdrawDepositsResponse + 60, // 80: looprpc.SwapClient.GetStaticAddressSummary:output_type -> looprpc.StaticAddressSummaryResponse + 63, // 81: looprpc.SwapClient.StaticAddressLoopIn:output_type -> looprpc.StaticAddressLoopInResponse + 56, // [56:82] is the sub-list for method output_type + 30, // [30:56] is the sub-list for method input_type + 30, // [30:30] is the sub-list for extension type_name + 30, // [30:30] is the sub-list for extension extendee + 0, // [0:30] is the sub-list for field type_name } func init() { file_client_proto_init() } @@ -6240,6 +6445,30 @@ func file_client_proto_init() { return nil } } + file_client_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StaticAddressLoopInRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_client_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StaticAddressLoopInResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -6247,7 +6476,7 @@ func file_client_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_client_proto_rawDesc, NumEnums: 8, - NumMessages: 54, + NumMessages: 56, NumExtensions: 0, NumServices: 1, }, diff --git a/looprpc/client.proto b/looprpc/client.proto index 43d4e3822b..026ae14fe4 100644 --- a/looprpc/client.proto +++ b/looprpc/client.proto @@ -168,6 +168,9 @@ service SwapClient { */ rpc GetStaticAddressSummary (StaticAddressSummaryRequest) returns (StaticAddressSummaryResponse); + + rpc StaticAddressLoopIn (StaticAddressLoopInRequest) + returns (StaticAddressLoopInResponse); } message LoopOutRequest { @@ -1615,10 +1618,15 @@ message StaticAddressSummaryResponse { */ int64 value_withdrawn = 6; + /* + The total value of all loop-ins that have been finalized. + */ + int64 value_looped_in = 7; + /* A list of all deposits that match the filtered state. */ - repeated Deposit filtered_deposits = 7; + repeated Deposit filtered_deposits = 8; } enum DepositState { @@ -1645,28 +1653,40 @@ enum DepositState { */ WITHDRAWN = 3; + /* + LOOPING_IN indicates that the deposit is currently being used in a static + address loop-in swap. + */ + LOOPING_IN = 4; + + /* + LOOPED_IN indicates that the deposit was used in a static address loop-in + swap. + */ + LOOPED_IN = 5; + /* PUBLISH_EXPIRED indicates that the deposit has expired and the sweep transaction has been published. */ - PUBLISH_EXPIRED = 4; + PUBLISH_EXPIRED = 6; /* WAIT_FOR_EXPIRY_SWEEP indicates that the deposit has expired and the sweep transaction has not yet been sufficiently confirmed. */ - WAIT_FOR_EXPIRY_SWEEP = 5; + WAIT_FOR_EXPIRY_SWEEP = 7; /* EXPIRED indicates that the deposit has expired and the sweep transaction has been sufficiently confirmed. */ - EXPIRED = 6; + EXPIRED = 8; /* FAILED_STATE indicates that the deposit has failed. */ - FAILED_STATE = 7; + FAILED_STATE = 9; } message Deposit { @@ -1695,3 +1715,55 @@ message Deposit { */ int64 confirmation_height = 5; } + +message StaticAddressLoopInRequest { + /* + The outpoints of the deposits to loop-in. + */ + repeated string outpoints = 1; + + /* + Maximum we are willing to pay the server for the 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 value is taken from the response of + the GetQuote call. + */ + int64 max_swap_fee = 2; + + /* + Optionally the client can specify the last hop pubkey when requesting a + loop-in quote. This is useful to get better off-chain routing fee from the + server. + */ + bytes last_hop = 3; + + /* + 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 = 4; + + /* + An optional identification string that will be appended to the user agent + string sent to the server to give information about the usage of loop. This + initiator part is meant for user interfaces to add their name to give the + full picture of the binary used (loopd, LiT) and the method used for + triggering the swap (loop CLI, autolooper, LiT UI, other 3rd party UI). + */ + string initiator = 5; + + /* + Optional route hints to reach the destination through private channels. + */ + repeated looprpc.RouteHint route_hints = 6; + + /* + Private indicates whether the destination node should be considered private. + In which case, loop will generate hop hints to assist with probing and + payment. + */ + bool private = 7; +} + +message StaticAddressLoopInResponse { +} diff --git a/looprpc/client.swagger.json b/looprpc/client.swagger.json index 91d7a8aa1a..38a7b2637e 100644 --- a/looprpc/client.swagger.json +++ b/looprpc/client.swagger.json @@ -698,13 +698,15 @@ "DEPOSITED", "WITHDRAWING", "WITHDRAWN", + "LOOPING_IN", + "LOOPED_IN", "PUBLISH_EXPIRED", "WAIT_FOR_EXPIRY_SWEEP", "EXPIRED", "FAILED_STATE" ], "default": "UNKNOWN_STATE", - "description": " - UNKNOWN_STATE: UNKNOWN_STATE is the default state of a deposit.\n - DEPOSITED: DEPOSITED indicates that the deposit has been sufficiently confirmed on\nchain.\n - WITHDRAWING: WITHDRAWING indicates that the deposit is currently being withdrawn. It\nflips to WITHDRAWN once the withdrawal transaction has been sufficiently\nconfirmed.\n - WITHDRAWN: WITHDRAWN indicates that the deposit has been withdrawn.\n - PUBLISH_EXPIRED: PUBLISH_EXPIRED indicates that the deposit has expired and the sweep\ntransaction has been published.\n - WAIT_FOR_EXPIRY_SWEEP: WAIT_FOR_EXPIRY_SWEEP indicates that the deposit has expired and the sweep\ntransaction has not yet been sufficiently confirmed.\n - EXPIRED: EXPIRED indicates that the deposit has expired and the sweep transaction\nhas been sufficiently confirmed.\n - FAILED_STATE: FAILED_STATE indicates that the deposit has failed." + "description": " - UNKNOWN_STATE: UNKNOWN_STATE is the default state of a deposit.\n - DEPOSITED: DEPOSITED indicates that the deposit has been sufficiently confirmed on\nchain.\n - WITHDRAWING: WITHDRAWING indicates that the deposit is currently being withdrawn. It\nflips to WITHDRAWN once the withdrawal transaction has been sufficiently\nconfirmed.\n - WITHDRAWN: WITHDRAWN indicates that the deposit has been withdrawn.\n - LOOPING_IN: LOOPING_IN indicates that the deposit is currently being used in a static\naddress loop-in swap.\n - LOOPED_IN: LOOPED_IN indicates that the deposit was used in a static address loop-in\nswap.\n - PUBLISH_EXPIRED: PUBLISH_EXPIRED indicates that the deposit has expired and the sweep\ntransaction has been published.\n - WAIT_FOR_EXPIRY_SWEEP: WAIT_FOR_EXPIRY_SWEEP indicates that the deposit has expired and the sweep\ntransaction has not yet been sufficiently confirmed.\n - EXPIRED: EXPIRED indicates that the deposit has expired and the sweep transaction\nhas been sufficiently confirmed.\n - FAILED_STATE: FAILED_STATE indicates that the deposit has failed." }, "looprpcDisqualified": { "type": "object", @@ -1503,6 +1505,9 @@ "looprpcSetLiquidityParamsResponse": { "type": "object" }, + "looprpcStaticAddressLoopInResponse": { + "type": "object" + }, "looprpcStaticAddressSummaryResponse": { "type": "object", "properties": { @@ -1535,6 +1540,11 @@ "format": "int64", "description": "The total value of all deposits that have been withdrawn." }, + "value_looped_in": { + "type": "string", + "format": "int64", + "description": "The total value of all loop-ins that have been finalized." + }, "filtered_deposits": { "type": "array", "items": { diff --git a/looprpc/client_grpc.pb.go b/looprpc/client_grpc.pb.go index f9a47f4b79..af88da49aa 100644 --- a/looprpc/client_grpc.pb.go +++ b/looprpc/client_grpc.pb.go @@ -115,6 +115,7 @@ type SwapClientClient interface { // GetStaticAddressSummary returns a summary of static address related // statistics. GetStaticAddressSummary(ctx context.Context, in *StaticAddressSummaryRequest, opts ...grpc.CallOption) (*StaticAddressSummaryResponse, error) + StaticAddressLoopIn(ctx context.Context, in *StaticAddressLoopInRequest, opts ...grpc.CallOption) (*StaticAddressLoopInResponse, error) } type swapClientClient struct { @@ -373,6 +374,15 @@ func (c *swapClientClient) GetStaticAddressSummary(ctx context.Context, in *Stat return out, nil } +func (c *swapClientClient) StaticAddressLoopIn(ctx context.Context, in *StaticAddressLoopInRequest, opts ...grpc.CallOption) (*StaticAddressLoopInResponse, error) { + out := new(StaticAddressLoopInResponse) + err := c.cc.Invoke(ctx, "/looprpc.SwapClient/StaticAddressLoopIn", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // SwapClientServer is the server API for SwapClient service. // All implementations must embed UnimplementedSwapClientServer // for forward compatibility @@ -474,6 +484,7 @@ type SwapClientServer interface { // GetStaticAddressSummary returns a summary of static address related // statistics. GetStaticAddressSummary(context.Context, *StaticAddressSummaryRequest) (*StaticAddressSummaryResponse, error) + StaticAddressLoopIn(context.Context, *StaticAddressLoopInRequest) (*StaticAddressLoopInResponse, error) mustEmbedUnimplementedSwapClientServer() } @@ -556,6 +567,9 @@ func (UnimplementedSwapClientServer) WithdrawDeposits(context.Context, *Withdraw func (UnimplementedSwapClientServer) GetStaticAddressSummary(context.Context, *StaticAddressSummaryRequest) (*StaticAddressSummaryResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetStaticAddressSummary not implemented") } +func (UnimplementedSwapClientServer) StaticAddressLoopIn(context.Context, *StaticAddressLoopInRequest) (*StaticAddressLoopInResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method StaticAddressLoopIn not implemented") +} func (UnimplementedSwapClientServer) mustEmbedUnimplementedSwapClientServer() {} // UnsafeSwapClientServer may be embedded to opt out of forward compatibility for this service. @@ -1022,6 +1036,24 @@ func _SwapClient_GetStaticAddressSummary_Handler(srv interface{}, ctx context.Co return interceptor(ctx, in, info, handler) } +func _SwapClient_StaticAddressLoopIn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StaticAddressLoopInRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SwapClientServer).StaticAddressLoopIn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/looprpc.SwapClient/StaticAddressLoopIn", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SwapClientServer).StaticAddressLoopIn(ctx, req.(*StaticAddressLoopInRequest)) + } + return interceptor(ctx, in, info, handler) +} + // SwapClient_ServiceDesc is the grpc.ServiceDesc for SwapClient service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -1125,6 +1157,10 @@ var SwapClient_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetStaticAddressSummary", Handler: _SwapClient_GetStaticAddressSummary_Handler, }, + { + MethodName: "StaticAddressLoopIn", + Handler: _SwapClient_StaticAddressLoopIn_Handler, + }, }, Streams: []grpc.StreamDesc{ { diff --git a/looprpc/swapclient.pb.json.go b/looprpc/swapclient.pb.json.go index ab13090a21..d825fe53c3 100644 --- a/looprpc/swapclient.pb.json.go +++ b/looprpc/swapclient.pb.json.go @@ -662,4 +662,29 @@ func RegisterSwapClientJSONCallbacks(registry map[string]func(ctx context.Contex } callback(string(respBytes), nil) } + + registry["looprpc.SwapClient.StaticAddressLoopIn"] = func(ctx context.Context, + conn *grpc.ClientConn, reqJSON string, callback func(string, error)) { + + req := &StaticAddressLoopInRequest{} + err := marshaler.Unmarshal([]byte(reqJSON), req) + if err != nil { + callback("", err) + return + } + + client := NewSwapClientClient(conn) + resp, err := client.StaticAddressLoopIn(ctx, req) + if err != nil { + callback("", err) + return + } + + respBytes, err := marshaler.Marshal(resp) + if err != nil { + callback("", err) + return + } + callback(string(respBytes), nil) + } } diff --git a/staticaddr/deposit/actions.go b/staticaddr/deposit/actions.go index 199fe6cc78..7be3a8c420 100644 --- a/staticaddr/deposit/actions.go +++ b/staticaddr/deposit/actions.go @@ -148,9 +148,9 @@ func (f *FSM) SweptExpiredDepositAction(_ fsm.EventContext) fsm.EventType { return fsm.NoOp } -// WithdrawnDepositAction is the final action after a withdrawal. It signals to +// FinalizeDepositAction is the final action after a withdrawal. It signals to // the manager that the deposit has been swept and the FSM can be removed. -func (f *FSM) WithdrawnDepositAction(_ fsm.EventContext) fsm.EventType { +func (f *FSM) FinalizeDepositAction(_ fsm.EventContext) fsm.EventType { select { case <-f.ctx.Done(): return fsm.OnError diff --git a/staticaddr/deposit/deposit.go b/staticaddr/deposit/deposit.go index 3e23f9a6fc..a9ba732bc1 100644 --- a/staticaddr/deposit/deposit.go +++ b/staticaddr/deposit/deposit.go @@ -72,7 +72,9 @@ func (d *Deposit) IsInFinalState() bool { d.Lock() defer d.Unlock() - return d.state == Expired || d.state == Withdrawn || d.state == Failed + return d.state == Expired || d.state == Withdrawn || + d.state == Failed || d.state == LoopedIn || + d.state == HtlcTimeoutSwept } func (d *Deposit) IsExpired(currentHeight, expiry uint32) bool { diff --git a/staticaddr/deposit/fsm.go b/staticaddr/deposit/fsm.go index a2607a6e5b..30c08af9d8 100644 --- a/staticaddr/deposit/fsm.go +++ b/staticaddr/deposit/fsm.go @@ -33,6 +33,14 @@ var ( Withdrawn = fsm.StateType("Withdrawn") + LoopingIn = fsm.StateType("LoopingIn") + + SweepHtlcTimout = fsm.StateType("SweepHtlcTimout") + + HtlcTimeoutSwept = fsm.StateType("HtlcTimeoutSwept") + + LoopedIn = fsm.StateType("LoopedIn") + PublishExpiredDeposit = fsm.StateType("PublishExpiredDeposit") WaitForExpirySweep = fsm.StateType("WaitForExpirySweep") @@ -44,13 +52,17 @@ var ( // Events. var ( - OnStart = fsm.EventType("OnStart") - OnWithdrawInitiated = fsm.EventType("OnWithdrawInitiated") - OnWithdrawn = fsm.EventType("OnWithdrawn") - OnExpiry = fsm.EventType("OnExpiry") - OnExpiryPublished = fsm.EventType("OnExpiryPublished") - OnExpirySwept = fsm.EventType("OnExpirySwept") - OnRecover = fsm.EventType("OnRecover") + OnStart = fsm.EventType("OnStart") + OnWithdrawInitiated = fsm.EventType("OnWithdrawInitiated") + OnWithdrawn = fsm.EventType("OnWithdrawn") + OnLoopinInitiated = fsm.EventType("OnLoopinInitiated") + OnSweepingHtlcTimout = fsm.EventType("OnSweepingHtlcTimout") + OnHtlcTimeoutSwept = fsm.EventType("OnHtlcTimeoutSwept") + OnLoopedIn = fsm.EventType("OnLoopedIn") + OnExpiry = fsm.EventType("OnExpiry") + OnExpiryPublished = fsm.EventType("OnExpiryPublished") + OnExpirySwept = fsm.EventType("OnExpirySwept") + OnRecover = fsm.EventType("OnRecover") ) // FSM is the state machine that handles the instant out. @@ -169,6 +181,7 @@ func (f *FSM) DepositStatesV0() fsm.States { Transitions: fsm.Transitions{ OnExpiry: PublishExpiredDeposit, OnWithdrawInitiated: Withdrawing, + OnLoopinInitiated: LoopingIn, OnRecover: Deposited, }, Action: fsm.NoOpAction, @@ -232,7 +245,57 @@ func (f *FSM) DepositStatesV0() fsm.States { Transitions: fsm.Transitions{ OnExpiry: Expired, }, - Action: f.WithdrawnDepositAction, + Action: f.FinalizeDepositAction, + }, + LoopingIn: fsm.State{ + Transitions: fsm.Transitions{ + // This event is triggered when the loop in + // payment has been received. We consider the + // swap to be completed and transition to a + // final state. + OnLoopedIn: LoopedIn, + + // If the deposit expires while the loop in is + // still pending, we publish the expiry sweep. + OnExpiry: PublishExpiredDeposit, + + // We encounter this signal if the server + // published the htlc tx without paying us. We + // then need to monitor for the timeout path to + // open up to sweep it. + OnSweepingHtlcTimout: SweepHtlcTimout, + + OnLoopinInitiated: LoopingIn, + + OnRecover: LoopingIn, + fsm.OnError: Deposited, + }, + Action: fsm.NoOpAction, + }, + LoopedIn: fsm.State{ + Transitions: fsm.Transitions{ + OnExpiry: Expired, + }, + Action: f.FinalizeDepositAction, + }, + SweepHtlcTimout: fsm.State{ + Transitions: fsm.Transitions{ + OnHtlcTimeoutSwept: HtlcTimeoutSwept, + OnRecover: SweepHtlcTimout, + }, + Action: fsm.NoOpAction, + }, + HtlcTimeoutSwept: fsm.State{ + Transitions: fsm.Transitions{ + OnExpiry: HtlcTimeoutSwept, + }, + Action: f.FinalizeDepositAction, + }, + Withdrawn: fsm.State{ + Transitions: fsm.Transitions{ + OnExpiry: Expired, + }, + Action: f.FinalizeDepositAction, }, Failed: fsm.State{ Transitions: fsm.Transitions{ @@ -257,14 +320,7 @@ func (f *FSM) updateDeposit(notification fsm.Notification) { f.deposit.SetState(notification.NextState) - // Don't update the deposit if we are in an initial state or if we - // are transitioning from an initial state to a failed state. - d := f.deposit - if d.IsInState(fsm.EmptyState) || d.IsInState(Deposited) || - (notification.PreviousState == Deposited && d.IsInState( - Failed, - )) { - + if skipUpdate(notification, f.deposit) { return } @@ -274,6 +330,23 @@ func (f *FSM) updateDeposit(notification fsm.Notification) { } } +// Don't update the deposit if we are in an initial state or if we are +// transitioning from an initial state to a failed state. +func skipUpdate(notification fsm.Notification, d *Deposit) bool { + prevState := notification.PreviousState + if d.IsInState(fsm.EmptyState) || d.IsInState(Deposited) && + prevState == fsm.EmptyState || + d.IsInState(prevState) || + prevState == Deposited && d.IsInState(Deposited) || + prevState == Deposited && d.IsInState(Failed) || + prevState == LoopingIn && d.IsInState(LoopingIn) { + + return true + } + + return false +} + // Infof logs an info message with the deposit outpoint. func (f *FSM) Infof(format string, args ...interface{}) { log.Infof( diff --git a/staticaddr/deposit/manager.go b/staticaddr/deposit/manager.go index 26ce7e8027..8e0ec3b942 100644 --- a/staticaddr/deposit/manager.go +++ b/staticaddr/deposit/manager.go @@ -3,6 +3,7 @@ package deposit import ( "context" "fmt" + "github.com/btcsuite/btcd/btcutil" "sort" "sync" "time" @@ -423,7 +424,7 @@ func (m *Manager) startDepositFsm(deposit *Deposit) error { func (m *Manager) finalizeDeposit(outpoint wire.OutPoint) { m.Lock() delete(m.activeDeposits, outpoint) - delete(m.deposits, outpoint) + // delete(m.deposits, outpoint) m.Unlock() } @@ -456,7 +457,8 @@ func (m *Manager) GetAllDeposits() ([]*Deposit, error) { } // AllOutpointsActiveDeposits checks if all deposits referenced by the outpoints -// are active and in the specified state. +// are active and in the specified state. If fsm.EmptyState is reference as +// stateFilter all deposits are returned regardless of their state. func (m *Manager) AllOutpointsActiveDeposits(outpoints []wire.OutPoint, stateFilter fsm.StateType) ([]*Deposit, bool) { @@ -470,7 +472,8 @@ func (m *Manager) AllOutpointsActiveDeposits(outpoints []wire.OutPoint, } deposit := m.deposits[o] - if deposit.GetState() != stateFilter { + if stateFilter != fsm.EmptyState && + deposit.GetState() != stateFilter { return nil, false } @@ -480,6 +483,22 @@ func (m *Manager) AllOutpointsActiveDeposits(outpoints []wire.OutPoint, return deposits, true } +func (m *Manager) AllStringOutpointsActiveDeposits(outpoints []string, + stateFilter fsm.StateType) ([]*Deposit, bool) { + + outPoints := make([]wire.OutPoint, len(outpoints)) + for i, o := range outpoints { + op, err := wire.NewOutPointFromString(o) + if err != nil { + return nil, false + } + + outPoints[i] = *op + } + + return m.AllOutpointsActiveDeposits(outPoints, stateFilter) +} + // TransitionDeposits allows a caller to transition a set of deposits to a new // state. func (m *Manager) TransitionDeposits(deposits []*Deposit, event fsm.EventType, @@ -512,3 +531,11 @@ func (m *Manager) TransitionDeposits(deposits []*Deposit, event fsm.EventType, func (m *Manager) UpdateDeposit(d *Deposit) error { return m.cfg.Store.UpdateDeposit(m.runCtx, d) } + +func TotalDepositAmount(deposits []*Deposit) btcutil.Amount { + var total btcutil.Amount + for _, d := range deposits { + total += d.Value + } + return total +} diff --git a/staticaddr/deposit/sql_store.go b/staticaddr/deposit/sql_store.go index e9cb301b01..16d2a2c292 100644 --- a/staticaddr/deposit/sql_store.go +++ b/staticaddr/deposit/sql_store.go @@ -214,8 +214,3 @@ func (s *SqlStore) toDeposit(row sqlc.Deposit, WithdrawalSweepAddress: row.WithdrawalSweepAddress.String, }, nil } - -// Close closes the database connection. -func (s *SqlStore) Close() { - s.baseDB.DB.Close() -} diff --git a/staticaddr/log.go b/staticaddr/log.go index fc5eb0108c..cfd9e0b9df 100644 --- a/staticaddr/log.go +++ b/staticaddr/log.go @@ -4,6 +4,7 @@ import ( "github.com/btcsuite/btclog" "github.com/lightninglabs/loop/staticaddr/address" "github.com/lightninglabs/loop/staticaddr/deposit" + "github.com/lightninglabs/loop/staticaddr/loopin" "github.com/lightninglabs/loop/staticaddr/withdraw" "github.com/lightningnetwork/lnd/build" ) @@ -27,4 +28,5 @@ func UseLogger(logger btclog.Logger) { address.UseLogger(log) deposit.UseLogger(log) withdraw.UseLogger(log) + loopin.UseLogger(log) } diff --git a/staticaddr/loopin/actions.go b/staticaddr/loopin/actions.go new file mode 100644 index 0000000000..7662c3a9db --- /dev/null +++ b/staticaddr/loopin/actions.go @@ -0,0 +1,535 @@ +package loopin + +import ( + "crypto/rand" + "crypto/sha256" + "fmt" + "strings" + "time" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" + "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/txscript" + "github.com/lightninglabs/loop/fsm" + "github.com/lightninglabs/loop/staticaddr/deposit" + "github.com/lightninglabs/loop/staticaddr/version" + "github.com/lightninglabs/loop/swap" + "github.com/lightninglabs/loop/swapserverrpc" + "github.com/lightningnetwork/lnd/invoices" + "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" + "github.com/lightningnetwork/lnd/lnrpc/walletrpc" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnwallet" + "github.com/lightningnetwork/lnd/lnwallet/chainfee" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/routing/route" + "github.com/lightningnetwork/lnd/zpay32" +) + +const ( + defaultConfTarget = 3 +) + +// RequestContext is the context passed to the instant out FSM when +// it is initialized. +type RequestContext struct { + loopInitiationHeight uint32 + depositOutpoints []string + maxSwapFee btcutil.Amount + maxMinerFee btcutil.Amount + lastHop *route.Vertex + label string + userAgent string + private bool + routeHints [][]zpay32.HopHint +} + +// InitHtlcAction ... +func (f *FSM) InitHtlcAction(_ fsm.EventContext) fsm.EventType { + // Lock the deposits and transition them to the LoopingIn state. + err := f.cfg.DepositManager.TransitionDeposits( + f.loopIn.Deposits, deposit.OnLoopinInitiated, deposit.LoopingIn, + ) + if err != nil { + return f.HandleError(err) + } + + // Calculate the swap invoice amount. The pre-pay is added which + // effectively forces the server to pay us back our prepayment on a + // successful swap. + swapInvoiceAmt := f.loopIn.TotalDepositAmount() - f.loopIn.QuotedSwapFee + + // Generate random preimage. + var swapPreimage lntypes.Preimage + if _, err := rand.Read(swapPreimage[:]); err != nil { + log.Error("Cannot generate preimage") + } + f.loopIn.SwapPreimage = swapPreimage + f.loopIn.SwapHash = sha256.Sum256(swapPreimage[:]) + + // Derive a client key for the HTLC. + keyDesc, err := f.cfg.WalletKit.DeriveNextKey( + f.ctx, swap.StaticAddressKeyFamily, + ) + if err != nil { + return f.HandleError(err) + } + f.loopIn.ClientPubkey = keyDesc.PubKey + f.loopIn.HtlcKeyLocator = keyDesc.KeyLocator + + var clientKey [33]byte + copy(clientKey[:], keyDesc.PubKey.SerializeCompressed()) + + // Create the swap invoice in lnd. + _, swapInvoice, err := f.cfg.LndClient.AddInvoice( + f.ctx, &invoicesrpc.AddInvoiceData{ + Preimage: &swapPreimage, + Value: lnwire.NewMSatFromSatoshis(swapInvoiceAmt), + Memo: "static address loop-in", + Expiry: 3600 * 24 * 365, + RouteHints: f.loopIn.RouteHints, + }, + ) + if err != nil { + return f.HandleError(err) + } + f.loopIn.SwapInvoice = swapInvoice + + f.loopIn.ProtocolVersion = version.AddressProtocolVersion( + version.CurrentRPCProtocolVersion(), + ) + + loopInReq := &swapserverrpc.ServerStaticAddressLoopInRequest{ + SwapHash: f.loopIn.SwapHash[:], + DepositOutpoints: f.loopIn.DepositOutpoints, + HtlcClientKey: f.loopIn.ClientPubkey.SerializeCompressed(), + SwapInvoice: f.loopIn.SwapInvoice, + ProtocolVersion: version.CurrentRPCProtocolVersion(), + UserAgent: f.loopIn.Initiator, + } + if f.loopIn.LastHop != nil { + loopInReq.LastHop = f.loopIn.LastHop[:] + } + + loopInResp, err := f.cfg.StaticAddressServerClient.ServerStaticAddressLoopIn( //nolint:lll + f.ctx, loopInReq, + ) + if err != nil { + return f.HandleError(err) + } + + serverPubkey, err := btcec.ParsePubKey(loopInResp.HtlcServerKey) + if err != nil { + return f.HandleError(err) + } + f.loopIn.ServerPubkey = serverPubkey + // TODO: add cltv validity check. + f.loopIn.HtlcCltvExpiry = loopInResp.HtlcExpiry + f.htlcServerNonces, err = toNonces(loopInResp.HtlcServerNonces) + f.loopIn.HtlcTxFeeRate = chainfee.SatPerKWeight(loopInResp.HtlcFeeRate) + + // Derive the sweep address for the htlc timeout sweep tx. + sweepAddress, err := f.cfg.WalletKit.NextAddr( + f.ctx, lnwallet.DefaultAccountName, + walletrpc.AddressType_TAPROOT_PUBKEY, false, + ) + if err != nil { + return f.HandleError(err) + } + f.loopIn.HtlcTimeoutSweepAddress = sweepAddress + + return OnHtlcInitiated +} + +// SignHtlcTxAction ... +func (f *FSM) SignHtlcTxAction(_ fsm.EventContext) fsm.EventType { + var err error + + f.loopIn.AddressParams, err = f.cfg.AddressManager.GetStaticAddressParameters( //nolint:lll + f.ctx, + ) + if err != nil { + return f.HandleError(err) + } + + f.loopIn.Address, err = f.cfg.AddressManager.GetStaticAddress(f.ctx) + if err != nil { + return f.HandleError(err) + } + + // Create a musig2 session for each deposit. + htlcSessions, clientHtlcNonces, err := f.loopIn.createMusig2Sessions( + f.ctx, f.cfg.Signer, + ) + if err != nil { + return f.HandleError(err) + } + f.htlcMusig2Sessions = htlcSessions + f.htlcClientNonces, err = toNonces(clientHtlcNonces) + if err != nil { + return f.HandleError(err) + } + + htlcTx, err := f.loopIn.createHtlcTx(f.cfg.ChainParams) + if err != nil { + return f.HandleError(err) + } + + // Next we'll get our htlc tx signatures. + htlcSigs, err := f.loopIn.signMusig2Tx( + f.ctx, htlcTx, f.cfg.Signer, htlcSessions, f.htlcServerNonces, + ) + if err != nil { + return f.HandleError(err) + } + f.htlcClientSigs = htlcSigs + + // Push htlc tx sigs to server. + pushHtlcReq := &swapserverrpc.PushStaticAddressHtlcSigsRequest{ + SwapHash: f.loopIn.SwapHash[:], + HtlcClientNonces: clientHtlcNonces, + HtlcClientSigs: htlcSigs, + } + sigPushResp, err := f.cfg.StaticAddressServerClient.PushStaticAddressHtlcSigs( //nolint:lll + f.ctx, pushHtlcReq, + ) + if err != nil { + return f.HandleError(err) + } + f.loopIn.HtlcTx = htlcTx + + // From here on we need to monitor for the htlc tx hitting the chain + // until the invoice is settled because the server can now publish the + // htlc tx without paying the invoice. In this case we need to wait till + // the htlc times out and then sweep it back to us. + // If the following calls produce an error we only log them and continue + // with monitoring the invoice settlement and listen for the htlc tx to + // be mined. Otherwise, if we returned on an error in the following, we + // wouldn't be able to monitor the htlc tx. + // Also, if the following code fails we couldn't sign the server's + // sweepless sweep, which wouldn't hinder the swap to succeed. + f.sweeplessServerNonces, err = toNonces( + sigPushResp.SweeplessServerNonces, + ) + if err != nil { + log.Warnf("unable to convert server nonces: %v", err) + } + sweeplessAddress, err := btcutil.DecodeAddress( + sigPushResp.SweeplessSweepAddr, f.cfg.ChainParams, + ) + if err != nil { + log.Warnf("unable to decode sweep address: %v", err) + } + f.loopIn.SweeplessSweepAddress = sweeplessAddress + f.loopIn.SweeplessSweepFeeRate = chainfee.SatPerKWeight( + sigPushResp.SweeplessFeeRate, + ) + + return OnHtlcTxSigned +} + +// MonitorInvoiceAndHtlcTxAction is called after the htlc tx has been signed by +// us. The server from here on has the ability to publish the htlc tx. If the +// server publishes the htlc tx without paying the invoice, we have to monitor +// for the timeout path and sweep the funds back to us. If, while waiting for +// the htlc timeout, our invoice gets paid, the swap is considered successful, +// and we can stop monitoring the htlc confirmation and continue to sign the +// sweepless sweep. +func (f *FSM) MonitorInvoiceAndHtlcTxAction(_ fsm.EventContext) fsm.EventType { + // Subscribe to swap invoice settlement. + invoiceUpdateChan, invoiceErrChan, err := f.cfg.InvoicesClient.SubscribeSingleInvoice( //nolint:lll + f.ctx, f.loopIn.SwapHash, + ) + if err != nil { + return f.HandleError(err) + } + + htlc, err := f.loopIn.getHtlc(f.cfg.ChainParams) + if err != nil { + return f.HandleError(err) + } + + // Subscribe to htlc tx confirmation. + htlcConfChan, htlcErrConfChan, err := f.cfg.ChainNotifier.RegisterConfirmationsNtfn( //nolint:lll + f.ctx, nil, htlc.PkScript, defaultConfTarget, + int32(f.loopIn.InitiationHeight), + ) + + // Subscribe to new blocks. + blockChan, blockChanErr, err := f.cfg.ChainNotifier.RegisterBlockEpochNtfn(f.ctx) //nolint:lll + if err != nil { + return f.HandleError(err) + } + + htlcConfirmed := false + for { + select { + case <-htlcConfChan: + htlcConfirmed = true + + case err = <-htlcErrConfChan: + return f.HandleError(err) + + case currentHeight := <-blockChan: + if !htlcConfirmed { + continue + } + + if f.loopIn.isHtlcTimedOut(currentHeight) { + // Unlock the deposits and transition them to + // the LoopedIn state. + err = f.cfg.DepositManager.TransitionDeposits( + f.loopIn.Deposits, + deposit.OnSweepingHtlcTimout, + deposit.SweepHtlcTimout, + ) + if err != nil { + return f.HandleError(err) + } + return OnSweepHtlcTimout + } + + case err = <-blockChanErr: + return f.HandleError(err) + + case err = <-invoiceErrChan: + return f.HandleError(err) + + case update := <-invoiceUpdateChan: + switch update.State { + case invoices.ContractOpen: + case invoices.ContractAccepted: + case invoices.ContractSettled: + f.Debugf("received off-chain payment: %v "+ + "update: %v", f.loopIn.SwapHash, + update.State) + + // Unlock the deposits and transition them to + // the LoopedIn state. + err = f.cfg.DepositManager.TransitionDeposits( + f.loopIn.Deposits, + deposit.OnLoopedIn, + deposit.LoopedIn, + ) + if err != nil { + return f.HandleError(err) + } + + return OnPaymentReceived + + case invoices.ContractCanceled: + return f.HandleError(fmt.Errorf("invoice " + + "canceled")) + + default: + return f.HandleError(fmt.Errorf("unexpected "+ + "invoice state: %v", update.State)) + } + + case <-time.After(5 * time.Minute): + // TODO: pack timeout into a config. + return f.HandleError(fmt.Errorf("timeout waiting for " + + "invoice to be paid")) + + case <-f.ctx.Done(): + return f.HandleError(f.ctx.Err()) + } + } + + return f.HandleError(fmt.Errorf("unexpected payment state")) +} + +func (f *FSM) SweepHtlcTimeoutAction(_ fsm.EventContext) fsm.EventType { + for { + err := f.createAndPublishHtlcTimoutSweepTx() + if err == nil { + break + } + + // TODO: pack into a timeout config. + <-time.After(1 * time.Hour) + } + + return OnHtlcTimeoutSweepPublished +} + +func (f *FSM) createAndPublishHtlcTimoutSweepTx() error { + // Get a fee rate. + feeRate, err := f.cfg.WalletKit.EstimateFeeRate( + f.ctx, defaultConfTarget, + ) + if err != nil { + return err + } + + getInfo, err := f.cfg.LndClient.GetInfo(f.ctx) + if err != nil { + return err + } + + // Create htlc timeout transaction. + timeoutTx, err := f.loopIn.createHtlcSweepTx( + f.ctx, f.cfg.Signer, f.loopIn.HtlcTimeoutSweepAddress, feeRate, + f.cfg.ChainParams, getInfo.BlockHeight, + ) + if err != nil { + return err + } + + // Broadcast htlc timeout transaction. + txLabel := fmt.Sprintf("htlc-timeout-sweep-%v", + f.loopIn.SwapHash) + + err = f.cfg.WalletKit.PublishTransaction(f.ctx, timeoutTx, txLabel) + if err != nil { + if !strings.Contains(err.Error(), "output already spent") { + log.Errorf("%v: %v", txLabel, err) + f.LastActionError = err + return err + } + } else { + f.Debugf("published htlc timeout sweep with txid: %v", + timeoutTx.TxHash()) + } + f.loopIn.HtlcTimeoutSweepTx = timeoutTx + + return nil +} + +func (f *FSM) MonitorHtlcTimeoutSweepAction(_ fsm.EventContext) fsm.EventType { + htlcTimeoutTxid := f.loopIn.HtlcTimeoutSweepTx.TxHash() + timeoutSweepPkScript, err := txscript.PayToAddrScript( + f.loopIn.HtlcTimeoutSweepAddress, + ) + if err != nil { + return f.HandleError(err) + } + + htlcTimeoutTxidChan, errChan, err := f.cfg.ChainNotifier.RegisterConfirmationsNtfn( //nolint:lll + f.ctx, &htlcTimeoutTxid, timeoutSweepPkScript, + defaultConfTarget, int32(f.loopIn.InitiationHeight), + ) + if err != nil { + return f.HandleError(err) + } + + for { + select { + case err := <-errChan: + return f.HandleError(err) + + case <-htlcTimeoutTxidChan: + err = f.cfg.DepositManager.TransitionDeposits( + f.loopIn.Deposits, + deposit.OnHtlcTimeoutSwept, + deposit.HtlcTimeoutSwept, + ) + if err != nil { + return f.HandleError(err) + } + + return OnHtlcTimeoutSwept + + case <-f.ctx.Done(): + return f.HandleError(f.ctx.Err()) + } + } +} + +func (f *FSM) SignSweeplessSweepAction(_ fsm.EventContext) fsm.EventType { + // Create a musig2 session for each deposit. + musig2Sessions, clientNonces, err := f.loopIn.createMusig2Sessions( + f.ctx, f.cfg.Signer, + ) + if err != nil { + return f.HandleError(err) + } + f.sweeplessMusig2Sessions = musig2Sessions + f.sweeplessClientNonces, err = toNonces(clientNonces) + if err != nil { + return f.HandleError(err) + } + + // Create the sweepless sweep transaction. + sweeplessSweepTx, err := f.loopIn.createSweeplessSweepTx() + if err != nil { + return f.HandleError(err) + } + + // Next we'll get our htlc tx signatures. + sweeplessSigs, err := f.loopIn.signMusig2Tx( + f.ctx, sweeplessSweepTx, f.cfg.Signer, + f.sweeplessMusig2Sessions, f.sweeplessServerNonces, + ) + if err != nil { + return f.HandleError(err) + } + f.sweeplessClientSigs = sweeplessSigs + + // Push Htlc sigs to server + pushSweeplessSigsReq := &swapserverrpc.PushStaticAddressSweeplessSigsRequest{ //nolint:lll + SwapHash: f.loopIn.SwapHash[:], + SweeplessClientNonces: fromNonces(f.sweeplessClientNonces), + SweeplessClientSigs: f.sweeplessClientSigs, + } + _, err = f.cfg.StaticAddressServerClient.PushStaticAddressSweeplessSigs( //nolint:lll + f.ctx, pushSweeplessSigsReq, + ) + if err != nil { + return f.HandleError(err) + } + + return OnSweeplessSweepSigned +} + +func (f *FSM) ResetDepositsAction(_ fsm.EventContext) fsm.EventType { + err := f.cfg.DepositManager.TransitionDeposits( + f.loopIn.Deposits, fsm.OnError, deposit.Deposited, + ) + if err != nil { + return f.HandleError(err) + } + + return fsm.OnError +} + +// toNonces converts a byte slice to a 66 byte slice. +func toNonces(nonces [][]byte) ([][musig2.PubNonceSize]byte, error) { + res := make([][musig2.PubNonceSize]byte, 0, len(nonces)) + for _, n := range nonces { + n := n + nonce, err := byteSliceTo66ByteSlice(n) + if err != nil { + return nil, err + } + + res = append(res, nonce) + } + + return res, nil +} + +// byteSliceTo66ByteSlice converts a byte slice to a 66 byte slice. +func byteSliceTo66ByteSlice(b []byte) ([musig2.PubNonceSize]byte, error) { + if len(b) != musig2.PubNonceSize { + return [musig2.PubNonceSize]byte{}, + fmt.Errorf("invalid byte slice length") + } + + var res [musig2.PubNonceSize]byte + copy(res[:], b) + + return res, nil +} + +func fromNonces(nonces [][musig2.PubNonceSize]byte) [][]byte { + var result [][]byte + for _, nonce := range nonces { + temp := make([]byte, musig2.PubNonceSize) + copy(temp, nonce[:]) + result = append(result, temp) + } + + return result +} diff --git a/staticaddr/loopin/fsm.go b/staticaddr/loopin/fsm.go new file mode 100644 index 0000000000..6b8b3e0ba8 --- /dev/null +++ b/staticaddr/loopin/fsm.go @@ -0,0 +1,275 @@ +package loopin + +import ( + "context" + "fmt" + + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" + "github.com/lightninglabs/loop/fsm" + "github.com/lightninglabs/loop/staticaddr/deposit" + "github.com/lightninglabs/loop/staticaddr/version" + "github.com/lightningnetwork/lnd/input" +) + +// FSM embeds an FSM and extends it with a static loop-in and a config. +// It is used to run a reservation state machine. +type FSM struct { + *fsm.StateMachine + + cfg *Config + + loopIn *StaticAddressLoopIn + + ctx context.Context + + // htlcMusig2Sessions contains all the reservations input musig2 + // sessions that will be used for the htlc transaction. + htlcMusig2Sessions []*input.MuSig2SessionInfo + + // htlcClientNonces contains all the nonces that the client sent for + // the htlc musig2 sessions. + htlcClientNonces [][musig2.PubNonceSize]byte + + // htlcServerNonces contains all the nonces that the server generated + // for the htlc musig2 sessions. + htlcServerNonces [][musig2.PubNonceSize]byte + + // htlcClientSigs contains all the signatures that the client generated + // for the htlc musig2 sessions. + htlcClientSigs [][]byte + + // sweeplessMusig2Sessions ... + sweeplessMusig2Sessions []*input.MuSig2SessionInfo + + // sweeplessClientNonces ... + sweeplessClientNonces [][musig2.PubNonceSize]byte + + // sweeplessServerNonces ... + sweeplessServerNonces [][musig2.PubNonceSize]byte + + // sweeplessClientSigs ... + sweeplessClientSigs [][]byte +} + +// NewFSM creates... +func NewFSM(ctx context.Context, loopIn *StaticAddressLoopIn, cfg *Config, + recoverStateMachine bool) (*FSM, error) { + + loopInFsm := &FSM{ + ctx: ctx, + cfg: cfg, + loopIn: loopIn, + } + + params, err := cfg.AddressManager.GetStaticAddressParameters(ctx) + if err != nil { + return nil, fmt.Errorf("unable to get static address "+ + "parameters: %v", err) + } + + loopInStates := loopInFsm.LoopInStatesV0() + switch params.ProtocolVersion { + case version.ProtocolVersion_V0: + + default: + return nil, deposit.ErrProtocolVersionNotSupported + } + + if recoverStateMachine { + loopInFsm.StateMachine = fsm.NewStateMachineWithState( + loopInStates, loopIn.GetState(), + deposit.DefaultObserverSize, + ) + } else { + loopInFsm.StateMachine = fsm.NewStateMachine( + loopInStates, deposit.DefaultObserverSize, + ) + } + + loopInFsm.ActionEntryFunc = loopInFsm.updateLoopIn + + return loopInFsm, nil +} + +// States. The full FSM diagram can be seen in the reservation/fsm.md file. +var ( + InitHtlc = fsm.StateType("InitHtlc") + SignHtlcTx = fsm.StateType("SignHtlcTx") + MonitorInvoiceAndHtlcTx = fsm.StateType("MonitorInvoiceAndHtlcTx") + MonitorInvoiceAndHtlcTxFailed = fsm.StateType("MonitorInvoiceAndHtlcTxFailed") + SweepHtlcTimout = fsm.StateType("SweepHtlcTimout") + MonitorHtlcTimeoutSweep = fsm.StateType("MonitorHtlcTimeoutSweep") + HtlcTimeoutSwept = fsm.StateType("HtlcTimeoutSwept") + SignSweeplessSweep = fsm.StateType("SignSweeplessSweep") + Succeeded = fsm.StateType("Succeeded") + SucceededSweeplessSigFailed = fsm.StateType("SucceededSweeplessSigFailed") + ResetDeposits = fsm.StateType("ResetDeposits") + PublishingHtlcTimoutSweepFailed = fsm.StateType("PublishingHtlcTimoutSweepFailed") + Failed = fsm.StateType("Failed") +) + +// Events +var ( + OnInitHtlc = fsm.EventType("OnInitHtlc") + OnHtlcInitiated = fsm.EventType("OnHtlcInitiated") + OnHtlcTxSigned = fsm.EventType("OnHtlcTxSigned") + OnSweepHtlcTimout = fsm.EventType("OnSweepHtlcTimout") + OnHtlcTimeoutSweepPublished = fsm.EventType("OnHtlcTimeoutSweepPublished") + OnHtlcTimeoutSwept = fsm.EventType("OnHtlcTimeoutSwept") + OnPaymentReceived = fsm.EventType("OnPaymentReceived") + OnSweeplessSweepSigned = fsm.EventType("OnSweeplessSweepSigned") + OnRecover = fsm.EventType("OnRecover") +) + +// LoopInStatesV0 returns the state and transition map for the reservation state +// machine. The state map can be viewed in the fsm.md file. +func (f *FSM) LoopInStatesV0() fsm.States { + return fsm.States{ + fsm.EmptyState: fsm.State{ + Transitions: fsm.Transitions{ + OnInitHtlc: InitHtlc, + }, + Action: fsm.NoOpAction, + }, + InitHtlc: fsm.State{ + Transitions: fsm.Transitions{ + OnHtlcInitiated: SignHtlcTx, + OnRecover: ResetDeposits, + fsm.OnError: ResetDeposits, + }, + Action: f.InitHtlcAction, + }, + SignHtlcTx: fsm.State{ + Transitions: fsm.Transitions{ + OnHtlcTxSigned: MonitorInvoiceAndHtlcTx, + OnRecover: ResetDeposits, + fsm.OnError: ResetDeposits, + }, + Action: f.SignHtlcTxAction, + }, + MonitorInvoiceAndHtlcTx: fsm.State{ + Transitions: fsm.Transitions{ + OnPaymentReceived: SignSweeplessSweep, + OnSweepHtlcTimout: SweepHtlcTimout, + OnRecover: MonitorInvoiceAndHtlcTx, + fsm.OnError: MonitorInvoiceAndHtlcTxFailed, + }, + Action: f.MonitorInvoiceAndHtlcTxAction, + }, + MonitorInvoiceAndHtlcTxFailed: fsm.State{ + Transitions: fsm.Transitions{ + OnRecover: MonitorInvoiceAndHtlcTx, + }, + Action: fsm.NoOpAction, + }, + SweepHtlcTimout: fsm.State{ + Transitions: fsm.Transitions{ + OnHtlcTimeoutSweepPublished: MonitorHtlcTimeoutSweep, + OnRecover: SweepHtlcTimout, + fsm.OnError: Failed, + }, + Action: f.SweepHtlcTimeoutAction, + }, + MonitorHtlcTimeoutSweep: fsm.State{ + Transitions: fsm.Transitions{ + OnHtlcTimeoutSwept: HtlcTimeoutSwept, + OnRecover: MonitorHtlcTimeoutSweep, + fsm.OnError: Failed, + }, + Action: f.MonitorHtlcTimeoutSweepAction, + }, + SignSweeplessSweep: fsm.State{ + Transitions: fsm.Transitions{ + OnSweeplessSweepSigned: Succeeded, + OnRecover: SucceededSweeplessSigFailed, + fsm.OnError: SucceededSweeplessSigFailed, + }, + Action: f.SignSweeplessSweepAction, + }, + HtlcTimeoutSwept: fsm.State{ + Action: fsm.NoOpAction, + }, + Succeeded: fsm.State{ + Action: fsm.NoOpAction, + }, + SucceededSweeplessSigFailed: fsm.State{ + Action: fsm.NoOpAction, + }, + ResetDeposits: fsm.State{ + Transitions: fsm.Transitions{ + OnRecover: ResetDeposits, + fsm.OnError: Failed, + }, + Action: f.ResetDepositsAction, + }, + Failed: fsm.State{ + Action: fsm.NoOpAction, + }, + } +} + +// updateReservation is called after every action and updates the reservation +// in the db. +func (f *FSM) updateLoopIn(notification fsm.Notification) { + f.Infof("Current: %v", notification.NextState) + + // Skip the update if the reservation is not yet initialized. + if f.loopIn == nil { + return + } + + f.loopIn.SetState(notification.NextState) + + // If we're in the early stages we don't have created the loop-in in the + // store yet and won't need to update it. + prevState := notification.PreviousState + if f.loopIn.IsInState(fsm.EmptyState) || + f.loopIn.IsInState(prevState) || + prevState == fsm.EmptyState && f.loopIn.IsInState(InitHtlc) { + + return + } + + err := f.cfg.Store.UpdateLoopIn(f.ctx, f.loopIn) + if err != nil { + log.Errorf("Error updating loop-in: %v", err) + return + } + +} + +// Infof logs an info message with the reservation id. +func (f *FSM) Infof(format string, args ...interface{}) { + if f.loopIn == nil { + log.Infof(format, args...) + return + } + log.Infof( + "StaticAddr loop-in %x: %s", f.loopIn.SwapHash, + fmt.Sprintf(format, args...), + ) +} + +// Debugf logs a debug message with the reservation id. +func (f *FSM) Debugf(format string, args ...interface{}) { + if f.loopIn == nil { + log.Infof(format, args...) + return + } + log.Debugf( + "StaticAddr loop-in %x: %s", f.loopIn.SwapHash, + fmt.Sprintf(format, args...), + ) +} + +// Errorf logs an error message with the reservation id. +func (f *FSM) Errorf(format string, args ...interface{}) { + if f.loopIn == nil { + log.Errorf(format, args...) + return + } + log.Errorf( + "StaticAddr loop-in %x: %s", f.loopIn.SwapHash, + fmt.Sprintf(format, args...), + ) +} diff --git a/staticaddr/loopin/interface.go b/staticaddr/loopin/interface.go new file mode 100644 index 0000000000..5573f1d956 --- /dev/null +++ b/staticaddr/loopin/interface.go @@ -0,0 +1,116 @@ +package loopin + +import ( + "context" + "github.com/btcsuite/btcd/btcutil" + "github.com/lightningnetwork/lnd/routing/route" + "github.com/lightningnetwork/lnd/zpay32" + + "github.com/btcsuite/btcd/wire" + "github.com/lightninglabs/loop/fsm" + "github.com/lightninglabs/loop/staticaddr/address" + "github.com/lightninglabs/loop/staticaddr/deposit" + "github.com/lightninglabs/loop/staticaddr/script" + "github.com/lightningnetwork/lnd/lnwallet" +) + +const ( + IdLength = 32 +) + +// Request contains the required parameters for the swap. +type Request struct { + // Amount specifies the requested swap amount in sat. This does not + // include the swap and miner fee. + Amount btcutil.Amount + + // 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 + // the server asks for a higher fee, we abort the swap. Typically this + // value is taken from the response of the LoopInQuote call. It + // includes the prepay amount. + MaxSwapFee btcutil.Amount + + // MaxMinerFee is the maximum in on-chain fees that we are willing to + // spent. If we publish the on-chain htlc and the fee estimate turns out + // higher than this value, we cancel the swap. + // + // MaxMinerFee is typically taken from the response of the LoopInQuote + // call. + MaxMinerFee btcutil.Amount + + // HtlcConfTarget specifies the targeted confirmation target for the + // client htlc tx. + HtlcConfTarget int32 + + // LastHop optionally specifies the last hop to use for the loop in + // payment. + LastHop *route.Vertex + + // ExternalHtlc specifies whether the htlc is published by an external + // source. + ExternalHtlc bool + + // Label contains an optional label for the swap. + Label string + + // Initiator is an optional string that identifies what software + // initiated the swap (loop CLI, autolooper, LiT UI and so on) and is + // appended to the user agent string. + Initiator string + + // Private indicates whether the destination node should be considered + // private. In which case, loop will generate hophints to assist with + // probing and payment. + Private bool + + // RouteHints are optional route hints to reach the destination through + // private channels. + RouteHints [][]zpay32.HopHint +} + +// AddressManager handles fetching of address parameters. +type AddressManager interface { + // GetStaticAddressParameters returns the static address parameters. + GetStaticAddressParameters(ctx context.Context) (*address.Parameters, + error) + + // GetStaticAddress returns the deposit address for the given + // client and server public keys. + GetStaticAddress(ctx context.Context) (*script.StaticAddress, error) + + // ListUnspent returns a list of utxos at the static address. + ListUnspent(ctx context.Context, minConfs, + maxConfs int32) ([]*lnwallet.Utxo, error) +} + +type DepositManager interface { + GetActiveDepositsInState(stateFilter fsm.StateType) ([]*deposit.Deposit, + error) + + AllOutpointsActiveDeposits(outpoints []wire.OutPoint, + stateFilter fsm.StateType) ([]*deposit.Deposit, bool) + + AllStringOutpointsActiveDeposits(outpoints []string, + stateFilter fsm.StateType) ([]*deposit.Deposit, bool) + + TransitionDeposits(deposits []*deposit.Deposit, event fsm.EventType, + expectedFinalState fsm.StateType) error + + UpdateDeposit(d *deposit.Deposit) error +} + +type WithdrawalManager interface { +} + +// StaticAddressLoopInStore ... +type StaticAddressLoopInStore interface { + // CreateLoopIn ... + CreateLoopIn(ctx context.Context, loopIn *StaticAddressLoopIn) error + + // UpdateLoopIn ... + UpdateLoopIn(ctx context.Context, loopIn *StaticAddressLoopIn) error + + // AllLoopIns ... + AllLoopIns(ctx context.Context) ([]*StaticAddressLoopIn, error) +} diff --git a/staticaddr/loopin/log.go b/staticaddr/loopin/log.go new file mode 100644 index 0000000000..99816e9cbd --- /dev/null +++ b/staticaddr/loopin/log.go @@ -0,0 +1,24 @@ +package loopin + +import ( + "github.com/btcsuite/btclog" + "github.com/lightningnetwork/lnd/build" +) + +// Subsystem defines the sub system name of this package. +const Subsystem = "SADDR" + +// log is a logger that is initialized with no output filters. This means the +// package will not perform any logging by default until the caller requests it. +var log btclog.Logger + +// The default amount of logging is none. +func init() { + UseLogger(build.NewSubLogger(Subsystem, nil)) +} + +// UseLogger uses a specified Logger to output package logging info. This should +// be used in preference to SetLogWriter if the caller is also using btclog. +func UseLogger(logger btclog.Logger) { + log = logger +} diff --git a/staticaddr/loopin/loopin.go b/staticaddr/loopin/loopin.go new file mode 100644 index 0000000000..4342355669 --- /dev/null +++ b/staticaddr/loopin/loopin.go @@ -0,0 +1,545 @@ +package loopin + +import ( + "context" + "errors" + "fmt" + "reflect" + "sync" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" + "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" + "github.com/lightninglabs/lndclient" + "github.com/lightninglabs/loop/fsm" + "github.com/lightninglabs/loop/staticaddr/address" + "github.com/lightninglabs/loop/staticaddr/deposit" + "github.com/lightninglabs/loop/staticaddr/script" + "github.com/lightninglabs/loop/staticaddr/version" + "github.com/lightninglabs/loop/swap" + "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnwallet/chainfee" + "github.com/lightningnetwork/lnd/zpay32" +) + +// StaticAddressLoopIn ... +type StaticAddressLoopIn struct { + + // Swap fields. + + // SwapHash is the hashed preimage of the swap invoice. It represents + // the primary identifier of the swap. + SwapHash lntypes.Hash + + // SwapPreimage is the preimage that is used for the swap. + SwapPreimage lntypes.Preimage + + // HtlcCltvExpiry is the expiry of the swap. + HtlcCltvExpiry int32 + + // MaxSwapFee is the swap fee in sats that the user accepted when + // initiating the swap. It is the upper limit for the QuotedSwapFee. + MaxSwapFee btcutil.Amount + + // InitiationHeight is the height at which the swap was initiated. + InitiationHeight uint32 + + // ProtocolVersion is the protocol version of the static address. + ProtocolVersion version.AddressProtocolVersion + + // Label contains an optional label for the swap. + Label string + + // Htlc key fields + + // ClientPubkey is the pubkey of the client that is used for the swap. + ClientPubkey *btcec.PublicKey + + // ServerPubkey is the pubkey of the server that is used for the swap. + ServerPubkey *btcec.PublicKey + + // HtlcKeyLocator is the locator of the server's htlc key. + HtlcKeyLocator keychain.KeyLocator + + // Static address loop-in fields. + + // SwapInvoice is the invoice that needs to be paid by the server to + // complete the loop-in swap. + SwapInvoice string + + // LastHop is an optional parameter that specifies the last hop to be + // used for a loop in swap. + LastHop []byte + + // QuotedSwapFee is the swap fee in sats that the server returned in the + // swap quote. + QuotedSwapFee btcutil.Amount + + DepositOutpoints []string + + // Update data + + // State is the current state of the swap. + state fsm.StateType + + // Non-persistent convenience fields + + Initiator string + + Private bool + + RouteHints [][]zpay32.HopHint + + Deposits []*deposit.Deposit + + AddressParams *address.Parameters + + Address *script.StaticAddress + + // SweeplessSweepAddress is the address that is used to sweep the + // deposits as part of the loop in swap. + SweeplessSweepAddress btcutil.Address + + // SweeplessFeeRate is the fee rate that is used for the htlc + // transaction. + SweeplessSweepFeeRate chainfee.SatPerKWeight + + // HTLC Fields + + // HtlcTx is the htlc transaction that is used in the non-cooperative + // path for the static address loop-in swap. It is not finalized as it + // lacks the server signatures. + HtlcTx *wire.MsgTx + + // HtlcTxFeeRate is the fee rate that is used for the htlc transaction. + HtlcTxFeeRate chainfee.SatPerKWeight + + // HtlcTimeoutSweepTx + HtlcTimeoutSweepTx *wire.MsgTx + + // HtlcTimeoutSweepAddress + HtlcTimeoutSweepAddress btcutil.Address + + sync.Mutex +} + +func (l *StaticAddressLoopIn) getHtlc(chainParams *chaincfg.Params) (*swap.Htlc, + error) { + + return swap.NewHtlcV2( + l.HtlcCltvExpiry, pubkeyTo33ByteSlice(l.ClientPubkey), + pubkeyTo33ByteSlice(l.ServerPubkey), l.SwapHash, chainParams, + ) +} + +// createMusig2Sessions creates a musig2 session for a number of deposits. +func (l *StaticAddressLoopIn) createMusig2Sessions(ctx context.Context, + signer lndclient.SignerClient) ([]*input.MuSig2SessionInfo, [][]byte, + error) { + + musig2Sessions := make([]*input.MuSig2SessionInfo, len(l.Deposits)) + clientNonces := make([][]byte, len(l.Deposits)) + + // Create the sessions and nonces from the deposits. + for i := 0; i < len(l.Deposits); i++ { + session, err := l.createMusig2Session(ctx, signer) + if err != nil { + return nil, nil, err + } + + musig2Sessions[i] = session + clientNonces[i] = session.PublicNonce[:] + } + + return musig2Sessions, clientNonces, nil +} + +// Musig2CreateSession creates a musig2 session for the deposit. +func (l *StaticAddressLoopIn) createMusig2Session(ctx context.Context, + signer lndclient.SignerClient) (*input.MuSig2SessionInfo, error) { + + signers := [][]byte{ + l.AddressParams.ClientPubkey.SerializeCompressed(), + l.AddressParams.ServerPubkey.SerializeCompressed(), + } + + expiryLeaf := l.Address.TimeoutLeaf + + rootHash := expiryLeaf.TapHash() + + return signer.MuSig2CreateSession( + ctx, input.MuSig2Version100RC2, &l.AddressParams.KeyLocator, + signers, lndclient.MuSig2TaprootTweakOpt(rootHash[:], false), + ) +} + +// createSweeplessSweepTx ... +func (l *StaticAddressLoopIn) createSweeplessSweepTx() (*wire.MsgTx, error) { + // Create the tx. + msgTx := wire.NewMsgTx(2) + + // Add the deposit inputs to the transaction in the order the server + // signed them. + outpoints := l.Outpoints() + for _, outpoint := range outpoints { + msgTx.AddTxIn(&wire.TxIn{ + PreviousOutPoint: outpoint, + }) + } + + // Calculate tx fee for server provided fee rate. + weight, err := sweeplessSweepWeight( + len(outpoints), l.SweeplessSweepAddress, + ) + if err != nil { + return nil, err + } + fee := l.SweeplessSweepFeeRate.FeeForWeight(weight) + + pkscript, err := txscript.PayToAddrScript(l.SweeplessSweepAddress) + if err != nil { + return nil, err + } + + // Create the sweep output + sweepOutput := &wire.TxOut{ + Value: int64(l.TotalDepositAmount()) - int64(fee), + PkScript: pkscript, + } + + msgTx.AddTxOut(sweepOutput) + + return msgTx, nil +} + +// sweeplessSweepWeight ... +func sweeplessSweepWeight(numInputs int, + sweepAddress btcutil.Address) (lntypes.WeightUnit, error) { + + var weightEstimator input.TxWeightEstimator + for i := 0; i < numInputs; i++ { + weightEstimator.AddTaprootKeySpendInput( + txscript.SigHashDefault, + ) + } + + // Get the weight of the sweep output. + switch sweepAddress.(type) { + case *btcutil.AddressWitnessPubKeyHash: + weightEstimator.AddP2WKHOutput() + + case *btcutil.AddressTaproot: + weightEstimator.AddP2TROutput() + + default: + return 0, fmt.Errorf("invalid sweep address type %T", + sweepAddress) + } + + return weightEstimator.Weight(), nil +} + +// signMusig2Tx adds the server nonces to the musig2 sessions and signs +// the transaction. +func (l *StaticAddressLoopIn) signMusig2Tx(ctx context.Context, + tx *wire.MsgTx, signer lndclient.SignerClient, + musig2sessions []*input.MuSig2SessionInfo, + counterPartyNonces [][musig2.PubNonceSize]byte) ([][]byte, error) { + + prevOuts := l.toPrevOuts(l.Deposits, l.AddressParams.PkScript) + prevOutFetcher := txscript.NewMultiPrevOutFetcher(prevOuts) + + outpoints := l.Outpoints() + sigHashes := txscript.NewTxSigHashes(tx, prevOutFetcher) + sigs := make([][]byte, len(outpoints)) + + for idx, outpoint := range outpoints { + if !reflect.DeepEqual(tx.TxIn[idx].PreviousOutPoint, + outpoint) { + + return nil, fmt.Errorf("tx input does not match " + + "deposits") + } + + taprootSigHash, err := txscript.CalcTaprootSignatureHash( + sigHashes, txscript.SigHashDefault, tx, idx, + prevOutFetcher, + ) + if err != nil { + return nil, err + } + + var digest [32]byte + copy(digest[:], taprootSigHash) + + // Register the server's nonce before attempting to create our + // partial signature. + haveAllNonces, err := signer.MuSig2RegisterNonces( + ctx, musig2sessions[idx].SessionID, + [][musig2.PubNonceSize]byte{counterPartyNonces[idx]}, + ) + if err != nil { + return nil, err + } + + // Sanity check that we have all the nonces. + if !haveAllNonces { + return nil, fmt.Errorf("invalid MuSig2 session: " + + "nonces missing") + } + + // Since our MuSig2 session has all nonces, we can now create + // the local partial signature by signing the sig hash. + sig, err := signer.MuSig2Sign( + ctx, musig2sessions[idx].SessionID, digest, false, + ) + if err != nil { + return nil, err + } + + sigs[idx] = sig + } + + return sigs, nil +} + +func (l *StaticAddressLoopIn) createHtlcTx(chainParams *chaincfg.Params) ( + *wire.MsgTx, error) { + + // First Create the tx. + msgTx := wire.NewMsgTx(2) + + // Add the deposit inputs to the transaction in the order the server + // signed them. + outpoints := l.Outpoints() + for _, outpoint := range outpoints { + msgTx.AddTxIn(&wire.TxIn{ + PreviousOutPoint: outpoint, + }) + } + + // Calculate htlc tx fee for server provided fee rate. + weight := htlcWeight(len(outpoints)) + fee := l.HtlcTxFeeRate.FeeForWeight(weight) + + htlc, err := l.getHtlc(chainParams) + if err != nil { + return nil, err + } + + pkscript, err := txscript.PayToAddrScript(htlc.Address) + if err != nil { + return nil, err + } + + // Create the sweep output + sweepOutput := &wire.TxOut{ + Value: int64(l.TotalDepositAmount()) - int64(fee), + PkScript: pkscript, + } + + msgTx.AddTxOut(sweepOutput) + + return msgTx, nil +} + +func (l *StaticAddressLoopIn) isHtlcTimedOut(height int32) bool { + if height >= l.HtlcCltvExpiry { + return true + } + + return false +} + +// htlcWeight returns the weight for the htlc transaction. +func htlcWeight(numInputs int) lntypes.WeightUnit { + var weightEstimator input.TxWeightEstimator + for i := 0; i < numInputs; i++ { + weightEstimator.AddTaprootKeySpendInput( + txscript.SigHashDefault, + ) + } + + weightEstimator.AddP2WSHOutput() + + return weightEstimator.Weight() +} + +// createHtlcSweepTx creates the htlc sweep transaction for the loop-in. +func (l *StaticAddressLoopIn) createHtlcSweepTx(ctx context.Context, + signer lndclient.SignerClient, sweepAddress btcutil.Address, + feeRate chainfee.SatPerKWeight, network *chaincfg.Params, + blockHeight uint32) (*wire.MsgTx, error) { + + if network == nil { + return nil, errors.New("no network provided") + } + + if l.HtlcTx == nil { + return nil, errors.New("no finalized htlc tx") + } + + htlc, err := l.getHtlc(network) + if err != nil { + return nil, err + } + + fmt.Printf("HTLC Pkscript before publishing sweep: %x\n", htlc.PkScript) + + // Create the sweep transaction. + sweepTx := wire.NewMsgTx(2) + sweepTx.LockTime = blockHeight + + var weightEstimator input.TxWeightEstimator + weightEstimator.AddP2TROutput() + + err = htlc.AddSuccessToEstimator(&weightEstimator) + if err != nil { + return nil, err + } + + htlcHash := l.HtlcTx.TxHash() + + // Add the htlc input. + sweepTx.AddTxIn(&wire.TxIn{ + PreviousOutPoint: wire.OutPoint{ + Hash: htlcHash, + Index: 0, + }, + SignatureScript: htlc.SigScript, + Sequence: htlc.SuccessSequence(), + }) + + // Add the sweep output. + sweepPkScript, err := txscript.PayToAddrScript(sweepAddress) + if err != nil { + return nil, err + } + + fee := feeRate.FeeForWeight(weightEstimator.Weight()) + + htlcOutValue := l.HtlcTx.TxOut[0].Value + output := &wire.TxOut{ + Value: htlcOutValue - int64(fee), + PkScript: sweepPkScript, + } + + sweepTx.AddTxOut(output) + + signDesc := lndclient.SignDescriptor{ + WitnessScript: htlc.TimeoutScript(), + Output: &wire.TxOut{ + Value: htlcOutValue, + PkScript: htlc.PkScript, + }, + HashType: htlc.SigHash(), + InputIndex: 0, + KeyDesc: keychain.KeyDescriptor{ + KeyLocator: l.HtlcKeyLocator, + }, + } + signDesc.SignMethod = input.WitnessV0SignMethod + + rawSigs, err := signer.SignOutputRaw( + ctx, sweepTx, []*lndclient.SignDescriptor{&signDesc}, nil, + ) + if err != nil { + return nil, fmt.Errorf("sign output error: %v", err) + } + sig := rawSigs[0] + + // Add witness stack to the tx input. + sweepTx.TxIn[0].Witness, err = htlc.GenTimeoutWitness(sig) + if err != nil { + return nil, err + } + + return sweepTx, nil +} + +// pubkeyTo33ByteSlice converts a pubkey to a 33 byte slice. +func pubkeyTo33ByteSlice(pubkey *btcec.PublicKey) [33]byte { + var pubkeyBytes [33]byte + copy(pubkeyBytes[:], pubkey.SerializeCompressed()) + + return pubkeyBytes +} + +func (l *StaticAddressLoopIn) TotalDepositAmount() btcutil.Amount { + var total btcutil.Amount + if len(l.Deposits) == 0 { + return total + } + + for _, d := range l.Deposits { + total += d.Value + } + return total +} + +func (l *StaticAddressLoopIn) Outpoints() []wire.OutPoint { + outpoints := make([]wire.OutPoint, len(l.Deposits)) + for i, d := range l.Deposits { + outpoints[i] = wire.OutPoint{ + Hash: d.Hash, + Index: d.Index, + } + } + + return outpoints +} + +func (l *StaticAddressLoopIn) toPrevOuts(deposits []*deposit.Deposit, + pkScript []byte) map[wire.OutPoint]*wire.TxOut { + + prevOuts := make(map[wire.OutPoint]*wire.TxOut, len(deposits)) + for _, d := range deposits { + outpoint := wire.OutPoint{ + Hash: d.Hash, + Index: d.Index, + } + txOut := &wire.TxOut{ + Value: int64(d.Value), + PkScript: pkScript, + } + prevOuts[outpoint] = txOut + } + + return prevOuts +} + +func (l *StaticAddressLoopIn) GetState() fsm.StateType { + l.Lock() + defer l.Unlock() + + return l.state +} + +func (l *StaticAddressLoopIn) SetState(state fsm.StateType) { + l.Lock() + defer l.Unlock() + + l.state = state +} + +func (l *StaticAddressLoopIn) IsInState(state fsm.StateType) bool { + l.Lock() + defer l.Unlock() + + return l.state == state +} + +// IsInFinalState returns true if the deposit is final. +func (l *StaticAddressLoopIn) IsInFinalState() bool { + l.Lock() + defer l.Unlock() + + return l.state == HtlcTimeoutSwept || l.state == Succeeded || + l.state == SucceededSweeplessSigFailed || + l.state == PublishingHtlcTimoutSweepFailed || l.state == Failed +} diff --git a/staticaddr/loopin/manager.go b/staticaddr/loopin/manager.go new file mode 100644 index 0000000000..e7b6660265 --- /dev/null +++ b/staticaddr/loopin/manager.go @@ -0,0 +1,322 @@ +package loopin + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/btcsuite/btcd/chaincfg" + "github.com/lightninglabs/lndclient" + "github.com/lightninglabs/loop" + fsm2 "github.com/lightninglabs/loop/fsm" + "github.com/lightninglabs/loop/labels" + "github.com/lightninglabs/loop/staticaddr/deposit" + "github.com/lightninglabs/loop/swapserverrpc" + "github.com/lightningnetwork/lnd/routing/route" +) + +var ( + // hopHintFactor is factor by which we scale the total amount of + // inbound capacity we want our hop hints to represent, allowing us to + // have some leeway if peers go offline. + hopHintFactor = 2 +) + +// Config contains the services required for the loop-in manager. +type Config struct { + StaticAddressServerClient swapserverrpc.StaticAddressServerClient + + // AddressManager gives the withdrawal manager access to static address + // parameters. + AddressManager AddressManager + + // DepositManager gives the withdrawal manager access to the deposits + // enabling it to create and manage withdrawals. + DepositManager DepositManager + + WithdrawalManager WithdrawalManager + + LndClient lndclient.LightningClient + + InvoicesClient lndclient.InvoicesClient + + SwapClient *loop.Client + + NodePubkey route.Vertex + + // WalletKit is the wallet client that is used to derive new keys from + // lnd's wallet. + WalletKit lndclient.WalletKitClient + + // ChainParams is the chain configuration(mainnet, testnet...) this + // manager uses. + ChainParams *chaincfg.Params + + // ChainNotifier is the chain notifier that is used to listen for new + // blocks. + ChainNotifier lndclient.ChainNotifierClient + + // Signer is the signer client that is used to sign transactions. + Signer lndclient.SignerClient + + // Store is the database store that is used to store static address + // related records. + Store StaticAddressLoopInStore +} + +// Manager manages the address state machines. +type Manager struct { + cfg *Config + + runCtx context.Context + + sync.Mutex + + // initChan signals the daemon that the address manager has completed + // its initialization. + initChan chan struct{} + + // initiationHeight stores the currently best known block height. + initiationHeight uint32 + + // currentHeight stores the currently best known block height. + currentHeight uint32 +} + +// NewManager creates a new deposit withdrawal manager. +func NewManager(cfg *Config) *Manager { + return &Manager{ + cfg: cfg, + initChan: make(chan struct{}), + } +} + +// Run runs the deposit withdrawal manager. +func (m *Manager) Run(ctx context.Context, currentHeight uint32) error { + m.runCtx = ctx + + m.Lock() + m.currentHeight, m.initiationHeight = currentHeight, currentHeight + m.Unlock() + + newBlockChan, newBlockErrChan, err := m.cfg.ChainNotifier.RegisterBlockEpochNtfn(m.runCtx) //nolint:lll + if err != nil { + return err + } + + err = m.recover() + if err != nil { + return err + } + + // Communicate to the caller that the address manager has completed its + // initialization. + close(m.initChan) + + for { + select { + case height := <-newBlockChan: + m.Lock() + m.currentHeight = uint32(height) + m.Unlock() + + case err = <-newBlockErrChan: + return err + + case <-m.runCtx.Done(): + return m.runCtx.Err() + } + } +} + +func (m *Manager) recover() error { + log.Infof("Recovering static address loop-ins...") + + // Recover deposits. + loopIns, err := m.cfg.Store.AllLoopIns(m.runCtx) + if err != nil { + return err + } + + for _, loopIn := range loopIns { + // If the current deposit is final it wasn't active when we + // shut down the client last. So we don't need to start a fsm + // for it. + if loopIn.IsInFinalState() { + continue + } + + log.Debugf("Recovering loopIn %x", loopIn.SwapHash) + + loopIn.Deposits, _ = m.cfg.DepositManager.AllStringOutpointsActiveDeposits( //nolint:lll + loopIn.DepositOutpoints, fsm2.EmptyState, + ) + + loopIn.AddressParams, err = m.cfg.AddressManager.GetStaticAddressParameters( //nolint:lll + m.runCtx, + ) + if err != nil { + return err + } + + loopIn.Address, err = m.cfg.AddressManager.GetStaticAddress( + m.runCtx, + ) + if err != nil { + return err + } + + // Create a state machine for a given deposit. + recovery := true + fsm, err := NewFSM(m.runCtx, loopIn, m.cfg, recovery) + if err != nil { + return err + } + + // Send the OnRecover event to the state machine. + go func() { + err = fsm.SendEvent(OnRecover, nil) + if err != nil { + log.Errorf("Error sending OnStart event: %v", + err) + } + }() + } + + return nil +} + +// WaitInitComplete waits until the static address loop-in manager has completed +// its setup. +func (m *Manager) WaitInitComplete() { + defer log.Debugf("Static address loop-in manager initiation complete.") + <-m.initChan +} + +// InitiateLoopIn ... +func (m *Manager) InitiateLoopIn(req *loop.StaticAddressLoopInRequest) error { + loopIn := &StaticAddressLoopIn{} + + // Validate the loop-in request. + if len(req.DepositOutpoints) == 0 { + return fmt.Errorf("no deposit outpoints provided") + } + loopIn.DepositOutpoints = req.DepositOutpoints + + // Retrieve all deposits referenced by the outpoints and ensure that + // they are in state Deposited. + deposits, active := m.cfg.DepositManager.AllStringOutpointsActiveDeposits( //nolint:lll + loopIn.DepositOutpoints, deposit.Deposited, + ) + if !active { + return fmt.Errorf("one or more deposits are not in state %s", + deposit.Deposited) + } + loopIn.Deposits = deposits + totalDepositAmount := loopIn.TotalDepositAmount() + + // Check that the label is valid. + err := labels.Validate(req.Label) + if err != nil { + return fmt.Errorf("invalid label: %v", err) + } + loopIn.Label = req.Label + loopIn.Initiator = req.Initiator + + // Private and route hints are mutually exclusive as setting private + // means we retrieve our own route hints from the connected node. + if len(req.RouteHints) != 0 && req.Private { + return fmt.Errorf("private and route hints are mutually " + + "exclusive") + } + + // If private is set, we generate route hints. + if req.Private { + // If last_hop is set, we'll only add channels with peers set to + // the last_hop parameter. + includeNodes := make(map[route.Vertex]struct{}) + if req.LastHop != nil { + includeNodes[*req.LastHop] = struct{}{} + } + + // Because the Private flag is set, we'll generate our own set + // of hop hints. + req.RouteHints, err = loop.SelectHopHints( + m.runCtx, m.cfg.LndClient, totalDepositAmount, + loop.DefaultMaxHopHints, includeNodes, + ) + if err != nil { + return fmt.Errorf("unable to generate hop hints: %v", + err) + } + } + loopIn.RouteHints = req.RouteHints + loopIn.Private = req.Private + + // 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. We pass nil as optional route + // hints as hop hint selection when generating invoices with private + // channels is an LND side black box feature. Advanced users will quote + // directly anyway and there they have the option to add specific route + // hints. + // The quote call will also request a probe from the server to ensure + // feasibility of a loop-in for the totalDepositAmount. + quote, err := m.cfg.SwapClient.Server.GetLoopInQuote( + m.runCtx, totalDepositAmount, m.cfg.NodePubkey, req.LastHop, + req.RouteHints, req.Initiator, uint32(len(loopIn.Deposits)), + ) + if err != nil { + return fmt.Errorf("unable to get loop in quote: %v", err) + } + + if quote.SwapFee > req.MaxSwapFee { + log.Warnf("Swap fee %v exceeding maximum of %v", + quote.SwapFee, req.MaxSwapFee) + + return loop.ErrSwapFeeTooHigh + } + loopIn.QuotedSwapFee = quote.SwapFee + loopIn.MaxSwapFee = req.MaxSwapFee + + m.Lock() + loopIn.InitiationHeight = m.currentHeight + m.Unlock() + + return m.startLoopInFsm(loopIn) +} + +func (m *Manager) startLoopInFsm(loopIn *StaticAddressLoopIn) error { + // Create a state machine for a given deposit. + recovery := false + fsm, err := NewFSM(m.runCtx, loopIn, m.cfg, recovery) + if err != nil { + return err + } + + // Send the start event to the state machine. + go func() { + err := fsm.SendEvent(OnInitHtlc, nil) + if err != nil { + log.Errorf("Error sending OnNewRequest event: %v", err) + } + }() + + err = fsm.DefaultObserver.WaitForState( + m.runCtx, time.Minute, SignHtlcTx, + fsm2.WithAbortEarlyOnErrorOption(), + ) + if err != nil { + return err + } + + // Once the SignHtlcTx state is reached the server registered the + // loop-in and assigned it an ID that we can store. + err = m.cfg.Store.CreateLoopIn(m.runCtx, loopIn) + if err != nil { + return err + } + + return nil +} diff --git a/staticaddr/loopin/sql_store.go b/staticaddr/loopin/sql_store.go new file mode 100644 index 0000000000..67e3f7958f --- /dev/null +++ b/staticaddr/loopin/sql_store.go @@ -0,0 +1,375 @@ +package loopin + +import ( + "bytes" + "context" + "database/sql" + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/wire" + "github.com/lightninglabs/loop/fsm" + "github.com/lightninglabs/loop/loopdb" + "github.com/lightninglabs/loop/loopdb/sqlc" + "github.com/lightninglabs/loop/staticaddr/deposit" + "github.com/lightninglabs/loop/staticaddr/version" + "github.com/lightningnetwork/lnd/clock" + "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/lnwallet/chainfee" +) + +const OutpointSeparator = ";" + +// Querier is the interface that contains all the queries generated by sqlc for +// the static_address_swaps table. +type Querier interface { + // InsertSwap inserts a new base swap. + InsertSwap(ctx context.Context, arg sqlc.InsertSwapParams) error + + // InsertHtlcKeys inserts the htlc keys for a swap. + InsertHtlcKeys(ctx context.Context, arg sqlc.InsertHtlcKeysParams) error + + // InsertStaticAddressLoopIn inserts a new static address loop-in swap. + InsertStaticAddressLoopIn(ctx context.Context, + arg sqlc.InsertStaticAddressLoopInParams) error + + // InsertStaticAddressMetaUpdate inserts metadata about loop-in + // updates. + InsertStaticAddressMetaUpdate(ctx context.Context, + arg sqlc.InsertStaticAddressMetaUpdateParams) error + + // UpdateStaticAddressLoopIn updates an instant out swap. + UpdateStaticAddressLoopIn(ctx context.Context, + arg sqlc.UpdateStaticAddressLoopInParams) error + + // GetStaticAddressLoopInSwap ... + GetStaticAddressLoopInSwap(ctx context.Context, + swapHash []byte) (sqlc.GetStaticAddressLoopInSwapRow, error) + + // GetStaticAddressLoopInSwaps ... + GetStaticAddressLoopInSwaps(ctx context.Context) ( + []sqlc.GetStaticAddressLoopInSwapsRow, error) + + // GetLoopInSwapUpdates ... + GetLoopInSwapUpdates(ctx context.Context, + swapHash []byte) ([]sqlc.StaticAddressSwapUpdate, error) +} + +// BaseDB is the interface that contains all the queries generated by sqlc for +// the static_address_swaps table and transaction functionality. +type BaseDB interface { + Querier + + // ExecTx allows for executing a function in the context of a database + // transaction. + ExecTx(ctx context.Context, txOptions loopdb.TxOptions, + txBody func(Querier) error) error +} + +// DepositStore ... +type DepositStore interface { + // GetDeposit returns the deposit for the given id. + GetDeposit(ctx context.Context, id deposit.ID) (*deposit.Deposit, error) +} + +// SqlStore is the backing store for static address loop-ins. +type SqlStore struct { + baseDB BaseDB + depositStore DepositStore + clock clock.Clock + network *chaincfg.Params +} + +// NewSqlStore constructs a new SQLStore from a BaseDB. The BaseDB is agnostic +// to the underlying driver which can be postgres or sqlite. +func NewSqlStore(db BaseDB, clock clock.Clock, + depositStore DepositStore, network *chaincfg.Params) *SqlStore { + + return &SqlStore{ + baseDB: db, + depositStore: depositStore, + clock: clock, + network: network, + } +} + +// AllLoopIns ... +func (s *SqlStore) AllLoopIns(ctx context.Context) ([]*StaticAddressLoopIn, + error) { + + rows, err := s.baseDB.GetStaticAddressLoopInSwaps(ctx) + if err != nil { + return nil, err + } + + var loopIns []*StaticAddressLoopIn + for _, row := range rows { + updates, err := s.baseDB.GetLoopInSwapUpdates( + ctx, row.SwapHash, + ) + if err != nil { + return nil, err + } + + loopIn, err := toStaticAddressLoopIn( + ctx, s.network, sqlc.GetStaticAddressLoopInSwapRow(row), + updates, + ) + if err != nil { + return nil, err + } + + loopIns = append(loopIns, loopIn) + } + + return loopIns, nil +} + +// CreateLoopIn ... +func (s *SqlStore) CreateLoopIn(ctx context.Context, + loopIn *StaticAddressLoopIn) error { + + swapArgs := sqlc.InsertSwapParams{ + SwapHash: loopIn.SwapHash[:], + Preimage: loopIn.SwapPreimage[:], + InitiationTime: s.clock.Now(), + AmountRequested: int64(loopIn.TotalDepositAmount()), + CltvExpiry: loopIn.HtlcCltvExpiry, + MaxSwapFee: int64(loopIn.MaxSwapFee), + InitiationHeight: int32(loopIn.InitiationHeight), + ProtocolVersion: int32(loopIn.ProtocolVersion), + Label: loopIn.Label, + } + + htlcKeyArgs := sqlc.InsertHtlcKeysParams{ + SwapHash: loopIn.SwapHash[:], + SenderScriptPubkey: loopIn.ClientPubkey.SerializeCompressed(), + ReceiverScriptPubkey: loopIn.ServerPubkey.SerializeCompressed(), + ClientKeyFamily: int32(loopIn.HtlcKeyLocator.Family), + ClientKeyIndex: int32(loopIn.HtlcKeyLocator.Index), + } + + depositOutpointByteSlice := depositOutpointsToByteSlice( + loopIn.DepositOutpoints, + ) + staticAddressLoopInParams := sqlc.InsertStaticAddressLoopInParams{ + SwapHash: loopIn.SwapHash[:], + SwapInvoice: loopIn.SwapInvoice, + LastHop: loopIn.LastHop, + QuotedSwapFee: int64(loopIn.QuotedSwapFee), + DepositOutpoints: depositOutpointByteSlice, + } + + updateArgs := sqlc.InsertStaticAddressMetaUpdateParams{ + SwapHash: loopIn.SwapHash[:], + UpdateTimestamp: s.clock.Now(), + UpdateState: string(loopIn.GetState()), + } + + return s.baseDB.ExecTx(ctx, loopdb.NewSqlWriteOpts(), + func(q Querier) error { + err := q.InsertSwap(ctx, swapArgs) + if err != nil { + return err + } + + err = q.InsertHtlcKeys(ctx, htlcKeyArgs) + if err != nil { + return err + } + + err = q.InsertStaticAddressLoopIn( + ctx, staticAddressLoopInParams, + ) + if err != nil { + return err + } + + return q.InsertStaticAddressMetaUpdate(ctx, updateArgs) + }) +} + +// UpdateLoopIn updates the loop-in in the database. +func (s *SqlStore) UpdateLoopIn(ctx context.Context, + loopIn *StaticAddressLoopIn) error { + + var htlcTx []byte + if loopIn.HtlcTx != nil { + var buffer bytes.Buffer + err := loopIn.HtlcTx.Serialize( + &buffer, + ) + if err != nil { + return err + } + htlcTx = buffer.Bytes() + } + + var htlcTimeoutSweepTx []byte + if loopIn.HtlcTimeoutSweepTx != nil { + var buffer bytes.Buffer + err := loopIn.HtlcTimeoutSweepTx.Serialize( + &buffer, + ) + if err != nil { + return err + } + htlcTimeoutSweepTx = buffer.Bytes() + } + + var htlcTimeoutSweepAddress sql.NullString + if loopIn.HtlcTimeoutSweepAddress != nil { + htlcTimeoutSweepAddress = sql.NullString{ + String: loopIn.HtlcTimeoutSweepAddress.String(), + Valid: loopIn.HtlcTimeoutSweepAddress.String() != "", + } + } + + updateParams := sqlc.UpdateStaticAddressLoopInParams{ + SwapHash: loopIn.SwapHash[:], + HtlcTx: htlcTx, + HtlcTxFeeRate: int64(loopIn.HtlcTxFeeRate), + HtlcTimeoutSweepTx: htlcTimeoutSweepTx, + HtlcTimeoutSweepAddress: htlcTimeoutSweepAddress, + } + + updateArgs := sqlc.InsertStaticAddressMetaUpdateParams{ + SwapHash: loopIn.SwapHash[:], + UpdateState: string(loopIn.GetState()), + UpdateTimestamp: s.clock.Now(), + } + + return s.baseDB.ExecTx(ctx, loopdb.NewSqlWriteOpts(), + func(q Querier) error { + err := q.UpdateStaticAddressLoopIn(ctx, updateParams) + if err != nil { + return err + } + + return q.InsertStaticAddressMetaUpdate(ctx, updateArgs) + }, + ) + + return nil +} + +// depositOutpointsToByteSlice converts a slice of deposit outpoints to a byte +// slice. +func depositOutpointsToByteSlice(outpoints []string) []byte { + var outpointSlice []byte + for _, o := range outpoints { + outpointSlice = append(outpointSlice, []byte(o)...) + outpointSlice = append(outpointSlice, []byte(OutpointSeparator)...) + } + + return outpointSlice +} + +// toStaticAddressLoopIn converts sql rows to an instant out struct. +func toStaticAddressLoopIn(ctx context.Context, network *chaincfg.Params, + row sqlc.GetStaticAddressLoopInSwapRow, + updates []sqlc.StaticAddressSwapUpdate) (*StaticAddressLoopIn, error) { + + swapHash, err := lntypes.MakeHash(row.SwapHash) + if err != nil { + return nil, err + } + + swapPreImage, err := lntypes.MakePreimage(row.Preimage) + if err != nil { + return nil, err + } + + clientKey, err := btcec.ParsePubKey(row.SenderScriptPubkey) + if err != nil { + return nil, err + } + + serverKey, err := btcec.ParsePubKey(row.ReceiverScriptPubkey) + if err != nil { + return nil, err + } + + var htlcTx *wire.MsgTx + if row.HtlcTx != nil { + htlcTx = &wire.MsgTx{} + err = htlcTx.Deserialize(bytes.NewReader(row.HtlcTx)) + if err != nil { + return nil, err + } + } + + var htlcTimeoutSweepTx *wire.MsgTx + if row.HtlcTimeoutSweepTx != nil { + htlcTimeoutSweepTx = &wire.MsgTx{} + err := htlcTimeoutSweepTx.Deserialize(bytes.NewReader( + row.HtlcTimeoutSweepTx, + )) + if err != nil { + return nil, err + } + } + + depositOutpoints, err := byteSliceToDepositOutpoints( + row.DepositOutpoints, + ) + if err != nil { + return nil, err + } + + timeoutAddressString := row.HtlcTimeoutSweepAddress.String + var timeoutAddress btcutil.Address + if timeoutAddressString != "" { + timeoutAddress, err = btcutil.DecodeAddress( + timeoutAddressString, network, + ) + if err != nil { + return nil, err + } + } + + loopIn := &StaticAddressLoopIn{ + SwapHash: swapHash, + SwapPreimage: swapPreImage, + HtlcCltvExpiry: row.CltvExpiry, + MaxSwapFee: btcutil.Amount(row.MaxSwapFee), + InitiationHeight: uint32(row.InitiationHeight), + ProtocolVersion: version.AddressProtocolVersion(row.ProtocolVersion), + Label: row.Label, + ClientPubkey: clientKey, + ServerPubkey: serverKey, + HtlcKeyLocator: keychain.KeyLocator{ + Family: keychain.KeyFamily(row.ClientKeyFamily), + Index: uint32(row.ClientKeyIndex), + }, + SwapInvoice: row.SwapInvoice, + LastHop: row.LastHop, + QuotedSwapFee: btcutil.Amount(row.QuotedSwapFee), + DepositOutpoints: depositOutpoints, + HtlcTxFeeRate: chainfee.SatPerKWeight(row.HtlcTxFeeRate), + HtlcTimeoutSweepAddress: timeoutAddress, + HtlcTx: htlcTx, + HtlcTimeoutSweepTx: htlcTimeoutSweepTx, + } + + if len(updates) > 0 { + lastUpdate := updates[len(updates)-1] + loopIn.SetState(fsm.StateType(lastUpdate.UpdateState)) + } + + return loopIn, nil +} + +func byteSliceToDepositOutpoints(byteSlice []byte) ([]string, error) { + var outpoints []string + outpointBytes := bytes.Split(byteSlice, []byte(OutpointSeparator)) + for _, o := range outpointBytes { + outpoint := string(o) + if outpoint != "" { + outpoints = append(outpoints, outpoint) + } + } + + return outpoints, nil +} diff --git a/swapserverrpc/server.pb.go b/swapserverrpc/server.pb.go index a30cbe9158..593c027f08 100644 --- a/swapserverrpc/server.pb.go +++ b/swapserverrpc/server.pb.go @@ -3108,6 +3108,420 @@ func (x *ServerWithdrawResponse) GetServerNonces() [][]byte { return nil } +type ServerStaticAddressLoopInRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HtlcClientKey []byte `protobuf:"bytes,1,opt,name=htlc_client_key,json=htlcClientKey,proto3" json:"htlc_client_key,omitempty"` + SwapHash []byte `protobuf:"bytes,2,opt,name=swap_hash,json=swapHash,proto3" json:"swap_hash,omitempty"` + DepositOutpoints []string `protobuf:"bytes,3,rep,name=deposit_outpoints,json=depositOutpoints,proto3" json:"deposit_outpoints,omitempty"` + SwapInvoice string `protobuf:"bytes,4,opt,name=swap_invoice,json=swapInvoice,proto3" json:"swap_invoice,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. + ProtocolVersion StaticAddressProtocolVersion `protobuf:"varint,6,opt,name=protocol_version,json=protocolVersion,proto3,enum=looprpc.StaticAddressProtocolVersion" json:"protocol_version,omitempty"` + // The user agent string that identifies the software running on the user's + // side. This can be changed in the user's client software but it _SHOULD_ + // conform to the following pattern: + // + // Agent-Name/semver-version(/additional-info) + // + // Examples: + // + // loopd/v0.10.0-beta/commit=3b635821 + // litd/v0.2.0-alpha/commit=326d754 + UserAgent string `protobuf:"bytes,7,opt,name=user_agent,json=userAgent,proto3" json:"user_agent,omitempty"` +} + +func (x *ServerStaticAddressLoopInRequest) Reset() { + *x = ServerStaticAddressLoopInRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_server_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServerStaticAddressLoopInRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerStaticAddressLoopInRequest) ProtoMessage() {} + +func (x *ServerStaticAddressLoopInRequest) ProtoReflect() protoreflect.Message { + mi := &file_server_proto_msgTypes[39] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerStaticAddressLoopInRequest.ProtoReflect.Descriptor instead. +func (*ServerStaticAddressLoopInRequest) Descriptor() ([]byte, []int) { + return file_server_proto_rawDescGZIP(), []int{39} +} + +func (x *ServerStaticAddressLoopInRequest) GetHtlcClientKey() []byte { + if x != nil { + return x.HtlcClientKey + } + return nil +} + +func (x *ServerStaticAddressLoopInRequest) GetSwapHash() []byte { + if x != nil { + return x.SwapHash + } + return nil +} + +func (x *ServerStaticAddressLoopInRequest) GetDepositOutpoints() []string { + if x != nil { + return x.DepositOutpoints + } + return nil +} + +func (x *ServerStaticAddressLoopInRequest) GetSwapInvoice() string { + if x != nil { + return x.SwapInvoice + } + return "" +} + +func (x *ServerStaticAddressLoopInRequest) GetLastHop() []byte { + if x != nil { + return x.LastHop + } + return nil +} + +func (x *ServerStaticAddressLoopInRequest) GetProtocolVersion() StaticAddressProtocolVersion { + if x != nil { + return x.ProtocolVersion + } + return StaticAddressProtocolVersion_V0 +} + +func (x *ServerStaticAddressLoopInRequest) GetUserAgent() string { + if x != nil { + return x.UserAgent + } + return "" +} + +type ServerStaticAddressLoopInResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + HtlcServerKey []byte `protobuf:"bytes,1,opt,name=htlc_server_key,json=htlcServerKey,proto3" json:"htlc_server_key,omitempty"` + HtlcExpiry int32 `protobuf:"varint,2,opt,name=htlc_expiry,json=htlcExpiry,proto3" json:"htlc_expiry,omitempty"` + // The nonces that the server used to generate the htlc sigs. + HtlcServerNonces [][]byte `protobuf:"bytes,3,rep,name=htlc_server_nonces,json=htlcServerNonces,proto3" json:"htlc_server_nonces,omitempty"` + // The fee rate in sat/kw that the server wants to use for the htlc tx. + HtlcFeeRate uint64 `protobuf:"varint,4,opt,name=htlc_fee_rate,json=htlcFeeRate,proto3" json:"htlc_fee_rate,omitempty"` +} + +func (x *ServerStaticAddressLoopInResponse) Reset() { + *x = ServerStaticAddressLoopInResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_server_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServerStaticAddressLoopInResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerStaticAddressLoopInResponse) ProtoMessage() {} + +func (x *ServerStaticAddressLoopInResponse) ProtoReflect() protoreflect.Message { + mi := &file_server_proto_msgTypes[40] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerStaticAddressLoopInResponse.ProtoReflect.Descriptor instead. +func (*ServerStaticAddressLoopInResponse) Descriptor() ([]byte, []int) { + return file_server_proto_rawDescGZIP(), []int{40} +} + +func (x *ServerStaticAddressLoopInResponse) GetHtlcServerKey() []byte { + if x != nil { + return x.HtlcServerKey + } + return nil +} + +func (x *ServerStaticAddressLoopInResponse) GetHtlcExpiry() int32 { + if x != nil { + return x.HtlcExpiry + } + return 0 +} + +func (x *ServerStaticAddressLoopInResponse) GetHtlcServerNonces() [][]byte { + if x != nil { + return x.HtlcServerNonces + } + return nil +} + +func (x *ServerStaticAddressLoopInResponse) GetHtlcFeeRate() uint64 { + if x != nil { + return x.HtlcFeeRate + } + return 0 +} + +type PushStaticAddressHtlcSigsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SwapHash []byte `protobuf:"bytes,1,opt,name=swap_hash,json=swapHash,proto3" json:"swap_hash,omitempty"` + // The nonces that the client used to generate the htlc sigs. + HtlcClientNonces [][]byte `protobuf:"bytes,2,rep,name=htlc_client_nonces,json=htlcClientNonces,proto3" json:"htlc_client_nonces,omitempty"` + // The musig2 htlc sigs that the client generated for the htlc. + HtlcClientSigs [][]byte `protobuf:"bytes,3,rep,name=htlc_client_sigs,json=htlcClientSigs,proto3" json:"htlc_client_sigs,omitempty"` +} + +func (x *PushStaticAddressHtlcSigsRequest) Reset() { + *x = PushStaticAddressHtlcSigsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_server_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushStaticAddressHtlcSigsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushStaticAddressHtlcSigsRequest) ProtoMessage() {} + +func (x *PushStaticAddressHtlcSigsRequest) ProtoReflect() protoreflect.Message { + mi := &file_server_proto_msgTypes[41] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushStaticAddressHtlcSigsRequest.ProtoReflect.Descriptor instead. +func (*PushStaticAddressHtlcSigsRequest) Descriptor() ([]byte, []int) { + return file_server_proto_rawDescGZIP(), []int{41} +} + +func (x *PushStaticAddressHtlcSigsRequest) GetSwapHash() []byte { + if x != nil { + return x.SwapHash + } + return nil +} + +func (x *PushStaticAddressHtlcSigsRequest) GetHtlcClientNonces() [][]byte { + if x != nil { + return x.HtlcClientNonces + } + return nil +} + +func (x *PushStaticAddressHtlcSigsRequest) GetHtlcClientSigs() [][]byte { + if x != nil { + return x.HtlcClientSigs + } + return nil +} + +type PushStaticAddressHtlcSigsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The nonces that the client used to generate the htlc sigs. + SweeplessServerNonces [][]byte `protobuf:"bytes,1,rep,name=sweepless_server_nonces,json=sweeplessServerNonces,proto3" json:"sweepless_server_nonces,omitempty"` + // The fee rate in sat/kw that the server wants to use for the htlc tx. + SweeplessFeeRate uint64 `protobuf:"varint,2,opt,name=sweepless_fee_rate,json=sweeplessFeeRate,proto3" json:"sweepless_fee_rate,omitempty"` + // The address that the client wants to sweep the static address deposits + // to. + SweeplessSweepAddr string `protobuf:"bytes,3,opt,name=sweepless_sweep_addr,json=sweeplessSweepAddr,proto3" json:"sweepless_sweep_addr,omitempty"` +} + +func (x *PushStaticAddressHtlcSigsResponse) Reset() { + *x = PushStaticAddressHtlcSigsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_server_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushStaticAddressHtlcSigsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushStaticAddressHtlcSigsResponse) ProtoMessage() {} + +func (x *PushStaticAddressHtlcSigsResponse) ProtoReflect() protoreflect.Message { + mi := &file_server_proto_msgTypes[42] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushStaticAddressHtlcSigsResponse.ProtoReflect.Descriptor instead. +func (*PushStaticAddressHtlcSigsResponse) Descriptor() ([]byte, []int) { + return file_server_proto_rawDescGZIP(), []int{42} +} + +func (x *PushStaticAddressHtlcSigsResponse) GetSweeplessServerNonces() [][]byte { + if x != nil { + return x.SweeplessServerNonces + } + return nil +} + +func (x *PushStaticAddressHtlcSigsResponse) GetSweeplessFeeRate() uint64 { + if x != nil { + return x.SweeplessFeeRate + } + return 0 +} + +func (x *PushStaticAddressHtlcSigsResponse) GetSweeplessSweepAddr() string { + if x != nil { + return x.SweeplessSweepAddr + } + return "" +} + +type PushStaticAddressSweeplessSigsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SwapHash []byte `protobuf:"bytes,1,opt,name=swap_hash,json=swapHash,proto3" json:"swap_hash,omitempty"` + // The nonces that the client used to generate the htlc sigs. + SweeplessClientNonces [][]byte `protobuf:"bytes,2,rep,name=sweepless_client_nonces,json=sweeplessClientNonces,proto3" json:"sweepless_client_nonces,omitempty"` + // The musig2 htlc sigs that the client generated for the htlc. + SweeplessClientSigs [][]byte `protobuf:"bytes,3,rep,name=sweepless_client_sigs,json=sweeplessClientSigs,proto3" json:"sweepless_client_sigs,omitempty"` +} + +func (x *PushStaticAddressSweeplessSigsRequest) Reset() { + *x = PushStaticAddressSweeplessSigsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_server_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushStaticAddressSweeplessSigsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushStaticAddressSweeplessSigsRequest) ProtoMessage() {} + +func (x *PushStaticAddressSweeplessSigsRequest) ProtoReflect() protoreflect.Message { + mi := &file_server_proto_msgTypes[43] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushStaticAddressSweeplessSigsRequest.ProtoReflect.Descriptor instead. +func (*PushStaticAddressSweeplessSigsRequest) Descriptor() ([]byte, []int) { + return file_server_proto_rawDescGZIP(), []int{43} +} + +func (x *PushStaticAddressSweeplessSigsRequest) GetSwapHash() []byte { + if x != nil { + return x.SwapHash + } + return nil +} + +func (x *PushStaticAddressSweeplessSigsRequest) GetSweeplessClientNonces() [][]byte { + if x != nil { + return x.SweeplessClientNonces + } + return nil +} + +func (x *PushStaticAddressSweeplessSigsRequest) GetSweeplessClientSigs() [][]byte { + if x != nil { + return x.SweeplessClientSigs + } + return nil +} + +type PushStaticAddressSweeplessSigsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *PushStaticAddressSweeplessSigsResponse) Reset() { + *x = PushStaticAddressSweeplessSigsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_server_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushStaticAddressSweeplessSigsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushStaticAddressSweeplessSigsResponse) ProtoMessage() {} + +func (x *PushStaticAddressSweeplessSigsResponse) ProtoReflect() protoreflect.Message { + mi := &file_server_proto_msgTypes[44] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushStaticAddressSweeplessSigsResponse.ProtoReflect.Descriptor instead. +func (*PushStaticAddressSweeplessSigsResponse) Descriptor() ([]byte, []int) { + return file_server_proto_rawDescGZIP(), []int{44} +} + var File_server_proto protoreflect.FileDescriptor var file_server_proto_rawDesc = []byte{ @@ -3475,183 +3889,274 @@ var file_server_proto_rawDesc = []byte{ 0x0f, 0x6d, 0x75, 0x73, 0x69, 0x67, 0x32, 0x53, 0x77, 0x65, 0x65, 0x70, 0x53, 0x69, 0x67, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, - 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x2a, 0xef, 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x47, - 0x41, 0x43, 0x59, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x4c, - 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x4e, 0x41, 0x54, - 0x49, 0x56, 0x45, 0x5f, 0x53, 0x45, 0x47, 0x57, 0x49, 0x54, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, - 0x49, 0x4e, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x50, 0x52, 0x45, 0x49, 0x4d, 0x41, 0x47, 0x45, - 0x5f, 0x50, 0x55, 0x53, 0x48, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x03, - 0x12, 0x18, 0x0a, 0x14, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59, 0x5f, - 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x54, - 0x4c, 0x43, 0x5f, 0x56, 0x32, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x55, 0x4c, 0x54, 0x49, - 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, - 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x07, 0x12, - 0x09, 0x0a, 0x05, 0x50, 0x52, 0x4f, 0x42, 0x45, 0x10, 0x08, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x4f, - 0x55, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x50, 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x09, 0x12, 0x0b, - 0x0a, 0x07, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x56, 0x33, 0x10, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x4d, - 0x55, 0x53, 0x49, 0x47, 0x32, 0x10, 0x0b, 0x2a, 0x9e, 0x04, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x53, 0x77, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x53, - 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x45, 0x44, 0x10, - 0x00, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x48, 0x54, 0x4c, 0x43, - 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, - 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x02, - 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, - 0x44, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x53, - 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4e, 0x4f, 0x5f, - 0x48, 0x54, 0x4c, 0x43, 0x10, 0x04, 0x12, 0x25, 0x0a, 0x21, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, - 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, - 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x05, 0x12, 0x23, 0x0a, - 0x1f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4f, - 0x46, 0x46, 0x5f, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, - 0x10, 0x06, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, - 0x4c, 0x45, 0x44, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x07, 0x12, 0x1f, 0x0a, - 0x1b, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x53, - 0x57, 0x41, 0x50, 0x5f, 0x44, 0x45, 0x41, 0x44, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x08, 0x12, 0x22, - 0x0a, 0x1e, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, - 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, - 0x10, 0x09, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x54, 0x49, 0x4d, - 0x45, 0x4f, 0x55, 0x54, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x0a, - 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x45, 0x58, 0x50, - 0x45, 0x43, 0x54, 0x45, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x0b, 0x12, - 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x43, - 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x0c, 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x45, - 0x52, 0x56, 0x45, 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x52, 0x45, 0x50, - 0x41, 0x59, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x0d, 0x12, 0x20, 0x0a, 0x1c, 0x53, - 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x49, 0x4e, 0x56, - 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x0e, 0x12, 0x27, 0x0a, - 0x23, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4d, - 0x55, 0x4c, 0x54, 0x49, 0x50, 0x4c, 0x45, 0x5f, 0x53, 0x57, 0x41, 0x50, 0x5f, 0x53, 0x43, 0x52, - 0x49, 0x50, 0x54, 0x53, 0x10, 0x0f, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, - 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, - 0x5a, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x10, 0x2a, 0x4a, 0x0a, 0x10, 0x52, 0x6f, 0x75, 0x74, - 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, 0x0d, - 0x52, 0x4f, 0x55, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, - 0x10, 0x0a, 0x0c, 0x50, 0x52, 0x45, 0x50, 0x41, 0x59, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, - 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x52, 0x4f, 0x55, - 0x54, 0x45, 0x10, 0x02, 0x2a, 0xf1, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, - 0x17, 0x4c, 0x4e, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, - 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4c, 0x4e, - 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, - 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x4c, 0x4e, - 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, - 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x02, 0x12, 0x1c, 0x0a, 0x18, 0x4c, - 0x4e, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, - 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x30, 0x0a, 0x2c, 0x4c, 0x4e, 0x44, + 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x22, 0xc3, 0x02, 0x0a, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x6f, + 0x70, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x68, 0x74, + 0x6c, 0x63, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x68, 0x74, 0x6c, 0x63, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4b, + 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x77, 0x61, 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, + 0x2b, 0x0a, 0x11, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x64, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x0c, + 0x73, 0x77, 0x61, 0x70, 0x5f, 0x69, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x73, 0x77, 0x61, 0x70, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, + 0x19, 0x0a, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x07, 0x6c, 0x61, 0x73, 0x74, 0x48, 0x6f, 0x70, 0x12, 0x50, 0x0a, 0x10, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x22, 0xbe, 0x01, 0x0a, 0x21, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x68, 0x74, 0x6c, 0x63, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x68, 0x74, 0x6c, + 0x63, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, + 0x68, 0x74, 0x6c, 0x63, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x12, 0x2c, 0x0a, 0x12, 0x68, 0x74, + 0x6c, 0x63, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x10, 0x68, 0x74, 0x6c, 0x63, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x68, 0x74, 0x6c, 0x63, + 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0b, 0x68, 0x74, 0x6c, 0x63, 0x46, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x22, 0x97, 0x01, 0x0a, + 0x20, 0x50, 0x75, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x48, 0x74, 0x6c, 0x63, 0x53, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x77, 0x61, 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2c, + 0x0a, 0x12, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x6f, + 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x10, 0x68, 0x74, 0x6c, 0x63, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, + 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, 0x68, 0x74, 0x6c, 0x63, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x53, 0x69, 0x67, 0x73, 0x22, 0xbb, 0x01, 0x0a, 0x21, 0x50, 0x75, 0x73, 0x68, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x74, 0x6c, 0x63, + 0x53, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x17, + 0x73, 0x77, 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x15, 0x73, + 0x77, 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x6f, + 0x6e, 0x63, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x77, 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, + 0x73, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x10, 0x73, 0x77, 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, 0x73, 0x46, 0x65, 0x65, 0x52, 0x61, + 0x74, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x73, 0x77, 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, 0x73, 0x5f, + 0x73, 0x77, 0x65, 0x65, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x12, 0x73, 0x77, 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, 0x73, 0x53, 0x77, 0x65, 0x65, 0x70, + 0x41, 0x64, 0x64, 0x72, 0x22, 0xb0, 0x01, 0x0a, 0x25, 0x50, 0x75, 0x73, 0x68, 0x53, 0x74, 0x61, + 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x77, 0x65, 0x65, 0x70, 0x6c, + 0x65, 0x73, 0x73, 0x53, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, + 0x0a, 0x09, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x08, 0x73, 0x77, 0x61, 0x70, 0x48, 0x61, 0x73, 0x68, 0x12, 0x36, 0x0a, 0x17, 0x73, + 0x77, 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, 0x73, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, + 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x15, 0x73, 0x77, + 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, 0x73, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x6f, 0x6e, + 0x63, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x73, 0x77, 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, 0x73, + 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0c, 0x52, 0x13, 0x73, 0x77, 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, 0x73, 0x43, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x73, 0x22, 0x28, 0x0a, 0x26, 0x50, 0x75, 0x73, 0x68, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x77, 0x65, 0x65, + 0x70, 0x6c, 0x65, 0x73, 0x73, 0x53, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x2a, 0xef, 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x45, 0x47, 0x41, 0x43, 0x59, 0x10, + 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, + 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x4e, 0x41, 0x54, 0x49, 0x56, 0x45, 0x5f, + 0x53, 0x45, 0x47, 0x57, 0x49, 0x54, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x02, + 0x12, 0x1a, 0x0a, 0x16, 0x50, 0x52, 0x45, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x5f, 0x50, 0x55, 0x53, + 0x48, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, + 0x55, 0x53, 0x45, 0x52, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x59, 0x5f, 0x4c, 0x4f, 0x4f, 0x50, + 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x04, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x56, + 0x32, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x4c, 0x4f, 0x4f, + 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x4c, 0x4f, 0x4f, 0x50, 0x5f, 0x4f, + 0x55, 0x54, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x07, 0x12, 0x09, 0x0a, 0x05, 0x50, + 0x52, 0x4f, 0x42, 0x45, 0x10, 0x08, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x4f, 0x55, 0x54, 0x49, 0x4e, + 0x47, 0x5f, 0x50, 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x09, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x54, + 0x4c, 0x43, 0x5f, 0x56, 0x33, 0x10, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x55, 0x53, 0x49, 0x47, + 0x32, 0x10, 0x0b, 0x2a, 0x9e, 0x04, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x77, + 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x45, 0x52, 0x56, 0x45, + 0x52, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, + 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x50, 0x55, 0x42, + 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x45, 0x52, 0x56, + 0x45, 0x52, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, + 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, + 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4e, 0x4f, 0x5f, 0x48, 0x54, 0x4c, 0x43, + 0x10, 0x04, 0x12, 0x25, 0x0a, 0x21, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, + 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x48, 0x54, 0x4c, 0x43, + 0x5f, 0x41, 0x4d, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x05, 0x12, 0x23, 0x0a, 0x1f, 0x53, 0x45, 0x52, + 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4f, 0x46, 0x46, 0x5f, 0x43, + 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x06, 0x12, 0x19, + 0x0a, 0x15, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, + 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x07, 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x45, 0x52, + 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x53, 0x57, 0x41, 0x50, 0x5f, + 0x44, 0x45, 0x41, 0x44, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x08, 0x12, 0x22, 0x0a, 0x1e, 0x53, 0x45, + 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x48, 0x54, 0x4c, 0x43, + 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x09, 0x12, 0x1c, + 0x0a, 0x18, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, + 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x0a, 0x12, 0x1d, 0x0a, 0x19, + 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, + 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x53, + 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x48, 0x54, 0x4c, 0x43, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, + 0x52, 0x4d, 0x45, 0x44, 0x10, 0x0c, 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, + 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x52, 0x45, 0x50, 0x41, 0x59, 0x5f, 0x43, + 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x0d, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x45, 0x52, 0x56, 0x45, + 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, + 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x0e, 0x12, 0x27, 0x0a, 0x23, 0x53, 0x45, 0x52, + 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4d, 0x55, 0x4c, 0x54, 0x49, + 0x50, 0x4c, 0x45, 0x5f, 0x53, 0x57, 0x41, 0x50, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x53, + 0x10, 0x0f, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x46, 0x41, 0x49, + 0x4c, 0x45, 0x44, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, 0x5a, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x10, 0x10, 0x2a, 0x4a, 0x0a, 0x10, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x50, 0x61, 0x79, + 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x4f, 0x55, 0x54, + 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x50, + 0x52, 0x45, 0x50, 0x41, 0x59, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x01, 0x12, 0x11, 0x0a, + 0x0d, 0x49, 0x4e, 0x56, 0x4f, 0x49, 0x43, 0x45, 0x5f, 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x02, + 0x2a, 0xf1, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, 0x6c, + 0x75, 0x72, 0x65, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x17, 0x4c, 0x4e, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, - 0x49, 0x4e, 0x43, 0x4f, 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, - 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, 0x10, 0x04, 0x12, 0x2b, 0x0a, 0x27, 0x4c, - 0x4e, 0x44, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, - 0x4e, 0x5f, 0x49, 0x4e, 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x42, - 0x41, 0x4c, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x05, 0x2a, 0x27, 0x0a, 0x0d, 0x52, 0x6f, 0x75, 0x74, - 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, - 0x45, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x4c, 0x4f, 0x57, 0x5f, 0x48, 0x49, 0x47, 0x48, 0x10, - 0x01, 0x2a, 0x26, 0x0a, 0x1c, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x06, 0x0a, 0x02, 0x56, 0x30, 0x10, 0x00, 0x32, 0xdc, 0x0a, 0x0a, 0x0a, 0x53, 0x77, - 0x61, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, - 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4c, 0x4e, 0x44, 0x5f, 0x46, 0x41, + 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, + 0x45, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x4c, 0x4e, 0x44, 0x5f, 0x46, 0x41, + 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x4e, 0x4f, 0x5f, + 0x52, 0x4f, 0x55, 0x54, 0x45, 0x10, 0x02, 0x12, 0x1c, 0x0a, 0x18, 0x4c, 0x4e, 0x44, 0x5f, 0x46, + 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x45, 0x52, + 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x30, 0x0a, 0x2c, 0x4c, 0x4e, 0x44, 0x5f, 0x46, 0x41, 0x49, + 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x43, 0x4f, + 0x52, 0x52, 0x45, 0x43, 0x54, 0x5f, 0x50, 0x41, 0x59, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x45, + 0x54, 0x41, 0x49, 0x4c, 0x53, 0x10, 0x04, 0x12, 0x2b, 0x0a, 0x27, 0x4c, 0x4e, 0x44, 0x5f, 0x46, + 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, + 0x53, 0x55, 0x46, 0x46, 0x49, 0x43, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x42, 0x41, 0x4c, 0x41, 0x4e, + 0x43, 0x45, 0x10, 0x05, 0x2a, 0x27, 0x0a, 0x0d, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, + 0x0c, 0x0a, 0x08, 0x4c, 0x4f, 0x57, 0x5f, 0x48, 0x49, 0x47, 0x48, 0x10, 0x01, 0x2a, 0x26, 0x0a, + 0x1c, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x06, 0x0a, + 0x02, 0x56, 0x30, 0x10, 0x00, 0x32, 0xdc, 0x0a, 0x0a, 0x0a, 0x53, 0x77, 0x61, 0x70, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, + 0x65, 0x72, 0x6d, 0x73, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, - 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, - 0x70, 0x4f, 0x75, 0x74, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x4f, 0x0a, 0x0e, 0x4e, 0x65, 0x77, - 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x12, 0x1d, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, - 0x4f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, - 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x4c, 0x6f, + 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x4f, 0x0a, 0x0e, 0x4e, 0x65, 0x77, 0x4c, 0x6f, 0x6f, 0x70, + 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x12, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, + 0x74, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x29, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, - 0x65, 0x12, 0x29, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x65, - 0x69, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, - 0x70, 0x4f, 0x75, 0x74, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, - 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, - 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, - 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, - 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, - 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6f, - 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, - 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x4c, 0x0a, 0x0d, 0x4e, 0x65, 0x77, 0x4c, 0x6f, - 0x6f, 0x70, 0x49, 0x6e, 0x53, 0x77, 0x61, 0x70, 0x12, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, - 0x75, 0x6f, 0x74, 0x65, 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, - 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x17, 0x53, + 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x65, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x0c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, + 0x75, 0x6f, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x51, 0x75, 0x6f, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, + 0x51, 0x75, 0x6f, 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, + 0x65, 0x72, 0x6d, 0x73, 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, 0x72, 0x6d, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x54, 0x65, + 0x72, 0x6d, 0x73, 0x12, 0x4c, 0x0a, 0x0d, 0x4e, 0x65, 0x77, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, + 0x53, 0x77, 0x61, 0x70, 0x12, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, + 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x17, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, 0x70, - 0x4f, 0x75, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x30, 0x01, 0x12, 0x65, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x20, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x27, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x11, 0x43, - 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, - 0x12, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x62, 0x65, - 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, - 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x72, - 0x6f, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x16, 0x52, - 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, - 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, + 0x12, 0x65, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x4c, 0x6f, 0x6f, + 0x70, 0x49, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x11, 0x43, 0x61, 0x6e, 0x63, 0x65, + 0x6c, 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x12, 0x21, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4c, 0x6f, 0x6f, + 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x4c, 0x6f, 0x6f, 0x70, 0x4f, 0x75, 0x74, 0x53, 0x77, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x12, 0x1b, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, + 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x16, 0x52, 0x65, 0x63, 0x6f, 0x6d, + 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, + 0x6e, 0x12, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x63, 0x6f, + 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, + 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, - 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x22, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x52, 0x6f, 0x75, - 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x57, 0x0a, - 0x13, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x0f, 0x4d, 0x75, 0x53, 0x69, 0x67, 0x32, - 0x53, 0x69, 0x67, 0x6e, 0x53, 0x77, 0x65, 0x65, 0x70, 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x75, 0x53, 0x69, 0x67, 0x32, 0x53, 0x69, 0x67, 0x6e, 0x53, 0x77, - 0x65, 0x65, 0x70, 0x52, 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, - 0x2e, 0x4d, 0x75, 0x53, 0x69, 0x67, 0x32, 0x53, 0x69, 0x67, 0x6e, 0x53, 0x77, 0x65, 0x65, 0x70, - 0x52, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x07, 0x50, 0x75, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x19, - 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, - 0x75, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x73, 0x68, 0x4b, 0x65, - 0x79, 0x52, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x09, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x34, 0x30, - 0x32, 0x12, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x74, 0x63, - 0x68, 0x4c, 0x34, 0x30, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, - 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x34, 0x30, 0x32, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc9, 0x01, 0x0a, 0x13, 0x53, 0x74, 0x61, - 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x12, 0x57, 0x0a, 0x10, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x16, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x44, 0x65, 0x70, 0x6f, 0x73, - 0x69, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, - 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x73, 0x77, 0x61, 0x70, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x57, 0x0a, 0x13, 0x52, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x12, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, + 0x71, 0x1a, 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, + 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x0f, 0x4d, 0x75, 0x53, 0x69, 0x67, 0x32, 0x53, 0x69, 0x67, 0x6e, + 0x53, 0x77, 0x65, 0x65, 0x70, 0x12, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x4d, 0x75, 0x53, 0x69, 0x67, 0x32, 0x53, 0x69, 0x67, 0x6e, 0x53, 0x77, 0x65, 0x65, 0x70, 0x52, + 0x65, 0x71, 0x1a, 0x1b, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x75, 0x53, + 0x69, 0x67, 0x32, 0x53, 0x69, 0x67, 0x6e, 0x53, 0x77, 0x65, 0x65, 0x70, 0x52, 0x65, 0x73, 0x12, + 0x3f, 0x0a, 0x07, 0x50, 0x75, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x73, 0x68, 0x4b, + 0x65, 0x79, 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x75, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, + 0x12, 0x42, 0x0a, 0x09, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x34, 0x30, 0x32, 0x12, 0x19, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x34, 0x30, + 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x4c, 0x34, 0x30, 0x32, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xb5, 0x04, 0x0a, 0x13, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x57, 0x0a, 0x10, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x20, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x16, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x57, + 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x44, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x73, 0x12, + 0x1e, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1f, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x72, 0x0a, 0x19, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x12, 0x29, 0x2e, + 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, + 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x6f, 0x70, 0x49, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x6f, 0x70, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x19, 0x50, 0x75, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, + 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x74, 0x6c, 0x63, 0x53, 0x69, 0x67, + 0x73, 0x12, 0x29, 0x2e, 0x6c, 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, 0x73, 0x68, + 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x74, 0x6c, + 0x63, 0x53, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x6c, + 0x6f, 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x69, + 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x74, 0x6c, 0x63, 0x53, 0x69, 0x67, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x1e, 0x50, 0x75, 0x73, + 0x68, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x77, + 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, 0x73, 0x53, 0x69, 0x67, 0x73, 0x12, 0x2e, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x77, 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, 0x73, + 0x53, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x6c, 0x6f, + 0x6f, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x77, 0x65, 0x65, 0x70, 0x6c, 0x65, 0x73, 0x73, + 0x53, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2d, 0x5a, 0x2b, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, + 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x73, 0x77, + 0x61, 0x70, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -3667,61 +4172,67 @@ func file_server_proto_rawDescGZIP() []byte { } var file_server_proto_enumTypes = make([]protoimpl.EnumInfo, 6) -var file_server_proto_msgTypes = make([]protoimpl.MessageInfo, 39) +var file_server_proto_msgTypes = make([]protoimpl.MessageInfo, 45) var file_server_proto_goTypes = []interface{}{ - (ProtocolVersion)(0), // 0: looprpc.ProtocolVersion - (ServerSwapState)(0), // 1: looprpc.ServerSwapState - (RoutePaymentType)(0), // 2: looprpc.RoutePaymentType - (PaymentFailureReason)(0), // 3: looprpc.PaymentFailureReason - (RoutingPlugin)(0), // 4: looprpc.RoutingPlugin - (StaticAddressProtocolVersion)(0), // 5: looprpc.StaticAddressProtocolVersion - (*ServerLoopOutRequest)(nil), // 6: looprpc.ServerLoopOutRequest - (*ServerLoopOutResponse)(nil), // 7: looprpc.ServerLoopOutResponse - (*ServerLoopOutQuoteRequest)(nil), // 8: looprpc.ServerLoopOutQuoteRequest - (*ServerLoopOutQuote)(nil), // 9: looprpc.ServerLoopOutQuote - (*ServerLoopOutTermsRequest)(nil), // 10: looprpc.ServerLoopOutTermsRequest - (*ServerLoopOutTerms)(nil), // 11: looprpc.ServerLoopOutTerms - (*ServerLoopInRequest)(nil), // 12: looprpc.ServerLoopInRequest - (*ServerLoopInResponse)(nil), // 13: looprpc.ServerLoopInResponse - (*ServerLoopInQuoteRequest)(nil), // 14: looprpc.ServerLoopInQuoteRequest - (*ServerLoopInQuoteResponse)(nil), // 15: looprpc.ServerLoopInQuoteResponse - (*ServerLoopInTermsRequest)(nil), // 16: looprpc.ServerLoopInTermsRequest - (*ServerLoopInTerms)(nil), // 17: looprpc.ServerLoopInTerms - (*ServerLoopOutPushPreimageRequest)(nil), // 18: looprpc.ServerLoopOutPushPreimageRequest - (*ServerLoopOutPushPreimageResponse)(nil), // 19: looprpc.ServerLoopOutPushPreimageResponse - (*SubscribeUpdatesRequest)(nil), // 20: looprpc.SubscribeUpdatesRequest - (*SubscribeLoopOutUpdatesResponse)(nil), // 21: looprpc.SubscribeLoopOutUpdatesResponse - (*SubscribeLoopInUpdatesResponse)(nil), // 22: looprpc.SubscribeLoopInUpdatesResponse - (*RouteCancel)(nil), // 23: looprpc.RouteCancel - (*HtlcAttempt)(nil), // 24: looprpc.HtlcAttempt - (*CancelLoopOutSwapRequest)(nil), // 25: looprpc.CancelLoopOutSwapRequest - (*CancelLoopOutSwapResponse)(nil), // 26: looprpc.CancelLoopOutSwapResponse - (*ServerProbeRequest)(nil), // 27: looprpc.ServerProbeRequest - (*ServerProbeResponse)(nil), // 28: looprpc.ServerProbeResponse - (*RecommendRoutingPluginReq)(nil), // 29: looprpc.RecommendRoutingPluginReq - (*RecommendRoutingPluginRes)(nil), // 30: looprpc.RecommendRoutingPluginRes - (*ReportRoutingResultReq)(nil), // 31: looprpc.ReportRoutingResultReq - (*ReportRoutingResultRes)(nil), // 32: looprpc.ReportRoutingResultRes - (*MuSig2SignSweepReq)(nil), // 33: looprpc.MuSig2SignSweepReq - (*PrevoutInfo)(nil), // 34: looprpc.PrevoutInfo - (*MuSig2SignSweepRes)(nil), // 35: looprpc.MuSig2SignSweepRes - (*ServerPushKeyReq)(nil), // 36: looprpc.ServerPushKeyReq - (*ServerPushKeyRes)(nil), // 37: looprpc.ServerPushKeyRes - (*FetchL402Request)(nil), // 38: looprpc.FetchL402Request - (*FetchL402Response)(nil), // 39: looprpc.FetchL402Response - (*ServerNewAddressRequest)(nil), // 40: looprpc.ServerNewAddressRequest - (*ServerNewAddressResponse)(nil), // 41: looprpc.ServerNewAddressResponse - (*ServerAddressParameters)(nil), // 42: looprpc.ServerAddressParameters - (*ServerWithdrawRequest)(nil), // 43: looprpc.ServerWithdrawRequest - (*ServerWithdrawResponse)(nil), // 44: looprpc.ServerWithdrawResponse - (*RouteHint)(nil), // 45: looprpc.RouteHint + (ProtocolVersion)(0), // 0: looprpc.ProtocolVersion + (ServerSwapState)(0), // 1: looprpc.ServerSwapState + (RoutePaymentType)(0), // 2: looprpc.RoutePaymentType + (PaymentFailureReason)(0), // 3: looprpc.PaymentFailureReason + (RoutingPlugin)(0), // 4: looprpc.RoutingPlugin + (StaticAddressProtocolVersion)(0), // 5: looprpc.StaticAddressProtocolVersion + (*ServerLoopOutRequest)(nil), // 6: looprpc.ServerLoopOutRequest + (*ServerLoopOutResponse)(nil), // 7: looprpc.ServerLoopOutResponse + (*ServerLoopOutQuoteRequest)(nil), // 8: looprpc.ServerLoopOutQuoteRequest + (*ServerLoopOutQuote)(nil), // 9: looprpc.ServerLoopOutQuote + (*ServerLoopOutTermsRequest)(nil), // 10: looprpc.ServerLoopOutTermsRequest + (*ServerLoopOutTerms)(nil), // 11: looprpc.ServerLoopOutTerms + (*ServerLoopInRequest)(nil), // 12: looprpc.ServerLoopInRequest + (*ServerLoopInResponse)(nil), // 13: looprpc.ServerLoopInResponse + (*ServerLoopInQuoteRequest)(nil), // 14: looprpc.ServerLoopInQuoteRequest + (*ServerLoopInQuoteResponse)(nil), // 15: looprpc.ServerLoopInQuoteResponse + (*ServerLoopInTermsRequest)(nil), // 16: looprpc.ServerLoopInTermsRequest + (*ServerLoopInTerms)(nil), // 17: looprpc.ServerLoopInTerms + (*ServerLoopOutPushPreimageRequest)(nil), // 18: looprpc.ServerLoopOutPushPreimageRequest + (*ServerLoopOutPushPreimageResponse)(nil), // 19: looprpc.ServerLoopOutPushPreimageResponse + (*SubscribeUpdatesRequest)(nil), // 20: looprpc.SubscribeUpdatesRequest + (*SubscribeLoopOutUpdatesResponse)(nil), // 21: looprpc.SubscribeLoopOutUpdatesResponse + (*SubscribeLoopInUpdatesResponse)(nil), // 22: looprpc.SubscribeLoopInUpdatesResponse + (*RouteCancel)(nil), // 23: looprpc.RouteCancel + (*HtlcAttempt)(nil), // 24: looprpc.HtlcAttempt + (*CancelLoopOutSwapRequest)(nil), // 25: looprpc.CancelLoopOutSwapRequest + (*CancelLoopOutSwapResponse)(nil), // 26: looprpc.CancelLoopOutSwapResponse + (*ServerProbeRequest)(nil), // 27: looprpc.ServerProbeRequest + (*ServerProbeResponse)(nil), // 28: looprpc.ServerProbeResponse + (*RecommendRoutingPluginReq)(nil), // 29: looprpc.RecommendRoutingPluginReq + (*RecommendRoutingPluginRes)(nil), // 30: looprpc.RecommendRoutingPluginRes + (*ReportRoutingResultReq)(nil), // 31: looprpc.ReportRoutingResultReq + (*ReportRoutingResultRes)(nil), // 32: looprpc.ReportRoutingResultRes + (*MuSig2SignSweepReq)(nil), // 33: looprpc.MuSig2SignSweepReq + (*PrevoutInfo)(nil), // 34: looprpc.PrevoutInfo + (*MuSig2SignSweepRes)(nil), // 35: looprpc.MuSig2SignSweepRes + (*ServerPushKeyReq)(nil), // 36: looprpc.ServerPushKeyReq + (*ServerPushKeyRes)(nil), // 37: looprpc.ServerPushKeyRes + (*FetchL402Request)(nil), // 38: looprpc.FetchL402Request + (*FetchL402Response)(nil), // 39: looprpc.FetchL402Response + (*ServerNewAddressRequest)(nil), // 40: looprpc.ServerNewAddressRequest + (*ServerNewAddressResponse)(nil), // 41: looprpc.ServerNewAddressResponse + (*ServerAddressParameters)(nil), // 42: looprpc.ServerAddressParameters + (*ServerWithdrawRequest)(nil), // 43: looprpc.ServerWithdrawRequest + (*ServerWithdrawResponse)(nil), // 44: looprpc.ServerWithdrawResponse + (*ServerStaticAddressLoopInRequest)(nil), // 45: looprpc.ServerStaticAddressLoopInRequest + (*ServerStaticAddressLoopInResponse)(nil), // 46: looprpc.ServerStaticAddressLoopInResponse + (*PushStaticAddressHtlcSigsRequest)(nil), // 47: looprpc.PushStaticAddressHtlcSigsRequest + (*PushStaticAddressHtlcSigsResponse)(nil), // 48: looprpc.PushStaticAddressHtlcSigsResponse + (*PushStaticAddressSweeplessSigsRequest)(nil), // 49: looprpc.PushStaticAddressSweeplessSigsRequest + (*PushStaticAddressSweeplessSigsResponse)(nil), // 50: looprpc.PushStaticAddressSweeplessSigsResponse + (*RouteHint)(nil), // 51: looprpc.RouteHint } var file_server_proto_depIdxs = []int32{ 0, // 0: looprpc.ServerLoopOutRequest.protocol_version:type_name -> looprpc.ProtocolVersion 0, // 1: looprpc.ServerLoopOutQuoteRequest.protocol_version:type_name -> looprpc.ProtocolVersion 0, // 2: looprpc.ServerLoopOutTermsRequest.protocol_version:type_name -> looprpc.ProtocolVersion 0, // 3: looprpc.ServerLoopInRequest.protocol_version:type_name -> looprpc.ProtocolVersion - 45, // 4: looprpc.ServerLoopInQuoteRequest.route_hints:type_name -> looprpc.RouteHint + 51, // 4: looprpc.ServerLoopInQuoteRequest.route_hints:type_name -> looprpc.RouteHint 0, // 5: looprpc.ServerLoopInQuoteRequest.protocol_version:type_name -> looprpc.ProtocolVersion 0, // 6: looprpc.ServerLoopInTermsRequest.protocol_version:type_name -> looprpc.ProtocolVersion 0, // 7: looprpc.ServerLoopOutPushPreimageRequest.protocol_version:type_name -> looprpc.ProtocolVersion @@ -3734,7 +4245,7 @@ var file_server_proto_depIdxs = []int32{ 0, // 14: looprpc.CancelLoopOutSwapRequest.protocol_version:type_name -> looprpc.ProtocolVersion 23, // 15: looprpc.CancelLoopOutSwapRequest.route_cancel:type_name -> looprpc.RouteCancel 0, // 16: looprpc.ServerProbeRequest.protocol_version:type_name -> looprpc.ProtocolVersion - 45, // 17: looprpc.ServerProbeRequest.route_hints:type_name -> looprpc.RouteHint + 51, // 17: looprpc.ServerProbeRequest.route_hints:type_name -> looprpc.RouteHint 0, // 18: looprpc.RecommendRoutingPluginReq.protocol_version:type_name -> looprpc.ProtocolVersion 4, // 19: looprpc.RecommendRoutingPluginRes.plugin:type_name -> looprpc.RoutingPlugin 0, // 20: looprpc.ReportRoutingResultReq.protocol_version:type_name -> looprpc.ProtocolVersion @@ -3745,47 +4256,54 @@ var file_server_proto_depIdxs = []int32{ 5, // 25: looprpc.ServerNewAddressRequest.protocol_version:type_name -> looprpc.StaticAddressProtocolVersion 42, // 26: looprpc.ServerNewAddressResponse.params:type_name -> looprpc.ServerAddressParameters 34, // 27: looprpc.ServerWithdrawRequest.outpoints:type_name -> looprpc.PrevoutInfo - 10, // 28: looprpc.SwapServer.LoopOutTerms:input_type -> looprpc.ServerLoopOutTermsRequest - 6, // 29: looprpc.SwapServer.NewLoopOutSwap:input_type -> looprpc.ServerLoopOutRequest - 18, // 30: looprpc.SwapServer.LoopOutPushPreimage:input_type -> looprpc.ServerLoopOutPushPreimageRequest - 8, // 31: looprpc.SwapServer.LoopOutQuote:input_type -> looprpc.ServerLoopOutQuoteRequest - 16, // 32: looprpc.SwapServer.LoopInTerms:input_type -> looprpc.ServerLoopInTermsRequest - 12, // 33: looprpc.SwapServer.NewLoopInSwap:input_type -> looprpc.ServerLoopInRequest - 14, // 34: looprpc.SwapServer.LoopInQuote:input_type -> looprpc.ServerLoopInQuoteRequest - 20, // 35: looprpc.SwapServer.SubscribeLoopOutUpdates:input_type -> looprpc.SubscribeUpdatesRequest - 20, // 36: looprpc.SwapServer.SubscribeLoopInUpdates:input_type -> looprpc.SubscribeUpdatesRequest - 25, // 37: looprpc.SwapServer.CancelLoopOutSwap:input_type -> looprpc.CancelLoopOutSwapRequest - 27, // 38: looprpc.SwapServer.Probe:input_type -> looprpc.ServerProbeRequest - 29, // 39: looprpc.SwapServer.RecommendRoutingPlugin:input_type -> looprpc.RecommendRoutingPluginReq - 31, // 40: looprpc.SwapServer.ReportRoutingResult:input_type -> looprpc.ReportRoutingResultReq - 33, // 41: looprpc.SwapServer.MuSig2SignSweep:input_type -> looprpc.MuSig2SignSweepReq - 36, // 42: looprpc.SwapServer.PushKey:input_type -> looprpc.ServerPushKeyReq - 38, // 43: looprpc.SwapServer.FetchL402:input_type -> looprpc.FetchL402Request - 40, // 44: looprpc.StaticAddressServer.ServerNewAddress:input_type -> looprpc.ServerNewAddressRequest - 43, // 45: looprpc.StaticAddressServer.ServerWithdrawDeposits:input_type -> looprpc.ServerWithdrawRequest - 11, // 46: looprpc.SwapServer.LoopOutTerms:output_type -> looprpc.ServerLoopOutTerms - 7, // 47: looprpc.SwapServer.NewLoopOutSwap:output_type -> looprpc.ServerLoopOutResponse - 19, // 48: looprpc.SwapServer.LoopOutPushPreimage:output_type -> looprpc.ServerLoopOutPushPreimageResponse - 9, // 49: looprpc.SwapServer.LoopOutQuote:output_type -> looprpc.ServerLoopOutQuote - 17, // 50: looprpc.SwapServer.LoopInTerms:output_type -> looprpc.ServerLoopInTerms - 13, // 51: looprpc.SwapServer.NewLoopInSwap:output_type -> looprpc.ServerLoopInResponse - 15, // 52: looprpc.SwapServer.LoopInQuote:output_type -> looprpc.ServerLoopInQuoteResponse - 21, // 53: looprpc.SwapServer.SubscribeLoopOutUpdates:output_type -> looprpc.SubscribeLoopOutUpdatesResponse - 22, // 54: looprpc.SwapServer.SubscribeLoopInUpdates:output_type -> looprpc.SubscribeLoopInUpdatesResponse - 26, // 55: looprpc.SwapServer.CancelLoopOutSwap:output_type -> looprpc.CancelLoopOutSwapResponse - 28, // 56: looprpc.SwapServer.Probe:output_type -> looprpc.ServerProbeResponse - 30, // 57: looprpc.SwapServer.RecommendRoutingPlugin:output_type -> looprpc.RecommendRoutingPluginRes - 32, // 58: looprpc.SwapServer.ReportRoutingResult:output_type -> looprpc.ReportRoutingResultRes - 35, // 59: looprpc.SwapServer.MuSig2SignSweep:output_type -> looprpc.MuSig2SignSweepRes - 37, // 60: looprpc.SwapServer.PushKey:output_type -> looprpc.ServerPushKeyRes - 39, // 61: looprpc.SwapServer.FetchL402:output_type -> looprpc.FetchL402Response - 41, // 62: looprpc.StaticAddressServer.ServerNewAddress:output_type -> looprpc.ServerNewAddressResponse - 44, // 63: looprpc.StaticAddressServer.ServerWithdrawDeposits:output_type -> looprpc.ServerWithdrawResponse - 46, // [46:64] is the sub-list for method output_type - 28, // [28:46] is the sub-list for method input_type - 28, // [28:28] is the sub-list for extension type_name - 28, // [28:28] is the sub-list for extension extendee - 0, // [0:28] is the sub-list for field type_name + 5, // 28: looprpc.ServerStaticAddressLoopInRequest.protocol_version:type_name -> looprpc.StaticAddressProtocolVersion + 10, // 29: looprpc.SwapServer.LoopOutTerms:input_type -> looprpc.ServerLoopOutTermsRequest + 6, // 30: looprpc.SwapServer.NewLoopOutSwap:input_type -> looprpc.ServerLoopOutRequest + 18, // 31: looprpc.SwapServer.LoopOutPushPreimage:input_type -> looprpc.ServerLoopOutPushPreimageRequest + 8, // 32: looprpc.SwapServer.LoopOutQuote:input_type -> looprpc.ServerLoopOutQuoteRequest + 16, // 33: looprpc.SwapServer.LoopInTerms:input_type -> looprpc.ServerLoopInTermsRequest + 12, // 34: looprpc.SwapServer.NewLoopInSwap:input_type -> looprpc.ServerLoopInRequest + 14, // 35: looprpc.SwapServer.LoopInQuote:input_type -> looprpc.ServerLoopInQuoteRequest + 20, // 36: looprpc.SwapServer.SubscribeLoopOutUpdates:input_type -> looprpc.SubscribeUpdatesRequest + 20, // 37: looprpc.SwapServer.SubscribeLoopInUpdates:input_type -> looprpc.SubscribeUpdatesRequest + 25, // 38: looprpc.SwapServer.CancelLoopOutSwap:input_type -> looprpc.CancelLoopOutSwapRequest + 27, // 39: looprpc.SwapServer.Probe:input_type -> looprpc.ServerProbeRequest + 29, // 40: looprpc.SwapServer.RecommendRoutingPlugin:input_type -> looprpc.RecommendRoutingPluginReq + 31, // 41: looprpc.SwapServer.ReportRoutingResult:input_type -> looprpc.ReportRoutingResultReq + 33, // 42: looprpc.SwapServer.MuSig2SignSweep:input_type -> looprpc.MuSig2SignSweepReq + 36, // 43: looprpc.SwapServer.PushKey:input_type -> looprpc.ServerPushKeyReq + 38, // 44: looprpc.SwapServer.FetchL402:input_type -> looprpc.FetchL402Request + 40, // 45: looprpc.StaticAddressServer.ServerNewAddress:input_type -> looprpc.ServerNewAddressRequest + 43, // 46: looprpc.StaticAddressServer.ServerWithdrawDeposits:input_type -> looprpc.ServerWithdrawRequest + 45, // 47: looprpc.StaticAddressServer.ServerStaticAddressLoopIn:input_type -> looprpc.ServerStaticAddressLoopInRequest + 47, // 48: looprpc.StaticAddressServer.PushStaticAddressHtlcSigs:input_type -> looprpc.PushStaticAddressHtlcSigsRequest + 49, // 49: looprpc.StaticAddressServer.PushStaticAddressSweeplessSigs:input_type -> looprpc.PushStaticAddressSweeplessSigsRequest + 11, // 50: looprpc.SwapServer.LoopOutTerms:output_type -> looprpc.ServerLoopOutTerms + 7, // 51: looprpc.SwapServer.NewLoopOutSwap:output_type -> looprpc.ServerLoopOutResponse + 19, // 52: looprpc.SwapServer.LoopOutPushPreimage:output_type -> looprpc.ServerLoopOutPushPreimageResponse + 9, // 53: looprpc.SwapServer.LoopOutQuote:output_type -> looprpc.ServerLoopOutQuote + 17, // 54: looprpc.SwapServer.LoopInTerms:output_type -> looprpc.ServerLoopInTerms + 13, // 55: looprpc.SwapServer.NewLoopInSwap:output_type -> looprpc.ServerLoopInResponse + 15, // 56: looprpc.SwapServer.LoopInQuote:output_type -> looprpc.ServerLoopInQuoteResponse + 21, // 57: looprpc.SwapServer.SubscribeLoopOutUpdates:output_type -> looprpc.SubscribeLoopOutUpdatesResponse + 22, // 58: looprpc.SwapServer.SubscribeLoopInUpdates:output_type -> looprpc.SubscribeLoopInUpdatesResponse + 26, // 59: looprpc.SwapServer.CancelLoopOutSwap:output_type -> looprpc.CancelLoopOutSwapResponse + 28, // 60: looprpc.SwapServer.Probe:output_type -> looprpc.ServerProbeResponse + 30, // 61: looprpc.SwapServer.RecommendRoutingPlugin:output_type -> looprpc.RecommendRoutingPluginRes + 32, // 62: looprpc.SwapServer.ReportRoutingResult:output_type -> looprpc.ReportRoutingResultRes + 35, // 63: looprpc.SwapServer.MuSig2SignSweep:output_type -> looprpc.MuSig2SignSweepRes + 37, // 64: looprpc.SwapServer.PushKey:output_type -> looprpc.ServerPushKeyRes + 39, // 65: looprpc.SwapServer.FetchL402:output_type -> looprpc.FetchL402Response + 41, // 66: looprpc.StaticAddressServer.ServerNewAddress:output_type -> looprpc.ServerNewAddressResponse + 44, // 67: looprpc.StaticAddressServer.ServerWithdrawDeposits:output_type -> looprpc.ServerWithdrawResponse + 46, // 68: looprpc.StaticAddressServer.ServerStaticAddressLoopIn:output_type -> looprpc.ServerStaticAddressLoopInResponse + 48, // 69: looprpc.StaticAddressServer.PushStaticAddressHtlcSigs:output_type -> looprpc.PushStaticAddressHtlcSigsResponse + 50, // 70: looprpc.StaticAddressServer.PushStaticAddressSweeplessSigs:output_type -> looprpc.PushStaticAddressSweeplessSigsResponse + 50, // [50:71] is the sub-list for method output_type + 29, // [29:50] is the sub-list for method input_type + 29, // [29:29] is the sub-list for extension type_name + 29, // [29:29] is the sub-list for extension extendee + 0, // [0:29] is the sub-list for field type_name } func init() { file_server_proto_init() } @@ -4263,6 +4781,78 @@ func file_server_proto_init() { return nil } } + file_server_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ServerStaticAddressLoopInRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_server_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ServerStaticAddressLoopInResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_server_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushStaticAddressHtlcSigsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_server_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushStaticAddressHtlcSigsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_server_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushStaticAddressSweeplessSigsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_server_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PushStaticAddressSweeplessSigsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_server_proto_msgTypes[19].OneofWrappers = []interface{}{ (*CancelLoopOutSwapRequest_RouteCancel)(nil), @@ -4273,7 +4863,7 @@ func file_server_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_server_proto_rawDesc, NumEnums: 6, - NumMessages: 39, + NumMessages: 45, NumExtensions: 0, NumServices: 2, }, diff --git a/swapserverrpc/server.proto b/swapserverrpc/server.proto index dcd4344817..9fd1514cb2 100644 --- a/swapserverrpc/server.proto +++ b/swapserverrpc/server.proto @@ -672,6 +672,15 @@ service StaticAddressServer { // the partial sigs for the client's selected deposits. rpc ServerWithdrawDeposits (ServerWithdrawRequest) returns (ServerWithdrawResponse); + + rpc ServerStaticAddressLoopIn (ServerStaticAddressLoopInRequest) + returns (ServerStaticAddressLoopInResponse); + + rpc PushStaticAddressHtlcSigs (PushStaticAddressHtlcSigsRequest) + returns (PushStaticAddressHtlcSigsResponse); + + rpc PushStaticAddressSweeplessSigs (PushStaticAddressSweeplessSigsRequest) + returns (PushStaticAddressSweeplessSigsResponse); } message ServerNewAddressRequest { @@ -715,4 +724,75 @@ message ServerWithdrawResponse { // The nonces that the server used to generate the sweepless sweep sigs. repeated bytes server_nonces = 2; +} + +message ServerStaticAddressLoopInRequest { + bytes htlc_client_key = 1; + + bytes swap_hash = 2; + + repeated string deposit_outpoints = 3; + + string swap_invoice = 4; + + bytes last_hop = 5; + + // The protocol version that the client adheres to. + StaticAddressProtocolVersion protocol_version = 6; + + // The user agent string that identifies the software running on the user's + // side. This can be changed in the user's client software but it _SHOULD_ + // conform to the following pattern: + // Agent-Name/semver-version(/additional-info) + // Examples: + // loopd/v0.10.0-beta/commit=3b635821 + // litd/v0.2.0-alpha/commit=326d754 + string user_agent = 7; +} + +message ServerStaticAddressLoopInResponse { + bytes htlc_server_key = 1; + + int32 htlc_expiry = 2; + + // The nonces that the server used to generate the htlc sigs. + repeated bytes htlc_server_nonces = 3; + + // The fee rate in sat/kw that the server wants to use for the htlc tx. + uint64 htlc_fee_rate = 4; +} + +message PushStaticAddressHtlcSigsRequest { + bytes swap_hash = 1; + + // The nonces that the client used to generate the htlc sigs. + repeated bytes htlc_client_nonces = 2; + + // The musig2 htlc sigs that the client generated for the htlc. + repeated bytes htlc_client_sigs = 3; +} + +message PushStaticAddressHtlcSigsResponse { + // The nonces that the client used to generate the htlc sigs. + repeated bytes sweepless_server_nonces = 1; + + // The fee rate in sat/kw that the server wants to use for the htlc tx. + uint64 sweepless_fee_rate = 2; + + // The address that the client wants to sweep the static address deposits + // to. + string sweepless_sweep_addr = 3; +} + +message PushStaticAddressSweeplessSigsRequest { + bytes swap_hash = 1; + + // The nonces that the client used to generate the htlc sigs. + repeated bytes sweepless_client_nonces = 2; + + // The musig2 htlc sigs that the client generated for the htlc. + repeated bytes sweepless_client_sigs = 3; +} + +message PushStaticAddressSweeplessSigsResponse { } \ No newline at end of file diff --git a/swapserverrpc/server_grpc.pb.go b/swapserverrpc/server_grpc.pb.go index 21e6f5c759..0949cc55c8 100644 --- a/swapserverrpc/server_grpc.pb.go +++ b/swapserverrpc/server_grpc.pb.go @@ -711,6 +711,9 @@ type StaticAddressServerClient interface { // haven't timed out yet to the client's wallet. The server will generate // the partial sigs for the client's selected deposits. ServerWithdrawDeposits(ctx context.Context, in *ServerWithdrawRequest, opts ...grpc.CallOption) (*ServerWithdrawResponse, error) + ServerStaticAddressLoopIn(ctx context.Context, in *ServerStaticAddressLoopInRequest, opts ...grpc.CallOption) (*ServerStaticAddressLoopInResponse, error) + PushStaticAddressHtlcSigs(ctx context.Context, in *PushStaticAddressHtlcSigsRequest, opts ...grpc.CallOption) (*PushStaticAddressHtlcSigsResponse, error) + PushStaticAddressSweeplessSigs(ctx context.Context, in *PushStaticAddressSweeplessSigsRequest, opts ...grpc.CallOption) (*PushStaticAddressSweeplessSigsResponse, error) } type staticAddressServerClient struct { @@ -739,6 +742,33 @@ func (c *staticAddressServerClient) ServerWithdrawDeposits(ctx context.Context, return out, nil } +func (c *staticAddressServerClient) ServerStaticAddressLoopIn(ctx context.Context, in *ServerStaticAddressLoopInRequest, opts ...grpc.CallOption) (*ServerStaticAddressLoopInResponse, error) { + out := new(ServerStaticAddressLoopInResponse) + err := c.cc.Invoke(ctx, "/looprpc.StaticAddressServer/ServerStaticAddressLoopIn", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *staticAddressServerClient) PushStaticAddressHtlcSigs(ctx context.Context, in *PushStaticAddressHtlcSigsRequest, opts ...grpc.CallOption) (*PushStaticAddressHtlcSigsResponse, error) { + out := new(PushStaticAddressHtlcSigsResponse) + err := c.cc.Invoke(ctx, "/looprpc.StaticAddressServer/PushStaticAddressHtlcSigs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *staticAddressServerClient) PushStaticAddressSweeplessSigs(ctx context.Context, in *PushStaticAddressSweeplessSigsRequest, opts ...grpc.CallOption) (*PushStaticAddressSweeplessSigsResponse, error) { + out := new(PushStaticAddressSweeplessSigsResponse) + err := c.cc.Invoke(ctx, "/looprpc.StaticAddressServer/PushStaticAddressSweeplessSigs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // StaticAddressServerServer is the server API for StaticAddressServer service. // All implementations must embed UnimplementedStaticAddressServerServer // for forward compatibility @@ -751,6 +781,9 @@ type StaticAddressServerServer interface { // haven't timed out yet to the client's wallet. The server will generate // the partial sigs for the client's selected deposits. ServerWithdrawDeposits(context.Context, *ServerWithdrawRequest) (*ServerWithdrawResponse, error) + ServerStaticAddressLoopIn(context.Context, *ServerStaticAddressLoopInRequest) (*ServerStaticAddressLoopInResponse, error) + PushStaticAddressHtlcSigs(context.Context, *PushStaticAddressHtlcSigsRequest) (*PushStaticAddressHtlcSigsResponse, error) + PushStaticAddressSweeplessSigs(context.Context, *PushStaticAddressSweeplessSigsRequest) (*PushStaticAddressSweeplessSigsResponse, error) mustEmbedUnimplementedStaticAddressServerServer() } @@ -764,6 +797,15 @@ func (UnimplementedStaticAddressServerServer) ServerNewAddress(context.Context, func (UnimplementedStaticAddressServerServer) ServerWithdrawDeposits(context.Context, *ServerWithdrawRequest) (*ServerWithdrawResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ServerWithdrawDeposits not implemented") } +func (UnimplementedStaticAddressServerServer) ServerStaticAddressLoopIn(context.Context, *ServerStaticAddressLoopInRequest) (*ServerStaticAddressLoopInResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ServerStaticAddressLoopIn not implemented") +} +func (UnimplementedStaticAddressServerServer) PushStaticAddressHtlcSigs(context.Context, *PushStaticAddressHtlcSigsRequest) (*PushStaticAddressHtlcSigsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PushStaticAddressHtlcSigs not implemented") +} +func (UnimplementedStaticAddressServerServer) PushStaticAddressSweeplessSigs(context.Context, *PushStaticAddressSweeplessSigsRequest) (*PushStaticAddressSweeplessSigsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PushStaticAddressSweeplessSigs not implemented") +} func (UnimplementedStaticAddressServerServer) mustEmbedUnimplementedStaticAddressServerServer() {} // UnsafeStaticAddressServerServer may be embedded to opt out of forward compatibility for this service. @@ -813,6 +855,60 @@ func _StaticAddressServer_ServerWithdrawDeposits_Handler(srv interface{}, ctx co return interceptor(ctx, in, info, handler) } +func _StaticAddressServer_ServerStaticAddressLoopIn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ServerStaticAddressLoopInRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StaticAddressServerServer).ServerStaticAddressLoopIn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/looprpc.StaticAddressServer/ServerStaticAddressLoopIn", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StaticAddressServerServer).ServerStaticAddressLoopIn(ctx, req.(*ServerStaticAddressLoopInRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StaticAddressServer_PushStaticAddressHtlcSigs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PushStaticAddressHtlcSigsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StaticAddressServerServer).PushStaticAddressHtlcSigs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/looprpc.StaticAddressServer/PushStaticAddressHtlcSigs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StaticAddressServerServer).PushStaticAddressHtlcSigs(ctx, req.(*PushStaticAddressHtlcSigsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StaticAddressServer_PushStaticAddressSweeplessSigs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PushStaticAddressSweeplessSigsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StaticAddressServerServer).PushStaticAddressSweeplessSigs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/looprpc.StaticAddressServer/PushStaticAddressSweeplessSigs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StaticAddressServerServer).PushStaticAddressSweeplessSigs(ctx, req.(*PushStaticAddressSweeplessSigsRequest)) + } + return interceptor(ctx, in, info, handler) +} + // StaticAddressServer_ServiceDesc is the grpc.ServiceDesc for StaticAddressServer service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -828,6 +924,18 @@ var StaticAddressServer_ServiceDesc = grpc.ServiceDesc{ MethodName: "ServerWithdrawDeposits", Handler: _StaticAddressServer_ServerWithdrawDeposits_Handler, }, + { + MethodName: "ServerStaticAddressLoopIn", + Handler: _StaticAddressServer_ServerStaticAddressLoopIn_Handler, + }, + { + MethodName: "PushStaticAddressHtlcSigs", + Handler: _StaticAddressServer_PushStaticAddressHtlcSigs_Handler, + }, + { + MethodName: "PushStaticAddressSweeplessSigs", + Handler: _StaticAddressServer_PushStaticAddressSweeplessSigs_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "server.proto",