From cf0ffcaa3a03d8740b1d45893cbb657576d7c6c7 Mon Sep 17 00:00:00 2001 From: Gustavo Stingelin Date: Fri, 17 Jul 2026 17:37:25 -0300 Subject: [PATCH 1/6] loopdb: persist static address labels --- .../000022_static_address_label.down.sql | 2 ++ .../000022_static_address_label.up.sql | 4 +++ loopdb/sqlc/models.go | 1 + loopdb/sqlc/querier.go | 1 + loopdb/sqlc/queries/static_addresses.sql | 13 ++++++-- loopdb/sqlc/static_addresses.sql.go | 33 ++++++++++++++++--- 6 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 loopdb/sqlc/migrations/000022_static_address_label.down.sql create mode 100644 loopdb/sqlc/migrations/000022_static_address_label.up.sql diff --git a/loopdb/sqlc/migrations/000022_static_address_label.down.sql b/loopdb/sqlc/migrations/000022_static_address_label.down.sql new file mode 100644 index 000000000..adb7392de --- /dev/null +++ b/loopdb/sqlc/migrations/000022_static_address_label.down.sql @@ -0,0 +1,2 @@ +-- Drop local static-address label metadata. +ALTER TABLE static_addresses DROP COLUMN label; diff --git a/loopdb/sqlc/migrations/000022_static_address_label.up.sql b/loopdb/sqlc/migrations/000022_static_address_label.up.sql new file mode 100644 index 000000000..417289be4 --- /dev/null +++ b/loopdb/sqlc/migrations/000022_static_address_label.up.sql @@ -0,0 +1,4 @@ +-- label records local operator metadata for a static address. It is not part of +-- the address script or server protocol state; an empty value means the address +-- is unlabeled. +ALTER TABLE static_addresses ADD COLUMN label TEXT NOT NULL DEFAULT ''; diff --git a/loopdb/sqlc/models.go b/loopdb/sqlc/models.go index 78a75d042..a25e05444 100644 --- a/loopdb/sqlc/models.go +++ b/loopdb/sqlc/models.go @@ -134,6 +134,7 @@ type StaticAddress struct { Pkscript []byte ProtocolVersion int32 InitiationHeight int32 + Label string } type StaticAddressSwap struct { diff --git a/loopdb/sqlc/querier.go b/loopdb/sqlc/querier.go index ba3c35eb9..c023157f0 100644 --- a/loopdb/sqlc/querier.go +++ b/loopdb/sqlc/querier.go @@ -74,6 +74,7 @@ type Querier interface { UpdateInstantOut(ctx context.Context, arg UpdateInstantOutParams) error UpdateLoopOutAssetOffchainPayments(ctx context.Context, arg UpdateLoopOutAssetOffchainPaymentsParams) error UpdateReservation(ctx context.Context, arg UpdateReservationParams) error + UpdateStaticAddressLabel(ctx context.Context, arg UpdateStaticAddressLabelParams) (int64, error) UpdateStaticAddressLoopIn(ctx context.Context, arg UpdateStaticAddressLoopInParams) error UpdateWithdrawal(ctx context.Context, arg UpdateWithdrawalParams) error UpsertLiquidityParams(ctx context.Context, params []byte) error diff --git a/loopdb/sqlc/queries/static_addresses.sql b/loopdb/sqlc/queries/static_addresses.sql index c613cfd93..b124ad304 100644 --- a/loopdb/sqlc/queries/static_addresses.sql +++ b/loopdb/sqlc/queries/static_addresses.sql @@ -14,7 +14,8 @@ INSERT INTO static_addresses ( client_key_index, pkscript, protocol_version, - initiation_height + initiation_height, + label ) VALUES ( $1, $2, @@ -23,5 +24,11 @@ INSERT INTO static_addresses ( $5, $6, $7, - $8 - ); \ No newline at end of file + $8, + $9 + ); + +-- name: UpdateStaticAddressLabel :execrows +UPDATE static_addresses +SET label = $2 +WHERE pkscript = $1; diff --git a/loopdb/sqlc/static_addresses.sql.go b/loopdb/sqlc/static_addresses.sql.go index 054c07364..78d54a824 100644 --- a/loopdb/sqlc/static_addresses.sql.go +++ b/loopdb/sqlc/static_addresses.sql.go @@ -10,7 +10,7 @@ import ( ) const allStaticAddresses = `-- name: AllStaticAddresses :many -SELECT id, client_pubkey, server_pubkey, expiry, client_key_family, client_key_index, pkscript, protocol_version, initiation_height FROM static_addresses +SELECT id, client_pubkey, server_pubkey, expiry, client_key_family, client_key_index, pkscript, protocol_version, initiation_height, label FROM static_addresses ` func (q *Queries) AllStaticAddresses(ctx context.Context) ([]StaticAddress, error) { @@ -32,6 +32,7 @@ func (q *Queries) AllStaticAddresses(ctx context.Context) ([]StaticAddress, erro &i.Pkscript, &i.ProtocolVersion, &i.InitiationHeight, + &i.Label, ); err != nil { return nil, err } @@ -55,7 +56,8 @@ INSERT INTO static_addresses ( client_key_index, pkscript, protocol_version, - initiation_height + initiation_height, + label ) VALUES ( $1, $2, @@ -64,7 +66,8 @@ INSERT INTO static_addresses ( $5, $6, $7, - $8 + $8, + $9 ) ` @@ -77,6 +80,7 @@ type CreateStaticAddressParams struct { Pkscript []byte ProtocolVersion int32 InitiationHeight int32 + Label string } func (q *Queries) CreateStaticAddress(ctx context.Context, arg CreateStaticAddressParams) error { @@ -89,12 +93,13 @@ func (q *Queries) CreateStaticAddress(ctx context.Context, arg CreateStaticAddre arg.Pkscript, arg.ProtocolVersion, arg.InitiationHeight, + arg.Label, ) return err } const getStaticAddress = `-- name: GetStaticAddress :one -SELECT id, client_pubkey, server_pubkey, expiry, client_key_family, client_key_index, pkscript, protocol_version, initiation_height FROM static_addresses +SELECT id, client_pubkey, server_pubkey, expiry, client_key_family, client_key_index, pkscript, protocol_version, initiation_height, label FROM static_addresses WHERE pkscript=$1 ` @@ -111,6 +116,26 @@ func (q *Queries) GetStaticAddress(ctx context.Context, pkscript []byte) (Static &i.Pkscript, &i.ProtocolVersion, &i.InitiationHeight, + &i.Label, ) return i, err } + +const updateStaticAddressLabel = `-- name: UpdateStaticAddressLabel :execrows +UPDATE static_addresses +SET label = $2 +WHERE pkscript = $1 +` + +type UpdateStaticAddressLabelParams struct { + Pkscript []byte + Label string +} + +func (q *Queries) UpdateStaticAddressLabel(ctx context.Context, arg UpdateStaticAddressLabelParams) (int64, error) { + result, err := q.db.ExecContext(ctx, updateStaticAddressLabel, arg.Pkscript, arg.Label) + if err != nil { + return 0, err + } + return result.RowsAffected() +} From a4da3f92f5bb9c7fb4cef460911edb6b87ee3108 Mon Sep 17 00:00:00 2001 From: Gustavo Stingelin Date: Fri, 17 Jul 2026 17:37:57 -0300 Subject: [PATCH 2/6] staticaddr/script: track static address labels --- staticaddr/script/parameters.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/staticaddr/script/parameters.go b/staticaddr/script/parameters.go index 89e2470b6..91d3a405e 100644 --- a/staticaddr/script/parameters.go +++ b/staticaddr/script/parameters.go @@ -33,4 +33,8 @@ type Parameters struct { // InitiationHeight is the height at which the address was initiated. InitiationHeight int32 + + // Label is local operator metadata for the static address. It is persisted for + // display and filtering only, and is not part of the script or server protocol. + Label string } From 235d929959abe8df40da8ea9d36efbc98650db02 Mon Sep 17 00:00:00 2001 From: Gustavo Stingelin Date: Fri, 17 Jul 2026 17:39:20 -0300 Subject: [PATCH 3/6] staticaddr/address: store static address labels --- loopd/swapclient_server_test.go | 28 ++++++ staticaddr/address/interface.go | 6 ++ staticaddr/address/sql_store.go | 29 ++++++- staticaddr/address/sql_store_test.go | 122 +++++++++++++++++++++++++++ 4 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 staticaddr/address/sql_store_test.go diff --git a/loopd/swapclient_server_test.go b/loopd/swapclient_server_test.go index f3fab0328..0968cf386 100644 --- a/loopd/swapclient_server_test.go +++ b/loopd/swapclient_server_test.go @@ -2,6 +2,7 @@ package loopd import ( "context" + "errors" "fmt" "os" "testing" @@ -1301,6 +1302,33 @@ func (s *mockAddressStore) GetAllStaticAddresses(_ context.Context) ( return s.params, nil } +// UpdateStaticAddressLabel mutates only the matched local record so RPC tests +// prove relabeling has no server/protocol side effect. +func (s *mockAddressStore) UpdateStaticAddressLabel(_ context.Context, + pkScript []byte, label string) error { + + params := s.staticAddress(pkScript) + if params == nil { + return errors.New("static address not found") + } + + params.Label = label + + return nil +} + +// staticAddress finds a record by pkScript to mirror the real store's update +// key and catch attempts to relabel an unknown static address. +func (s *mockAddressStore) staticAddress(pkScript []byte) *script.Parameters { + for _, params := range s.params { + if string(params.PkScript) == string(pkScript) { + return params + } + } + + return nil +} + // mockDepositStore implements deposit.Store minimally for DepositsForOutpoints. type mockDepositStore struct { byOutpoint map[string]*deposit.Deposit diff --git a/staticaddr/address/interface.go b/staticaddr/address/interface.go index 63b6cf7c1..606af8888 100644 --- a/staticaddr/address/interface.go +++ b/staticaddr/address/interface.go @@ -17,4 +17,10 @@ type Store interface { // GetAllStaticAddresses retrieves all static addresses from the store. GetAllStaticAddresses(ctx context.Context) ([]*script.Parameters, error) + + // UpdateStaticAddressLabel updates the local label for a static address by + // its pkScript so metadata changes never alter address scripts or server + // state. + UpdateStaticAddressLabel(ctx context.Context, pkScript []byte, + label string) error } diff --git a/staticaddr/address/sql_store.go b/staticaddr/address/sql_store.go index 43257b81d..b83c27e0a 100644 --- a/staticaddr/address/sql_store.go +++ b/staticaddr/address/sql_store.go @@ -2,6 +2,7 @@ package address import ( "context" + "fmt" "github.com/btcsuite/btcd/btcec/v2" "github.com/lightninglabs/loop/loopdb" @@ -24,7 +25,7 @@ func NewSqlStore(db *loopdb.BaseDB) *SqlStore { } } -// CreateStaticAddress creates a static address record in the database. +// CreateStaticAddress creates a static address record. func (s *SqlStore) CreateStaticAddress(ctx context.Context, addrParams *script.Parameters) error { @@ -37,6 +38,7 @@ func (s *SqlStore) CreateStaticAddress(ctx context.Context, Pkscript: addrParams.PkScript, ProtocolVersion: int32(addrParams.ProtocolVersion), InitiationHeight: addrParams.InitiationHeight, + Label: addrParams.Label, } return s.baseDB.Queries.CreateStaticAddress(ctx, createArgs) @@ -64,6 +66,30 @@ func (s *SqlStore) GetAllStaticAddresses(ctx context.Context) ( return result, nil } +// UpdateStaticAddressLabel updates the local label for a static address by its +// pkScript, keeping relabeling a metadata-only database change that cannot +// create a new address record. +func (s *SqlStore) UpdateStaticAddressLabel(ctx context.Context, + pkScript []byte, label string) error { + + updateArgs := sqlc.UpdateStaticAddressLabelParams{ + Pkscript: pkScript, + Label: label, + } + + rowsAffected, err := s.baseDB.Queries.UpdateStaticAddressLabel( + ctx, updateArgs, + ) + if err != nil { + return err + } + if rowsAffected == 0 { + return fmt.Errorf("static address not found") + } + + return nil +} + // toAddressParameters transforms a database representation of a static address // to an AddressParameters struct. func (s *SqlStore) toAddressParameters(row sqlc.StaticAddress) ( @@ -92,5 +118,6 @@ func (s *SqlStore) toAddressParameters(row sqlc.StaticAddress) ( row.ProtocolVersion, ), InitiationHeight: row.InitiationHeight, + Label: row.Label, }, nil } diff --git a/staticaddr/address/sql_store_test.go b/staticaddr/address/sql_store_test.go new file mode 100644 index 000000000..565b31175 --- /dev/null +++ b/staticaddr/address/sql_store_test.go @@ -0,0 +1,122 @@ +package address + +import ( + "testing" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/lightninglabs/loop/loopdb" + "github.com/lightninglabs/loop/staticaddr/script" + "github.com/lightninglabs/loop/staticaddr/version" + "github.com/lightningnetwork/lnd/input" + "github.com/lightningnetwork/lnd/keychain" + "github.com/stretchr/testify/require" +) + +// TestSqlStoreStaticAddressLabel_whenCreatedAndUpdated proves labels survive +// the create and update path because operators rely on them after restarts. +func TestSqlStoreStaticAddressLabel_whenCreatedAndUpdated(t *testing.T) { + ctx := t.Context() + store := NewSqlStore(loopdb.NewTestDB(t).BaseDB) + addrParams := testAddressParams(t) + addrParams.Label = "first" + + err := store.CreateStaticAddress(ctx, addrParams) + require.NoError(t, err) + + params, err := store.GetAllStaticAddresses(ctx) + require.NoError(t, err) + require.Len(t, params, 1) + require.Equal(t, "first", params[0].Label) + + err = store.UpdateStaticAddressLabel(ctx, addrParams.PkScript, "second") + require.NoError(t, err) + + params, err = store.GetAllStaticAddresses(ctx) + require.NoError(t, err) + require.Len(t, params, 1) + require.Equal(t, "second", params[0].Label) +} + +// TestSqlStoreStaticAddressLabel_whenCleared ensures an empty label is persisted +// as the supported way to remove local operator metadata. +func TestSqlStoreStaticAddressLabel_whenCleared(t *testing.T) { + ctx := t.Context() + store := NewSqlStore(loopdb.NewTestDB(t).BaseDB) + addrParams := testAddressParams(t) + addrParams.Label = "first" + + err := store.CreateStaticAddress(ctx, addrParams) + require.NoError(t, err) + + err = store.UpdateStaticAddressLabel(ctx, addrParams.PkScript, "") + require.NoError(t, err) + + params, err := store.GetAllStaticAddresses(ctx) + require.NoError(t, err) + require.Len(t, params, 1) + require.Empty(t, params[0].Label) +} + +// TestSqlStoreStaticAddressLabel_whenCreatedWithoutLabel protects unlabeled +// static addresses so label support remains optional metadata. +func TestSqlStoreStaticAddressLabel_whenCreatedWithoutLabel(t *testing.T) { + ctx := t.Context() + store := NewSqlStore(loopdb.NewTestDB(t).BaseDB) + addrParams := testAddressParams(t) + + err := store.CreateStaticAddress(ctx, addrParams) + require.NoError(t, err) + + params, err := store.GetAllStaticAddresses(ctx) + require.NoError(t, err) + require.Len(t, params, 1) + require.Empty(t, params[0].Label) +} + +// TestSqlStoreStaticAddressLabel_whenAddressMissing ensures relabel requests do +// not silently create metadata for an address the wallet does not own. +func TestSqlStoreStaticAddressLabel_whenAddressMissing(t *testing.T) { + ctx := t.Context() + store := NewSqlStore(loopdb.NewTestDB(t).BaseDB) + addrParams := testAddressParams(t) + + err := store.UpdateStaticAddressLabel(ctx, addrParams.PkScript, "missing") + require.Error(t, err) + require.ErrorContains(t, err, "static address not found") +} + +// testAddressParams builds a valid static-address record so label tests vary +// only metadata while preserving real script and key material constraints. +func testAddressParams(t *testing.T) *script.Parameters { + t.Helper() + + clientKey, err := btcec.NewPrivateKey() + require.NoError(t, err) + + serverKey, err := btcec.NewPrivateKey() + require.NoError(t, err) + + staticAddress, err := script.NewStaticAddress( + input.MuSig2Version100RC2, int64(defaultExpiry), clientKey.PubKey(), + serverKey.PubKey(), + ) + require.NoError(t, err) + + pkScript, err := staticAddress.StaticAddressScript() + require.NoError(t, err) + + return &script.Parameters{ + ClientPubkey: clientKey.PubKey(), + ServerPubkey: serverKey.PubKey(), + PkScript: pkScript, + Expiry: defaultExpiry, + KeyLocator: keychain.KeyLocator{ + Family: keychain.KeyFamily(1), + Index: 2, + }, + ProtocolVersion: version.AddressProtocolVersion( + version.CurrentRPCProtocolVersion(), + ), + InitiationHeight: 100, + } +} From 7c6ee09e72175b8c8bebe2f7b6d0c2cdd3d13c24 Mon Sep 17 00:00:00 2001 From: Gustavo Stingelin Date: Fri, 17 Jul 2026 17:41:17 -0300 Subject: [PATCH 4/6] looprpc: expose static address labels --- looprpc/client.pb.go | 504 ++++++++++++++++++++++------------ looprpc/client.pb.gw.go | 77 ++++++ looprpc/client.proto | 51 ++++ looprpc/client.swagger.json | 75 +++++ looprpc/client.yaml | 3 + looprpc/client_grpc.pb.go | 40 +++ looprpc/perms.go | 7 + looprpc/swapclient.pb.json.go | 25 ++ 8 files changed, 610 insertions(+), 172 deletions(-) diff --git a/looprpc/client.pb.go b/looprpc/client.pb.go index 3305bfcde..49a5c934b 100644 --- a/looprpc/client.pb.go +++ b/looprpc/client.pb.go @@ -4838,7 +4838,9 @@ func (x *InstantOut) GetSweepTxId() string { type NewStaticAddressRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // The client's public key for the 2-of-2 MuSig2 taproot static address. - ClientKey []byte `protobuf:"bytes,1,opt,name=client_key,json=clientKey,proto3" json:"client_key,omitempty"` + ClientKey []byte `protobuf:"bytes,1,opt,name=client_key,json=clientKey,proto3" json:"client_key,omitempty"` + // An optional label for this static address. Empty string means no label. + Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -4880,12 +4882,21 @@ func (x *NewStaticAddressRequest) GetClientKey() []byte { return nil } +func (x *NewStaticAddressRequest) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + type NewStaticAddressResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // The taproot static address. Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // The CSV expiry of the static address. - Expiry uint32 `protobuf:"varint,2,opt,name=expiry,proto3" json:"expiry,omitempty"` + Expiry uint32 `protobuf:"varint,2,opt,name=expiry,proto3" json:"expiry,omitempty"` + // The label for this static address. Empty string means no label. + Label string `protobuf:"bytes,3,opt,name=label,proto3" json:"label,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -4934,6 +4945,121 @@ func (x *NewStaticAddressResponse) GetExpiry() uint32 { return 0 } +func (x *NewStaticAddressResponse) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +type UpdateStaticAddressLabelRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The static address whose label should be updated. + StaticAddress string `protobuf:"bytes,1,opt,name=static_address,json=staticAddress,proto3" json:"static_address,omitempty"` + // The updated label for the static address. Empty string means no label. + Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateStaticAddressLabelRequest) Reset() { + *x = UpdateStaticAddressLabelRequest{} + mi := &file_client_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateStaticAddressLabelRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateStaticAddressLabelRequest) ProtoMessage() {} + +func (x *UpdateStaticAddressLabelRequest) ProtoReflect() protoreflect.Message { + mi := &file_client_proto_msgTypes[57] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateStaticAddressLabelRequest.ProtoReflect.Descriptor instead. +func (*UpdateStaticAddressLabelRequest) Descriptor() ([]byte, []int) { + return file_client_proto_rawDescGZIP(), []int{57} +} + +func (x *UpdateStaticAddressLabelRequest) GetStaticAddress() string { + if x != nil { + return x.StaticAddress + } + return "" +} + +func (x *UpdateStaticAddressLabelRequest) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +type UpdateStaticAddressLabelResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The static address whose label was updated. + StaticAddress string `protobuf:"bytes,1,opt,name=static_address,json=staticAddress,proto3" json:"static_address,omitempty"` + // The updated label for the static address. Empty string means no label. + Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateStaticAddressLabelResponse) Reset() { + *x = UpdateStaticAddressLabelResponse{} + mi := &file_client_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateStaticAddressLabelResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateStaticAddressLabelResponse) ProtoMessage() {} + +func (x *UpdateStaticAddressLabelResponse) ProtoReflect() protoreflect.Message { + mi := &file_client_proto_msgTypes[58] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateStaticAddressLabelResponse.ProtoReflect.Descriptor instead. +func (*UpdateStaticAddressLabelResponse) Descriptor() ([]byte, []int) { + return file_client_proto_rawDescGZIP(), []int{58} +} + +func (x *UpdateStaticAddressLabelResponse) GetStaticAddress() string { + if x != nil { + return x.StaticAddress + } + return "" +} + +func (x *UpdateStaticAddressLabelResponse) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + type ListUnspentDepositsRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // The number of minimum confirmations a utxo must have to be listed. @@ -4947,7 +5073,7 @@ type ListUnspentDepositsRequest struct { func (x *ListUnspentDepositsRequest) Reset() { *x = ListUnspentDepositsRequest{} - mi := &file_client_proto_msgTypes[57] + mi := &file_client_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4959,7 +5085,7 @@ func (x *ListUnspentDepositsRequest) String() string { func (*ListUnspentDepositsRequest) ProtoMessage() {} func (x *ListUnspentDepositsRequest) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[57] + mi := &file_client_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4972,7 +5098,7 @@ func (x *ListUnspentDepositsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListUnspentDepositsRequest.ProtoReflect.Descriptor instead. func (*ListUnspentDepositsRequest) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{57} + return file_client_proto_rawDescGZIP(), []int{59} } func (x *ListUnspentDepositsRequest) GetMinConfs() int32 { @@ -4999,7 +5125,7 @@ type ListUnspentDepositsResponse struct { func (x *ListUnspentDepositsResponse) Reset() { *x = ListUnspentDepositsResponse{} - mi := &file_client_proto_msgTypes[58] + mi := &file_client_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5011,7 +5137,7 @@ func (x *ListUnspentDepositsResponse) String() string { func (*ListUnspentDepositsResponse) ProtoMessage() {} func (x *ListUnspentDepositsResponse) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[58] + mi := &file_client_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5024,7 +5150,7 @@ func (x *ListUnspentDepositsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListUnspentDepositsResponse.ProtoReflect.Descriptor instead. func (*ListUnspentDepositsResponse) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{58} + return file_client_proto_rawDescGZIP(), []int{60} } func (x *ListUnspentDepositsResponse) GetUtxos() []*Utxo { @@ -5044,13 +5170,16 @@ type Utxo struct { Outpoint string `protobuf:"bytes,3,opt,name=outpoint,proto3" json:"outpoint,omitempty"` // The number of confirmations for the Utxo. Confirmations int64 `protobuf:"varint,4,opt,name=confirmations,proto3" json:"confirmations,omitempty"` + // The label for the static address that owns this Utxo. Empty string means no + // label. + Label string `protobuf:"bytes,5,opt,name=label,proto3" json:"label,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Utxo) Reset() { *x = Utxo{} - mi := &file_client_proto_msgTypes[59] + mi := &file_client_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5062,7 +5191,7 @@ func (x *Utxo) String() string { func (*Utxo) ProtoMessage() {} func (x *Utxo) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[59] + mi := &file_client_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5075,7 +5204,7 @@ func (x *Utxo) ProtoReflect() protoreflect.Message { // Deprecated: Use Utxo.ProtoReflect.Descriptor instead. func (*Utxo) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{59} + return file_client_proto_rawDescGZIP(), []int{61} } func (x *Utxo) GetStaticAddress() string { @@ -5106,6 +5235,13 @@ func (x *Utxo) GetConfirmations() int64 { return 0 } +func (x *Utxo) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + type WithdrawDepositsRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // The outpoints of the deposits to withdraw. @@ -5128,7 +5264,7 @@ type WithdrawDepositsRequest struct { func (x *WithdrawDepositsRequest) Reset() { *x = WithdrawDepositsRequest{} - mi := &file_client_proto_msgTypes[60] + mi := &file_client_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5140,7 +5276,7 @@ func (x *WithdrawDepositsRequest) String() string { func (*WithdrawDepositsRequest) ProtoMessage() {} func (x *WithdrawDepositsRequest) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[60] + mi := &file_client_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5153,7 +5289,7 @@ func (x *WithdrawDepositsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WithdrawDepositsRequest.ProtoReflect.Descriptor instead. func (*WithdrawDepositsRequest) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{60} + return file_client_proto_rawDescGZIP(), []int{62} } func (x *WithdrawDepositsRequest) GetOutpoints() []*lnrpc.OutPoint { @@ -5203,7 +5339,7 @@ type WithdrawDepositsResponse struct { func (x *WithdrawDepositsResponse) Reset() { *x = WithdrawDepositsResponse{} - mi := &file_client_proto_msgTypes[61] + mi := &file_client_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5215,7 +5351,7 @@ func (x *WithdrawDepositsResponse) String() string { func (*WithdrawDepositsResponse) ProtoMessage() {} func (x *WithdrawDepositsResponse) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[61] + mi := &file_client_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5228,7 +5364,7 @@ func (x *WithdrawDepositsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use WithdrawDepositsResponse.ProtoReflect.Descriptor instead. func (*WithdrawDepositsResponse) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{61} + return file_client_proto_rawDescGZIP(), []int{63} } func (x *WithdrawDepositsResponse) GetWithdrawalTxHash() string { @@ -5257,7 +5393,7 @@ type ListStaticAddressDepositsRequest struct { func (x *ListStaticAddressDepositsRequest) Reset() { *x = ListStaticAddressDepositsRequest{} - mi := &file_client_proto_msgTypes[62] + mi := &file_client_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5269,7 +5405,7 @@ func (x *ListStaticAddressDepositsRequest) String() string { func (*ListStaticAddressDepositsRequest) ProtoMessage() {} func (x *ListStaticAddressDepositsRequest) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[62] + mi := &file_client_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5282,7 +5418,7 @@ func (x *ListStaticAddressDepositsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListStaticAddressDepositsRequest.ProtoReflect.Descriptor instead. func (*ListStaticAddressDepositsRequest) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{62} + return file_client_proto_rawDescGZIP(), []int{64} } func (x *ListStaticAddressDepositsRequest) GetStateFilter() DepositState { @@ -5309,7 +5445,7 @@ type ListStaticAddressDepositsResponse struct { func (x *ListStaticAddressDepositsResponse) Reset() { *x = ListStaticAddressDepositsResponse{} - mi := &file_client_proto_msgTypes[63] + mi := &file_client_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5321,7 +5457,7 @@ func (x *ListStaticAddressDepositsResponse) String() string { func (*ListStaticAddressDepositsResponse) ProtoMessage() {} func (x *ListStaticAddressDepositsResponse) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[63] + mi := &file_client_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5334,7 +5470,7 @@ func (x *ListStaticAddressDepositsResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ListStaticAddressDepositsResponse.ProtoReflect.Descriptor instead. func (*ListStaticAddressDepositsResponse) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{63} + return file_client_proto_rawDescGZIP(), []int{65} } func (x *ListStaticAddressDepositsResponse) GetFilteredDeposits() []*Deposit { @@ -5352,7 +5488,7 @@ type ListStaticAddressWithdrawalRequest struct { func (x *ListStaticAddressWithdrawalRequest) Reset() { *x = ListStaticAddressWithdrawalRequest{} - mi := &file_client_proto_msgTypes[64] + mi := &file_client_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5364,7 +5500,7 @@ func (x *ListStaticAddressWithdrawalRequest) String() string { func (*ListStaticAddressWithdrawalRequest) ProtoMessage() {} func (x *ListStaticAddressWithdrawalRequest) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[64] + mi := &file_client_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5377,7 +5513,7 @@ func (x *ListStaticAddressWithdrawalRequest) ProtoReflect() protoreflect.Message // Deprecated: Use ListStaticAddressWithdrawalRequest.ProtoReflect.Descriptor instead. func (*ListStaticAddressWithdrawalRequest) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{64} + return file_client_proto_rawDescGZIP(), []int{66} } type ListStaticAddressWithdrawalResponse struct { @@ -5390,7 +5526,7 @@ type ListStaticAddressWithdrawalResponse struct { func (x *ListStaticAddressWithdrawalResponse) Reset() { *x = ListStaticAddressWithdrawalResponse{} - mi := &file_client_proto_msgTypes[65] + mi := &file_client_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5402,7 +5538,7 @@ func (x *ListStaticAddressWithdrawalResponse) String() string { func (*ListStaticAddressWithdrawalResponse) ProtoMessage() {} func (x *ListStaticAddressWithdrawalResponse) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[65] + mi := &file_client_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5415,7 +5551,7 @@ func (x *ListStaticAddressWithdrawalResponse) ProtoReflect() protoreflect.Messag // Deprecated: Use ListStaticAddressWithdrawalResponse.ProtoReflect.Descriptor instead. func (*ListStaticAddressWithdrawalResponse) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{65} + return file_client_proto_rawDescGZIP(), []int{67} } func (x *ListStaticAddressWithdrawalResponse) GetWithdrawals() []*StaticAddressWithdrawal { @@ -5433,7 +5569,7 @@ type ListStaticAddressSwapsRequest struct { func (x *ListStaticAddressSwapsRequest) Reset() { *x = ListStaticAddressSwapsRequest{} - mi := &file_client_proto_msgTypes[66] + mi := &file_client_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5445,7 +5581,7 @@ func (x *ListStaticAddressSwapsRequest) String() string { func (*ListStaticAddressSwapsRequest) ProtoMessage() {} func (x *ListStaticAddressSwapsRequest) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[66] + mi := &file_client_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5458,7 +5594,7 @@ func (x *ListStaticAddressSwapsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListStaticAddressSwapsRequest.ProtoReflect.Descriptor instead. func (*ListStaticAddressSwapsRequest) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{66} + return file_client_proto_rawDescGZIP(), []int{68} } type ListStaticAddressSwapsResponse struct { @@ -5471,7 +5607,7 @@ type ListStaticAddressSwapsResponse struct { func (x *ListStaticAddressSwapsResponse) Reset() { *x = ListStaticAddressSwapsResponse{} - mi := &file_client_proto_msgTypes[67] + mi := &file_client_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5483,7 +5619,7 @@ func (x *ListStaticAddressSwapsResponse) String() string { func (*ListStaticAddressSwapsResponse) ProtoMessage() {} func (x *ListStaticAddressSwapsResponse) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[67] + mi := &file_client_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5496,7 +5632,7 @@ func (x *ListStaticAddressSwapsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListStaticAddressSwapsResponse.ProtoReflect.Descriptor instead. func (*ListStaticAddressSwapsResponse) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{67} + return file_client_proto_rawDescGZIP(), []int{69} } func (x *ListStaticAddressSwapsResponse) GetSwaps() []*StaticAddressLoopInSwap { @@ -5514,7 +5650,7 @@ type StaticAddressSummaryRequest struct { func (x *StaticAddressSummaryRequest) Reset() { *x = StaticAddressSummaryRequest{} - mi := &file_client_proto_msgTypes[68] + mi := &file_client_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5526,7 +5662,7 @@ func (x *StaticAddressSummaryRequest) String() string { func (*StaticAddressSummaryRequest) ProtoMessage() {} func (x *StaticAddressSummaryRequest) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[68] + mi := &file_client_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5539,7 +5675,7 @@ func (x *StaticAddressSummaryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticAddressSummaryRequest.ProtoReflect.Descriptor instead. func (*StaticAddressSummaryRequest) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{68} + return file_client_proto_rawDescGZIP(), []int{70} } type StaticAddressSummaryResponse struct { @@ -5564,13 +5700,15 @@ type StaticAddressSummaryResponse struct { ValueHtlcTimeoutSweepsSatoshis int64 `protobuf:"varint,9,opt,name=value_htlc_timeout_sweeps_satoshis,json=valueHtlcTimeoutSweepsSatoshis,proto3" json:"value_htlc_timeout_sweeps_satoshis,omitempty"` // The total value of all deposits that have been used for channel openings. ValueChannelsOpened int64 `protobuf:"varint,10,opt,name=value_channels_opened,json=valueChannelsOpened,proto3" json:"value_channels_opened,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // The label for this static address. Empty string means no label. + Label string `protobuf:"bytes,11,opt,name=label,proto3" json:"label,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *StaticAddressSummaryResponse) Reset() { *x = StaticAddressSummaryResponse{} - mi := &file_client_proto_msgTypes[69] + mi := &file_client_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5582,7 +5720,7 @@ func (x *StaticAddressSummaryResponse) String() string { func (*StaticAddressSummaryResponse) ProtoMessage() {} func (x *StaticAddressSummaryResponse) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[69] + mi := &file_client_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5595,7 +5733,7 @@ func (x *StaticAddressSummaryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticAddressSummaryResponse.ProtoReflect.Descriptor instead. func (*StaticAddressSummaryResponse) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{69} + return file_client_proto_rawDescGZIP(), []int{71} } func (x *StaticAddressSummaryResponse) GetStaticAddress() string { @@ -5668,6 +5806,13 @@ func (x *StaticAddressSummaryResponse) GetValueChannelsOpened() int64 { return 0 } +func (x *StaticAddressSummaryResponse) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + type Deposit struct { state protoimpl.MessageState `protogen:"open.v1"` // The identifier of the deposit. @@ -5692,7 +5837,7 @@ type Deposit struct { func (x *Deposit) Reset() { *x = Deposit{} - mi := &file_client_proto_msgTypes[70] + mi := &file_client_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5704,7 +5849,7 @@ func (x *Deposit) String() string { func (*Deposit) ProtoMessage() {} func (x *Deposit) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[70] + mi := &file_client_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5717,7 +5862,7 @@ func (x *Deposit) ProtoReflect() protoreflect.Message { // Deprecated: Use Deposit.ProtoReflect.Descriptor instead. func (*Deposit) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{70} + return file_client_proto_rawDescGZIP(), []int{72} } func (x *Deposit) GetId() []byte { @@ -5791,7 +5936,7 @@ type StaticAddressWithdrawal struct { func (x *StaticAddressWithdrawal) Reset() { *x = StaticAddressWithdrawal{} - mi := &file_client_proto_msgTypes[71] + mi := &file_client_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5803,7 +5948,7 @@ func (x *StaticAddressWithdrawal) String() string { func (*StaticAddressWithdrawal) ProtoMessage() {} func (x *StaticAddressWithdrawal) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[71] + mi := &file_client_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5816,7 +5961,7 @@ func (x *StaticAddressWithdrawal) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticAddressWithdrawal.ProtoReflect.Descriptor instead. func (*StaticAddressWithdrawal) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{71} + return file_client_proto_rawDescGZIP(), []int{73} } func (x *StaticAddressWithdrawal) GetTxId() string { @@ -5891,7 +6036,7 @@ type StaticAddressLoopInSwap struct { func (x *StaticAddressLoopInSwap) Reset() { *x = StaticAddressLoopInSwap{} - mi := &file_client_proto_msgTypes[72] + mi := &file_client_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5903,7 +6048,7 @@ func (x *StaticAddressLoopInSwap) String() string { func (*StaticAddressLoopInSwap) ProtoMessage() {} func (x *StaticAddressLoopInSwap) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[72] + mi := &file_client_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5916,7 +6061,7 @@ func (x *StaticAddressLoopInSwap) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticAddressLoopInSwap.ProtoReflect.Descriptor instead. func (*StaticAddressLoopInSwap) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{72} + return file_client_proto_rawDescGZIP(), []int{74} } func (x *StaticAddressLoopInSwap) GetSwapHash() []byte { @@ -6049,7 +6194,7 @@ type StaticAddressLoopInRequest struct { func (x *StaticAddressLoopInRequest) Reset() { *x = StaticAddressLoopInRequest{} - mi := &file_client_proto_msgTypes[73] + mi := &file_client_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6061,7 +6206,7 @@ func (x *StaticAddressLoopInRequest) String() string { func (*StaticAddressLoopInRequest) ProtoMessage() {} func (x *StaticAddressLoopInRequest) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[73] + mi := &file_client_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6074,7 +6219,7 @@ func (x *StaticAddressLoopInRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticAddressLoopInRequest.ProtoReflect.Descriptor instead. func (*StaticAddressLoopInRequest) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{73} + return file_client_proto_rawDescGZIP(), []int{75} } func (x *StaticAddressLoopInRequest) GetOutpoints() []string { @@ -6194,7 +6339,7 @@ type StaticAddressLoopInResponse struct { func (x *StaticAddressLoopInResponse) Reset() { *x = StaticAddressLoopInResponse{} - mi := &file_client_proto_msgTypes[74] + mi := &file_client_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6206,7 +6351,7 @@ func (x *StaticAddressLoopInResponse) String() string { func (*StaticAddressLoopInResponse) ProtoMessage() {} func (x *StaticAddressLoopInResponse) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[74] + mi := &file_client_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6219,7 +6364,7 @@ func (x *StaticAddressLoopInResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StaticAddressLoopInResponse.ProtoReflect.Descriptor instead. func (*StaticAddressLoopInResponse) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{74} + return file_client_proto_rawDescGZIP(), []int{76} } func (x *StaticAddressLoopInResponse) GetSwapHash() []byte { @@ -6348,7 +6493,7 @@ type AssetLoopOutRequest struct { func (x *AssetLoopOutRequest) Reset() { *x = AssetLoopOutRequest{} - mi := &file_client_proto_msgTypes[75] + mi := &file_client_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6360,7 +6505,7 @@ func (x *AssetLoopOutRequest) String() string { func (*AssetLoopOutRequest) ProtoMessage() {} func (x *AssetLoopOutRequest) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[75] + mi := &file_client_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6373,7 +6518,7 @@ func (x *AssetLoopOutRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AssetLoopOutRequest.ProtoReflect.Descriptor instead. func (*AssetLoopOutRequest) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{75} + return file_client_proto_rawDescGZIP(), []int{77} } func (x *AssetLoopOutRequest) GetAssetId() []byte { @@ -6428,7 +6573,7 @@ type AssetRfqInfo struct { func (x *AssetRfqInfo) Reset() { *x = AssetRfqInfo{} - mi := &file_client_proto_msgTypes[76] + mi := &file_client_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6440,7 +6585,7 @@ func (x *AssetRfqInfo) String() string { func (*AssetRfqInfo) ProtoMessage() {} func (x *AssetRfqInfo) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[76] + mi := &file_client_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6453,7 +6598,7 @@ func (x *AssetRfqInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use AssetRfqInfo.ProtoReflect.Descriptor instead. func (*AssetRfqInfo) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{76} + return file_client_proto_rawDescGZIP(), []int{78} } func (x *AssetRfqInfo) GetPrepayRfqId() []byte { @@ -6542,7 +6687,7 @@ type FixedPoint struct { func (x *FixedPoint) Reset() { *x = FixedPoint{} - mi := &file_client_proto_msgTypes[77] + mi := &file_client_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6554,7 +6699,7 @@ func (x *FixedPoint) String() string { func (*FixedPoint) ProtoMessage() {} func (x *FixedPoint) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[77] + mi := &file_client_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6567,7 +6712,7 @@ func (x *FixedPoint) ProtoReflect() protoreflect.Message { // Deprecated: Use FixedPoint.ProtoReflect.Descriptor instead. func (*FixedPoint) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{77} + return file_client_proto_rawDescGZIP(), []int{79} } func (x *FixedPoint) GetCoefficient() string { @@ -6598,7 +6743,7 @@ type AssetLoopOutInfo struct { func (x *AssetLoopOutInfo) Reset() { *x = AssetLoopOutInfo{} - mi := &file_client_proto_msgTypes[78] + mi := &file_client_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6610,7 +6755,7 @@ func (x *AssetLoopOutInfo) String() string { func (*AssetLoopOutInfo) ProtoMessage() {} func (x *AssetLoopOutInfo) ProtoReflect() protoreflect.Message { - mi := &file_client_proto_msgTypes[78] + mi := &file_client_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6623,7 +6768,7 @@ func (x *AssetLoopOutInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use AssetLoopOutInfo.ProtoReflect.Descriptor instead. func (*AssetLoopOutInfo) Descriptor() ([]byte, []int) { - return file_client_proto_rawDescGZIP(), []int{78} + return file_client_proto_rawDescGZIP(), []int{80} } func (x *AssetLoopOutInfo) GetAssetId() string { @@ -6952,24 +7097,33 @@ const file_client_proto_rawDesc = "" + "\x05state\x18\x02 \x01(\tR\x05state\x12\x16\n" + "\x06amount\x18\x03 \x01(\x04R\x06amount\x12'\n" + "\x0freservation_ids\x18\x04 \x03(\fR\x0ereservationIds\x12\x1e\n" + - "\vsweep_tx_id\x18\x05 \x01(\tR\tsweepTxId\"8\n" + + "\vsweep_tx_id\x18\x05 \x01(\tR\tsweepTxId\"N\n" + "\x17NewStaticAddressRequest\x12\x1d\n" + "\n" + - "client_key\x18\x01 \x01(\fR\tclientKey\"L\n" + + "client_key\x18\x01 \x01(\fR\tclientKey\x12\x14\n" + + "\x05label\x18\x02 \x01(\tR\x05label\"b\n" + "\x18NewStaticAddressResponse\x12\x18\n" + "\aaddress\x18\x01 \x01(\tR\aaddress\x12\x16\n" + - "\x06expiry\x18\x02 \x01(\rR\x06expiry\"V\n" + + "\x06expiry\x18\x02 \x01(\rR\x06expiry\x12\x14\n" + + "\x05label\x18\x03 \x01(\tR\x05label\"^\n" + + "\x1fUpdateStaticAddressLabelRequest\x12%\n" + + "\x0estatic_address\x18\x01 \x01(\tR\rstaticAddress\x12\x14\n" + + "\x05label\x18\x02 \x01(\tR\x05label\"_\n" + + " UpdateStaticAddressLabelResponse\x12%\n" + + "\x0estatic_address\x18\x01 \x01(\tR\rstaticAddress\x12\x14\n" + + "\x05label\x18\x02 \x01(\tR\x05label\"V\n" + "\x1aListUnspentDepositsRequest\x12\x1b\n" + "\tmin_confs\x18\x01 \x01(\x05R\bminConfs\x12\x1b\n" + "\tmax_confs\x18\x02 \x01(\x05R\bmaxConfs\"B\n" + "\x1bListUnspentDepositsResponse\x12#\n" + - "\x05utxos\x18\x01 \x03(\v2\r.looprpc.UtxoR\x05utxos\"\x8e\x01\n" + + "\x05utxos\x18\x01 \x03(\v2\r.looprpc.UtxoR\x05utxos\"\xa4\x01\n" + "\x04Utxo\x12%\n" + "\x0estatic_address\x18\x01 \x01(\tR\rstaticAddress\x12\x1d\n" + "\n" + "amount_sat\x18\x02 \x01(\x03R\tamountSat\x12\x1a\n" + "\boutpoint\x18\x03 \x01(\tR\boutpoint\x12$\n" + - "\rconfirmations\x18\x04 \x01(\x03R\rconfirmations\"\xb3\x01\n" + + "\rconfirmations\x18\x04 \x01(\x03R\rconfirmations\x12\x14\n" + + "\x05label\x18\x05 \x01(\tR\x05label\"\xb3\x01\n" + "\x17WithdrawDepositsRequest\x12-\n" + "\toutpoints\x18\x01 \x03(\v2\x0f.lnrpc.OutPointR\toutpoints\x12\x10\n" + "\x03all\x18\x02 \x01(\bR\x03all\x12\x1b\n" + @@ -6990,7 +7144,7 @@ const file_client_proto_rawDesc = "" + "\x1dListStaticAddressSwapsRequest\"X\n" + "\x1eListStaticAddressSwapsResponse\x126\n" + "\x05swaps\x18\x01 \x03(\v2 .looprpc.StaticAddressLoopInSwapR\x05swaps\"\x1d\n" + - "\x1bStaticAddressSummaryRequest\"\xca\x04\n" + + "\x1bStaticAddressSummaryRequest\"\xe0\x04\n" + "\x1cStaticAddressSummaryResponse\x12%\n" + "\x0estatic_address\x18\x01 \x01(\tR\rstaticAddress\x124\n" + "\x16relative_expiry_blocks\x18\x02 \x01(\x04R\x14relativeExpiryBlocks\x12,\n" + @@ -7002,7 +7156,8 @@ const file_client_proto_rawDesc = "" + "\x18value_looped_in_satoshis\x18\b \x01(\x03R\x15valueLoopedInSatoshis\x12J\n" + "\"value_htlc_timeout_sweeps_satoshis\x18\t \x01(\x03R\x1evalueHtlcTimeoutSweepsSatoshis\x122\n" + "\x15value_channels_opened\x18\n" + - " \x01(\x03R\x13valueChannelsOpened\"\xf6\x01\n" + + " \x01(\x03R\x13valueChannelsOpened\x12\x14\n" + + "\x05label\x18\v \x01(\tR\x05label\"\xf6\x01\n" + "\aDeposit\x12\x0e\n" + "\x02id\x18\x01 \x01(\fR\x02id\x12+\n" + "\x05state\x18\x02 \x01(\x0e2\x15.looprpc.DepositStateR\x05state\x12\x1a\n" + @@ -7165,7 +7320,7 @@ const file_client_proto_rawDesc = "" + "\x1eSUCCEEDED_TRANSITIONING_FAILED\x10\t\x12\x13\n" + "\x0fUNLOCK_DEPOSITS\x10\n" + "\x12\x1e\n" + - "\x1aFAILED_STATIC_ADDRESS_SWAP\x10\v2\xca\x14\n" + + "\x1aFAILED_STATIC_ADDRESS_SWAP\x10\v2\xbb\x15\n" + "\n" + "SwapClient\x129\n" + "\aLoopOut\x12\x17.looprpc.LoopOutRequest\x1a\x15.looprpc.SwapResponse\x127\n" + @@ -7194,7 +7349,8 @@ const file_client_proto_rawDesc = "" + "InstantOut\x12\x1a.looprpc.InstantOutRequest\x1a\x1b.looprpc.InstantOutResponse\x12T\n" + "\x0fInstantOutQuote\x12\x1f.looprpc.InstantOutQuoteRequest\x1a .looprpc.InstantOutQuoteResponse\x12T\n" + "\x0fListInstantOuts\x12\x1f.looprpc.ListInstantOutsRequest\x1a .looprpc.ListInstantOutsResponse\x12W\n" + - "\x10NewStaticAddress\x12 .looprpc.NewStaticAddressRequest\x1a!.looprpc.NewStaticAddressResponse\x12`\n" + + "\x10NewStaticAddress\x12 .looprpc.NewStaticAddressRequest\x1a!.looprpc.NewStaticAddressResponse\x12o\n" + + "\x18UpdateStaticAddressLabel\x12(.looprpc.UpdateStaticAddressLabelRequest\x1a).looprpc.UpdateStaticAddressLabelResponse\x12`\n" + "\x13ListUnspentDeposits\x12#.looprpc.ListUnspentDepositsRequest\x1a$.looprpc.ListUnspentDepositsResponse\x12W\n" + "\x10WithdrawDeposits\x12 .looprpc.WithdrawDepositsRequest\x1a!.looprpc.WithdrawDepositsResponse\x12r\n" + "\x19ListStaticAddressDeposits\x12).looprpc.ListStaticAddressDepositsRequest\x1a*.looprpc.ListStaticAddressDepositsResponse\x12y\n" + @@ -7217,7 +7373,7 @@ func file_client_proto_rawDescGZIP() []byte { } var file_client_proto_enumTypes = make([]protoimpl.EnumInfo, 10) -var file_client_proto_msgTypes = make([]protoimpl.MessageInfo, 80) +var file_client_proto_msgTypes = make([]protoimpl.MessageInfo, 82) var file_client_proto_goTypes = []any{ (AddressType)(0), // 0: looprpc.AddressType (SwapType)(0), // 1: looprpc.SwapType @@ -7286,59 +7442,61 @@ var file_client_proto_goTypes = []any{ (*InstantOut)(nil), // 64: looprpc.InstantOut (*NewStaticAddressRequest)(nil), // 65: looprpc.NewStaticAddressRequest (*NewStaticAddressResponse)(nil), // 66: looprpc.NewStaticAddressResponse - (*ListUnspentDepositsRequest)(nil), // 67: looprpc.ListUnspentDepositsRequest - (*ListUnspentDepositsResponse)(nil), // 68: looprpc.ListUnspentDepositsResponse - (*Utxo)(nil), // 69: looprpc.Utxo - (*WithdrawDepositsRequest)(nil), // 70: looprpc.WithdrawDepositsRequest - (*WithdrawDepositsResponse)(nil), // 71: looprpc.WithdrawDepositsResponse - (*ListStaticAddressDepositsRequest)(nil), // 72: looprpc.ListStaticAddressDepositsRequest - (*ListStaticAddressDepositsResponse)(nil), // 73: looprpc.ListStaticAddressDepositsResponse - (*ListStaticAddressWithdrawalRequest)(nil), // 74: looprpc.ListStaticAddressWithdrawalRequest - (*ListStaticAddressWithdrawalResponse)(nil), // 75: looprpc.ListStaticAddressWithdrawalResponse - (*ListStaticAddressSwapsRequest)(nil), // 76: looprpc.ListStaticAddressSwapsRequest - (*ListStaticAddressSwapsResponse)(nil), // 77: looprpc.ListStaticAddressSwapsResponse - (*StaticAddressSummaryRequest)(nil), // 78: looprpc.StaticAddressSummaryRequest - (*StaticAddressSummaryResponse)(nil), // 79: looprpc.StaticAddressSummaryResponse - (*Deposit)(nil), // 80: looprpc.Deposit - (*StaticAddressWithdrawal)(nil), // 81: looprpc.StaticAddressWithdrawal - (*StaticAddressLoopInSwap)(nil), // 82: looprpc.StaticAddressLoopInSwap - (*StaticAddressLoopInRequest)(nil), // 83: looprpc.StaticAddressLoopInRequest - (*StaticAddressLoopInResponse)(nil), // 84: looprpc.StaticAddressLoopInResponse - (*AssetLoopOutRequest)(nil), // 85: looprpc.AssetLoopOutRequest - (*AssetRfqInfo)(nil), // 86: looprpc.AssetRfqInfo - (*FixedPoint)(nil), // 87: looprpc.FixedPoint - (*AssetLoopOutInfo)(nil), // 88: looprpc.AssetLoopOutInfo - nil, // 89: looprpc.LiquidityParameters.EasyAssetParamsEntry - (*lnrpc.OpenChannelRequest)(nil), // 90: lnrpc.OpenChannelRequest - (*swapserverrpc.RouteHint)(nil), // 91: looprpc.RouteHint - (*lnrpc.OutPoint)(nil), // 92: lnrpc.OutPoint + (*UpdateStaticAddressLabelRequest)(nil), // 67: looprpc.UpdateStaticAddressLabelRequest + (*UpdateStaticAddressLabelResponse)(nil), // 68: looprpc.UpdateStaticAddressLabelResponse + (*ListUnspentDepositsRequest)(nil), // 69: looprpc.ListUnspentDepositsRequest + (*ListUnspentDepositsResponse)(nil), // 70: looprpc.ListUnspentDepositsResponse + (*Utxo)(nil), // 71: looprpc.Utxo + (*WithdrawDepositsRequest)(nil), // 72: looprpc.WithdrawDepositsRequest + (*WithdrawDepositsResponse)(nil), // 73: looprpc.WithdrawDepositsResponse + (*ListStaticAddressDepositsRequest)(nil), // 74: looprpc.ListStaticAddressDepositsRequest + (*ListStaticAddressDepositsResponse)(nil), // 75: looprpc.ListStaticAddressDepositsResponse + (*ListStaticAddressWithdrawalRequest)(nil), // 76: looprpc.ListStaticAddressWithdrawalRequest + (*ListStaticAddressWithdrawalResponse)(nil), // 77: looprpc.ListStaticAddressWithdrawalResponse + (*ListStaticAddressSwapsRequest)(nil), // 78: looprpc.ListStaticAddressSwapsRequest + (*ListStaticAddressSwapsResponse)(nil), // 79: looprpc.ListStaticAddressSwapsResponse + (*StaticAddressSummaryRequest)(nil), // 80: looprpc.StaticAddressSummaryRequest + (*StaticAddressSummaryResponse)(nil), // 81: looprpc.StaticAddressSummaryResponse + (*Deposit)(nil), // 82: looprpc.Deposit + (*StaticAddressWithdrawal)(nil), // 83: looprpc.StaticAddressWithdrawal + (*StaticAddressLoopInSwap)(nil), // 84: looprpc.StaticAddressLoopInSwap + (*StaticAddressLoopInRequest)(nil), // 85: looprpc.StaticAddressLoopInRequest + (*StaticAddressLoopInResponse)(nil), // 86: looprpc.StaticAddressLoopInResponse + (*AssetLoopOutRequest)(nil), // 87: looprpc.AssetLoopOutRequest + (*AssetRfqInfo)(nil), // 88: looprpc.AssetRfqInfo + (*FixedPoint)(nil), // 89: looprpc.FixedPoint + (*AssetLoopOutInfo)(nil), // 90: looprpc.AssetLoopOutInfo + nil, // 91: looprpc.LiquidityParameters.EasyAssetParamsEntry + (*lnrpc.OpenChannelRequest)(nil), // 92: lnrpc.OpenChannelRequest + (*swapserverrpc.RouteHint)(nil), // 93: looprpc.RouteHint + (*lnrpc.OutPoint)(nil), // 94: lnrpc.OutPoint } var file_client_proto_depIdxs = []int32{ - 90, // 0: looprpc.StaticOpenChannelRequest.open_channel_request:type_name -> lnrpc.OpenChannelRequest + 92, // 0: looprpc.StaticOpenChannelRequest.open_channel_request:type_name -> lnrpc.OpenChannelRequest 0, // 1: looprpc.LoopOutRequest.account_addr_type:type_name -> looprpc.AddressType - 85, // 2: looprpc.LoopOutRequest.asset_info:type_name -> looprpc.AssetLoopOutRequest - 86, // 3: looprpc.LoopOutRequest.asset_rfq_info:type_name -> looprpc.AssetRfqInfo - 91, // 4: looprpc.LoopInRequest.route_hints:type_name -> looprpc.RouteHint + 87, // 2: looprpc.LoopOutRequest.asset_info:type_name -> looprpc.AssetLoopOutRequest + 88, // 3: looprpc.LoopOutRequest.asset_rfq_info:type_name -> looprpc.AssetRfqInfo + 93, // 4: looprpc.LoopInRequest.route_hints:type_name -> looprpc.RouteHint 1, // 5: looprpc.SwapStatus.type:type_name -> looprpc.SwapType 2, // 6: looprpc.SwapStatus.state:type_name -> looprpc.SwapState 3, // 7: looprpc.SwapStatus.failure_reason:type_name -> looprpc.FailureReason - 88, // 8: looprpc.SwapStatus.asset_info:type_name -> looprpc.AssetLoopOutInfo + 90, // 8: looprpc.SwapStatus.asset_info:type_name -> looprpc.AssetLoopOutInfo 20, // 9: looprpc.ListSwapsRequest.list_swap_filter:type_name -> looprpc.ListSwapsFilter 9, // 10: looprpc.ListSwapsFilter.swap_type:type_name -> looprpc.ListSwapsFilter.SwapTypeFilter 18, // 11: looprpc.ListSwapsResponse.swaps:type_name -> looprpc.SwapStatus 24, // 12: looprpc.SweepHtlcResponse.not_requested:type_name -> looprpc.PublishNotRequested 25, // 13: looprpc.SweepHtlcResponse.published:type_name -> looprpc.PublishSucceeded 26, // 14: looprpc.SweepHtlcResponse.failed:type_name -> looprpc.PublishFailed - 91, // 15: looprpc.QuoteRequest.loop_in_route_hints:type_name -> looprpc.RouteHint - 85, // 16: looprpc.QuoteRequest.asset_info:type_name -> looprpc.AssetLoopOutRequest - 86, // 17: looprpc.OutQuoteResponse.asset_rfq_info:type_name -> looprpc.AssetRfqInfo - 91, // 18: looprpc.ProbeRequest.route_hints:type_name -> looprpc.RouteHint + 93, // 15: looprpc.QuoteRequest.loop_in_route_hints:type_name -> looprpc.RouteHint + 87, // 16: looprpc.QuoteRequest.asset_info:type_name -> looprpc.AssetLoopOutRequest + 88, // 17: looprpc.OutQuoteResponse.asset_rfq_info:type_name -> looprpc.AssetRfqInfo + 93, // 18: looprpc.ProbeRequest.route_hints:type_name -> looprpc.RouteHint 40, // 19: looprpc.TokensResponse.tokens:type_name -> looprpc.L402Token 41, // 20: looprpc.GetInfoResponse.loop_out_stats:type_name -> looprpc.LoopStats 41, // 21: looprpc.GetInfoResponse.loop_in_stats:type_name -> looprpc.LoopStats 47, // 22: looprpc.LiquidityParameters.rules:type_name -> looprpc.LiquidityRule 0, // 23: looprpc.LiquidityParameters.account_addr_type:type_name -> looprpc.AddressType - 89, // 24: looprpc.LiquidityParameters.easy_asset_params:type_name -> looprpc.LiquidityParameters.EasyAssetParamsEntry + 91, // 24: looprpc.LiquidityParameters.easy_asset_params:type_name -> looprpc.LiquidityParameters.EasyAssetParamsEntry 4, // 25: looprpc.LiquidityParameters.loop_in_source:type_name -> looprpc.LoopInSource 1, // 26: looprpc.LiquidityRule.swap_type:type_name -> looprpc.SwapType 5, // 27: looprpc.LiquidityRule.type:type_name -> looprpc.LiquidityRuleType @@ -7346,24 +7504,24 @@ var file_client_proto_depIdxs = []int32{ 6, // 29: looprpc.Disqualified.reason:type_name -> looprpc.AutoReason 14, // 30: looprpc.SuggestSwapsResponse.loop_out:type_name -> looprpc.LoopOutRequest 15, // 31: looprpc.SuggestSwapsResponse.loop_in:type_name -> looprpc.LoopInRequest - 83, // 32: looprpc.SuggestSwapsResponse.static_loop_in:type_name -> looprpc.StaticAddressLoopInRequest + 85, // 32: looprpc.SuggestSwapsResponse.static_loop_in:type_name -> looprpc.StaticAddressLoopInRequest 51, // 33: looprpc.SuggestSwapsResponse.disqualified:type_name -> looprpc.Disqualified 57, // 34: looprpc.ListReservationsResponse.reservations:type_name -> looprpc.ClientReservation 64, // 35: looprpc.ListInstantOutsResponse.swaps:type_name -> looprpc.InstantOut - 69, // 36: looprpc.ListUnspentDepositsResponse.utxos:type_name -> looprpc.Utxo - 92, // 37: looprpc.WithdrawDepositsRequest.outpoints:type_name -> lnrpc.OutPoint + 71, // 36: looprpc.ListUnspentDepositsResponse.utxos:type_name -> looprpc.Utxo + 94, // 37: looprpc.WithdrawDepositsRequest.outpoints:type_name -> lnrpc.OutPoint 7, // 38: looprpc.ListStaticAddressDepositsRequest.state_filter:type_name -> looprpc.DepositState - 80, // 39: looprpc.ListStaticAddressDepositsResponse.filtered_deposits:type_name -> looprpc.Deposit - 81, // 40: looprpc.ListStaticAddressWithdrawalResponse.withdrawals:type_name -> looprpc.StaticAddressWithdrawal - 82, // 41: looprpc.ListStaticAddressSwapsResponse.swaps:type_name -> looprpc.StaticAddressLoopInSwap + 82, // 39: looprpc.ListStaticAddressDepositsResponse.filtered_deposits:type_name -> looprpc.Deposit + 83, // 40: looprpc.ListStaticAddressWithdrawalResponse.withdrawals:type_name -> looprpc.StaticAddressWithdrawal + 84, // 41: looprpc.ListStaticAddressSwapsResponse.swaps:type_name -> looprpc.StaticAddressLoopInSwap 7, // 42: looprpc.Deposit.state:type_name -> looprpc.DepositState - 80, // 43: looprpc.StaticAddressWithdrawal.deposits:type_name -> looprpc.Deposit + 82, // 43: looprpc.StaticAddressWithdrawal.deposits:type_name -> looprpc.Deposit 8, // 44: looprpc.StaticAddressLoopInSwap.state:type_name -> looprpc.StaticAddressLoopInSwapState - 80, // 45: looprpc.StaticAddressLoopInSwap.deposits:type_name -> looprpc.Deposit - 91, // 46: looprpc.StaticAddressLoopInRequest.route_hints:type_name -> looprpc.RouteHint - 80, // 47: looprpc.StaticAddressLoopInResponse.used_deposits:type_name -> looprpc.Deposit - 87, // 48: looprpc.AssetRfqInfo.prepay_asset_rate:type_name -> looprpc.FixedPoint - 87, // 49: looprpc.AssetRfqInfo.swap_asset_rate:type_name -> looprpc.FixedPoint + 82, // 45: looprpc.StaticAddressLoopInSwap.deposits:type_name -> looprpc.Deposit + 93, // 46: looprpc.StaticAddressLoopInRequest.route_hints:type_name -> looprpc.RouteHint + 82, // 47: looprpc.StaticAddressLoopInResponse.used_deposits:type_name -> looprpc.Deposit + 89, // 48: looprpc.AssetRfqInfo.prepay_asset_rate:type_name -> looprpc.FixedPoint + 89, // 49: looprpc.AssetRfqInfo.swap_asset_rate:type_name -> looprpc.FixedPoint 46, // 50: looprpc.LiquidityParameters.EasyAssetParamsEntry.value:type_name -> looprpc.EasyAssetAutoloopParams 14, // 51: looprpc.SwapClient.LoopOut:input_type -> looprpc.LoopOutRequest 15, // 52: looprpc.SwapClient.LoopIn:input_type -> looprpc.LoopInRequest @@ -7390,49 +7548,51 @@ var file_client_proto_depIdxs = []int32{ 60, // 73: looprpc.SwapClient.InstantOutQuote:input_type -> looprpc.InstantOutQuoteRequest 62, // 74: looprpc.SwapClient.ListInstantOuts:input_type -> looprpc.ListInstantOutsRequest 65, // 75: looprpc.SwapClient.NewStaticAddress:input_type -> looprpc.NewStaticAddressRequest - 67, // 76: looprpc.SwapClient.ListUnspentDeposits:input_type -> looprpc.ListUnspentDepositsRequest - 70, // 77: looprpc.SwapClient.WithdrawDeposits:input_type -> looprpc.WithdrawDepositsRequest - 72, // 78: looprpc.SwapClient.ListStaticAddressDeposits:input_type -> looprpc.ListStaticAddressDepositsRequest - 74, // 79: looprpc.SwapClient.ListStaticAddressWithdrawals:input_type -> looprpc.ListStaticAddressWithdrawalRequest - 76, // 80: looprpc.SwapClient.ListStaticAddressSwaps:input_type -> looprpc.ListStaticAddressSwapsRequest - 78, // 81: looprpc.SwapClient.GetStaticAddressSummary:input_type -> looprpc.StaticAddressSummaryRequest - 83, // 82: looprpc.SwapClient.StaticAddressLoopIn:input_type -> looprpc.StaticAddressLoopInRequest - 10, // 83: looprpc.SwapClient.StaticOpenChannel:input_type -> looprpc.StaticOpenChannelRequest - 16, // 84: looprpc.SwapClient.LoopOut:output_type -> looprpc.SwapResponse - 16, // 85: looprpc.SwapClient.LoopIn:output_type -> looprpc.SwapResponse - 18, // 86: looprpc.SwapClient.Monitor:output_type -> looprpc.SwapStatus - 21, // 87: looprpc.SwapClient.ListSwaps:output_type -> looprpc.ListSwapsResponse - 23, // 88: looprpc.SwapClient.SweepHtlc:output_type -> looprpc.SweepHtlcResponse - 18, // 89: looprpc.SwapClient.SwapInfo:output_type -> looprpc.SwapStatus - 54, // 90: looprpc.SwapClient.AbandonSwap:output_type -> looprpc.AbandonSwapResponse - 30, // 91: looprpc.SwapClient.LoopOutTerms:output_type -> looprpc.OutTermsResponse - 33, // 92: looprpc.SwapClient.LoopOutQuote:output_type -> looprpc.OutQuoteResponse - 29, // 93: looprpc.SwapClient.GetLoopInTerms:output_type -> looprpc.InTermsResponse - 32, // 94: looprpc.SwapClient.GetLoopInQuote:output_type -> looprpc.InQuoteResponse - 35, // 95: looprpc.SwapClient.Probe:output_type -> looprpc.ProbeResponse - 37, // 96: looprpc.SwapClient.GetL402Tokens:output_type -> looprpc.TokensResponse - 37, // 97: looprpc.SwapClient.GetLsatTokens:output_type -> looprpc.TokensResponse - 39, // 98: looprpc.SwapClient.FetchL402Token:output_type -> looprpc.FetchL402TokenResponse - 43, // 99: looprpc.SwapClient.GetInfo:output_type -> looprpc.GetInfoResponse - 13, // 100: looprpc.SwapClient.StopDaemon:output_type -> looprpc.StopDaemonResponse - 45, // 101: looprpc.SwapClient.GetLiquidityParams:output_type -> looprpc.LiquidityParameters - 49, // 102: looprpc.SwapClient.SetLiquidityParams:output_type -> looprpc.SetLiquidityParamsResponse - 52, // 103: looprpc.SwapClient.SuggestSwaps:output_type -> looprpc.SuggestSwapsResponse - 56, // 104: looprpc.SwapClient.ListReservations:output_type -> looprpc.ListReservationsResponse - 59, // 105: looprpc.SwapClient.InstantOut:output_type -> looprpc.InstantOutResponse - 61, // 106: looprpc.SwapClient.InstantOutQuote:output_type -> looprpc.InstantOutQuoteResponse - 63, // 107: looprpc.SwapClient.ListInstantOuts:output_type -> looprpc.ListInstantOutsResponse - 66, // 108: looprpc.SwapClient.NewStaticAddress:output_type -> looprpc.NewStaticAddressResponse - 68, // 109: looprpc.SwapClient.ListUnspentDeposits:output_type -> looprpc.ListUnspentDepositsResponse - 71, // 110: looprpc.SwapClient.WithdrawDeposits:output_type -> looprpc.WithdrawDepositsResponse - 73, // 111: looprpc.SwapClient.ListStaticAddressDeposits:output_type -> looprpc.ListStaticAddressDepositsResponse - 75, // 112: looprpc.SwapClient.ListStaticAddressWithdrawals:output_type -> looprpc.ListStaticAddressWithdrawalResponse - 77, // 113: looprpc.SwapClient.ListStaticAddressSwaps:output_type -> looprpc.ListStaticAddressSwapsResponse - 79, // 114: looprpc.SwapClient.GetStaticAddressSummary:output_type -> looprpc.StaticAddressSummaryResponse - 84, // 115: looprpc.SwapClient.StaticAddressLoopIn:output_type -> looprpc.StaticAddressLoopInResponse - 11, // 116: looprpc.SwapClient.StaticOpenChannel:output_type -> looprpc.StaticOpenChannelResponse - 84, // [84:117] is the sub-list for method output_type - 51, // [51:84] is the sub-list for method input_type + 67, // 76: looprpc.SwapClient.UpdateStaticAddressLabel:input_type -> looprpc.UpdateStaticAddressLabelRequest + 69, // 77: looprpc.SwapClient.ListUnspentDeposits:input_type -> looprpc.ListUnspentDepositsRequest + 72, // 78: looprpc.SwapClient.WithdrawDeposits:input_type -> looprpc.WithdrawDepositsRequest + 74, // 79: looprpc.SwapClient.ListStaticAddressDeposits:input_type -> looprpc.ListStaticAddressDepositsRequest + 76, // 80: looprpc.SwapClient.ListStaticAddressWithdrawals:input_type -> looprpc.ListStaticAddressWithdrawalRequest + 78, // 81: looprpc.SwapClient.ListStaticAddressSwaps:input_type -> looprpc.ListStaticAddressSwapsRequest + 80, // 82: looprpc.SwapClient.GetStaticAddressSummary:input_type -> looprpc.StaticAddressSummaryRequest + 85, // 83: looprpc.SwapClient.StaticAddressLoopIn:input_type -> looprpc.StaticAddressLoopInRequest + 10, // 84: looprpc.SwapClient.StaticOpenChannel:input_type -> looprpc.StaticOpenChannelRequest + 16, // 85: looprpc.SwapClient.LoopOut:output_type -> looprpc.SwapResponse + 16, // 86: looprpc.SwapClient.LoopIn:output_type -> looprpc.SwapResponse + 18, // 87: looprpc.SwapClient.Monitor:output_type -> looprpc.SwapStatus + 21, // 88: looprpc.SwapClient.ListSwaps:output_type -> looprpc.ListSwapsResponse + 23, // 89: looprpc.SwapClient.SweepHtlc:output_type -> looprpc.SweepHtlcResponse + 18, // 90: looprpc.SwapClient.SwapInfo:output_type -> looprpc.SwapStatus + 54, // 91: looprpc.SwapClient.AbandonSwap:output_type -> looprpc.AbandonSwapResponse + 30, // 92: looprpc.SwapClient.LoopOutTerms:output_type -> looprpc.OutTermsResponse + 33, // 93: looprpc.SwapClient.LoopOutQuote:output_type -> looprpc.OutQuoteResponse + 29, // 94: looprpc.SwapClient.GetLoopInTerms:output_type -> looprpc.InTermsResponse + 32, // 95: looprpc.SwapClient.GetLoopInQuote:output_type -> looprpc.InQuoteResponse + 35, // 96: looprpc.SwapClient.Probe:output_type -> looprpc.ProbeResponse + 37, // 97: looprpc.SwapClient.GetL402Tokens:output_type -> looprpc.TokensResponse + 37, // 98: looprpc.SwapClient.GetLsatTokens:output_type -> looprpc.TokensResponse + 39, // 99: looprpc.SwapClient.FetchL402Token:output_type -> looprpc.FetchL402TokenResponse + 43, // 100: looprpc.SwapClient.GetInfo:output_type -> looprpc.GetInfoResponse + 13, // 101: looprpc.SwapClient.StopDaemon:output_type -> looprpc.StopDaemonResponse + 45, // 102: looprpc.SwapClient.GetLiquidityParams:output_type -> looprpc.LiquidityParameters + 49, // 103: looprpc.SwapClient.SetLiquidityParams:output_type -> looprpc.SetLiquidityParamsResponse + 52, // 104: looprpc.SwapClient.SuggestSwaps:output_type -> looprpc.SuggestSwapsResponse + 56, // 105: looprpc.SwapClient.ListReservations:output_type -> looprpc.ListReservationsResponse + 59, // 106: looprpc.SwapClient.InstantOut:output_type -> looprpc.InstantOutResponse + 61, // 107: looprpc.SwapClient.InstantOutQuote:output_type -> looprpc.InstantOutQuoteResponse + 63, // 108: looprpc.SwapClient.ListInstantOuts:output_type -> looprpc.ListInstantOutsResponse + 66, // 109: looprpc.SwapClient.NewStaticAddress:output_type -> looprpc.NewStaticAddressResponse + 68, // 110: looprpc.SwapClient.UpdateStaticAddressLabel:output_type -> looprpc.UpdateStaticAddressLabelResponse + 70, // 111: looprpc.SwapClient.ListUnspentDeposits:output_type -> looprpc.ListUnspentDepositsResponse + 73, // 112: looprpc.SwapClient.WithdrawDeposits:output_type -> looprpc.WithdrawDepositsResponse + 75, // 113: looprpc.SwapClient.ListStaticAddressDeposits:output_type -> looprpc.ListStaticAddressDepositsResponse + 77, // 114: looprpc.SwapClient.ListStaticAddressWithdrawals:output_type -> looprpc.ListStaticAddressWithdrawalResponse + 79, // 115: looprpc.SwapClient.ListStaticAddressSwaps:output_type -> looprpc.ListStaticAddressSwapsResponse + 81, // 116: looprpc.SwapClient.GetStaticAddressSummary:output_type -> looprpc.StaticAddressSummaryResponse + 86, // 117: looprpc.SwapClient.StaticAddressLoopIn:output_type -> looprpc.StaticAddressLoopInResponse + 11, // 118: looprpc.SwapClient.StaticOpenChannel:output_type -> looprpc.StaticOpenChannelResponse + 85, // [85:119] is the sub-list for method output_type + 51, // [51:85] is the sub-list for method input_type 51, // [51:51] is the sub-list for extension type_name 51, // [51:51] is the sub-list for extension extendee 0, // [0:51] is the sub-list for field type_name @@ -7454,7 +7614,7 @@ func file_client_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_client_proto_rawDesc), len(file_client_proto_rawDesc)), NumEnums: 10, - NumMessages: 80, + NumMessages: 82, NumExtensions: 0, NumServices: 1, }, diff --git a/looprpc/client.pb.gw.go b/looprpc/client.pb.gw.go index c2ef63f88..a2ad8a2de 100644 --- a/looprpc/client.pb.gw.go +++ b/looprpc/client.pb.gw.go @@ -691,6 +691,32 @@ func local_request_SwapClient_NewStaticAddress_0(ctx context.Context, marshaler } +func request_SwapClient_UpdateStaticAddressLabel_0(ctx context.Context, marshaler runtime.Marshaler, client SwapClientClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateStaticAddressLabelRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpdateStaticAddressLabel(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_SwapClient_UpdateStaticAddressLabel_0(ctx context.Context, marshaler runtime.Marshaler, server SwapClientServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateStaticAddressLabelRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.UpdateStaticAddressLabel(ctx, &protoReq) + return msg, metadata, err + +} + var ( filter_SwapClient_ListUnspentDeposits_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) @@ -1425,6 +1451,31 @@ func RegisterSwapClientHandlerServer(ctx context.Context, mux *runtime.ServeMux, }) + mux.Handle("POST", pattern_SwapClient_UpdateStaticAddressLabel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/looprpc.SwapClient/UpdateStaticAddressLabel", runtime.WithHTTPPathPattern("/v1/staticaddr/label")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_SwapClient_UpdateStaticAddressLabel_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_SwapClient_UpdateStaticAddressLabel_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_SwapClient_ListUnspentDeposits_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2125,6 +2176,28 @@ func RegisterSwapClientHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) + mux.Handle("POST", pattern_SwapClient_UpdateStaticAddressLabel_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/looprpc.SwapClient/UpdateStaticAddressLabel", runtime.WithHTTPPathPattern("/v1/staticaddr/label")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_SwapClient_UpdateStaticAddressLabel_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_SwapClient_UpdateStaticAddressLabel_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_SwapClient_ListUnspentDeposits_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2327,6 +2400,8 @@ var ( pattern_SwapClient_NewStaticAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "staticaddr"}, "")) + pattern_SwapClient_UpdateStaticAddressLabel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "staticaddr", "label"}, "")) + pattern_SwapClient_ListUnspentDeposits_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "staticaddr", "deposits", "unspent"}, "")) pattern_SwapClient_WithdrawDeposits_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "staticaddr", "withdraw"}, "")) @@ -2387,6 +2462,8 @@ var ( forward_SwapClient_NewStaticAddress_0 = runtime.ForwardResponseMessage + forward_SwapClient_UpdateStaticAddressLabel_0 = runtime.ForwardResponseMessage + forward_SwapClient_ListUnspentDeposits_0 = runtime.ForwardResponseMessage forward_SwapClient_WithdrawDeposits_0 = runtime.ForwardResponseMessage diff --git a/looprpc/client.proto b/looprpc/client.proto index 3ae690dc3..0f7ad880f 100644 --- a/looprpc/client.proto +++ b/looprpc/client.proto @@ -168,6 +168,12 @@ service SwapClient { rpc NewStaticAddress (NewStaticAddressRequest) returns (NewStaticAddressResponse); + /* loop: `static updatelabel` + UpdateStaticAddressLabel updates the local label for a static address. + */ + rpc UpdateStaticAddressLabel (UpdateStaticAddressLabelRequest) + returns (UpdateStaticAddressLabelResponse); + /* loop: `static listunspentdeposits` ListUnspentDeposits returns a list of utxos deposited at a static address. */ @@ -1767,6 +1773,11 @@ message NewStaticAddressRequest { The client's public key for the 2-of-2 MuSig2 taproot static address. */ bytes client_key = 1; + + /* + An optional label for this static address. Empty string means no label. + */ + string label = 2; } message NewStaticAddressResponse { @@ -1779,6 +1790,35 @@ message NewStaticAddressResponse { The CSV expiry of the static address. */ uint32 expiry = 2; + + /* + The label for this static address. Empty string means no label. + */ + string label = 3; +} + +message UpdateStaticAddressLabelRequest { + /* + The static address whose label should be updated. + */ + string static_address = 1; + + /* + The updated label for the static address. Empty string means no label. + */ + string label = 2; +} + +message UpdateStaticAddressLabelResponse { + /* + The static address whose label was updated. + */ + string static_address = 1; + + /* + The updated label for the static address. Empty string means no label. + */ + string label = 2; } message ListUnspentDepositsRequest { @@ -1821,6 +1861,12 @@ message Utxo { The number of confirmations for the Utxo. */ int64 confirmations = 4; + + /* + The label for the static address that owns this Utxo. Empty string means no + label. + */ + string label = 5; } message WithdrawDepositsRequest { @@ -1958,6 +2004,11 @@ message StaticAddressSummaryResponse { The total value of all deposits that have been used for channel openings. */ int64 value_channels_opened = 10; + + /* + The label for this static address. Empty string means no label. + */ + string label = 11; } enum DepositState { diff --git a/looprpc/client.swagger.json b/looprpc/client.swagger.json index a50814e4e..9140b6f13 100644 --- a/looprpc/client.swagger.json +++ b/looprpc/client.swagger.json @@ -1001,6 +1001,39 @@ ] } }, + "/v1/staticaddr/label": { + "post": { + "summary": "loop: `static updatelabel`\nUpdateStaticAddressLabel updates the local label for a static address.", + "operationId": "SwapClient_UpdateStaticAddressLabel", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/looprpcUpdateStaticAddressLabelResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/looprpcUpdateStaticAddressLabelRequest" + } + } + ], + "tags": [ + "SwapClient" + ] + } + }, "/v1/staticaddr/loopin": { "post": { "summary": "loop:`static in`\nStaticAddressLoopIn initiates a static address loop-in swap.", @@ -2515,6 +2548,10 @@ "type": "string", "format": "byte", "description": "The client's public key for the 2-of-2 MuSig2 taproot static address." + }, + "label": { + "type": "string", + "description": "An optional label for this static address. Empty string means no label." } } }, @@ -2529,6 +2566,10 @@ "type": "integer", "format": "int64", "description": "The CSV expiry of the static address." + }, + "label": { + "type": "string", + "description": "The label for this static address. Empty string means no label." } } }, @@ -2906,6 +2947,10 @@ "type": "string", "format": "int64", "description": "The total value of all deposits that have been used for channel openings." + }, + "label": { + "type": "string", + "description": "The label for this static address. Empty string means no label." } } }, @@ -3206,6 +3251,32 @@ } } }, + "looprpcUpdateStaticAddressLabelRequest": { + "type": "object", + "properties": { + "static_address": { + "type": "string", + "description": "The static address whose label should be updated." + }, + "label": { + "type": "string", + "description": "The updated label for the static address. Empty string means no label." + } + } + }, + "looprpcUpdateStaticAddressLabelResponse": { + "type": "object", + "properties": { + "static_address": { + "type": "string", + "description": "The static address whose label was updated." + }, + "label": { + "type": "string", + "description": "The updated label for the static address. Empty string means no label." + } + } + }, "looprpcUtxo": { "type": "object", "properties": { @@ -3226,6 +3297,10 @@ "type": "string", "format": "int64", "description": "The number of confirmations for the Utxo." + }, + "label": { + "type": "string", + "description": "The label for the static address that owns this Utxo. Empty string means no\nlabel." } } }, diff --git a/looprpc/client.yaml b/looprpc/client.yaml index 5213afe4d..1b30bca49 100644 --- a/looprpc/client.yaml +++ b/looprpc/client.yaml @@ -53,6 +53,9 @@ http: - selector: looprpc.SwapClient.NewStaticAddress post: "/v1/staticaddr" body: "*" + - selector: looprpc.SwapClient.UpdateStaticAddressLabel + post: "/v1/staticaddr/label" + body: "*" - selector: looprpc.SwapClient.ListUnspentDeposits get: "/v1/staticaddr/deposits/unspent" - selector: looprpc.SwapClient.WithdrawDeposits diff --git a/looprpc/client_grpc.pb.go b/looprpc/client_grpc.pb.go index b03cc9e87..351fce8c2 100644 --- a/looprpc/client_grpc.pb.go +++ b/looprpc/client_grpc.pb.go @@ -116,6 +116,9 @@ type SwapClientClient interface { // loop: `static newstaticaddress` // NewStaticAddress requests a new static address for loop-ins from the server. NewStaticAddress(ctx context.Context, in *NewStaticAddressRequest, opts ...grpc.CallOption) (*NewStaticAddressResponse, error) + // loop: `static updatelabel` + // UpdateStaticAddressLabel updates the local label for a static address. + UpdateStaticAddressLabel(ctx context.Context, in *UpdateStaticAddressLabelRequest, opts ...grpc.CallOption) (*UpdateStaticAddressLabelResponse, error) // loop: `static listunspentdeposits` // ListUnspentDeposits returns a list of utxos deposited at a static address. ListUnspentDeposits(ctx context.Context, in *ListUnspentDepositsRequest, opts ...grpc.CallOption) (*ListUnspentDepositsResponse, error) @@ -402,6 +405,15 @@ func (c *swapClientClient) NewStaticAddress(ctx context.Context, in *NewStaticAd return out, nil } +func (c *swapClientClient) UpdateStaticAddressLabel(ctx context.Context, in *UpdateStaticAddressLabelRequest, opts ...grpc.CallOption) (*UpdateStaticAddressLabelResponse, error) { + out := new(UpdateStaticAddressLabelResponse) + err := c.cc.Invoke(ctx, "/looprpc.SwapClient/UpdateStaticAddressLabel", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *swapClientClient) ListUnspentDeposits(ctx context.Context, in *ListUnspentDepositsRequest, opts ...grpc.CallOption) (*ListUnspentDepositsResponse, error) { out := new(ListUnspentDepositsResponse) err := c.cc.Invoke(ctx, "/looprpc.SwapClient/ListUnspentDeposits", in, out, opts...) @@ -576,6 +588,9 @@ type SwapClientServer interface { // loop: `static newstaticaddress` // NewStaticAddress requests a new static address for loop-ins from the server. NewStaticAddress(context.Context, *NewStaticAddressRequest) (*NewStaticAddressResponse, error) + // loop: `static updatelabel` + // UpdateStaticAddressLabel updates the local label for a static address. + UpdateStaticAddressLabel(context.Context, *UpdateStaticAddressLabelRequest) (*UpdateStaticAddressLabelResponse, error) // loop: `static listunspentdeposits` // ListUnspentDeposits returns a list of utxos deposited at a static address. ListUnspentDeposits(context.Context, *ListUnspentDepositsRequest) (*ListUnspentDepositsResponse, error) @@ -686,6 +701,9 @@ func (UnimplementedSwapClientServer) ListInstantOuts(context.Context, *ListInsta func (UnimplementedSwapClientServer) NewStaticAddress(context.Context, *NewStaticAddressRequest) (*NewStaticAddressResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method NewStaticAddress not implemented") } +func (UnimplementedSwapClientServer) UpdateStaticAddressLabel(context.Context, *UpdateStaticAddressLabelRequest) (*UpdateStaticAddressLabelResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateStaticAddressLabel not implemented") +} func (UnimplementedSwapClientServer) ListUnspentDeposits(context.Context, *ListUnspentDepositsRequest) (*ListUnspentDepositsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListUnspentDeposits not implemented") } @@ -1176,6 +1194,24 @@ func _SwapClient_NewStaticAddress_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _SwapClient_UpdateStaticAddressLabel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateStaticAddressLabelRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SwapClientServer).UpdateStaticAddressLabel(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/looprpc.SwapClient/UpdateStaticAddressLabel", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SwapClientServer).UpdateStaticAddressLabel(ctx, req.(*UpdateStaticAddressLabelRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _SwapClient_ListUnspentDeposits_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ListUnspentDepositsRequest) if err := dec(in); err != nil { @@ -1423,6 +1459,10 @@ var SwapClient_ServiceDesc = grpc.ServiceDesc{ MethodName: "NewStaticAddress", Handler: _SwapClient_NewStaticAddress_Handler, }, + { + MethodName: "UpdateStaticAddressLabel", + Handler: _SwapClient_UpdateStaticAddressLabel_Handler, + }, { MethodName: "ListUnspentDeposits", Handler: _SwapClient_ListUnspentDeposits_Handler, diff --git a/looprpc/perms.go b/looprpc/perms.go index d646f6671..dae9e5b30 100644 --- a/looprpc/perms.go +++ b/looprpc/perms.go @@ -87,6 +87,13 @@ var RequiredPermissions = map[string][]bakery.Op{ Entity: "loop", Action: "in", }}, + "/looprpc.SwapClient/UpdateStaticAddressLabel": {{ + Entity: "swap", + Action: "execute", + }, { + Entity: "loop", + Action: "in", + }}, "/looprpc.SwapClient/ListUnspentDeposits": {{ Entity: "swap", Action: "read", diff --git a/looprpc/swapclient.pb.json.go b/looprpc/swapclient.pb.json.go index ef1297dc3..4d1ca0469 100644 --- a/looprpc/swapclient.pb.json.go +++ b/looprpc/swapclient.pb.json.go @@ -663,6 +663,31 @@ func RegisterSwapClientJSONCallbacks(registry map[string]func(ctx context.Contex callback(string(respBytes), nil) } + registry["looprpc.SwapClient.UpdateStaticAddressLabel"] = func(ctx context.Context, + conn *grpc.ClientConn, reqJSON string, callback func(string, error)) { + + req := &UpdateStaticAddressLabelRequest{} + err := marshaler.Unmarshal([]byte(reqJSON), req) + if err != nil { + callback("", err) + return + } + + client := NewSwapClientClient(conn) + resp, err := client.UpdateStaticAddressLabel(ctx, req) + if err != nil { + callback("", err) + return + } + + respBytes, err := marshaler.Marshal(resp) + if err != nil { + callback("", err) + return + } + callback(string(respBytes), nil) + } + registry["looprpc.SwapClient.ListUnspentDeposits"] = func(ctx context.Context, conn *grpc.ClientConn, reqJSON string, callback func(string, error)) { From ed82de1c4626b81346daafbcd6b3fdf9a2cb9987 Mon Sep 17 00:00:00 2001 From: Gustavo Stingelin Date: Fri, 17 Jul 2026 17:43:38 -0300 Subject: [PATCH 5/6] staticaddr/loopd: wire static address labels --- loopd/swapclient_server.go | 80 +++++-- loopd/swapclient_server_test.go | 321 ++++++++++++++++++++++++++++- staticaddr/address/manager.go | 141 ++++++++----- staticaddr/address/manager_test.go | 115 ++++++++++- 4 files changed, 584 insertions(+), 73 deletions(-) diff --git a/loopd/swapclient_server.go b/loopd/swapclient_server.go index d89dbbce2..a2ec7dc61 100644 --- a/loopd/swapclient_server.go +++ b/loopd/swapclient_server.go @@ -17,6 +17,7 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/lightninglabs/aperture/l402" "github.com/lightninglabs/lndclient" @@ -1708,12 +1709,19 @@ func rpcInstantOut(instantOut *instantout.InstantOut) *looprpc.InstantOut { } // NewStaticAddress is the rpc endpoint for loop clients to request a new static -// address. +// address. The optional label is validated here because it is local operator +// metadata, not data the static-address server should interpret. func (s *swapClientServer) NewStaticAddress(ctx context.Context, - _ *looprpc.NewStaticAddressRequest) ( + req *looprpc.NewStaticAddressRequest) ( *looprpc.NewStaticAddressResponse, error) { - staticAddress, expiry, err := s.staticAddressManager.NewAddress(ctx) + label := req.GetLabel() + if err := labels.Validate(label); err != nil { + return nil, fmt.Errorf("invalid static address label: %w", err) + } + + staticAddress, expiry, storedLabel, err := + s.staticAddressManager.NewAddress(ctx, label) if err != nil { return nil, err } @@ -1721,6 +1729,43 @@ func (s *swapClientServer) NewStaticAddress(ctx context.Context, return &looprpc.NewStaticAddressResponse{ Address: staticAddress.String(), Expiry: uint32(expiry), + Label: storedLabel, + }, nil +} + +// UpdateStaticAddressLabel updates the local label for a static address so +// operators can rename it without changing the address script or contacting the +// Loop server. +func (s *swapClientServer) UpdateStaticAddressLabel(ctx context.Context, + req *looprpc.UpdateStaticAddressLabelRequest) ( + *looprpc.UpdateStaticAddressLabelResponse, error) { + + label := req.GetLabel() + if err := labels.Validate(label); err != nil { + return nil, fmt.Errorf("invalid static address label: %w", err) + } + + staticAddress, err := btcutil.DecodeAddress( + req.GetStaticAddress(), s.lnd.ChainParams, + ) + if err != nil { + return nil, fmt.Errorf("decode static address: %w", err) + } + + pkScript, err := txscript.PayToAddrScript(staticAddress) + if err != nil { + return nil, fmt.Errorf("static address pkScript: %w", err) + } + + if err := s.staticAddressManager.UpdateStaticAddressLabel( + ctx, pkScript, label, + ); err != nil { + return nil, fmt.Errorf("update static address label: %w", err) + } + + return &looprpc.UpdateStaticAddressLabelResponse{ + StaticAddress: staticAddress.String(), + Label: label, }, nil } @@ -1731,13 +1776,17 @@ func (s *swapClientServer) ListUnspentDeposits(ctx context.Context, // List all unspent utxos the wallet sees, regardless of the number of // confirmations. - staticAddress, utxos, err := s.staticAddressManager.ListUnspentRaw( + associatedUtxos, err := s.staticAddressManager.ListUnspentRaw( ctx, req.MinConfs, req.MaxConfs, ) if err != nil { return nil, err } + if associatedUtxos == nil { + return &looprpc.ListUnspentDepositsResponse{}, nil + } + // ListUnspentRaw returns the unspent wallet view of the backing lnd // wallet. Static loop-in initiation requires an active deposit record, // so only deposits that are both wallet-visible and tracked as @@ -1747,8 +1796,8 @@ func (s *swapClientServer) ListUnspentDeposits(ctx context.Context, isUnspent = make(map[wire.OutPoint]struct{}) ) - for _, utxo := range utxos { - outpoints = append(outpoints, utxo.OutPoint.String()) + for _, associatedUtxo := range associatedUtxos { + outpoints = append(outpoints, associatedUtxo.Utxo.OutPoint.String()) } err = s.depositManager.EnsureDepositsFresh(ctx) @@ -1777,18 +1826,20 @@ func (s *swapClientServer) ListUnspentDeposits(ctx context.Context, // Prepare the list of unspent deposits for the rpc response. var respUtxos []*looprpc.Utxo - for _, u := range utxos { - if _, ok := isUnspent[u.OutPoint]; !ok { + for _, associatedUtxo := range associatedUtxos { + utxo := associatedUtxo.Utxo + if _, ok := isUnspent[utxo.OutPoint]; !ok { continue } - utxo := &looprpc.Utxo{ - StaticAddress: staticAddress.String(), - AmountSat: int64(u.Value), - Confirmations: u.Confirmations, - Outpoint: u.OutPoint.String(), + respUtxo := &looprpc.Utxo{ + StaticAddress: associatedUtxo.Address.String(), + AmountSat: int64(utxo.Value), + Confirmations: utxo.Confirmations, + Outpoint: utxo.OutPoint.String(), + Label: associatedUtxo.Parameters.Label, } - respUtxos = append(respUtxos, utxo) + respUtxos = append(respUtxos, respUtxo) } return &looprpc.ListUnspentDepositsResponse{Utxos: respUtxos}, nil @@ -2188,6 +2239,7 @@ func (s *swapClientServer) GetStaticAddressSummary(ctx context.Context, ValueLoopedInSatoshis: valueLoopedIn, ValueChannelsOpened: valueChannelsOpened, ValueHtlcTimeoutSweepsSatoshis: htlcTimeoutSwept, + Label: params.Label, }, nil } diff --git a/loopd/swapclient_server_test.go b/loopd/swapclient_server_test.go index 0968cf386..8cca16e0d 100644 --- a/loopd/swapclient_server_test.go +++ b/loopd/swapclient_server_test.go @@ -11,6 +11,7 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btclog/v2" "github.com/lightninglabs/lndclient" @@ -1276,13 +1277,15 @@ func TestListSwapsFilterAndPagination(t *testing.T) { // mockAddressStore is a minimal in-memory store for address parameters. type mockAddressStore struct { - params []*script.Parameters + params []*script.Parameters + getAllStaticAddressesCalls int } func (s *mockAddressStore) CreateStaticAddress(_ context.Context, p *script.Parameters) error { s.params = append(s.params, p) + return nil } @@ -1299,6 +1302,8 @@ func (s *mockAddressStore) GetStaticAddress(_ context.Context, _ []byte) ( func (s *mockAddressStore) GetAllStaticAddresses(_ context.Context) ( []*script.Parameters, error) { + s.getAllStaticAddressesCalls++ + return s.params, nil } @@ -1329,6 +1334,203 @@ func (s *mockAddressStore) staticAddress(pkScript []byte) *script.Parameters { return nil } +// newStaticAddressLabelTestServer builds the smallest real RPC handler stack +// needed to prove labels round-trip as local static-address metadata. +func newStaticAddressLabelTestServer(t *testing.T, label string) ( + *swapClientServer, *mockAddressStore, string) { + + t.Helper() + + lnd := mock_lnd.NewMockLnd() + _, clientPubkey := mock_lnd.CreateKey(1) + _, serverPubkey := mock_lnd.CreateKey(2) + + addrMgr, err := address.NewManager(&address.ManagerConfig{ + ChainParams: lnd.ChainParams, + }, 1) + require.NoError(t, err) + + staticAddress, err := addrMgr.GetTaprootAddress( + clientPubkey, serverPubkey, 10, + ) + require.NoError(t, err) + + pkScript, err := txscript.PayToAddrScript(staticAddress) + require.NoError(t, err) + + addrStore := &mockAddressStore{} + err = addrStore.CreateStaticAddress( + context.Background(), &script.Parameters{ + ClientPubkey: clientPubkey, + ServerPubkey: serverPubkey, + Expiry: 10, + PkScript: pkScript, + Label: label, + }, + ) + require.NoError(t, err) + + addrMgr, err = address.NewManager(&address.ManagerConfig{ + Store: addrStore, + WalletKit: lnd.WalletKit, + ChainParams: lnd.ChainParams, + }, 1) + require.NoError(t, err) + + depositMgr := deposit.NewManager(&deposit.ManagerConfig{ + Store: &mockDepositStore{ + byOutpoint: make(map[string]*deposit.Deposit), + }, + }) + + return &swapClientServer{ + lnd: &lnd.LndServices, + staticAddressManager: addrMgr, + depositManager: depositMgr, + }, addrStore, staticAddress.String() +} + +// TestStaticAddressLabels covers the RPC boundary for local operator metadata: +// creation returns stored labels, updates mutate only local storage, and invalid +// labels are rejected before persistence changes. +func TestStaticAddressLabels(t *testing.T) { + ctx := context.Background() + + t.Run("new static address returns stored existing label", func(t *testing.T) { + server, store, _ := newStaticAddressLabelTestServer( + t, "stored label", + ) + + resp, err := server.NewStaticAddress( + ctx, &looprpc.NewStaticAddressRequest{Label: "requested"}, + ) + + require.NoError(t, err) + require.Equal(t, "stored label", resp.Label) + require.Len(t, store.params, 1) + require.Equal(t, "stored label", store.params[0].Label) + }) + + t.Run("new static address rejects invalid label", func(t *testing.T) { + server, store, _ := newStaticAddressLabelTestServer( + t, "stored label", + ) + + _, err := server.NewStaticAddress( + ctx, &looprpc.NewStaticAddressRequest{ + Label: labels.Reserved + " static", + }, + ) + + require.Error(t, err) + require.ErrorContains(t, err, "invalid static address label") + require.Len(t, store.params, 1) + require.Equal(t, "stored label", store.params[0].Label) + }) + + t.Run("summary returns stored label", func(t *testing.T) { + server, _, _ := newStaticAddressLabelTestServer( + t, "summary label", + ) + + resp, err := server.GetStaticAddressSummary( + ctx, &looprpc.StaticAddressSummaryRequest{}, + ) + + require.NoError(t, err) + require.Equal(t, "summary label", resp.Label) + }) + + t.Run("update changes stored label", func(t *testing.T) { + server, store, staticAddress := newStaticAddressLabelTestServer( + t, "old label", + ) + + resp, err := server.UpdateStaticAddressLabel( + ctx, &looprpc.UpdateStaticAddressLabelRequest{ + StaticAddress: staticAddress, + Label: "new label", + }, + ) + + require.NoError(t, err) + require.Equal(t, staticAddress, resp.StaticAddress) + require.Equal(t, "new label", resp.Label) + require.Len(t, store.params, 1) + require.Equal(t, "new label", store.params[0].Label) + }) + + t.Run("update clears stored label", func(t *testing.T) { + server, store, staticAddress := newStaticAddressLabelTestServer( + t, "old label", + ) + + resp, err := server.UpdateStaticAddressLabel( + ctx, &looprpc.UpdateStaticAddressLabelRequest{ + StaticAddress: staticAddress, + Label: "", + }, + ) + + require.NoError(t, err) + require.Equal(t, staticAddress, resp.StaticAddress) + require.Empty(t, resp.Label) + require.Len(t, store.params, 1) + require.Empty(t, store.params[0].Label) + }) + + t.Run("update unknown static address fails", func(t *testing.T) { + server, _, _ := newStaticAddressLabelTestServer(t, "old label") + + unknownAddress, err := btcutil.NewAddressScriptHash( + []byte{1}, server.lnd.ChainParams, + ) + require.NoError(t, err) + + _, err = server.UpdateStaticAddressLabel( + ctx, &looprpc.UpdateStaticAddressLabelRequest{ + StaticAddress: unknownAddress.String(), + Label: "new label", + }, + ) + + require.Error(t, err) + require.ErrorContains(t, err, "update static address label") + }) + + t.Run("update foreign static address fails", func(t *testing.T) { + server, _, _ := newStaticAddressLabelTestServer(t, "old label") + + _, err := server.UpdateStaticAddressLabel( + ctx, &looprpc.UpdateStaticAddressLabelRequest{ + StaticAddress: mainnetAddr.String(), + Label: "new label", + }, + ) + + require.Error(t, err) + require.ErrorContains(t, err, "decode static address") + }) + + t.Run("update rejects invalid label", func(t *testing.T) { + server, store, staticAddress := newStaticAddressLabelTestServer( + t, "old label", + ) + + _, err := server.UpdateStaticAddressLabel( + ctx, &looprpc.UpdateStaticAddressLabelRequest{ + StaticAddress: staticAddress, + Label: labels.Reserved + " static", + }, + ) + + require.Error(t, err) + require.ErrorContains(t, err, "invalid static address label") + require.Len(t, store.params, 1) + require.Equal(t, "old label", store.params[0].Label) + }) +} + // mockDepositStore implements deposit.Store minimally for DepositsForOutpoints. type mockDepositStore struct { byOutpoint map[string]*deposit.Deposit @@ -1464,7 +1666,17 @@ func TestListUnspentDeposits(t *testing.T) { // Prepare a single static address parameter set. _, client := mock_lnd.CreateKey(1) _, server := mock_lnd.CreateKey(2) - pkScript := []byte("pkscript") + addrMgr, err := address.NewManager(&address.ManagerConfig{ + ChainParams: mock.ChainParams, + }, 1) + require.NoError(t, err) + + staticAddress, err := addrMgr.GetTaprootAddress(client, server, 10) + require.NoError(t, err) + + pkScript, err := txscript.PayToAddrScript(staticAddress) + require.NoError(t, err) + addrParams := &script.Parameters{ ClientPubkey: client, ServerPubkey: server, @@ -1472,10 +1684,13 @@ func TestListUnspentDeposits(t *testing.T) { PkScript: pkScript, } - addrStore := &mockAddressStore{params: []*script.Parameters{addrParams}} + addrStore := &mockAddressStore{ + params: []*script.Parameters{addrParams}, + } + addrParams.Label = "list label" // Build an address manager using our mock lnd and fake address store. - addrMgr, err := address.NewManager(&address.ManagerConfig{ + addrMgr, err = address.NewManager(&address.ManagerConfig{ Store: addrStore, WalletKit: mock.WalletKit, ChainParams: mock.ChainParams, @@ -1544,6 +1759,7 @@ func TestListUnspentDeposits(t *testing.T) { ) require.NoError(t, err) require.Equal(t, 1, depMgr.ensureDepositsFreshCalls) + require.Equal(t, 1, addrStore.getAllStaticAddressesCalls) // Expect the Deposited utxo only. require.Len(t, resp.Utxos, 1) @@ -1553,6 +1769,7 @@ func TestListUnspentDeposits(t *testing.T) { // Confirm address string is non-empty and the // same across utxos. require.NotEmpty(t, u.StaticAddress) + require.Equal(t, "list label", u.Label) } _, ok := got[utxoDeposited.OutPoint.String()] require.True(t, ok) @@ -1588,6 +1805,7 @@ func TestListUnspentDeposits(t *testing.T) { got := map[string]struct{}{} for _, u := range resp.Utxos { got[u.Outpoint] = struct{}{} + require.Equal(t, "list label", u.Label) } _, ok := got[utxoDeposited.OutPoint.String()] require.True(t, ok) @@ -1625,5 +1843,100 @@ func TestListUnspentDeposits(t *testing.T) { t, utxoConfirmedUnknown.OutPoint.String(), resp.Utxos[0].Outpoint, ) + require.NotEmpty(t, resp.Utxos[0].StaticAddress) + require.Equal(t, "list label", resp.Utxos[0].Label) + }) + + t.Run("responses retain per address metadata", func(t *testing.T) { + _, secondClient := mock_lnd.CreateKey(3) + _, secondServer := mock_lnd.CreateKey(4) + secondAddress, err := addrMgr.GetTaprootAddress( + secondClient, secondServer, 10, + ) + require.NoError(t, err) + + secondPkScript, err := txscript.PayToAddrScript(secondAddress) + require.NoError(t, err) + + secondParams := &script.Parameters{ + ClientPubkey: secondClient, + ServerPubkey: secondServer, + Expiry: 10, + PkScript: secondPkScript, + Label: "second label", + } + addrStore.params = append(addrStore.params, secondParams) + + secondUtxo := &lnwallet.Utxo{ + AddressType: lnwallet.TaprootPubkey, + Value: 250_001, + Confirmations: 1, + PkScript: secondPkScript, + OutPoint: wire.OutPoint{ + Hash: chainhash.Hash{9}, + Index: 9, + }, + } + mock.SetListUnspent([]*lnwallet.Utxo{ + utxoDeposited, secondUtxo, + }) + + depMgr := buildDepositMgr(map[wire.OutPoint]fsm.StateType{ + utxoDeposited.OutPoint: deposit.Deposited, + secondUtxo.OutPoint: deposit.Deposited, + }) + server := &swapClientServer{ + staticAddressManager: addrMgr, + depositManager: depMgr, + } + + resp, err := server.ListUnspentDeposits( + ctx, &looprpc.ListUnspentDepositsRequest{}, + ) + require.NoError(t, err) + require.Len(t, resp.Utxos, 2) + + got := make(map[string]*looprpc.Utxo, len(resp.Utxos)) + for _, utxo := range resp.Utxos { + got[utxo.Outpoint] = utxo + } + require.Equal( + t, staticAddress.String(), + got[utxoDeposited.OutPoint.String()].StaticAddress, + ) + require.Equal( + t, "list label", got[utxoDeposited.OutPoint.String()].Label, + ) + require.Equal( + t, secondAddress.String(), + got[secondUtxo.OutPoint.String()].StaticAddress, + ) + require.Equal( + t, "second label", got[secondUtxo.OutPoint.String()].Label, + ) + }) + + t.Run("no static address returns an empty result", func(t *testing.T) { + addrStore := &mockAddressStore{} + addrMgr, err := address.NewManager(&address.ManagerConfig{ + Store: addrStore, + WalletKit: mock.WalletKit, + ChainParams: mock.ChainParams, + }, 1) + require.NoError(t, err) + + depMgr := &listUnspentDepositManager{} + server := &swapClientServer{ + staticAddressManager: addrMgr, + depositManager: depMgr, + } + + resp, err := server.ListUnspentDeposits( + ctx, &looprpc.ListUnspentDepositsRequest{}, + ) + + require.NoError(t, err) + require.Empty(t, resp.Utxos) + require.Zero(t, depMgr.ensureDepositsFreshCalls) }) } diff --git a/staticaddr/address/manager.go b/staticaddr/address/manager.go index 322eed739..67649b729 100644 --- a/staticaddr/address/manager.go +++ b/staticaddr/address/manager.go @@ -1,7 +1,6 @@ package address import ( - "bytes" "context" "fmt" "sync" @@ -64,6 +63,13 @@ type Manager struct { currentHeight atomic.Int32 } +// StaticAddressUtxo associates a wallet UTXO with its static address metadata. +type StaticAddressUtxo struct { + Utxo *lnwallet.Utxo + Parameters *script.Parameters + Address *btcutil.AddressTaproot +} + // NewManager creates a new address manager. func NewManager(cfg *ManagerConfig, currentHeight int32) (*Manager, error) { if currentHeight <= 0 { @@ -107,10 +113,11 @@ func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error { } } -// NewAddress creates a new static address with the server or returns an -// existing one. -func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot, - int64, error) { +// NewAddress creates a new static address with the server while carrying the +// label only as local operator metadata; the label is stored for display and is +// never sent to the Loop server or used in the address script. +func (m *Manager) NewAddress(ctx context.Context, label string) ( + *btcutil.AddressTaproot, int64, string, error) { // If there's already a static address in the database, we can return // it. @@ -119,23 +126,26 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot, if err != nil { m.Unlock() - return nil, 0, err + return nil, 0, "", err } if len(addresses) > 0 { - clientPubKey := addresses[0].ClientPubkey - serverPubKey := addresses[0].ServerPubkey - expiry := int64(addresses[0].Expiry) - defer m.Unlock() + // TODO: When multi-address support lands, resolve an existing address + // by label or create a new one when no matching label exists. + params := addresses[0] + clientPubKey := params.ClientPubkey + serverPubKey := params.ServerPubkey + expiry := int64(params.Expiry) + address, err := m.GetTaprootAddress( clientPubKey, serverPubKey, expiry, ) if err != nil { - return nil, 0, err + return nil, 0, "", err } - return address, expiry, nil + return address, expiry, params.Label, nil } m.Unlock() @@ -143,14 +153,14 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot, // address per L402 token allowed. err = m.cfg.FetchL402(ctx) if err != nil { - return nil, 0, err + return nil, 0, "", err } clientPubKey, err := m.cfg.WalletKit.DeriveNextKey( ctx, swap.StaticAddressKeyFamily, ) if err != nil { - return nil, 0, err + return nil, 0, "", err } // Send our clientPubKey to the server and wait for the server to @@ -163,21 +173,21 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot, }, ) if err != nil { - return nil, 0, err + return nil, 0, "", err } if resp == nil { - return nil, 0, fmt.Errorf("missing server new address response") + return nil, 0, "", fmt.Errorf("missing server new address response") } serverParams := resp.GetParams() if err := validateServerAddressParams(serverParams); err != nil { - return nil, 0, err + return nil, 0, "", err } serverPubKey, err := btcec.ParsePubKey(serverParams.GetServerKey()) if err != nil { - return nil, 0, err + return nil, 0, "", err } staticAddress, err := script.NewStaticAddress( @@ -185,12 +195,12 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot, clientPubKey.PubKey, serverPubKey, ) if err != nil { - return nil, 0, err + return nil, 0, "", err } pkScript, err := staticAddress.StaticAddressScript() if err != nil { - return nil, 0, err + return nil, 0, "", err } // Create the static address from the parameters the server provided and @@ -208,10 +218,11 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot, protocolVersion, ), InitiationHeight: m.currentHeight.Load(), + Label: label, } err = m.cfg.Store.CreateStaticAddress(ctx, addrParams) if err != nil { - return nil, 0, err + return nil, 0, "", err } // Import the static address tapscript into our lnd wallet, so we can @@ -221,7 +232,7 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot, ) addr, err := m.cfg.WalletKit.ImportTaprootScript(ctx, tapScript) if err != nil { - return nil, 0, err + return nil, 0, "", err } log.Infof("Imported static address taproot script to lnd wallet: %v", @@ -231,10 +242,10 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot, clientPubKey.PubKey, serverPubKey, int64(serverParams.Expiry), ) if err != nil { - return nil, 0, err + return nil, 0, "", err } - return address, int64(serverParams.Expiry), nil + return address, int64(serverParams.Expiry), label, nil } // validateServerAddressParams validates the server-controlled static address @@ -290,23 +301,17 @@ func (m *Manager) GetTaprootAddress(clientPubkey, serverPubkey *btcec.PublicKey, ) } -// ListUnspentRaw returns a list of utxos at the static address. +// ListUnspentRaw returns wallet UTXOs with their matching static address data. func (m *Manager) ListUnspentRaw(ctx context.Context, minConfs, - maxConfs int32) (*btcutil.AddressTaproot, []*lnwallet.Utxo, error) { + maxConfs int32) ([]StaticAddressUtxo, error) { addresses, err := m.cfg.Store.GetAllStaticAddresses(ctx) - switch { - case err != nil: - return nil, nil, err - - case len(addresses) == 0: - return nil, nil, nil - - case len(addresses) > 1: - return nil, nil, fmt.Errorf("more than one address found") + if err != nil { + return nil, err + } + if len(addresses) == 0 { + return nil, nil } - - staticAddress := addresses[0] // List all unspent utxos the wallet sees, regardless of the number of // confirmations. @@ -314,27 +319,45 @@ func (m *Manager) ListUnspentRaw(ctx context.Context, minConfs, ctx, minConfs, maxConfs, ) if err != nil { - return nil, nil, err + return nil, err } - // Filter the list of lnd's unspent utxos for the pkScript of our static - // address. - var filteredUtxos []*lnwallet.Utxo + paramsByPkScript := make(map[string]*script.Parameters, len(addresses)) + for _, params := range addresses { + paramsByPkScript[string(params.PkScript)] = params + } + + addressByPkScript := make(map[string]*btcutil.AddressTaproot) + associatedUtxos := make([]StaticAddressUtxo, 0, len(utxos)) for _, utxo := range utxos { - if bytes.Equal(utxo.PkScript, staticAddress.PkScript) { - filteredUtxos = append(filteredUtxos, utxo) + pkScript := string(utxo.PkScript) + params, ok := paramsByPkScript[pkScript] + if !ok { + continue } - } - taprootAddress, err := m.GetTaprootAddress( - staticAddress.ClientPubkey, staticAddress.ServerPubkey, - int64(staticAddress.Expiry), - ) - if err != nil { - return nil, nil, err + taprootAddress, ok := addressByPkScript[pkScript] + if !ok { + var err error + taprootAddress, err = m.GetTaprootAddress( + params.ClientPubkey, params.ServerPubkey, + int64(params.Expiry), + ) + if err != nil { + return nil, err + } + + addressByPkScript[pkScript] = taprootAddress + } + + associatedUtxos = append(associatedUtxos, StaticAddressUtxo{ + Utxo: utxo, + Parameters: params, + Address: taprootAddress, + }) } - return taprootAddress, filteredUtxos, nil + return associatedUtxos, nil } // GetStaticAddressParameters returns the parameters of the static address. @@ -353,6 +376,15 @@ func (m *Manager) GetStaticAddressParameters(ctx context.Context) ( return params[0], nil } +// UpdateStaticAddressLabel updates only the local label for the static address +// pkScript so operators can rename their reusable address without changing its +// script, deposits, or Loop server protocol state. +func (m *Manager) UpdateStaticAddressLabel(ctx context.Context, + pkScript []byte, label string) error { + + return m.cfg.Store.UpdateStaticAddressLabel(ctx, pkScript, label) +} + // GetStaticAddress returns a taproot address for the given client and server // public keys and expiry. func (m *Manager) GetStaticAddress(ctx context.Context) (*script.StaticAddress, @@ -378,10 +410,15 @@ func (m *Manager) GetStaticAddress(ctx context.Context) (*script.StaticAddress, func (m *Manager) ListUnspent(ctx context.Context, minConfs, maxConfs int32) ([]*lnwallet.Utxo, error) { - _, utxos, err := m.ListUnspentRaw(ctx, minConfs, maxConfs) + associatedUtxos, err := m.ListUnspentRaw(ctx, minConfs, maxConfs) if err != nil { return nil, err } + utxos := make([]*lnwallet.Utxo, 0, len(associatedUtxos)) + for _, associatedUtxo := range associatedUtxos { + utxos = append(utxos, associatedUtxo.Utxo) + } + return utxos, nil } diff --git a/staticaddr/address/manager_test.go b/staticaddr/address/manager_test.go index b7bbf79ae..3ee438ce4 100644 --- a/staticaddr/address/manager_test.go +++ b/staticaddr/address/manager_test.go @@ -16,6 +16,7 @@ import ( "github.com/lightninglabs/loop/test" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" + "github.com/lightningnetwork/lnd/lnwallet" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "google.golang.org/grpc" @@ -124,7 +125,7 @@ func TestManager(t *testing.T) { require.NoError(t, err) // Create a new static address. - taprootAddress, expiry, err := testContext.manager.NewAddress(ctxb) + taprootAddress, expiry, _, err := testContext.manager.NewAddress(ctxb, "") require.NoError(t, err) // The addresses have to match. @@ -134,6 +135,41 @@ func TestManager(t *testing.T) { require.EqualValues(t, defaultExpiry, expiry) } +// TestNewAddressPreservesExistingLabelWhenDifferentLabelRequested ensures that +// an existing static address keeps its stored label when callers request a +// different label. +func TestNewAddressPreservesExistingLabelWhenDifferentLabelRequested(t *testing.T) { + ctx := t.Context() + testContext := NewAddressManagerTestContext(t) + _, _, _, err := testContext.manager.NewAddress(ctx, "stored") + require.NoError(t, err) + + _, _, label, err := testContext.manager.NewAddress(ctx, "treasury") + + require.NoError(t, err) + require.Equal(t, "stored", label) + + params, err := testContext.manager.GetStaticAddressParameters(ctx) + require.NoError(t, err) + require.Equal(t, "stored", params.Label) +} + +func TestNewAddressPreservesExistingLabelWhenNoLabelRequested(t *testing.T) { + ctx := t.Context() + testContext := NewAddressManagerTestContext(t) + _, _, _, err := testContext.manager.NewAddress(ctx, "treasury") + require.NoError(t, err) + + _, _, label, err := testContext.manager.NewAddress(ctx, "") + + require.NoError(t, err) + require.Equal(t, "treasury", label) + + params, err := testContext.manager.GetStaticAddressParameters(ctx) + require.NoError(t, err) + require.Equal(t, "treasury", params.Label) +} + // TestNewAddressValidatesServerResponse tests that the untrusted // ServerNewAddress response is validated before the address script is created. func TestNewAddressValidatesServerResponse(t *testing.T) { @@ -211,7 +247,7 @@ func TestNewAddressValidatesServerResponse(t *testing.T) { t, test.resp, ) - _, _, err := testContext.manager.NewAddress(t.Context()) + _, _, _, err := testContext.manager.NewAddress(t.Context(), "") require.ErrorContains(t, err, test.expected) }) } @@ -223,11 +259,84 @@ func TestNewAddressAcceptsMaxCSVExpiry(t *testing.T) { t, newServerNewAddressResponse(maxStaticAddressCSVExpiry), ) - _, expiry, err := testContext.manager.NewAddress(t.Context()) + _, expiry, _, err := testContext.manager.NewAddress(t.Context(), "") require.NoError(t, err) require.EqualValues(t, maxStaticAddressCSVExpiry, expiry) } +// TestListUnspentSupportsMultipleStaticAddresses verifies that UTXOs retain the +// correct metadata and address association across multiple static addresses. +func TestListUnspentSupportsMultipleStaticAddresses(t *testing.T) { + ctx := t.Context() + testContext := NewAddressManagerTestContext(t) + firstAddress, _, _, err := testContext.manager.NewAddress(ctx, "first") + require.NoError(t, err) + + firstParams, err := testContext.manager.GetStaticAddressParameters(ctx) + require.NoError(t, err) + + secondParams := testAddressParams(t) + secondParams.Label = "second" + err = testContext.manager.cfg.Store.CreateStaticAddress(ctx, secondParams) + require.NoError(t, err) + secondAddress, err := testContext.manager.GetTaprootAddress( + secondParams.ClientPubkey, secondParams.ServerPubkey, + int64(secondParams.Expiry), + ) + require.NoError(t, err) + + firstUtxo := &lnwallet.Utxo{ + PkScript: firstParams.PkScript, + OutPoint: wire.OutPoint{Index: 1}, + } + secondUtxo := &lnwallet.Utxo{ + PkScript: secondParams.PkScript, + OutPoint: wire.OutPoint{Index: 2}, + } + unknownUtxo := &lnwallet.Utxo{ + PkScript: []byte("unknown"), + OutPoint: wire.OutPoint{Index: 3}, + } + testContext.mockLnd.SetListUnspent([]*lnwallet.Utxo{ + firstUtxo, secondUtxo, unknownUtxo, + }) + + associatedUtxos, err := testContext.manager.ListUnspentRaw(ctx, 0, 0) + + require.NoError(t, err) + require.Len(t, associatedUtxos, 2) + + gotAssociations := make(map[wire.OutPoint]StaticAddressUtxo, + len(associatedUtxos)) + for _, associatedUtxo := range associatedUtxos { + gotAssociations[associatedUtxo.Utxo.OutPoint] = associatedUtxo + require.Equal( + t, string(associatedUtxo.Utxo.PkScript), + string(associatedUtxo.Parameters.PkScript), + ) + } + require.Equal(t, firstParams, gotAssociations[firstUtxo.OutPoint].Parameters) + require.Equal(t, firstAddress, gotAssociations[firstUtxo.OutPoint].Address) + require.Equal(t, secondParams, gotAssociations[secondUtxo.OutPoint].Parameters) + require.Equal(t, secondAddress, gotAssociations[secondUtxo.OutPoint].Address) + _, ok := gotAssociations[unknownUtxo.OutPoint] + require.False(t, ok) + + utxos, err := testContext.manager.ListUnspent(ctx, 0, 0) + + require.NoError(t, err) + require.Len(t, utxos, 2) + + got := make(map[wire.OutPoint]*lnwallet.Utxo, len(utxos)) + for _, utxo := range utxos { + got[utxo.OutPoint] = utxo + } + require.Equal(t, firstUtxo, got[firstUtxo.OutPoint]) + require.Equal(t, secondUtxo, got[secondUtxo.OutPoint]) + _, ok = got[unknownUtxo.OutPoint] + require.False(t, ok) +} + // GenerateExpectedTaprootAddress generates the expected taproot address that // the predefined parameters are supposed to generate. func GenerateExpectedTaprootAddress(t *ManagerTestContext) ( From 92270e0ece9c244a950c9db249a6b06956692a85 Mon Sep 17 00:00:00 2001 From: Gustavo Stingelin Date: Fri, 17 Jul 2026 17:46:36 -0300 Subject: [PATCH 6/6] cmd/loop: support static address labels --- cmd/loop/staticaddr.go | 86 +++++- cmd/loop/staticaddr_test.go | 248 ++++++++++++++++++ cmd/loop/testdata/sessions/AGENTS.md | 1 + .../01_loop-static-new-label-treasury.json | 82 ++++++ ...02_loop-static-summary-label-treasury.json | 74 ++++++ .../03_loop-static-updatelabel-ops.json | 61 +++++ .../04_loop-static-updatelabel-ops-again.json | 61 +++++ .../05_loop-static-updatelabel-clear.json | 61 +++++ .../06_loop-static-updatelabel-treasury.json | 61 +++++ ...07_loop-static-summary-label-treasury.json | 74 ++++++ ...oop-static-listunspent-label-treasury.json | 73 ++++++ .../09_loop-static-l-label-treasury.json | 73 ++++++ .../static-loop-in/01_loop-static-new.json | 9 +- .../static-loop-in/04_loop-static.json | 1 + .../05_loop-static-listunspent.json | 4 +- .../static-loop-in/06_loop-static-l.json | 4 +- .../08_loop-static-listunspent.json | 4 +- .../09_loop-static-listunspent.json | 4 +- .../11_loop-static-summary.json | 2 + ...0_loop-static-summary-channels-opened.json | 2 + docs/loop.1 | 13 + docs/loop.md | 26 +- 22 files changed, 1013 insertions(+), 11 deletions(-) create mode 100644 cmd/loop/testdata/sessions/static-labels/01_loop-static-new-label-treasury.json create mode 100644 cmd/loop/testdata/sessions/static-labels/02_loop-static-summary-label-treasury.json create mode 100644 cmd/loop/testdata/sessions/static-labels/03_loop-static-updatelabel-ops.json create mode 100644 cmd/loop/testdata/sessions/static-labels/04_loop-static-updatelabel-ops-again.json create mode 100644 cmd/loop/testdata/sessions/static-labels/05_loop-static-updatelabel-clear.json create mode 100644 cmd/loop/testdata/sessions/static-labels/06_loop-static-updatelabel-treasury.json create mode 100644 cmd/loop/testdata/sessions/static-labels/07_loop-static-summary-label-treasury.json create mode 100644 cmd/loop/testdata/sessions/static-labels/08_loop-static-listunspent-label-treasury.json create mode 100644 cmd/loop/testdata/sessions/static-labels/09_loop-static-l-label-treasury.json diff --git a/cmd/loop/staticaddr.go b/cmd/loop/staticaddr.go index c973a0028..c0e3b5a4f 100644 --- a/cmd/loop/staticaddr.go +++ b/cmd/loop/staticaddr.go @@ -29,6 +29,7 @@ var staticAddressCommands = &cli.Command{ Usage: "perform on-chain to off-chain swaps using static addresses.", Commands: []*cli.Command{ newStaticAddressCommand, + updateStaticAddressLabelCommand, listUnspentCommand, listDepositsCommand, listWithdrawalsCommand, @@ -40,6 +41,8 @@ var staticAddressCommands = &cli.Command{ }, } +// newStaticAddressCommand creates a static address and lets operators +// optionally set a local label at creation time. var newStaticAddressCommand = &cli.Command{ Name: "new", Aliases: []string{"n"}, @@ -51,14 +54,24 @@ var newStaticAddressCommand = &cli.Command{ funds can either be cooperatively spent with a signature from the server or looped in. `, + Flags: []cli.Flag{ + labelFlag, + }, Action: newStaticAddress, } +// newStaticAddress requests a new static address while keeping the label as +// local operator metadata. func newStaticAddress(ctx context.Context, cmd *cli.Command) error { if cmd.NArg() > 0 { return showCommandHelp(ctx, cmd) } + label := cmd.String(labelFlag.Name) + if err := labels.Validate(label); err != nil { + return err + } + err := displayNewAddressWarning() if err != nil { return err @@ -71,7 +84,78 @@ func newStaticAddress(ctx context.Context, cmd *cli.Command) error { defer cleanup() resp, err := client.NewStaticAddress( - ctx, &looprpc.NewStaticAddressRequest{}, + ctx, &looprpc.NewStaticAddressRequest{ + Label: label, + }, + ) + if err != nil { + return err + } + + printRespJSON(resp) + + return nil +} + +// updateStaticAddressLabelCommand updates local metadata for an existing static +// address so operators can relabel it without affecting the address script or +// Loop server protocol state. +var updateStaticAddressLabelCommand = &cli.Command{ + Name: "updatelabel", + Usage: "Update the label for a static address.", + ArgsUsage: "